summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--!NetSurf/ChkSprites,ffbbin1531 -> 0 bytes
-rw-r--r--.clang-format94
-rw-r--r--.gitignore24
-rw-r--r--Docs/BUILDING-Cocoa87
-rw-r--r--Docs/Doxyfile1826
-rw-r--r--Docs/JavaScript16
-rw-r--r--Docs/Options241
-rw-r--r--Docs/QUICK-START108
-rw-r--r--Docs/USING-Monkey318
-rw-r--r--Docs/core-window-interface677
-rw-r--r--Makefile90
-rw-r--r--Makefile.config.example6
-rw-r--r--Makefile.defaults22
-rw-r--r--content/content.c93
-rw-r--r--content/content.h22
-rw-r--r--content/content_factory.c6
-rw-r--r--content/content_protected.h9
-rw-r--r--content/fetch.c89
-rw-r--r--content/fetchers/curl.c118
-rw-r--r--content/fetchers/data.c17
-rw-r--r--content/fetchers/resource.c6
-rw-r--r--content/fs_backing_store.c246
-rw-r--r--content/handlers/Makefile11
-rw-r--r--content/handlers/css/css.c32
-rw-r--r--content/handlers/css/dump.c46
-rw-r--r--content/handlers/css/hints.c7
-rw-r--r--content/handlers/css/select.c69
-rw-r--r--content/handlers/css/select.h1
-rw-r--r--content/handlers/css/utils.c144
-rw-r--r--content/handlers/css/utils.h115
-rw-r--r--content/handlers/html/Makefile7
-rw-r--r--content/handlers/html/box.c (renamed from render/box.c)77
-rw-r--r--content/handlers/html/box.h (renamed from render/box.h)31
-rw-r--r--content/handlers/html/box_construct.c (renamed from render/box_construct.c)85
-rw-r--r--content/handlers/html/box_normalise.c (renamed from render/box_normalise.c)169
-rw-r--r--content/handlers/html/box_textarea.c (renamed from render/box_textarea.c)40
-rw-r--r--content/handlers/html/box_textarea.h (renamed from render/box_textarea.h)19
-rw-r--r--content/handlers/html/font.c (renamed from render/font.c)25
-rw-r--r--content/handlers/html/font.h (renamed from render/font.h)16
-rw-r--r--content/handlers/html/form.c (renamed from render/form.c)399
-rw-r--r--content/handlers/html/form_internal.h (renamed from render/form_internal.h)8
-rw-r--r--content/handlers/html/html.c (renamed from render/html.c)207
-rw-r--r--content/handlers/html/html.h (renamed from render/html.h)96
-rw-r--r--content/handlers/html/html_css.c (renamed from render/html_css.c)57
-rw-r--r--content/handlers/html/html_css_fetcher.c (renamed from render/html_css_fetcher.c)53
-rw-r--r--content/handlers/html/html_forms.c (renamed from render/html_forms.c)12
-rw-r--r--content/handlers/html/html_interaction.c (renamed from render/html_interaction.c)176
-rw-r--r--content/handlers/html/html_internal.h (renamed from render/html_internal.h)74
-rw-r--r--content/handlers/html/html_object.c (renamed from render/html_object.c)119
-rw-r--r--content/handlers/html/html_redraw.c (renamed from render/html_redraw.c)1412
-rw-r--r--content/handlers/html/html_redraw_border.c928
-rw-r--r--content/handlers/html/html_save.h46
-rw-r--r--content/handlers/html/html_script.c (renamed from render/html_script.c)112
-rw-r--r--content/handlers/html/imagemap.c (renamed from render/imagemap.c)37
-rw-r--r--content/handlers/html/imagemap.h (renamed from render/imagemap.h)9
-rw-r--r--content/handlers/html/layout.c (renamed from render/layout.c)3701
-rw-r--r--content/handlers/html/layout.h (renamed from render/layout.h)37
-rw-r--r--content/handlers/html/search.c (renamed from render/search.c)31
-rw-r--r--content/handlers/html/search.h (renamed from render/search.h)9
-rw-r--r--content/handlers/html/table.c (renamed from render/table.c)450
-rw-r--r--content/handlers/html/table.h (renamed from render/table.h)17
-rw-r--r--content/handlers/image/bmp.c21
-rw-r--r--content/handlers/image/gif.c17
-rw-r--r--content/handlers/image/ico.c19
-rw-r--r--content/handlers/image/image.c14
-rw-r--r--content/handlers/image/image_cache.c125
-rw-r--r--content/handlers/image/jpeg.c61
-rw-r--r--content/handlers/image/nssprite.c54
-rw-r--r--content/handlers/image/png.c30
-rw-r--r--content/handlers/image/rsvg.c66
-rw-r--r--content/handlers/image/svg.c57
-rw-r--r--content/handlers/javascript/duktape/Console.bnd6
-rw-r--r--content/handlers/javascript/duktape/Document.bnd21
-rw-r--r--content/handlers/javascript/duktape/Element.bnd2
-rw-r--r--content/handlers/javascript/duktape/EventTarget.bnd3
-rw-r--r--content/handlers/javascript/duktape/Location.bnd8
-rw-r--r--content/handlers/javascript/duktape/Makefile2
-rw-r--r--content/handlers/javascript/duktape/Window.bnd20
-rw-r--r--content/handlers/javascript/duktape/duk_config.h1561
-rw-r--r--content/handlers/javascript/duktape/duk_custom.h1
-rw-r--r--content/handlers/javascript/duktape/dukky.c144
-rw-r--r--content/handlers/javascript/duktape/dukky.h4
-rw-r--r--content/handlers/javascript/duktape/duktape.c69597
-rw-r--r--content/handlers/javascript/duktape/duktape.h1425
-rw-r--r--content/handlers/text/Makefile3
-rw-r--r--content/handlers/text/textplain.c (renamed from render/textplain.c)1172
-rw-r--r--content/handlers/text/textplain.h139
-rw-r--r--content/hlcache.c36
-rw-r--r--content/llcache.c379
-rw-r--r--content/mimesniff.c357
-rw-r--r--content/mimesniff.h18
-rw-r--r--content/urldb.c1443
-rw-r--r--content/urldb.h57
-rw-r--r--desktop/Makefile2
-rw-r--r--desktop/browser.c624
-rw-r--r--desktop/browser_history.c588
-rw-r--r--desktop/browser_history.h162
-rw-r--r--desktop/browser_private.h214
-rw-r--r--desktop/cookie_manager.c19
-rw-r--r--desktop/font_haru.c26
-rw-r--r--desktop/frames.c52
-rw-r--r--desktop/global_history.c22
-rw-r--r--desktop/gui_factory.c17
-rw-r--r--desktop/hotlist.c249
-rw-r--r--desktop/hotlist.h14
-rw-r--r--desktop/knockout.c778
-rw-r--r--desktop/knockout.h14
-rw-r--r--desktop/local_history.c446
-rw-r--r--desktop/local_history.h144
-rw-r--r--desktop/mouse.c2
-rw-r--r--desktop/netsurf.c40
-rw-r--r--desktop/options.h5
-rw-r--r--desktop/plot_style.c14
-rw-r--r--desktop/print.c48
-rw-r--r--desktop/print.h3
-rw-r--r--desktop/save_complete.c37
-rw-r--r--desktop/save_pdf.c59
-rw-r--r--desktop/save_text.c12
-rw-r--r--desktop/scrollbar.c777
-rw-r--r--desktop/scrollbar.h98
-rw-r--r--desktop/searchweb.c20
-rw-r--r--desktop/selection.c75
-rw-r--r--desktop/selection.h7
-rw-r--r--desktop/sslcert_viewer.c214
-rw-r--r--desktop/sslcert_viewer.h15
-rw-r--r--desktop/system_colour.c23
-rw-r--r--desktop/system_colour.h46
-rw-r--r--desktop/textarea.c175
-rw-r--r--desktop/textarea.h171
-rw-r--r--desktop/textinput.c6
-rw-r--r--desktop/textinput.h14
-rw-r--r--desktop/treeview.c2535
-rw-r--r--desktop/treeview.h212
-rw-r--r--desktop/version.c4
-rw-r--r--docs/Doxyfile2389
-rw-r--r--docs/PACKAGING-GTK (renamed from Docs/PACKAGING-GTK)3
-rw-r--r--docs/UnimplementedJavascript.txt (renamed from Docs/UnimplementedJavascript.txt)0
-rw-r--r--docs/building-AmigaCross.md (renamed from Docs/BUILDING-AmigaCross)0
-rw-r--r--docs/building-AmigaOS.md (renamed from Docs/BUILDING-AmigaOS)0
-rw-r--r--docs/building-Framebuffer.md (renamed from Docs/BUILDING-Framebuffer)0
-rw-r--r--docs/building-GTK.md (renamed from Docs/BUILDING-GTK)0
-rw-r--r--docs/building-Haiku.md (renamed from Docs/BUILDING-BeOS)0
-rw-r--r--docs/building-Windows.md (renamed from Docs/BUILDING-Windows)0
-rw-r--r--docs/core-window-interface.md677
-rw-r--r--docs/env.sh (renamed from Docs/env.sh)372
-rwxr-xr-xdocs/gource.sh (renamed from Docs/gource.sh)0
-rw-r--r--docs/ideas/cache.txt (renamed from Docs/ideas/cache.txt)0
-rw-r--r--docs/ideas/css-engine.txt (renamed from Docs/ideas/css-engine.txt)0
-rw-r--r--docs/ideas/render-library.txt (renamed from Docs/ideas/render-library.txt)0
-rw-r--r--docs/logging.md96
-rw-r--r--docs/mainpage.md98
-rw-r--r--docs/netsurf-fb.1 (renamed from Docs/netsurf-fb.1)0
-rw-r--r--docs/netsurf-gtk.1 (renamed from Docs/netsurf-gtk.1)0
-rw-r--r--docs/netsurf-libraries.md (renamed from Docs/LIBRARIES)0
-rw-r--r--docs/netsurf-options.md147
-rw-r--r--docs/quick-start.md120
-rw-r--r--docs/source-object-backing-store.md (renamed from Docs/source-object-backing-store)0
-rw-r--r--docs/unit-testing (renamed from Docs/unit-testing)0
-rw-r--r--docs/updating-duktape.md29
-rw-r--r--docs/using-framebuffer.md (renamed from Docs/USING-Framebuffer)0
-rw-r--r--docs/using-monkey.md373
-rw-r--r--frontends/amiga/Makefile17
-rw-r--r--frontends/amiga/arexx.c6
-rw-r--r--frontends/amiga/bitmap.c58
-rwxr-xr-xfrontends/amiga/bitmap.h6
-rw-r--r--frontends/amiga/cookies.c6
-rw-r--r--frontends/amiga/corewindow.c65
-rw-r--r--frontends/amiga/corewindow.h4
-rw-r--r--frontends/amiga/ctxmenu.c10
-rwxr-xr-xfrontends/amiga/dist/NetSurf.guide3
-rw-r--r--frontends/amiga/download.c87
-rwxr-xr-xfrontends/amiga/download.h2
-rw-r--r--frontends/amiga/drag.c5
-rw-r--r--frontends/amiga/dt_anim.c23
-rw-r--r--frontends/amiga/dt_picture.c8
-rw-r--r--frontends/amiga/dt_sound.c40
-rw-r--r--frontends/amiga/filetype.c8
-rw-r--r--frontends/amiga/font.c14
-rw-r--r--frontends/amiga/font_bullet.c25
-rw-r--r--frontends/amiga/font_cache.c14
-rw-r--r--frontends/amiga/font_diskfont.c28
-rw-r--r--frontends/amiga/font_scan.c24
-rw-r--r--frontends/amiga/gui.c403
-rw-r--r--frontends/amiga/gui.h12
-rw-r--r--frontends/amiga/gui_menu.c11
-rw-r--r--frontends/amiga/gui_menu.h1
-rwxr-xr-xfrontends/amiga/gui_options.c22
-rw-r--r--frontends/amiga/history.c8
-rw-r--r--[-rwxr-xr-x]frontends/amiga/history_local.c523
-rw-r--r--[-rwxr-xr-x]frontends/amiga/history_local.h23
-rw-r--r--frontends/amiga/hotlist.c7
-rw-r--r--frontends/amiga/icon.c30
-rw-r--r--frontends/amiga/libs.c72
-rwxr-xr-xfrontends/amiga/memory.c73
-rw-r--r--frontends/amiga/menu.c6
-rwxr-xr-xfrontends/amiga/misc.c2
-rw-r--r--frontends/amiga/options.h2
-rw-r--r--frontends/amiga/os3support.c25
-rw-r--r--frontends/amiga/os3support.h1
-rwxr-xr-xfrontends/amiga/pkg/makereslinks24
-rw-r--r--frontends/amiga/plotters.c1004
-rw-r--r--frontends/amiga/plotters.h74
-rw-r--r--frontends/amiga/plugin_hack.c45
-rw-r--r--frontends/amiga/print.c18
l---------frontends/amiga/resources/AdBlock.css2
l---------frontends/amiga/resources/ca-bundle2
l---------frontends/amiga/resources/de1
l---------frontends/amiga/resources/en1
l---------frontends/amiga/resources/fr1
l---------frontends/amiga/resources/it1
l---------frontends/amiga/resources/nl1
l---------frontends/amiga/resources/nsdefault.css2
l---------frontends/amiga/resources/quirks.css2
-rw-r--r--frontends/amiga/schedule.c19
-rw-r--r--frontends/amiga/selectmenu.c3
-rw-r--r--frontends/amiga/sslcert.c6
-rwxr-xr-xfrontends/amiga/stringview/stringview.c3
-rwxr-xr-xfrontends/amiga/stringview/stringview.h5
-rw-r--r--frontends/amiga/stringview/urlhistory.c3
-rw-r--r--frontends/amiga/stringview/urlhistory.h5
-rw-r--r--frontends/amiga/theme.c8
-rw-r--r--frontends/amiga/version.c2
-rw-r--r--frontends/atari/Makefile35
-rw-r--r--frontends/atari/bitmap.c32
-rw-r--r--frontends/atari/certview.c16
-rw-r--r--frontends/atari/cookies.c15
-rw-r--r--frontends/atari/ctxmenu.c13
-rw-r--r--frontends/atari/deskmenu.c68
-rw-r--r--frontends/atari/download.c14
-rw-r--r--frontends/atari/filetype.c4
-rw-r--r--frontends/atari/findfile.c18
-rw-r--r--frontends/atari/gui.c171
-rw-r--r--frontends/atari/history.c15
-rw-r--r--frontends/atari/hotlist.c25
-rw-r--r--frontends/atari/misc.h10
-rw-r--r--frontends/atari/osspec.c6
-rw-r--r--frontends/atari/plot/font_freetype.c25
-rw-r--r--frontends/atari/plot/font_internal.c2
-rw-r--r--frontends/atari/plot/font_vdi.c16
-rw-r--r--frontends/atari/plot/plot.c2269
-rw-r--r--frontends/atari/plot/plot.h29
-rw-r--r--frontends/atari/rootwin.c67
-rw-r--r--frontends/atari/schedule.c32
-rw-r--r--frontends/atari/search.c12
-rw-r--r--frontends/atari/settings.c34
-rw-r--r--frontends/atari/statusbar.c4
-rw-r--r--frontends/atari/toolbar.c21
-rw-r--r--frontends/atari/treeview.c926
-rw-r--r--frontends/atari/treeview.h2
-rw-r--r--frontends/atari/verify_ssl.c27
-rw-r--r--frontends/beos/bitmap.cpp7
-rw-r--r--frontends/beos/fetch_rsrc.cpp22
-rw-r--r--frontends/beos/filetype.cpp1
-rw-r--r--frontends/beos/font.cpp9
-rw-r--r--frontends/beos/gui.cpp39
-rw-r--r--frontends/beos/plotters.cpp1128
l---------frontends/beos/res/adblock.css2
l---------frontends/beos/res/ca-bundle.txt2
l---------frontends/beos/res/de/welcome.html2
l---------frontends/beos/res/default.css2
l---------frontends/beos/res/en/credits.html2
l---------frontends/beos/res/en/licence.html2
l---------frontends/beos/res/en/maps.html2
l---------frontends/beos/res/en/welcome.html2
l---------frontends/beos/res/icons2
l---------frontends/beos/res/internal.css2
l---------frontends/beos/res/it/credits.html2
l---------frontends/beos/res/it/licence.html2
l---------frontends/beos/res/it/welcome.html2
l---------frontends/beos/res/ja/welcome.html2
l---------frontends/beos/res/netsurf.png2
l---------frontends/beos/res/quirks.css2
-rw-r--r--frontends/beos/scaffolding.cpp20
-rw-r--r--frontends/beos/schedule.cpp27
-rw-r--r--frontends/beos/throbber.cpp18
-rw-r--r--frontends/beos/window.cpp179
-rw-r--r--frontends/cocoa/ArrowBox.h34
-rw-r--r--frontends/cocoa/ArrowBox.m163
-rw-r--r--frontends/cocoa/ArrowWindow.h32
-rw-r--r--frontends/cocoa/ArrowWindow.m239
-rw-r--r--frontends/cocoa/BlackScroller.h20
-rw-r--r--frontends/cocoa/BlackScroller.m154
-rw-r--r--frontends/cocoa/BookmarksController.h41
-rw-r--r--frontends/cocoa/BookmarksController.m224
-rw-r--r--frontends/cocoa/BrowserView.h53
-rw-r--r--frontends/cocoa/BrowserView.m760
-rw-r--r--frontends/cocoa/BrowserViewController.h75
-rw-r--r--frontends/cocoa/BrowserViewController.m377
-rw-r--r--frontends/cocoa/BrowserWindow.h26
-rw-r--r--frontends/cocoa/BrowserWindow.m29
-rw-r--r--frontends/cocoa/BrowserWindowController.h57
-rw-r--r--frontends/cocoa/BrowserWindowController.m266
-rw-r--r--frontends/cocoa/DownloadWindowController.h53
-rw-r--r--frontends/cocoa/DownloadWindowController.m415
-rw-r--r--frontends/cocoa/FormSelectMenu.h32
-rw-r--r--frontends/cocoa/FormSelectMenu.m114
-rw-r--r--frontends/cocoa/HistoryView.h35
-rw-r--r--frontends/cocoa/HistoryView.m151
-rw-r--r--frontends/cocoa/HistoryWindowController.h31
-rw-r--r--frontends/cocoa/HistoryWindowController.m52
-rw-r--r--frontends/cocoa/LocalHistoryController.h40
-rw-r--r--frontends/cocoa/LocalHistoryController.m119
-rw-r--r--frontends/cocoa/Makefile250
-rw-r--r--frontends/cocoa/Makefile.defaults30
-rw-r--r--frontends/cocoa/NetSurf.xcodeproj/project.pbxproj1023
-rw-r--r--frontends/cocoa/NetSurfAppDelegate.h42
-rw-r--r--frontends/cocoa/NetSurfAppDelegate.m200
-rw-r--r--frontends/cocoa/NetsurfApp.h31
-rw-r--r--frontends/cocoa/NetsurfApp.m303
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front.pngbin292 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Pressed.pngbin292 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Rollover.pngbin297 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front.pngbin307 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Pressed.pngbin310 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Rollover.pngbin317 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabNew.pngbin371 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabNewPressed.pngbin380 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/AquaTabNewRollover.pngbin380 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/overflowImage.pngbin256 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/overflowImagePressed.pngbin250 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/Images/pi.pngbin564 -> 0 bytes
-rw-r--r--frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.h23
-rw-r--r--frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.m119
-rw-r--r--frontends/cocoa/PSMTabBarControl/NSString_AITruncation.h12
-rw-r--r--frontends/cocoa/PSMTabBarControl/NSString_AITruncation.m32
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.h28
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.m152
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.h15
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.m40
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMRolloverButton.h28
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMRolloverButton.m170
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarCell.h116
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m489
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarControl.h241
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m1995
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarController.h38
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarController.m643
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.h101
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m834
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragView.h21
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragView.m62
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.h20
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.m48
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.h33
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.m111
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabStyle.h57
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.h29
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.m573
-rw-r--r--frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/TXT.rtf186
-rw-r--r--frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/startpage.gifbin11246 -> 0 bytes
-rw-r--r--frontends/cocoa/PreferencesWindowController.h29
-rw-r--r--frontends/cocoa/PreferencesWindowController.m56
-rw-r--r--frontends/cocoa/Prefix.pch11
-rw-r--r--frontends/cocoa/ScrollableView.h31
-rw-r--r--frontends/cocoa/ScrollableView.m71
-rw-r--r--frontends/cocoa/SearchWindowController.h54
-rw-r--r--frontends/cocoa/SearchWindowController.m119
-rw-r--r--frontends/cocoa/Tree.h56
-rw-r--r--frontends/cocoa/Tree.m147
-rw-r--r--frontends/cocoa/TreeView.h34
-rw-r--r--frontends/cocoa/TreeView.m249
-rw-r--r--frontends/cocoa/URLFieldCell.h31
-rw-r--r--frontends/cocoa/URLFieldCell.m209
-rw-r--r--frontends/cocoa/apple_image.m257
-rw-r--r--frontends/cocoa/bitmap.m281
-rwxr-xr-xfrontends/cocoa/compile-xib.sh20
-rw-r--r--frontends/cocoa/coordinates.h105
-rw-r--r--frontends/cocoa/desktop-tree.h88
-rw-r--r--frontends/cocoa/desktop-tree.m353
-rwxr-xr-xfrontends/cocoa/extract-strings.sh11
-rw-r--r--frontends/cocoa/fetch.h19
-rw-r--r--frontends/cocoa/fetch.m113
-rw-r--r--frontends/cocoa/font.h28
-rw-r--r--frontends/cocoa/font.m243
-rw-r--r--frontends/cocoa/gui.h35
-rw-r--r--frontends/cocoa/gui.m333
-rw-r--r--frontends/cocoa/plotter.h33
-rw-r--r--frontends/cocoa/plotter.m335
-rw-r--r--frontends/cocoa/res/BookmarksWindow.xib610
-rw-r--r--frontends/cocoa/res/Browser.xib399
-rw-r--r--frontends/cocoa/res/BrowserWindow.xib1395
-rw-r--r--frontends/cocoa/res/DownloadWindow.xib493
-rw-r--r--frontends/cocoa/res/HistoryWindow.xib338
-rw-r--r--frontends/cocoa/res/HomeTemplate.pdf106
l---------frontends/cocoa/res/Icons1
-rw-r--r--frontends/cocoa/res/LocalHistoryPanel.xib357
-rw-r--r--frontends/cocoa/res/MainMenu.xib2369
-rw-r--r--frontends/cocoa/res/NetSurf-Info.plist111
-rw-r--r--frontends/cocoa/res/NetSurf.icnsbin203268 -> 0 bytes
-rw-r--r--frontends/cocoa/res/PreferencesWindow.xib512
-rw-r--r--frontends/cocoa/res/SearchWindow.xib614
l---------frontends/cocoa/res/adblock.css1
l---------frontends/cocoa/res/ca-bundle1
-rw-r--r--frontends/cocoa/res/de.lproj/BookmarksWindow.xib.stringsbin366 -> 0 bytes
-rw-r--r--frontends/cocoa/res/de.lproj/BrowserWindow.xib.stringsbin1892 -> 0 bytes
-rw-r--r--frontends/cocoa/res/de.lproj/DownloadWindow.xib.stringsbin536 -> 0 bytes
-rw-r--r--frontends/cocoa/res/de.lproj/HistoryWindow.xib.stringsbin172 -> 0 bytes
-rw-r--r--frontends/cocoa/res/de.lproj/Localizable.strings78
-rw-r--r--frontends/cocoa/res/de.lproj/MainMenu.xib.stringsbin11982 -> 0 bytes
l---------frontends/cocoa/res/de.lproj/Messages1
-rw-r--r--frontends/cocoa/res/de.lproj/PreferencesWindow.xib.stringsbin1206 -> 0 bytes
-rw-r--r--frontends/cocoa/res/de.lproj/SearchWindow.xib.stringsbin1148 -> 0 bytes
l---------frontends/cocoa/res/default.css1
-rw-r--r--frontends/cocoa/res/en.lproj/Localizable.stringsbin3322 -> 0 bytes
l---------frontends/cocoa/res/en.lproj/Messages1
-rw-r--r--frontends/cocoa/res/fr.lproj/Localizable.stringsbin3322 -> 0 bytes
l---------frontends/cocoa/res/fr.lproj/Messages1
l---------frontends/cocoa/res/internal.css1
-rw-r--r--frontends/cocoa/res/it.lproj/Localizable.stringsbin3496 -> 0 bytes
l---------frontends/cocoa/res/it.lproj/Messages1
l---------frontends/cocoa/res/netsurf.png1
-rw-r--r--frontends/cocoa/res/nl.lproj/Localizable.stringsbin3322 -> 0 bytes
l---------frontends/cocoa/res/nl.lproj/Messages1
l---------frontends/cocoa/res/quirks.css1
-rw-r--r--frontends/cocoa/schedule.h19
-rw-r--r--frontends/cocoa/schedule.m90
-rw-r--r--frontends/cocoa/selection.h19
-rw-r--r--frontends/cocoa/selection.m104
-rw-r--r--frontends/framebuffer/Makefile11
-rw-r--r--frontends/framebuffer/bitmap.c21
-rw-r--r--frontends/framebuffer/clipboard.c4
-rw-r--r--frontends/framebuffer/corewindow.c262
-rw-r--r--frontends/framebuffer/corewindow.h107
-rw-r--r--frontends/framebuffer/fbtk.h6
-rw-r--r--frontends/framebuffer/fbtk/event.c4
-rw-r--r--frontends/framebuffer/fbtk/fbtk.c46
-rw-r--r--frontends/framebuffer/fbtk/scroll.c4
-rw-r--r--frontends/framebuffer/fbtk/text.c46
-rw-r--r--frontends/framebuffer/fetch.c2
-rw-r--r--frontends/framebuffer/font_freetype.c21
-rw-r--r--frontends/framebuffer/font_internal.c6
-rw-r--r--frontends/framebuffer/framebuffer.c612
-rw-r--r--frontends/framebuffer/gui.c143
-rw-r--r--frontends/framebuffer/gui.h18
-rw-r--r--frontends/framebuffer/local_history.c248
-rw-r--r--frontends/framebuffer/local_history.h49
-rw-r--r--frontends/framebuffer/localhistory.c144
l---------frontends/framebuffer/res/Messages1
l---------frontends/framebuffer/res/adblock.css2
l---------frontends/framebuffer/res/credits.html2
l---------frontends/framebuffer/res/default.css2
l---------frontends/framebuffer/res/internal.css2
l---------frontends/framebuffer/res/licence.html2
l---------frontends/framebuffer/res/maps.html2
l---------frontends/framebuffer/res/netsurf.png2
l---------frontends/framebuffer/res/quirks.css2
l---------frontends/framebuffer/res/welcome.html2
-rw-r--r--frontends/framebuffer/schedule.c23
-rw-r--r--frontends/gtk/Makefile10
-rw-r--r--frontends/gtk/accelerator.c79
-rw-r--r--frontends/gtk/accelerator.h2
-rw-r--r--frontends/gtk/bitmap.c4
-rw-r--r--frontends/gtk/cookies.c9
-rw-r--r--frontends/gtk/corewindow.c53
-rw-r--r--frontends/gtk/corewindow.h2
-rw-r--r--frontends/gtk/download.c4
-rw-r--r--frontends/gtk/fetch.c6
-rw-r--r--frontends/gtk/gdk.c2
-rw-r--r--frontends/gtk/global_history.c17
-rw-r--r--frontends/gtk/gui.c160
-rw-r--r--frontends/gtk/hotlist.c9
-rw-r--r--frontends/gtk/layout_pango.c33
-rw-r--r--frontends/gtk/layout_pango.h2
-rw-r--r--frontends/gtk/local_history.c269
-rw-r--r--frontends/gtk/local_history.h49
-rw-r--r--frontends/gtk/login.c2
-rw-r--r--frontends/gtk/menu.c44
-rw-r--r--frontends/gtk/plotters.c601
-rw-r--r--frontends/gtk/plotters.h6
-rw-r--r--frontends/gtk/preferences.c13
-rw-r--r--frontends/gtk/print.c265
-rw-r--r--frontends/gtk/res/accelerators40
l---------frontends/gtk/res/adblock.css2
l---------frontends/gtk/res/ca-bundle.txt2
l---------frontends/gtk/res/de/welcome.html2
l---------frontends/gtk/res/default.css2
l---------frontends/gtk/res/en/credits.html2
l---------frontends/gtk/res/en/licence.html2
l---------frontends/gtk/res/en/maps.html2
l---------frontends/gtk/res/en/welcome.html2
-rw-r--r--frontends/gtk/res/globalhistory.gtk2.ui (renamed from frontends/gtk/res/history.gtk2.ui)0
-rw-r--r--frontends/gtk/res/globalhistory.gtk3.ui (renamed from frontends/gtk/res/history.gtk3.ui)0
l---------frontends/gtk/res/icons2
l---------frontends/gtk/res/internal.css2
l---------frontends/gtk/res/it/credits.html2
l---------frontends/gtk/res/it/licence.html2
l---------frontends/gtk/res/it/welcome.html2
l---------frontends/gtk/res/ja/welcome.html2
-rw-r--r--frontends/gtk/res/localhistory.gtk2.ui45
-rw-r--r--frontends/gtk/res/localhistory.gtk3.ui45
-rw-r--r--frontends/gtk/res/netsurf.gresource.xml43
l---------frontends/gtk/res/netsurf.png2
l---------frontends/gtk/res/nl/credits.html2
l---------frontends/gtk/res/nl/licence.html2
l---------frontends/gtk/res/nl/welcome.html2
-rw-r--r--frontends/gtk/res/options.gtk2.ui589
l---------frontends/gtk/res/quirks.css2
-rw-r--r--frontends/gtk/res/toolbar.gtk2.ui183
-rw-r--r--frontends/gtk/res/toolbar.gtk3.ui242
-rw-r--r--frontends/gtk/resources.c82
-rw-r--r--frontends/gtk/scaffolding.c445
-rw-r--r--frontends/gtk/schedule.c16
-rw-r--r--frontends/gtk/ssl_cert.c2
-rw-r--r--frontends/gtk/tabs.c8
-rw-r--r--frontends/gtk/throbber.c6
-rw-r--r--frontends/gtk/toolbar.c131
-rw-r--r--frontends/gtk/viewdata.c23
-rw-r--r--frontends/gtk/viewsource.c6
-rw-r--r--frontends/gtk/window.c152
-rw-r--r--frontends/monkey/401login.c32
-rw-r--r--frontends/monkey/bitmap.c112
-rw-r--r--frontends/monkey/browser.c596
-rw-r--r--frontends/monkey/browser.h14
-rw-r--r--frontends/monkey/cert.c32
-rw-r--r--frontends/monkey/dispatch.c110
-rw-r--r--frontends/monkey/download.c46
-rw-r--r--frontends/monkey/farmer.py363
-rw-r--r--frontends/monkey/fetch.c12
-rw-r--r--frontends/monkey/filetype.c4
-rw-r--r--frontends/monkey/layout.c62
-rw-r--r--frontends/monkey/main.c486
-rw-r--r--frontends/monkey/plot.c258
-rw-r--r--frontends/monkey/schedule.c288
-rw-r--r--frontends/riscos/401login.c5
-rw-r--r--frontends/riscos/Makefile31
-rw-r--r--frontends/riscos/appdir/!Boot,feb (renamed from !NetSurf/!Boot,feb)0
-rw-r--r--frontends/riscos/appdir/!Sprites,ff9 (renamed from !NetSurf/!Sprites,ff9)bin1580 -> 1580 bytes
-rw-r--r--frontends/riscos/appdir/!Sprites22,ff9 (renamed from !NetSurf/!Sprites22,ff9)bin11528 -> 11528 bytes
-rwxr-xr-xfrontends/riscos/appdir/5Sprites,ff9 (renamed from !NetSurf/5Sprites,ff9)bin30964 -> 30964 bytes
-rwxr-xr-xfrontends/riscos/appdir/5Sprites11,ff9 (renamed from !NetSurf/5Sprites11,ff9)bin64228 -> 64228 bytes
-rwxr-xr-xfrontends/riscos/appdir/5Sprites22,ff9 (renamed from !NetSurf/5Sprites22,ff9)bin40800 -> 40800 bytes
-rwxr-xr-xfrontends/riscos/appdir/ASprites,ff9 (renamed from !NetSurf/ASprites,ff9)bin3664 -> 3664 bytes
-rwxr-xr-xfrontends/riscos/appdir/ASprites11,ff9 (renamed from !NetSurf/ASprites11,ff9)bin15892 -> 15892 bytes
-rwxr-xr-xfrontends/riscos/appdir/ASprites22,ff9 (renamed from !NetSurf/ASprites22,ff9)bin12668 -> 12668 bytes
-rw-r--r--frontends/riscos/appdir/ChkSprites,ffbbin0 -> 2029 bytes
-rwxr-xr-xfrontends/riscos/appdir/Docs/online,b60 (renamed from !NetSurf/Docs/online,b60)bin165 -> 165 bytes
-rw-r--r--frontends/riscos/appdir/FixFonts,ffb (renamed from !NetSurf/FixFonts,ffb)0
-rw-r--r--frontends/riscos/appdir/KickNS,ffb (renamed from !NetSurf/KickNS,ffb)bin1511 -> 1511 bytes
-rwxr-xr-xfrontends/riscos/appdir/OpenChoices,feb (renamed from !NetSurf/OpenChoices,feb)0
-rw-r--r--frontends/riscos/appdir/OpenHelp,ffb (renamed from !NetSurf/OpenHelp,ffb)bin925 -> 925 bytes
-rwxr-xr-xfrontends/riscos/appdir/OpenScrap,feb (renamed from !NetSurf/OpenScrap,feb)0
l---------frontends/riscos/appdir/Resources/AdBlock,f791
-rw-r--r--frontends/riscos/appdir/Resources/Aletheia,ffd (renamed from !NetSurf/Resources/Aletheia,ffd)bin15237 -> 15237 bytes
l---------frontends/riscos/appdir/Resources/CSS,f791
-rw-r--r--frontends/riscos/appdir/Resources/Fonts/NSSymbol/Encoding (renamed from !NetSurf/Resources/Fonts/NSSymbol/Encoding)0
-rw-r--r--frontends/riscos/appdir/Resources/Fonts/NSSymbol/IntMetrics,ff6 (renamed from !NetSurf/Resources/Fonts/NSSymbol/IntMetrics,ff6)bin344 -> 344 bytes
-rw-r--r--frontends/riscos/appdir/Resources/Fonts/NSSymbol/Outlines,ff6 (renamed from !NetSurf/Resources/Fonts/NSSymbol/Outlines,ff6)bin904 -> 904 bytes
l---------frontends/riscos/appdir/Resources/Icons1
-rwxr-xr-xfrontends/riscos/appdir/Resources/Image,ff9 (renamed from !NetSurf/Resources/Image,ff9)bin111972 -> 111972 bytes
-rw-r--r--frontends/riscos/appdir/Resources/LangNames (renamed from !NetSurf/Resources/LangNames)0
l---------frontends/riscos/appdir/Resources/Quirks,f791
-rw-r--r--frontends/riscos/appdir/Resources/SearchEngines (renamed from !NetSurf/Resources/SearchEngines)0
-rwxr-xr-xfrontends/riscos/appdir/Resources/Sprites,ff9 (renamed from !NetSurf/Resources/Sprites,ff9)bin77336 -> 77336 bytes
l---------frontends/riscos/appdir/Resources/ca-bundle1
l---------frontends/riscos/appdir/Resources/de/Messages1
l---------frontends/riscos/appdir/Resources/de/welcome.html,faf1
-rw-r--r--frontends/riscos/appdir/Resources/en/!Help (renamed from !NetSurf/Resources/en/!Help)0
l---------frontends/riscos/appdir/Resources/en/Messages1
l---------frontends/riscos/appdir/Resources/en/credits.html,faf1
l---------frontends/riscos/appdir/Resources/en/licence.html,faf1
l---------frontends/riscos/appdir/Resources/en/maps.html,faf1
l---------frontends/riscos/appdir/Resources/en/welcome.html,faf1
l---------frontends/riscos/appdir/Resources/fr/Messages1
l---------frontends/riscos/appdir/Resources/internal.css,f791
l---------frontends/riscos/appdir/Resources/it/Messages1
l---------frontends/riscos/appdir/Resources/it/credits.html,faf1
l---------frontends/riscos/appdir/Resources/it/licence.html,faf1
l---------frontends/riscos/appdir/Resources/it/welcome.html,faf1
l---------frontends/riscos/appdir/Resources/ja/welcome.html,faf1
l---------frontends/riscos/appdir/Resources/netsurf.png,b601
-rw-r--r--frontends/riscos/appdir/Resources/nl/!Help (renamed from !NetSurf/Resources/nl/!Help)0
l---------frontends/riscos/appdir/Resources/nl/Messages1
l---------frontends/riscos/appdir/Resources/nl/credits.html,faf1
l---------frontends/riscos/appdir/Resources/nl/licence.html,faf1
l---------frontends/riscos/appdir/Resources/nl/welcome.html,faf1
-rw-r--r--frontends/riscos/bitmap.c32
-rw-r--r--frontends/riscos/buffer.c36
-rw-r--r--frontends/riscos/configure.c32
-rw-r--r--frontends/riscos/configure/con_image.c5
-rw-r--r--frontends/riscos/configure/con_language.c6
-rw-r--r--frontends/riscos/configure/con_theme.c23
-rw-r--r--frontends/riscos/content-handlers/artworks.c48
-rw-r--r--frontends/riscos/content-handlers/draw.c10
-rw-r--r--frontends/riscos/content-handlers/sprite.c11
-rw-r--r--frontends/riscos/cookies.c6
-rw-r--r--frontends/riscos/corewindow.c190
-rw-r--r--frontends/riscos/corewindow.h4
-rw-r--r--frontends/riscos/dialog.c70
-rw-r--r--frontends/riscos/dialog.h1
-rw-r--r--frontends/riscos/download.c152
-rw-r--r--frontends/riscos/filetype.c37
-rw-r--r--frontends/riscos/font.c77
-rw-r--r--frontends/riscos/global_history.c6
-rw-r--r--frontends/riscos/gui.c154
-rw-r--r--frontends/riscos/gui.h34
-rw-r--r--frontends/riscos/gui/button_bar.c30
-rw-r--r--frontends/riscos/gui/progress_bar.c33
-rw-r--r--frontends/riscos/gui/status_bar.c83
-rw-r--r--frontends/riscos/gui/throbber.c11
-rw-r--r--frontends/riscos/gui/url_bar.c48
-rw-r--r--frontends/riscos/help.c22
-rw-r--r--frontends/riscos/history.c336
-rw-r--r--frontends/riscos/hotlist.c11
-rw-r--r--frontends/riscos/iconbar.c6
-rw-r--r--frontends/riscos/image.c20
-rw-r--r--frontends/riscos/local_history.c442
-rw-r--r--frontends/riscos/local_history.h46
-rw-r--r--frontends/riscos/menus.c31
-rw-r--r--frontends/riscos/message.c8
-rw-r--r--frontends/riscos/mouse.c5
-rw-r--r--frontends/riscos/plotters.c824
-rw-r--r--frontends/riscos/print.c316
-rw-r--r--frontends/riscos/query.c21
-rw-r--r--frontends/riscos/save.c117
-rw-r--r--frontends/riscos/save_draw.c638
-rw-r--r--frontends/riscos/save_draw.h7
-rw-r--r--frontends/riscos/schedule.c2
-rw-r--r--frontends/riscos/sslcert.c36
-rw-r--r--frontends/riscos/textarea.c127
-rw-r--r--frontends/riscos/textselection.c41
-rw-r--r--frontends/riscos/theme.c55
-rw-r--r--frontends/riscos/theme_install.c5
-rw-r--r--frontends/riscos/toolbar.c48
-rw-r--r--frontends/riscos/ucstables.c7
-rw-r--r--frontends/riscos/uri.c6
-rw-r--r--frontends/riscos/url_complete.c67
-rw-r--r--frontends/riscos/url_protocol.c19
-rw-r--r--frontends/riscos/wimp.c135
-rw-r--r--frontends/riscos/wimp_event.c76
-rw-r--r--frontends/riscos/window.c5961
-rw-r--r--frontends/riscos/window.h207
-rw-r--r--frontends/windows/Makefile5
-rw-r--r--frontends/windows/about.c8
-rw-r--r--frontends/windows/bitmap.c34
-rw-r--r--frontends/windows/cookies.c19
-rw-r--r--frontends/windows/corewindow.c154
-rw-r--r--frontends/windows/corewindow.h2
-rw-r--r--frontends/windows/download.c8
-rw-r--r--frontends/windows/drawable.c71
-rw-r--r--frontends/windows/filetype.c13
-rw-r--r--frontends/windows/findfile.c4
-rw-r--r--frontends/windows/font.c113
-rw-r--r--frontends/windows/font.h13
-rw-r--r--frontends/windows/global_history.c6
-rw-r--r--frontends/windows/gui.c20
-rw-r--r--frontends/windows/hotlist.c6
-rw-r--r--frontends/windows/local_history.c255
-rw-r--r--frontends/windows/local_history.h (renamed from frontends/cocoa/apple_image.h)34
-rw-r--r--frontends/windows/localhistory.c413
-rw-r--r--frontends/windows/localhistory.h32
-rw-r--r--frontends/windows/main.c22
-rw-r--r--frontends/windows/plot.c1246
-rw-r--r--frontends/windows/prefs.c126
l---------frontends/windows/res/adblock.css2
l---------frontends/windows/res/ca-bundle.crt2
l---------frontends/windows/res/credits.html2
l---------frontends/windows/res/default.css2
l---------frontends/windows/res/internal.css2
l---------frontends/windows/res/licence.html2
l---------frontends/windows/res/netsurf.png2
l---------frontends/windows/res/quirks.css2
l---------frontends/windows/res/welcome.html2
-rw-r--r--frontends/windows/schedule.c38
-rw-r--r--frontends/windows/ssl_cert.c110
-rw-r--r--frontends/windows/windbg.h14
-rw-r--r--frontends/windows/window.c372
-rw-r--r--frontends/windows/window.h15
-rw-r--r--include/netsurf/bitmap.h2
-rw-r--r--include/netsurf/browser_window.h78
-rw-r--r--include/netsurf/content_type.h4
-rw-r--r--include/netsurf/core_window.h28
-rw-r--r--include/netsurf/mouse.h5
-rw-r--r--include/netsurf/plot_style.h34
-rw-r--r--include/netsurf/plotters.h344
-rw-r--r--include/netsurf/url_db.h9
-rw-r--r--include/netsurf/window.h180
-rw-r--r--render/Makefile9
-rw-r--r--render/textplain.h51
-rw-r--r--resources/FatMessages604
-rw-r--r--resources/adblock.css (renamed from !NetSurf/Resources/AdBlock,f79)0
-rw-r--r--resources/ca-bundle (renamed from !NetSurf/Resources/ca-bundle)1093
-rw-r--r--resources/de/welcome.html (renamed from !NetSurf/Resources/de/welcome.html,faf)10
-rw-r--r--resources/default.css (renamed from !NetSurf/Resources/CSS,f79)8
-rw-r--r--resources/en/credits.html (renamed from !NetSurf/Resources/en/credits.html,faf)2
-rw-r--r--resources/en/licence.html (renamed from !NetSurf/Resources/en/licence.html,faf)18
-rw-r--r--resources/en/maps.html (renamed from !NetSurf/Resources/en/maps.html,faf)0
-rw-r--r--resources/en/welcome.html (renamed from !NetSurf/Resources/en/welcome.html,faf)10
-rw-r--r--resources/icons/arrow-l.png (renamed from !NetSurf/Resources/Icons/arrow-l.png)bin284 -> 284 bytes
-rw-r--r--resources/icons/content.png (renamed from !NetSurf/Resources/Icons/content.png)bin598 -> 598 bytes
-rw-r--r--resources/icons/directory.png (renamed from !NetSurf/Resources/Icons/directory.png)bin259 -> 259 bytes
-rw-r--r--resources/icons/directory2.png (renamed from !NetSurf/Resources/Icons/directory2.png)bin336 -> 336 bytes
-rw-r--r--resources/icons/hotlist-add.png (renamed from !NetSurf/Resources/Icons/hotlist-add.png)bin356 -> 356 bytes
-rw-r--r--resources/icons/hotlist-rmv.png (renamed from !NetSurf/Resources/Icons/hotlist-rmv.png)bin610 -> 610 bytes
-rw-r--r--resources/icons/search.png (renamed from !NetSurf/Resources/Icons/search.png)bin536 -> 536 bytes
-rw-r--r--resources/internal.css (renamed from !NetSurf/Resources/internal.css,f79)0
-rw-r--r--resources/it/credits.html (renamed from !NetSurf/Resources/it/credits.html,faf)2
-rw-r--r--resources/it/licence.html (renamed from !NetSurf/Resources/it/licence.html,faf)14
-rw-r--r--resources/it/welcome.html (renamed from !NetSurf/Resources/it/welcome.html,faf)10
-rw-r--r--resources/ja/welcome.html (renamed from !NetSurf/Resources/ja/welcome.html,faf)10
-rw-r--r--resources/netsurf.png (renamed from !NetSurf/Resources/netsurf.png,b60)bin16486 -> 16486 bytes
-rw-r--r--resources/nl/credits.html (renamed from !NetSurf/Resources/nl/credits.html,faf)2
-rw-r--r--resources/nl/licence.html (renamed from !NetSurf/Resources/nl/licence.html,faf)14
-rw-r--r--resources/nl/welcome.html (renamed from !NetSurf/Resources/nl/welcome.html,faf)10
-rw-r--r--resources/quirks.css (renamed from !NetSurf/Resources/Quirks,f79)0
-rw-r--r--test/Makefile125
-rw-r--r--test/assert.c43
-rw-r--r--test/corestrings.c100
-rw-r--r--test/data/Choices-all2
-rw-r--r--test/data/cookies47
-rw-r--r--test/data/cookies-out31
-rw-r--r--test/data/urldb10
-rw-r--r--test/data/urldb-out39
-rw-r--r--test/hashtable.c2
-rw-r--r--test/log.c12
-rw-r--r--test/malloc_fig.c58
-rw-r--r--test/malloc_fig.h (renamed from frontends/cocoa/bitmap.h)18
-rw-r--r--test/messages.c33
-rw-r--r--test/mimesniff.c896
-rw-r--r--test/nsoption.c20
-rw-r--r--test/nsurl.c304
-rw-r--r--test/urldbtest.c610
-rw-r--r--test/utils.c210
-rw-r--r--utils/Makefile1
-rw-r--r--utils/ascii.h65
-rw-r--r--utils/corestringlist.h357
-rw-r--r--utils/corestrings.c943
-rw-r--r--utils/corestrings.h298
-rw-r--r--utils/errors.h75
-rw-r--r--utils/filename.c51
-rw-r--r--utils/hashtable.c237
-rw-r--r--utils/hashtable.h53
-rw-r--r--utils/http.h1
-rw-r--r--utils/http/Makefile5
-rw-r--r--utils/http/challenge.c2
-rw-r--r--utils/http/content-disposition.c2
-rw-r--r--utils/http/content-type.c2
-rw-r--r--utils/http/generics.h2
-rw-r--r--utils/http/strict-transport-security.c341
-rw-r--r--utils/http/strict-transport-security.h64
-rw-r--r--utils/idna.c38
-rwxr-xr-xutils/jenkins-build.sh28
-rw-r--r--utils/log.c284
-rw-r--r--utils/log.h68
-rwxr-xr-xutils/merge-messages.lua83
-rw-r--r--utils/messages.c233
-rw-r--r--utils/nsoption.c17
-rw-r--r--utils/nsoption.h4
-rw-r--r--utils/nsurl.h19
-rw-r--r--utils/nsurl/Makefile7
-rw-r--r--utils/nsurl/nsurl.c939
-rw-r--r--utils/nsurl/parse.c (renamed from utils/nsurl.c)1166
-rw-r--r--utils/nsurl/private.h232
-rw-r--r--utils/split-messages.pl17
-rw-r--r--utils/useragent.c3
-rw-r--r--utils/utf8.c5
755 files changed, 81680 insertions, 84141 deletions
diff --git a/!NetSurf/ChkSprites,ffb b/!NetSurf/ChkSprites,ffb
deleted file mode 100644
index 4e7d325fb..000000000
--- a/!NetSurf/ChkSprites,ffb
+++ /dev/null
Binary files differ
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000..3cee69bd9
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,94 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: All
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: true
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Linux
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^(<.*/)'
+ Priority: 3
+ - Regex: '^(<(nsutils)/)'
+ Priority: 2
+ - Regex: '"utils/'
+ Priority: 4
+ - Regex: '"netsurf/'
+ Priority: 5
+ - Regex: '.*'
+ Priority: 6
+IndentCaseLabels: false
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: false
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 8
+UseTab: Always
+...
+
diff --git a/.gitignore b/.gitignore
index 35de191c2..bb10ba503 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,16 @@
*~
-\!NetSurf/!Run,feb
-\!NetSurf/!RunImage,ff8
-\!NetSurf/!Help,feb
-\!NetSurf/Resources/en/Templates,fec
-\!NetSurf/Resources/en/Messages
-\!NetSurf/Resources/fr/Templates,fec
-\!NetSurf/Resources/fr/Messages
-\!NetSurf/Resources/de/Templates,fec
-\!NetSurf/Resources/de/Messages
-\!NetSurf/Resources/nl/Templates,fec
-\!NetSurf/Resources/nl/Messages
-\!NetSurf/Resources/it/Messages
+frontends/riscos/appdir/!Run,feb
+frontends/riscos/appdir/!RunImage,ff8
+frontends/riscos/appdir/!Help,feb
+frontends/riscos/appdir/Resources/en/Templates,fec
+frontends/riscos/appdir/Resources/fr/Templates,fec
+frontends/riscos/appdir/Resources/de/Templates,fec
+frontends/riscos/appdir/Resources/nl/Templates,fec
+resources/en/Messages
+resources/fr/Messages
+resources/de/Messages
+resources/nl/Messages
+resources/it/Messages
frontends/gtk/res/en/Messages
frontends/gtk/res/fr/Messages
frontends/gtk/res/de/Messages
diff --git a/Docs/BUILDING-Cocoa b/Docs/BUILDING-Cocoa
deleted file mode 100644
index d83800d79..000000000
--- a/Docs/BUILDING-Cocoa
+++ /dev/null
@@ -1,87 +0,0 @@
---------------------------------------------------------------------------------
- Build Instructions for Cocoa NetSurf 13 January 2011
---------------------------------------------------------------------------------
-
- This document provides instructions for building the Cocoa version of NetSurf
- and provides guidance on obtaining NetSurf's build dependencies.
-
- Cocoa NetSurf has been tested on Mac OS X 10.6 on Intel and on Mac OS X 10.5
- on ppc.
-
-
- Building NetSurf
-==================
-
- After installing the dependencies NetSurf can be built either using the Xcode
- project file 'cocoa/NetSurf.xcodeproj' or on the command line using the
- Makefile:
-
- $ make TARGET=cocoa
-
- In both cases the actual build process is controlled by the Makefile.
-
- Obtaining NetSurf's build dependencies
-========================================
-
- Many of NetSurf's dependencies are packaged on various operating systems.
- The remainder must be installed manually. Currently, some of the libraries
- developed as part of the NetSurf project have not had official releases.
- Hopefully they will soon be released with downloadable tarballs and packaged
- in common distros. For now, you'll have to make do with Git checkouts.
-
- Package installation
-----------------------
-
- For building the other NetSurf libraries and for configuring NetSurf the
- "pkg-config" tool is required. It can be installed either via fink, macports
- or homebrew or from source.
-
- OpenSSL, LibPNG, curl, iconv and zlib are provided by Mac OS X.
-
- The curl library provided by Mac OS X 10.6 causes a crash while fetching
- https resources, so you should install version 7.21.4 (or newer) of libcurl
- if you are running on 10.6.
-
- LibJPEG and LibMNG can be installed from source or using one of the mentioned
- package managers.
-
-
- The NetSurf project's libraries
----------------------------------
-
- The NetSurf project has developed several libraries which are required by
- the browser. These are:
-
- LibParserUtils -- Parser building utility functions
- LibWapcaplet -- String internment
- Hubbub -- HTML5 compliant HTML parser
- LibCSS -- CSS parser and selection engine
- LibNSGIF -- GIF format image decoder
- LibNSBMP -- BMP and ICO format image decoder
- LibROSprite -- RISC OS Sprite format image decoder
-
- To fetch each of these libraries, run the appropriate commands from the
- Docs/LIBRARIES file.
-
- $ make
- $ sudo make install
-
- This command builds the libraries only for the active architecture. To build
- universal binaries use those commands:
-
- $ make UNIVERSAL="i386 x86_64 ppc ppc64"
- $ sudo make install
-
- If you are building NetSurf for using it on only one computer this is not
- necessary, but if you want to distribute your binary you should build
- universal binaries. You can also leave some of the platform names out, if
- you don't require them.
-
- | Note: We advise enabling iconv() support in libparserutils, which vastly
- | increases the number of supported character sets. To do this,
- | create a file called Makefile.config.override in the libparserutils
- | directory, containing the following line:
- |
- | CFLAGS += -DWITH_ICONV_FILTER
- |
- | For more information, consult the libparserutils README file.
diff --git a/Docs/Doxyfile b/Docs/Doxyfile
deleted file mode 100644
index e2cb5639c..000000000
--- a/Docs/Doxyfile
+++ /dev/null
@@ -1,1826 +0,0 @@
-# Doxyfile 1.8.1.1
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
-
-PROJECT_NAME = NetSurf
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
-
-PROJECT_LOGO =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY =
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
-# itcl::class meaning.
-
-TCL_SUBST =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
-# Disable only in case of backward compatibilities issues.
-
-MARKDOWN_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE = 0
-
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = YES
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = YES
-
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = frontends/amiga \
- frontends/amiga/stringview \
- frontends/atari \
- frontends/atari/plot \
- frontends/beos \
- frontends/cocoa \
- frontends/framebuffer \
- frontends/framebuffer/fbtk \
- frontends/gtk \
- frontends/monkey \
- frontends/riscos \
- frontends/riscos/configure \
- frontends/riscos/gui \
- frontends/riscos/content-handlers \
- frontends/riscos/templates \
- frontends/riscos/scripts \
- frontends/windows \
- include/netsurf \
- render \
- desktop \
- content \
- content/fetchers \
- content/handlers/image \
- content/handlers/css \
- content/handlers/javascript \
- content/handlers/javascript/duktape \
- utils \
- utils/http \
- Docs/UnimplementedJavascript.txt
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
-
-FILE_PATTERNS = *.c \
- *.h \
- *.y \
- *.l \
- *.cpp \
- *.m
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
-
-FILTER_SOURCE_PATTERNS =
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
-
-STRIP_CODE_COMMENTS = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = YES
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = codedocs
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
-# and will result in a full expanded tree by default.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
-
-GENERATE_TREEVIEW = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax.
-# However, it is strongly recommended to install a local
-# copy of MathJax from http://www.mathjax.org before deployment.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
-
-MATHJAX_EXTENSIONS =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
-
-LATEX_FOOTER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
-
-LATEX_BIB_STYLE = plain
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED = gtk \
- WITH_THEME_INSTALL
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-#
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-#
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = YES
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS = 0
-
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH = YES
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
-
-INTERACTIVE_SVG = NO
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
-
-MSCFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES = 200
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS = YES
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
diff --git a/Docs/JavaScript b/Docs/JavaScript
deleted file mode 100644
index ced2fbe7c..000000000
--- a/Docs/JavaScript
+++ /dev/null
@@ -1,16 +0,0 @@
---------------------------------------------------------------------------------
- NetSurf: JavaScript 8 April 2013
---------------------------------------------------------------------------------
-
- NetSurf may be built with primitive support for JavaScript.
-
- | Note: NetSurf's JavaScript handling is currently:
- |
- | * incomplete,
- | * unsupported,
- | * disabled by default.
-
- To test it, you may build NetSurf with JavaScript and ensure NetSurf's
- "enable_javascript" run-time configuration option is set to "1". To do this
- you may set the option in the frontend's settings GUI, create/edit a Choices
- file, or pass --enable_javascript=1 to the executable.
diff --git a/Docs/Options b/Docs/Options
deleted file mode 100644
index 89b881414..000000000
--- a/Docs/Options
+++ /dev/null
@@ -1,241 +0,0 @@
---------------------------------------------------------------------------------
- Common NetSurf user options 4nd December 2014
---------------------------------------------------------------------------------
-
- This document outlines the common configuration options supported by the
- NetSurf core.
-
-Overview
-========
-
- The users configurations are generally stored in a "Choices" file
- and are loaded at browser startup. Most user interfaces provide a
- way to configure these parameters in a manner consistant with the
- toolkit in use.
-
- The user choices are stored as a simple key:value list.
-
- Each entry has a type, one of: boolean, integer, unsigned integer,
- hexadecimal colour value or string.
-
-General Options
-===============
-
-+----------------------+--------+-----------+----------------------------------+
-| Option Key | Type | Default | Description |
-+----------------------+--------+-----------+----------------------------------+
-| http_proxy | bool | false | An HTTP proxy should be used. |
-| | | | |
-| http_proxy | bool | false | An HTTP proxy should be used. |
-| | | | |
-| http_proxy_host | string | NULL | Hostname of proxy. |
-| | | | |
-| http_proxy_port | int | 8080 | Proxy port. |
-| | | | |
-| http_proxy_auth | int | 0 | Proxy authentication method. |
-| | | | |
-| http_proxy_auth_user | string | NULL | Proxy authentication user name |
-| | | | |
-| http_proxy_auth_pass | string | NULL | Proxy authentication password |
-| | | | |
-| http_proxy_noproxy | string | localhost | Proxy omission list |
-| | | | |
-| font_size | int | 128 | Default font size / 0.1pt. |
-| | | | |
-| font_min_size | int | 85 | Minimum font size. |
-| | | | |
-| font_sans | string | NULL | Default sans serif font |
-| | | | |
-| font_serif | string | NULL | Default serif font |
-| | | | |
-| font_mono | string | NULL | Default monospace font
-| | | | |
-| font_cursive | string | NULL | Default cursive font
-| | | | |
-| font_fantasy | string | NULL | Default fantasy font
-| | | | |
-| accept_language | string | NULL | Accept-Language header.
-| | | | |
-| accept_charset | string | NULL | Accept-Charset header.
-| | | | |
-| memory_cache_size | int | 12MiB | Preferred maximum size of memory |
-| | | | cache in bytes. |
-| | | | |
-| disc_cache_size | uint | 1GiB | Preferred expiry size of disc |
-| | | | cache in bytes. |
-| | | | |
-| disc_cache_age | int | 28 | Preferred expiry age of disc |
-| | | | cache in days. |
-| | | | |
-| block_advertisements | bool | false | Whether to block advertisements
-| | | | |
-| do_not_track | bool | false | Disable website tracking [1]
-| | | | |
-| minimum_gif_delay | int | 10 | Minimum GIF animation delay
-| | | | |
-| send_referer | bool | true | Whether to send the referer HTTP |
-| | | | header. |
-| | | | |
-| foreground_images | bool | true | Whether to fetch foreground images
-| | | | |
-| background_images | bool | true | Whether to fetch background images
-| | | | |
-| animate_images | bool | true | Whether to animate images
-| | | | |
-| enable_javascript | bool | false | Whether to execute javascript
-| | | | |
-| script_timeout | int | 10 | Maximum time to wait for a script|
-| | | | to run in seconds |
-| | | | |
-| expire_url | int | 28 | How many days to retain URL data |
-| | | | for. |
-| | | | |
-| font_default | int | 0 | Default font family
-| | | | |
-| ca_bundle | string | NULL | ca-bundle location
-| | | | |
-| ca_path | string | NULL | ca-path location
-| | | | |
-| cookie_file | string | NULL | Cookie file location
-| | | | |
-| cookie_jar | string | NULL | Cookie jar location
-| | | | |
-| homepage_url | string | NULL | Home page location
-| | | | |
-| search_url_bar | bool | false | search web from url bar
-| | | | |
-| search_provider | int | 0 | default web search provider
-| | | | |
-| url_suggestion | bool | true | URL completion in url bar
-| | | | |
-| window_x | int | 0 | default x position of new windows
-| | | | |
-| window_y | int | 0 | default y position of new windows
-| | | | |
-| window_width | int | 0 | default width of new windows
-| | | | |
-| window_height | int | 0 | default height of new windows
-| | | | |
-| window_screen_width | int | 0 | width of screen when above |
-| | | | options were saved |
-| | | | |
-| window_screen_height | int | 0 | height of screen when above |
-| | | | options were saved |
-| | | | |
-| toolbar_status_size | int | 6667 | default size of status bar vs. |
-| | | | h scroll bar |
-| | | | |
-| scale | int | 100 | default window scale
-| | | | |
-| incremental_reflow | bool | true | Whether to reflow web pages while|
-| | | | objects are fetching |
-| | | | |
-| min_reflow_period | uint | 25 | Minimum time (in cs) between HTML|
-| | | | reflows while objects are fetching
-| | | | |
-| core_select_menu | bool | false | Use core selection menu |
-| | | | |
-+----------------------+--------+-----------+----------------------------------+
-
-[1] http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas
-
-Fetcher options
-===============
-
-+--------------------------+------+------+-------------------------------------+
-| Option Key | Type | Dflt | Description |
-+--------------------------+------+------+-------------------------------------+
-| max_fetchers | int | 24 | Maximum simultaneous active fetchers|
-| | | | |
-| max_fetchers_per_host | int | 5 | Maximum simultaneous active fetchers|
-| | | | per host. (<=option_max_fetchers |
-| | | | else it makes no sense) [2] |
-| | | | |
-| max_cached_fetch_handles | int | 6 | Maximum number of inactive fetchers |
-| | | | cached. The total number of handles|
-| | | | netsurf will therefore have open is|
-| | | | this plus option_max_fetchers. |
-| | | | |
-| suppress_curl_debug | bool | true | Suppress debug output from cURL. |
-| | | | |
-| target_blank | bool | true | Whether to allow target="_blank" |
-| | | | |
-| button_2_tab | bool | true | Whether second mouse button opens in|
-| | | | new tab. |
-| | | | |
-+--------------------------+------+------+-------------------------------------+
-
-[2] Note that rfc2616 section 8.1.4 says that there should be no more
- than two keepalive connections per host. None of the main browsers
- follow this as it slows page fetches down considerably.
- See https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4
-
-
-PDF / Print options
-===================
-
-+------------------------+------+-------+--------------------------------------+
-| Option Key | Type | Deflt | Description |
-+------------------------+------+-------+--------------------------------------+
-| margin_top | int | 10 | top margin of exported page |
-| | | | |
-| margin_bottom | int | 10 | bottom margin of exported page |
-| | | | |
-| margin_left | int | 10 | left margin of exported page |
-| | | | |
-| margin_right | int | 10 | right margin of exported page |
-| | | | |
-| export_scale | int | 70 | scale of exported content |
-| | | | |
-| suppress_images | bool | false | suppressing images in printed content|
-| | | | |
-| remove_backgrounds | bool | false | turning off all backgrounds for |
-| | | | printed content |
-| | | | |
-| enable_loosening | bool | true | turning on content loosening for |
-| | | | printed content |
-| | | | |
-| enable_PDF_compression | bool | true | compression of PDF documents |
-| | | | |
-| enable_PDF_password | bool | false | setting a password and encoding PDF |
-| | | | documents |
-+------------------------+------+-------+--------------------------------------+
-
-System colours
-==============
-
-These are the css system colours which the browser also uses to style
-generated output.
-
-+--------------------------------+--------+------------+
-| Option Key | Type | Default |
-+--------------------------------+--------+------------+
-| sys_colour_ActiveBorder | colour | 0x00d3d3d3 |
-| sys_colour_ActiveCaption | colour | 0x00f1f1f1 |
-| sys_colour_AppWorkspace | colour | 0x00f1f1f1 |
-| sys_colour_Background | colour | 0x006e6e6e |
-| sys_colour_ButtonFace | colour | 0x00f9f9f9 |
-| sys_colour_ButtonHighlight | colour | 0x00ffffff |
-| sys_colour_ButtonShadow | colour | 0x00aeaeae |
-| sys_colour_ButtonText | colour | 0x004c4c4c |
-| sys_colour_CaptionText | colour | 0x004c4c4c |
-| sys_colour_GrayText | colour | 0x00505050 |
-| sys_colour_Highlight | colour | 0x00c00800 |
-| sys_colour_HighlightText | colour | 0x00ffffff |
-| sys_colour_InactiveBorder | colour | 0x00f1f1f1 |
-| sys_colour_InactiveCaption | colour | 0x00e6e6e6 |
-| sys_colour_InactiveCaptionText | colour | 0x00a6a6a6 |
-| sys_colour_InfoBackground | colour | 0x008fdfef |
-| sys_colour_InfoText | colour | 0x00000000 |
-| sys_colour_Menu | colour | 0x00f1f1f1 |
-| sys_colour_MenuText | colour | 0x004e4e4e |
-| sys_colour_Scrollbar | colour | 0x00cccccc |
-| sys_colour_ThreeDDarkShadow | colour | 0x00aeaeae |
-| sys_colour_ThreeDFace | colour | 0x00f9f9f9 |
-| sys_colour_ThreeDHighlight | colour | 0x00ffffff |
-| sys_colour_ThreeDLightShadow | colour | 0x00ffffff |
-| sys_colour_ThreeDShadow | colour | 0x00d5d5d5 |
-| sys_colour_Window | colour | 0x00f1f1f1 |
-| sys_colour_WindowFrame | colour | 0x004e4e4e |
-| sys_colour_WindowText | colour | 0x00000000 |
-+--------------------------------+--------+------------+
diff --git a/Docs/QUICK-START b/Docs/QUICK-START
deleted file mode 100644
index 9ff3fb5e9..000000000
--- a/Docs/QUICK-START
+++ /dev/null
@@ -1,108 +0,0 @@
---------------------------------------------------------------------------------
- Quick Build Steps for NetSurf 24 February 2015
---------------------------------------------------------------------------------
-
- This document provides steps for building NetSurf.
-
-
- Grab a temporary env.sh
---------------------------
-
- $ wget http://git.netsurf-browser.org/netsurf.git/plain/Docs/env.sh
- $ source env.sh
-
-
- Install any packages you need
--------------------------------
-
- Installs all packages required to build NetSurf and the NetSurf project
- libraries.
-
- $ ns-package-install
-
- If your package manager is not supported, you will have to install third
- party packages manually.
-
-
- Get the NetSurf project source code from Git
-----------------------------------------------
-
- $ ns-clone
-
-
- Build and install our project libraries
------------------------------------------
-
- Updates NetSurf project library sources to latest, builds and installs them.
-
- $ ns-pull-install
-
-
- Switch to new NetSurf workspace
----------------------------------
-
- $ rm env.sh
- $ cd ~/dev-netsurf/workspace
- $ source env.sh
-
-
- Build and run NetSurf
------------------------
-
- $ cd netsurf
-
- To build the native front end (the GTK front end on Linux, BSDs, etc) you
- could do:
-
- $ make
- $ ./nsgtk
-
- To build the framebuffer front end, you could do:
-
- $ make TARGET=framebuffer
- $ ./nsfb
-
-
- Cross Compiling
-=================
-
- If you are cross compiling, you can follow the above steps, but when sourcing
- env.sh, you should set TARGET_ABI to the appropriate triplet for your cross
- compiler. For example, to cross compile for RISC OS:
-
- $ TARGET_ABI=arm-unknown-riscos source env.sh
-
- After that, the commands such as `ns-package-install` and `ns-pull-install`
- will do what is appropriate for the platform you are building for.
-
- To do the final build of NetSurf, pass the appropriate TARGET to make. For
- example, to cross compile for RISC OS:
-
- $ make TARGET=riscos
-
- Finally, you can package up your build to transfer to the system you are
- developing for. For example, to produce a package for RISC OS:
-
- $ make TARGET=riscos package
-
- Getting a cross compiler set up
----------------------------------
-
- We maintain cross compilation environments and an SDK for a number of
- platforms. These may be found in our toolchains repository.
-
- $ git clone git://git.netsurf-browser.org/toolchains
-
- Pre-built versions of the toolchains for Debian systems are often available
- via our automated build and test infrastructure:
-
- http://ci.netsurf-browser.org/builds/toolchains/
-
-
- Not working?
-==============
-
- If the above steps are inapplicable, or don't work, you can build manually.
- Follow the instructions in the BUILDING-* documents in the Docs/ directory
- the NetSurf browser source tree.
-
diff --git a/Docs/USING-Monkey b/Docs/USING-Monkey
deleted file mode 100644
index 33e504239..000000000
--- a/Docs/USING-Monkey
+++ /dev/null
@@ -1,318 +0,0 @@
---------------------------------------------------------------------------------
- Usage Instructions for Monkey NetSurf 13 March 2011
---------------------------------------------------------------------------------
-
- This document provides usage instructions for the Monkey version of
- NetSurf.
-
- Monkey NetSurf has been tested on Ubuntu.
-
-Overview
-========
-
- What it is
- ----------
-
- The NetSurf Monkey front end is a developer debug tool used to
- test how the core interacts with the user interface. It allows
- the developers to profile NetSurf and to interact with the core
- directly as though the developer were a front end.
-
- What it is not
- --------------
-
- Monkey is not a tool for building web-crawling robots or indeed
- anything other than a debug tool for the NetSurf developers.
-
- How to interact with nsmonkey
- -----------------------------
-
- In brief, monkey will produce tagged output on stdout and expect
- commands on stdin. Windows are numbered and for the most part
- tokens are space separated. In some cases (e.g. title or status)
- the final element on the output line is a string which might have
- spaces embedded within it. As such, output from nsmonkey should be
- parsed a token at a time, so that when such a string is encountered,
- the parser can stop splitting and return the rest.
-
- Commands to Monkey are namespaced. For example commands related to
- browser windows are prefixed by WINDOW.
-
- Top level tags for nsmonkey
- ---------------------------
-
- QUIT
-
- WINDOW
-
- Top level response tags for nsmonkey
- ------------------------------------
-
- GENERIC
-
- WARN, ERROR, DIE
-
- WINDOW
-
- DOWNLOAD_WINDOW
-
- SSLCERT
-
- 401LOGIN
-
- PLOT
-
- In the below, %something% indicates a substitution made by Monkey.
-
- %url% will be a URL
- %id% will be an opaque ID
- %n% will be a number
- %bool% will be TRUE or FALSE
- %str% is a string and will only ever be at the end of an output line.
-
- Warnings, errors etc
- --------------------
-
- Warnings (tagged WARN) come from the NetSurf core.
- Errors (tagged ERROR) tend to come from Monkey's parsers
- Death (tagged DIE) comes from the core and kills Monkey dead.
-
-Commands
-========
-
- Generic commands
- ----------------
-
- QUIT
- Cause monkey to quit cleanly.
- This will cleanly destroy open windows etc.
-
- Window commands
- ---------------
-
- WINDOW NEW [%url%]
- Create a new browser window, optionally giving the core
- a URL to immediately navigate to.
- Minimally you will receive a WINDOW NEW WIN %id% response.
-
- WINDOW DESTROY %id%
- Destroy the given browser window.
- Minimally you will recieve a WINDOW DESTROY WIN %id% response.
-
- WINDOW GO %id% %url% [%url%]
- Cause the given browser window to visit the given URL.
- Optionally you can give a referrer URL to also use (simulating
- a click in the browser on a link).
- Minimally you can expect throbber, url etc responses.
-
- WINDOW REDRAW %id% [%num% %num% %num% %num%]
- Cause a browser window to redraw. Optionally you can give a
- set of coordinates to simulate a partial expose of the window.
- Said coordinates are in traditional X0 Y0 X1 Y1 order.
- The coordinates are in canvas, not window, coordinates. So you
- should take into account the scroll offsets when issuing this
- command.
- Minimally you can expect redraw start/stop messages and you
- can likely expect some number of PLOT results.
-
- WINDOW RELOAD %id%
- Cause a browser window to reload its current content.
- Expect responses similar to a GO command.
-
-
-Responses
-=========
-
- Generic messages
- ----------------
-
- GENERIC STARTED
- Monkey has started and is ready for commands
-
- GENERIC CLOSING_DOWN
- Monkey has been told to shut down and is doing so
-
- GENERIC FINISHED
- Monkey has finished and will now exit
-
- GENERIC LAUNCH URL %url%
- The core asked monkey to launch the given URL
-
- GENERIC THUMBNAIL URL %url%
- The core asked monkey to thumbnail a content without
- a window.
-
- GENERIC POLL BLOCKING
- Monkey reached a point where it could sleep waiting for
- commands or scheduled timeouts. No fetches nor redraws
- were pending.
-
- Window messages
- ---------------
-
- WINDOW NEW WIN %id% FOR %id% CLONE %id% NEWTAB %bool%
- The core asked Monkey to open a new window. The IDs for 'FOR' and
- 'CLONE' are core window IDs, the WIN id is a Monkey window ID.
-
- WINDOW SIZE WIN %id% WIDTH %n% HEIGHT %n%
- The window specified has been set to the shown width and height.
-
- WINDOW DESTROY WIN %id%
- The core has instructed Monkey to destroy the named window.
-
- WINDOW TITLE WIN %id% STR %str%
- The core supplied a titlebar title for the given window.
-
- WINDOW REDRAW WIN %id%
- The core asked that Monkey redraw the given window.
-
- WINDOW GET_DIMENSIONS WIN %id% WIDTH %n% HEIGHT %n%
- The core asked Monkey what the dimensions of the window are.
- Monkey has to respond immediately and returned the supplied width
- and height values to the core.
-
- WINDOW NEW_CONTENT WIN %id%
- The core has informed Monkey that the named window has a new
- content object.
-
- WINDOW NEW_ICON WIN %id%
- The core has informed Monkey that the named window hsa a new
- icon (favicon) available.
-
- WINDOW START_THROBBER WIN %id%
- The core asked Monkey to start the throbber for the named
- window. This indicates to the user that the window is busy.
-
- WINDOW STOP_THROBBER WIN %id%
- The core asked Monkey to stop the throbber for the named
- window. This indicates to the user that the window is finished.
-
- WINDOW SET_SCROLL WIN %id% X %n% Y %n%
- The core asked Monkey to set the named window's scroll offsets
- to the given X and Y position.
-
- WINDOW UPDATE_BOX WIN %id% X %n% Y %n% WIDTH %n% HEIGHT %n%
- The core asked Monkey to redraw the given portion of the content
- display. Note these coordinates refer to the content, not the
- viewport which Monkey is simulating.
-
- WINDOW UPDATE_EXTENT WIN %id% WIDTH %n% HEIGHT %n%
- The core has told us that the content in the given window has a
- total width and height as shown. This allows us (along with the
- window's width and height) to know the scroll limits.
-
- WINDOW SET_STATUS WIN %id% STR %str%
- The core has told us that the given window needs its status bar
- updating with the given message.
-
- WINDOW SET_POINTER WIN %id% POINTER %id%
- The core has told us to update the mouse pointer for the given
- window to the given pointer ID.
-
- WINDOW SET_SCALE WIN %id% SCALE %n%
- The core has asked us to scale the given window by the given scale
- factor.
-
- WINDOW SET_URL WIN %id% URL %url%
- The core has informed us that the given window's URL bar needs
- updating to the given url.
-
- WINDOW GET_SCROLL WIN %id% X %n% Y %n%
- The core asked Monkey for the scroll offsets. Monkey returned the
- numbers shown for the window named.
-
- WINDOW SCROLL_START WIN %id%
- The core asked Monkey to scroll the named window to the top/left.
-
- WINDOW POSITION_FRAME WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to position the named window as a frame at
- the given coordinates of its parent.
-
- WINDOW SCROLL_VISIBLE WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to scroll the named window until the
- indicated box is visible.
-
- WINDOW PLACE_CARET WIN %id% X %n% Y %n% HEIGHT %n%
- The core asked Monkey to render a caret in the named window at the
- indicated position with the indicated height.
-
- WINDOW REMOVE_CARET WIN %id%
- The core asked Monkey to remove any caret in the named window.
-
- WINDOW SCROLL_START WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to scroll the named window to the start of
- the given box.
-
- WINDOW SELECT_MENU WIN %id%
- The core asked Monkey to produce a selection menu for the named
- window.
-
- WINDOW SAVE_LINK WIN %id% URL %url% TITLE %str%
- The core asked Monkey to save a link from the given window with
- the given URL and anchor title.
-
- WINDOW THUMBNAIL WIN %id% URL %url%
- The core asked Monkey to render a thumbnail for the given window
- which is currently at the given URL.
-
- WINDOW REDRAW WIN %id% START
- WINDOW REDRAW WIN %id% STOP
- The core wraps redraws in these messages. Thus PLOT responses can
- be allocated to the appropriate window.
-
- Download window messages
- ------------------------
-
- DOWNLOAD_WINDOW CREATE DWIN %id% WIN %id%
- The core asked Monkey to create a download window owned by the
- given browser window.
-
- DOWNLOAD_WINDOW DATA DWIN %id% SIZE %n% DATA %str%
- The core asked Monkey to update the named download window with
- the given byte size and data string.
-
- DOWNLOAD_WINDOW ERROR DWIN %id% ERROR %str%
- The core asked Monkey to update the named download window with
- the given error message.
-
- DOWNLOAD_WINDOW DONE DWIN %id%
- The core asked Monkey to destroy the named download window.
-
- SSL Certificate messages
- ------------------------
-
- SSLCERT VERIFY CERT %id% URL %url%
- The core asked Monkey to say whether or not a given SSL
- certificate is OK.
-
- 401 Login messages
- ------------------
-
- 401LOGIN OPEN M4 %id% URL %url% REALM %str%
- The core asked Monkey to ask for identification for the named
- realm at the given URL.
-
- Plotter messages
- ----------------
-
- Note, Monkey won't clip coordinates, but sometimes the core does.
-
- PLOT CLIP X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to clip plotting to the given clipping
- rectangle (X0,Y0) (X1,Y1)
-
- PLOT TEXT X %n% Y %n% STR %str%
- The core asked Monkey to plot the given string at the
- given coordinates.
-
- PLOT LINE X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to plot a line with the given start
- and end coordinates.
-
- PLOT RECT X0 %n% Y0 %n% X1 %n% Y1 %n%
- The core asked Monkey to plot a rectangle with the given
- coordinates as the corners.
-
- PLOT BITMAP X %n% Y %n% WIDTH %n% HEIGHT %n%
- The core asked Monkey to plot a bitmap at the given
- coordinates, scaled to the given width/height.
diff --git a/Docs/core-window-interface b/Docs/core-window-interface
deleted file mode 100644
index 3dfbcaf47..000000000
--- a/Docs/core-window-interface
+++ /dev/null
@@ -1,677 +0,0 @@
-Core Window Interface
-=====================
-
-The NetSurf core provides an optional API to frontend implementations
-which allows a number of "standard" window content interfaces to be
-provided.
-
-The currently available user interfaces are:
-
- - Cookies
- - Global history
- - Hotlist
- - SSL certificate view
-
-Although not currently included in future additional user interfaces
-will be available for:
-
- - local history
- - browser render
-
-To be clear these are generic implementations of this functionality
-that any frontend may use. Frontends are free to implement these
-interfaces in any manner as they see fit, the corewindow interface
-simply provides a default.
-
-core window API
----------------
-
-The API is fairly simple and simply involves passing a callback table
-and context pointer to the interface element being constructed.
-
-The header that defines the callback interface is netsurf/core_window.h
-
-The callback table contains five function pointer interfaces which the
-frontend must implement for the core.
-
- - redraw_request
- request a redraw an area of a window
-
- - update_size
- Update the limits of the window
-
- - scroll_visible
- Scroll the window to make area visible
-
- - get_window_dimensions
- Get window viewport dimensions
-
- - drag_status
- Inform corewindow owner of drag status
-
-Each callback will be passed the context pointer for the corewindow
-instance and the relevant additional information necessary to perform
-the operation.
-
-Each exported user interface element wraps this generic interface with
-a concrete implementation. For example the SSL certificate viewer is
-initialised with:
-
-nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
- void *core_window_handle,
- struct sslcert_session_data *ssl_d);
-
-This call creates a context which will display and navigate the ssl
-session data passed. The frontend must service the callbacks from the
-core to provide the necessary interactions with the frontend windowing
-system.
-
-These actions should ideally use the standard frontend window
-processing. So for the GTK frontend when the core calls the redraw
-operation it simply marks the area passed as damaged (using
-gtk_widget_queue_draw_area()) and lets the standard expose event cause
-the redraw to occour.
-
-If the frontend needs to redraw an area of a window (perhaps an expose
-event occoured) it must call the corewindoe API wrappers
-implementation e.g in the case of ssl certificate viewer
-
-void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
- int x, int y, struct rect *clip,
- const struct redraw_context *ctx);
-
-which will perform the plot operations required to update an area of
-the window for that SSL data.
-
-Usage
------
-
-The usage pattern that is expected is for a frontend to create a core
-window impementation that implements the necessary five API in a
-generic way and allows the frontend to provide the specific
-specialisation for each of the user interface elements it wishes to
-use (cookies, SSL viewer etc).
-
-The GTK frontend for example:
-
-has source corewindow.[ch] which implement the five core callbacks
-using generic GTK operations (redraw_request calls
-gtk_widget_queue_draw_area() etc.) and then provides additional
-operations on a GTK drawing area object to attach expose event
-processing, keypress processing etc.
-
-The GTK corewindow (not to be confused with the core window API
-itself, this is purely the gtk wrapper) is used by ssl_cert.c which
-creates a nsgtk_crtvrfy_window structure containing the
-nsgtk_corewindow structure. It attaches actual GTK window handles to
-this structure and populates elements of nsgtk_corewindow and then
-calls sslcert_viewer_init() directly.
-
-frontend skeleton
------------------
-
-An example core window implementation for a frontend ssl certficiate
-viewer is presented here. This implements the suggested usage above
-and provides generic corewindow helpers.
-
-
-frontends/example/corewindow.h
-------------------------------
-
-/*
- * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EXAMPLE_COREWINDOW_H
-#define EXAMPLE_COREWINDOW_H
-
-#include "netsurf/core_window.h"
-
-/**
- * example core window state
- */
-struct example_corewindow {
-
-
- /*
- * Any variables common to any frontend window would go here.
- * e.g. drawing area handles, toolkit pointers or other state
- */
- example_toolkit_widget *tk_widget;
-
-
-
- /** drag status set by core */
- core_window_drag_status drag_staus;
-
- /** table of callbacks for core window operations */
- struct core_window_callback_table *cb_table;
-
- /**
- * callback to draw on drawable area of example core window
- *
- * \param example_cw The example core window structure.
- * \param r The rectangle of the window that needs updating.
- * \return NSERROR_OK on success otherwise apropriate error code
- */
- nserror (*draw)(struct example_corewindow *example_cw, struct rect *r);
-
- /**
- * callback for keypress on example core window
- *
- * \param example_cw The example core window structure.
- * \param nskey The netsurf key code.
- * \return NSERROR_OK if key processed,
- * NSERROR_NOT_IMPLEMENTED if key not processed
- * otherwise apropriate error code
- */
- nserror (*key)(struct example_corewindow *example_cw, uint32_t nskey);
-
- /**
- * callback for mouse event on example core window
- *
- * \param example_cw The example core window structure.
- * \param mouse_state mouse state
- * \param x location of event
- * \param y location of event
- * \return NSERROR_OK on sucess otherwise apropriate error code.
- */
- nserror (*mouse)(struct example_corewindow *example_cw, browser_mouse_state mouse_state, int x, int y);
-};
-
-/**
- * initialise elements of example core window.
- *
- * As a pre-requisite the draw, key and mouse callbacks must be defined
- *
- * \param example_cw A example core window structure to initialise
- * \return NSERROR_OK on successful initialisation otherwise error code.
- */
-nserror example_corewindow_init(struct example_corewindow *example_cw);
-
-/**
- * finalise elements of example core window.
- *
- * \param example_cw A example core window structure to initialise
- * \return NSERROR_OK on successful finalisation otherwise error code.
- */
-nserror example_corewindow_fini(struct example_corewindow *example_cw);
-
-#endif
-
-frontends/example/corewindow.c
-------------------------------
-
-/*
- * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * EXAMPLE generic core window interface.
- *
- * Provides interface for core renderers to the example toolkit drawable area.
- *
- * This module is an object that must be encapsulated. Client users
- * should embed a struct example_corewindow at the beginning of their
- * context for this display surface, fill in relevant data and then
- * call example_corewindow_init()
- *
- * The example core window structure requires the callback for draw, key and
- * mouse operations.
- */
-
-#include <assert.h>
-#include <string.h>
-#include <math.h>
-
-#include "utils/log.h"
-#include "utils/utils.h"
-#include "utils/messages.h"
-#include "utils/utf8.h"
-#include "netsurf/keypress.h"
-#include "netsurf/mouse.h"
-#include "netsurf/plot_style.h"
-
-/* extremely likely there will be additional headers required in a real frontend */
-#include "example/corewindow.h"
-
-
-/* toolkit event handlers that do generic things and call internal callbacks */
-
-
-static bool
-example_cw_mouse_press_event(toolkit_widget *widget, toolkit_button bt, int x, int y, void *ctx)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
-
- example_cw->mouse(example_cw, state, x, y);
-
- return true;
-}
-
-static bool
-example_cw_keyrelease_event(toolkit_widget *widget, void *ctx)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
-
- example_cw->key(example_cw, keycode);
-
- return true;
-}
-
-
-
-/* signal handler for toolkit window redraw */
-static bool
-example_cw_draw_event(toolkit_widget *widget,
- toolkit_area *tk_area,
- void *ctx)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
- struct rect clip;
-
- clip.x0 = tk_area.x;
- clip.y0 = tk_area.y;
- clip.x1 = tk_area.width;
- clip.y1 = tk_area.height;
-
- example_cw->draw(example_cw, &clip);
-
- return true;
-}
-
-
-/**
- * callback from core to request a redraw
- */
-static void
-example_cw_redraw_request(struct core_window *cw, const struct rect *r)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)cw;
-
- toolkit_widget_queue_draw_area(example_cw->widget,
- r->x0, r->y0,
- r->x1 - r->x0, r->y1 - r->y0);
-}
-
-
-static void
-example_cw_update_size(struct core_window *cw, int width, int height)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)cw;
-
- toolkit_widget_set_size_request(EXAMPLE_WIDGET(example_cw->drawing_area),
- width, height);
-}
-
-
-static void
-example_cw_scroll_visible(struct core_window *cw, const struct rect *r)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)cw;
-
- toolkit_scroll_widget(example_cw->widget, r);
-}
-
-
-static void
-example_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)cw;
-
- *width = toolkit_get_widget_width(example_cw->widget);
- *height = toolkit_get_widget_height(example_cw->widget);
-}
-
-
-static void
-example_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
-{
- struct example_corewindow *example_cw = (struct example_corewindow *)cw;
- example_cw->drag_staus = ds;
-}
-
-
-struct core_window_callback_table example_cw_cb_table = {
- .redraw_request = example_cw_redraw_request,
- .update_size = example_cw_update_size,
- .scroll_visible = example_cw_scroll_visible,
- .get_window_dimensions = example_cw_get_window_dimensions,
- .drag_status = example_cw_drag_status
-};
-
-/* exported function documented example/corewindow.h */
-nserror example_corewindow_init(struct example_corewindow *example_cw)
-{
- /* setup the core window callback table */
- example_cw->cb_table = &example_cw_cb_table;
-
- /* frontend toolkit specific method of causing example_cw_draw_event to be called when a drawing operation is required */
- toolkit_connect_draw_event(example_cw->tk_widget,
- example_cw_draw_event,
- example_cw);
-
- /* frontend toolkit specific method of causing example_cw_button_press_event to be called when a button press occours */
- toolkit_connect_button_press_event(example_cw->tk_widget,
- example_cw_button_press_event,
- example_cw);
-
- /* frontend toolkit specific method of causing example_cw_button_release_event to be called when a button release occours */
- toolkit_connect_button_release_event(example_cw->tk_widget,
- example_cw_button_release_event,
- example_cw);
-
- /* frontend toolkit specific method of causing example_cw_motion_notify_event to be called when there is motion over the widget */
- toolkit_connect_motion_event(example_cw->tk_widget,
- example_cw_motion_notify_event,
- example_cw);
-
- /* frontend toolkit specific method of causing example_cw_key_press_event to be called when a key press occours */
- toolkit_connect_button_press_event(example_cw->tk_widget,
- example_cw_key_press_event,
- example_cw);
-
- /* frontend toolkit specific method of causing example_cw_key_release_event to be called when a key release occours */
- toolkit_connect_button_release_event(example_cw->tk_widget,
- example_cw_key_release_event,
- example_cw);
-
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in example/corewindow.h */
-nserror example_corewindow_fini(struct example_corewindow *example_cw)
-{
- return NSERROR_OK;
-}
-
-
-frontends/example/ssl_cert.h
-----------------------------
-
-/*
- * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NETSURF_EXAMPLE_SSL_CERT_H
-#define NETSURF_EXAMPLE_SSL_CERT_H 1
-
-struct nsurl;
-struct ssl_cert_info;
-
-/**
- * Prompt the user to verify a certificate with issuse.
- *
- * \param url The URL being verified.
- * \param certs The certificate to be verified
- * \param num The number of certificates to be verified.
- * \param cb Callback upon user decision.
- * \param cbpw Context pointer passed to cb
- * \return NSERROR_OK or error code if prompt creation failed.
- */
-nserror example_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
-
-#endif
-
-frontends/example/ssl_cert.c
-----------------------------
-
-/*
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Implementation of example certificate viewing using example core windows.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "utils/log.h"
-#include "netsurf/keypress.h"
-#include "netsurf/plotters.h"
-#include "desktop/sslcert_viewer.h"
-
-#include "example/corewindow.h"
-
-
-/**
- * EXAMPLE certificate viewing window context
- */
-struct example_crtvrfy_window {
- /** example core window context */
- struct example_corewindow core;
-
- /** SSL certificate viewer context data */
- struct sslcert_session_data *ssl_data;
-};
-
-/**
- * destroy a previously created certificate view
- */
-static nserror example_crtvrfy_destroy(struct example_crtvrfy_window *crtvrfy_win)
-{
- nserror res;
-
- res = sslcert_viewer_fini(crtvrfy_win->ssl_data);
- if (res == NSERROR_OK) {
- res = example_corewindow_fini(&crtvrfy_win->core);
- toolkit_windown_destroy(crtvrfy_win->window);
- free(crtvrfy_win);
- }
- return res;
-}
-
-static void
-example_crtvrfy_accept(ExampleButton *w, gpointer data)
-{
- struct example_crtvrfy_window *crtvrfy_win;
- crtvrfy_win = (struct example_crtvrfy_window *)data;
-
- sslcert_viewer_accept(crtvrfy_win->ssl_data);
-
- example_crtvrfy_destroy(crtvrfy_win);
-}
-
-static void
-example_crtvrfy_reject(ExampleWidget *w, gpointer data)
-{
- struct example_crtvrfy_window *crtvrfy_win;
- crtvrfy_win = (struct example_crtvrfy_window *)data;
-
- sslcert_viewer_reject(crtvrfy_win->ssl_data);
-
- example_crtvrfy_destroy(crtvrfy_win);
-}
-
-
-/**
- * callback for mouse action for certificate verify on core window
- *
- * \param example_cw The example core window structure.
- * \param mouse_state netsurf mouse state on event
- * \param x location of event
- * \param y location of event
- * \return NSERROR_OK on success otherwise apropriate error code
- */
-static nserror
-example_crtvrfy_mouse(struct example_corewindow *example_cw,
- browser_mouse_state mouse_state,
- int x, int y)
-{
- struct example_crtvrfy_window *crtvrfy_win;
- /* technically degenerate container of */
- crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
-
- sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y);
-
- return NSERROR_OK;
-}
-
-/**
- * callback for keypress for certificate verify on core window
- *
- * \param example_cw The example core window structure.
- * \param nskey The netsurf key code
- * \return NSERROR_OK on success otherwise apropriate error code
- */
-static nserror
-example_crtvrfy_key(struct example_corewindow *example_cw, uint32_t nskey)
-{
- struct example_crtvrfy_window *crtvrfy_win;
-
- /* technically degenerate container of */
- crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
-
- if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) {
- return NSERROR_OK;
- }
- return NSERROR_NOT_IMPLEMENTED;
-}
-
-/**
- * callback on draw event for certificate verify on core window
- *
- * \param example_cw The example core window structure.
- * \param r The rectangle of the window that needs updating.
- * \return NSERROR_OK on success otherwise apropriate error code
- */
-static nserror
-example_crtvrfy_draw(struct example_corewindow *example_cw, struct rect *r)
-{
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &example_plotters
- };
- struct example_crtvrfy_window *crtvrfy_win;
-
- /* technically degenerate container of */
- crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
-
- sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in example/ssl_cert.h */
-nserror example_cert_verify(struct nsurl *url,
- const struct ssl_cert_info *certs,
- unsigned long num,
- nserror (*cb)(bool proceed, void *pw),
- void *cbpw)
-{
- struct example_crtvrfy_window *ncwin;
- nserror res;
-
- ncwin = malloc(sizeof(struct example_crtvrfy_window));
- if (ncwin == NULL) {
- return NSERROR_NOMEM;
- }
-
- res = toolkit_create_window(&ncwin->window);
- if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
- free(ncwin);
- return res;
- }
-
- /* store the widget that the toolkit is drawing into */
- ncwin->core.widget = toolkit_get_widget(ncwin->window, "SSLDrawingArea"));
-
- /* would typicaly setup toolkit accept/reject buttons etc. here */
- toolkit_connect_button_press(ncwin->tk_accept_button,
- example_crtvrfy_accept,
- ncwin);
-
-
- /* initialise example core window */
- ncwin->core.draw = example_crtvrfy_draw;
- ncwin->core.key = example_crtvrfy_key;
- ncwin->core.mouse = example_crtvrfy_mouse;
-
- res = example_corewindow_init(&ncwin->core);
- if (res != NSERROR_OK) {
- free(ncwin);
- return res;
- }
-
- /* initialise certificate viewing interface */
- res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs,
- &ncwin->ssl_data);
- if (res != NSERROR_OK) {
- free(ncwin);
- return res;
- }
-
- res = sslcert_viewer_init(ncwin->core.cb_table,
- (struct core_window *)ncwin,
- ncwin->ssl_data);
- if (res != NSERROR_OK) {
- free(ncwin);
- return res;
- }
-
- toolkit_widget_show(ncwin->window);
-
- return NSERROR_OK;
-}
diff --git a/Makefile b/Makefile
index 5f2697fdc..3e63fb242 100644
--- a/Makefile
+++ b/Makefile
@@ -84,13 +84,6 @@ ifeq ($(HOST),AmigaOS)
endif
endif
-ifeq ($(HOST),Darwin)
- HOST := macosx
- ifeq ($(TARGET),)
- TARGET := cocoa
- endif
-endif
-
ifeq ($(HOST),FreeMiNT)
HOST := mint
endif
@@ -116,7 +109,7 @@ ifeq ($(TARGET),)
endif
# valid values for the TARGET
-VLDTARGET := riscos gtk gtk3 beos amiga amigaos3 framebuffer windows atari cocoa monkey
+VLDTARGET := riscos gtk gtk3 beos amiga amigaos3 framebuffer windows atari monkey
# Check for valid TARGET
ifeq ($(filter $(VLDTARGET),$(TARGET)),)
@@ -137,7 +130,7 @@ MESSAGES_FILTER=any
# The languages in the fat messages to convert
MESSAGES_LANGUAGES=de en fr it nl
# The target directory for the split messages
-MESSAGES_TARGET=!NetSurf/Resources
+MESSAGES_TARGET=resources
# Defaults for tools
PERL=perl
@@ -255,9 +248,6 @@ else
PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
endif
else
- ifeq ($(TARGET),cocoa)
- PKG_CONFIG := PKG_CONFIG_PATH="$(PKG_CONFIG_PATH):/usr/local/lib/pkgconfig" pkg-config
- else
ifeq ($(TARGET),atari)
ifeq ($(HOST),atari)
PKG_CONFIG := pkg-config
@@ -323,7 +313,6 @@ else
endif
endif
endif
- endif
endif
endif
endif
@@ -516,9 +505,12 @@ CXXWARNFLAGS :=
# C default warning flags
CWARNFLAGS := -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs
-# Pull in the configuration
+# Pull in the default configuration
include Makefile.defaults
+# Pull in the user configuration
+-include Makefile.config
+
# libraries enabled by feature switch without pkgconfig file
$(eval $(call feature_switch,JPEG,JPEG (libjpeg),-DWITH_JPEG,-ljpeg,-UWITH_JPEG,))
$(eval $(call feature_switch,HARU_PDF,PDF export (haru),-DWITH_PDF_EXPORT,-lhpdf -lpng,-UWITH_PDF_EXPORT,))
@@ -545,6 +537,7 @@ NETSURF_FEATURE_NSSVG_CFLAGS := -DWITH_NS_SVG
NETSURF_FEATURE_OPENSSL_CFLAGS := -DWITH_OPENSSL
NETSURF_FEATURE_ROSPRITE_CFLAGS := -DWITH_NSSPRITE
NETSURF_FEATURE_NSPSL_CFLAGS := -DWITH_NSPSL
+NETSURF_FEATURE_NSLOG_CFLAGS := -DWITH_NSLOG
# libcurl and openssl ordering matters as if libcurl requires ssl it
# needs to come first in link order to ensure its symbols can be
@@ -565,6 +558,7 @@ $(eval $(call pkg_config_find_and_add_enabled,GIF,libnsgif,GIF))
$(eval $(call pkg_config_find_and_add_enabled,NSSVG,libsvgtiny,SVG))
$(eval $(call pkg_config_find_and_add_enabled,ROSPRITE,librosprite,Sprite))
$(eval $(call pkg_config_find_and_add_enabled,NSPSL,libnspsl,PSL))
+$(eval $(call pkg_config_find_and_add_enabled,NSLOG,libnslog,LOG))
# List of directories in which headers are searched for
INCLUDE_DIRS :=. include $(OBJROOT)
@@ -577,6 +571,36 @@ CXXFLAGS += -DNETSURF_UA_FORMAT_STRING=\"$(NETSURF_UA_FORMAT_STRING)\"
CFLAGS += -DNETSURF_HOMEPAGE=\"$(NETSURF_HOMEPAGE)\"
CXXFLAGS += -DNETSURF_HOMEPAGE=\"$(NETSURF_HOMEPAGE)\"
+# set the logging level
+CFLAGS += -DNETSURF_LOG_LEVEL=$(NETSURF_LOG_LEVEL)
+CXXFLAGS += -DNETSURF_LOG_LEVEL=$(NETSURF_LOG_LEVEL)
+
+# If we're building the sanitize goal, override things
+ifneq ($(filter-out sanitize,$(MAKECMDGOALS)),$(MAKECMDGOALS))
+override NETSURF_USE_SANITIZER := YES
+override NETSURF_RECOVER_SANITIZERS := NO
+endif
+
+# If we're going to use the sanitizer set it up
+ifeq ($(NETSURF_USE_SANITIZER),YES)
+SAN_FLAGS := -fsanitize=address -fsanitize=undefined
+ifeq ($(NETSURF_RECOVER_SANITIZERS),NO)
+SAN_FLAGS += -fno-sanitize-recover
+endif
+else
+SAN_FLAGS :=
+endif
+CFLAGS += $(SAN_FLAGS)
+CXXFLAGS += $(SAN_FLAGS)
+LDFLAGS += $(SAN_FLAGS)
+
+# and the logging filter
+CFLAGS += -DNETSURF_BUILTIN_LOG_FILTER=\"$(NETSURF_BUILTIN_LOG_FILTER)\"
+CXXFLAGS += -DNETSURF_BUILTIN_LOG_FILTER=\"$(NETSURF_BUILTIN_LOG_FILTER)\"
+# and the verbose logging filter
+CFLAGS += -DNETSURF_BUILTIN_VERBOSE_FILTER=\"$(NETSURF_BUILTIN_VERBOSE_FILTER)\"
+CXXFLAGS += -DNETSURF_BUILTIN_VERBOSE_FILTER=\"$(NETSURF_BUILTIN_VERBOSE_FILTER)\"
+
# ----------------------------------------------------------------------------
# General make rules
# ----------------------------------------------------------------------------
@@ -612,21 +636,27 @@ include frontends/Makefile
# Content sources
include content/Makefile
-# render sources
-include render/Makefile
-
# utility sources
include utils/Makefile
# http utility sources
include utils/http/Makefile
+# nsurl utility sources
+include utils/nsurl/Makefile
+
# Desktop sources
include desktop/Makefile
# S_COMMON are sources common to all builds
-S_COMMON := $(S_CONTENT) $(S_FETCHERS) $(S_RENDER) $(S_UTILS) $(S_HTTP) \
- $(S_DESKTOP) $(S_JAVASCRIPT_BINDING)
+S_COMMON := \
+ $(S_CONTENT) \
+ $(S_FETCHERS) \
+ $(S_UTILS) \
+ $(S_HTTP) \
+ $(S_NSURL) \
+ $(S_DESKTOP) \
+ $(S_JAVASCRIPT_BINDING)
# ----------------------------------------------------------------------------
@@ -636,16 +666,12 @@ S_COMMON := $(S_CONTENT) $(S_FETCHERS) $(S_RENDER) $(S_UTILS) $(S_HTTP) \
# Message splitting rule generation macro
# 1 = Language
define split_messages
-.INTERMEDIATE:$$(MESSAGES_TARGET)/$(1)/Messages.tmp
-$$(MESSAGES_TARGET)/$(1)/Messages.tmp: resources/FatMessages
+$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages
$$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
$$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
- $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ $$<
-
-$$(MESSAGES_TARGET)/$(1)/Messages: $$(MESSAGES_TARGET)/$(1)/Messages.tmp
- $$(VQ)echo "COMPRESS: $$@"
- $$(Q)gzip -9n < $$< > $$@
+ $$(Q)$$(RM) $$@
+ $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
@@ -737,7 +763,6 @@ DEPFILES :=
# 3 = obj filename, no prefix
define dependency_generate_c
DEPFILES += $(2)
-$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1) Makefile.config
endef
@@ -746,7 +771,6 @@ endef
# 3 = obj filename, no prefix
define dependency_generate_s
DEPFILES += $(2)
-$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1)
endef
@@ -756,7 +780,7 @@ endef
ifeq ($(CC_MAJOR),2)
# simpler deps tracking for gcc2...
define compile_target_c
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
@@ -769,7 +793,7 @@ $$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
endef
else
define compile_target_c
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " COMPILE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
@@ -781,7 +805,7 @@ endef
endif
define compile_target_cpp
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
@@ -797,7 +821,7 @@ endef
# 2 = obj filename, no prefix
# 3 = dep filename, no prefix
define compile_target_s
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo "ASSEMBLE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
@@ -880,7 +904,7 @@ install: all-program install-$(TARGET)
.PHONY: docs
-docs: Docs/Doxyfile
+docs: docs/Doxyfile
doxygen $<
diff --git a/Makefile.config.example b/Makefile.config.example
index aeddc1071..7fa7f41cc 100644
--- a/Makefile.config.example
+++ b/Makefile.config.example
@@ -33,3 +33,9 @@
### To change flags to javascript binding generator
# GBFLAGS:=-g
+
+### To enable ASAN and UBSAN support in builds regardless of target
+# override NETSURF_USE_SANITIZER := YES
+
+### If you're using the sanitizers and you want it to stop on failure...
+# override NETSURF_RECOVER_SANITIZERS := NO
diff --git a/Makefile.defaults b/Makefile.defaults
index 619b8db08..51090109e 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -70,8 +70,21 @@ NETSURF_USE_DUKTAPE := YES
NETSURF_USE_HARU_PDF := NO
# Enable the use of the Public suffix library to detect supercookies
+# Valid options: YES, NO, AUTO (highly recommended)
NETSURF_USE_NSPSL := AUTO
+# Enable use of filtered logging library
+# Valid options: YES, NO, AUTO (highly recommended)
+NETSURF_USE_NSLOG := AUTO
+# The minimum logging level *compiled* into netsurf
+# Valid options are: DEEPDEBUG, DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL
+NETSURF_LOG_LEVEL := INFO
+# The log filter set during log initialisation before options are available
+NETSURF_BUILTIN_LOG_FILTER := level:WARNING
+# The log filter set during log initialisation before options are available
+# if the logging level is set to verbose
+NETSURF_BUILTIN_VERBOSE_FILTER := level:VERBOSE
+
# Enable stripping the NetSurf binary
# Valid options: YES, NO
NETSURF_STRIP_BINARY := NO
@@ -96,6 +109,11 @@ NETSURF_USE_LIBICONV_PLUG := YES
# Valid options: YES, NO
NETSURF_FS_BACKING_STORE := NO
+# Enable the ASAN and UBSAN flags regardless of targets
+NETSURF_USE_SANITIZERS := NO
+# But recover after sanitizer failure
+NETSURF_RECOVER_SANITIZERS := YES
+
# Initial CFLAGS. Optimisation level etc. tend to be target specific.
CFLAGS :=
@@ -136,11 +154,9 @@ endif
# ----------------------------------------------------------------------------
-# Include any local configuration
+# Detect double inclusion
# ----------------------------------------------------------------------------
ifneq ($(MAKEFILE_DEFAULTS_FINISHED),)
$(error Makefile.defaults has been double-included. If you did something utterly brain-dead such as copying Makefile.defaults to Makefile.config then you deserve all the pain you can imagine. Do NOT do that. Why not read the comments at the top of Makefile.defaults. They are there to help you, you numpty)
endif
MAKEFILE_DEFAULTS_FINISHED=yes
--include Makefile.config
-
diff --git a/content/content.c b/content/content.c
index 2eb035cdf..9a240417d 100644
--- a/content/content.c
+++ b/content/content.c
@@ -73,7 +73,8 @@ nserror content__init(struct content *c, const content_handler *handler,
struct content_user *user_sentinel;
nserror error;
- LOG("url "URL_FMT_SPC" -> %p", nsurl_access(llcache_handle_get_url(llcache)), c);
+ NSLOG(netsurf, INFO, "url "URL_FMT_SPC" -> %p",
+ nsurl_access(llcache_handle_get_url(llcache)), c);
user_sentinel = calloc(1, sizeof(struct content_user));
if (user_sentinel == NULL) {
@@ -163,7 +164,7 @@ nserror content_llcache_callback(llcache_handle *llcache,
content_set_status(c, messages_get("Processing"));
msg_data.explicit_status_text = NULL;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
content_convert(c);
}
@@ -172,17 +173,17 @@ nserror content_llcache_callback(llcache_handle *llcache,
/** \todo Error page? */
c->status = CONTENT_STATUS_ERROR;
msg_data.error = event->data.msg;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
break;
case LLCACHE_EVENT_PROGRESS:
content_set_status(c, event->data.msg);
msg_data.explicit_status_text = NULL;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
break;
case LLCACHE_EVENT_REDIRECT:
msg_data.redirect.from = event->data.redirect.from;
msg_data.redirect.to = event->data.redirect.to;
- content_broadcast(c, CONTENT_MSG_REDIRECT, msg_data);
+ content_broadcast(c, CONTENT_MSG_REDIRECT, &msg_data);
break;
}
@@ -272,7 +273,8 @@ void content_convert(struct content *c)
if (c->locked == true)
return;
- LOG("content "URL_FMT_SPC" (%p)", nsurl_access(llcache_handle_get_url(c->llcache)), c);
+ NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p)",
+ nsurl_access(llcache_handle_get_url(c->llcache)), c);
if (c->handler->data_complete != NULL) {
c->locked = true;
@@ -292,8 +294,6 @@ void content_convert(struct content *c)
void content_set_ready(struct content *c)
{
- union content_msg_data msg_data;
-
/* The content must be locked at this point, as it can only
* become READY after conversion. */
assert(c->locked);
@@ -301,7 +301,7 @@ void content_set_ready(struct content *c)
c->status = CONTENT_STATUS_READY;
content_update_status(c);
- content_broadcast(c, CONTENT_MSG_READY, msg_data);
+ content_broadcast(c, CONTENT_MSG_READY, NULL);
}
/**
@@ -310,7 +310,6 @@ void content_set_ready(struct content *c)
void content_set_done(struct content *c)
{
- union content_msg_data msg_data;
uint64_t now_ms;
nsu_getmonotonic_ms(&now_ms);
@@ -318,7 +317,7 @@ void content_set_done(struct content *c)
c->status = CONTENT_STATUS_DONE;
c->time = now_ms - c->time;
content_update_status(c);
- content_broadcast(c, CONTENT_MSG_DONE, msg_data);
+ content_broadcast(c, CONTENT_MSG_DONE, NULL);
}
/**
@@ -363,7 +362,7 @@ void content__reformat(struct content *c, bool background,
c->locked = false;
data.background = background;
- content_broadcast(c, CONTENT_MSG_REFORMAT, data);
+ content_broadcast(c, CONTENT_MSG_REFORMAT, &data);
}
}
@@ -379,7 +378,8 @@ void content_destroy(struct content *c)
struct content_rfc5988_link *link;
assert(c);
- LOG("content %p %s", c, nsurl_access(llcache_handle_get_url(c->llcache)));
+ NSLOG(netsurf, INFO, "content %p %s", c,
+ nsurl_access(llcache_handle_get_url(c->llcache)));
assert(c->locked == false);
if (c->handler->destroy != NULL)
@@ -436,7 +436,7 @@ void content_mouse_track(hlcache_handle *h, struct browser_window *bw,
} else {
union content_msg_data msg_data;
msg_data.pointer = BROWSER_POINTER_AUTO;
- content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
+ content_broadcast(c, CONTENT_MSG_POINTER, &msg_data);
}
@@ -540,7 +540,7 @@ void content__request_redraw(struct content *c,
data.redraw.object_width = c->width;
data.redraw.object_height = c->height;
- content_broadcast(c, CONTENT_MSG_REDRAW, data);
+ content_broadcast(c, CONTENT_MSG_REDRAW, &data);
}
@@ -588,7 +588,7 @@ bool content_scaled_redraw(struct hlcache_handle *h,
return true;
}
- LOG("Content %p %dx%d ctx:%p", c, width, height, ctx);
+ NSLOG(netsurf, INFO, "Content %p %dx%d ctx:%p", c, width, height, ctx);
if (ctx->plot->option_knockout) {
knockout_plot_start(ctx, &new_ctx);
@@ -600,12 +600,12 @@ bool content_scaled_redraw(struct hlcache_handle *h,
clip.x1 = width;
clip.y1 = height;
- new_ctx.plot->clip(&clip);
+ new_ctx.plot->clip(&new_ctx, &clip);
/* Plot white background */
- plot_ok &= new_ctx.plot->rectangle(clip.x0, clip.y0, clip.x1, clip.y1,
- plot_style_fill_white);
-
+ plot_ok &= (new_ctx.plot->rectangle(&new_ctx,
+ plot_style_fill_white,
+ &clip) == NSERROR_OK);
/* Set up content redraw data */
data.x = 0;
@@ -628,7 +628,7 @@ bool content_scaled_redraw(struct hlcache_handle *h,
plot_ok &= c->handler->redraw(c, &data, &clip, &new_ctx);
if (ctx->plot->option_knockout) {
- knockout_plot_end();
+ knockout_plot_end(ctx);
}
return plot_ok;
@@ -646,14 +646,20 @@ bool content_scaled_redraw(struct hlcache_handle *h,
* called with the content.
*/
-bool content_add_user(struct content *c,
- void (*callback)(struct content *c, content_msg msg,
- union content_msg_data data, void *pw),
+bool content_add_user(
+ struct content *c,
+ void (*callback)(
+ struct content *c,
+ content_msg msg,
+ const union content_msg_data *data,
+ void *pw),
void *pw)
{
struct content_user *user;
- LOG("content "URL_FMT_SPC" (%p), user %p %p", nsurl_access(llcache_handle_get_url(c->llcache)), c, callback, pw);
+ NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p), user %p %p",
+ nsurl_access(llcache_handle_get_url(c->llcache)), c, callback,
+ pw);
user = malloc(sizeof(struct content_user));
if (!user)
return false;
@@ -676,13 +682,19 @@ bool content_add_user(struct content *c,
* content_add_user().
*/
-void content_remove_user(struct content *c,
- void (*callback)(struct content *c, content_msg msg,
- union content_msg_data data, void *pw),
+void content_remove_user(
+ struct content *c,
+ void (*callback)(
+ struct content *c,
+ content_msg msg,
+ const union content_msg_data *data,
+ void *pw),
void *pw)
{
struct content_user *user, *next;
- LOG("content "URL_FMT_SPC" (%p), user %p %p", nsurl_access(llcache_handle_get_url(c->llcache)), c, callback, pw);
+ NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p), user %p %p",
+ nsurl_access(llcache_handle_get_url(c->llcache)), c, callback,
+ pw);
/* user_list starts with a sentinel */
for (user = c->user_list; user->next != 0 &&
@@ -690,7 +702,7 @@ void content_remove_user(struct content *c,
user->next->pw == pw); user = user->next)
;
if (user->next == 0) {
- LOG("user not found in list");
+ NSLOG(netsurf, INFO, "user not found in list");
assert(0);
return;
}
@@ -753,11 +765,12 @@ bool content_is_shareable(struct content *c)
*/
void content_broadcast(struct content *c, content_msg msg,
- union content_msg_data data)
+ const union content_msg_data *data)
{
struct content_user *user, *next;
assert(c);
-// LOG("%p %s -> %d", c, c->url, msg);
+
+ NSLOG(netsurf, DEEPDEBUG, "%p -> msg:%d", c, msg);
for (user = c->user_list->next; user != 0; user = next) {
next = user->next; /* user may be destroyed during callback */
if (user->callback != 0)
@@ -777,8 +790,10 @@ void content_broadcast_errorcode(struct content *c, nserror errorcode)
for (user = c->user_list->next; user != 0; user = next) {
next = user->next; /* user may be destroyed during callback */
- if (user->callback != 0)
- user->callback(c, CONTENT_MSG_ERRORCODE, data, user->pw);
+ if (user->callback != 0) {
+ user->callback(c, CONTENT_MSG_ERRORCODE,
+ &data, user->pw);
+ }
}
}
@@ -800,7 +815,8 @@ void content_open(hlcache_handle *h, struct browser_window *bw,
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
- LOG("content %p %s", c, nsurl_access(llcache_handle_get_url(c->llcache)));
+ NSLOG(netsurf, INFO, "content %p %s", c,
+ nsurl_access(llcache_handle_get_url(c->llcache)));
if (c->handler->open != NULL)
c->handler->open(c, bw, page, params);
}
@@ -816,7 +832,8 @@ void content_close(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
- LOG("content %p %s", c, nsurl_access(llcache_handle_get_url(c->llcache)));
+ NSLOG(netsurf, INFO, "content %p %s", c,
+ nsurl_access(llcache_handle_get_url(c->llcache)));
if (c->handler->close != NULL)
c->handler->close(c);
}
@@ -1040,7 +1057,7 @@ bool content__add_rfc5988_link(struct content *c,
/* broadcast the data */
msg_data.rfc5988_link = newlink;
- content_broadcast(c, CONTENT_MSG_LINK, msg_data);
+ content_broadcast(c, CONTENT_MSG_LINK, &msg_data);
return true;
}
@@ -1464,7 +1481,7 @@ nserror content__clone(const struct content *c, struct content *nc)
*/
nserror content_abort(struct content *c)
{
- LOG("Aborting %p", c);
+ NSLOG(netsurf, INFO, "Aborting %p", c);
if (c->handler->stop != NULL)
c->handler->stop(c);
diff --git a/content/content.h b/content/content.h
index 308b2113b..e555df269 100644
--- a/content/content.h
+++ b/content/content.h
@@ -200,10 +200,24 @@ union content_msg_data {
void content_destroy(struct content *c);
-bool content_add_user(struct content *h, void (*callback)(struct content *c, content_msg msg, union content_msg_data data, void *pw), void *pw);
-
-
-void content_remove_user(struct content *c, void (*callback)(struct content *c, content_msg msg, union content_msg_data data, void *pw), void *pw);
+bool content_add_user(
+ struct content *h,
+ void (*callback)(
+ struct content *c,
+ content_msg msg,
+ const union content_msg_data *data,
+ void *pw),
+ void *pw);
+
+
+void content_remove_user(
+ struct content *c,
+ void (*callback)(
+ struct content *c,
+ content_msg msg,
+ const union content_msg_data *data,
+ void *pw),
+ void *pw);
uint32_t content_count_users(struct content *c);
diff --git a/content/content_factory.c b/content/content_factory.c
index 224220796..935354a5d 100644
--- a/content/content_factory.c
+++ b/content/content_factory.c
@@ -125,12 +125,14 @@ static const content_handler *content_lookup(lwc_string *mime_type)
for (entry = content_handlers; entry != NULL; entry = entry->next) {
if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
- &match) == lwc_error_ok && match)
+ &match) == lwc_error_ok && match) {
break;
+ }
}
- if (entry != NULL)
+ if (entry != NULL) {
return entry->handler;
+ }
return NULL;
}
diff --git a/content/content_protected.h b/content/content_protected.h
index ef38cb12d..21b73a662 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -92,8 +92,11 @@ struct content_handler {
/** Linked list of users of a content. */
struct content_user
{
- void (*callback)(struct content *c, content_msg msg,
- union content_msg_data data, void *pw);
+ void (*callback)(
+ struct content *c,
+ content_msg msg,
+ const union content_msg_data *data,
+ void *pw);
void *pw;
struct content_user *next;
@@ -166,7 +169,7 @@ void content_set_error(struct content *c);
void content_set_status(struct content *c, const char *status_message);
void content_broadcast(struct content *c, content_msg msg,
- union content_msg_data data);
+ const union content_msg_data *data);
/**
* Send an errorcode message to all users.
*/
diff --git a/content/fetch.c b/content/fetch.c
index a1542eb01..766502941 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -26,8 +26,8 @@
* around the fetcher specific methods.
*
* Active fetches are held in the circular linked list ::fetch_ring. There may
- * be at most ::option_max_fetchers_per_host active requests per Host: header.
- * There may be at most ::option_max_fetchers active requests overall. Inactive
+ * be at most nsoption max_fetchers_per_host active requests per Host: header.
+ * There may be at most nsoption max_fetchers active requests overall. Inactive
* fetches are stored in the ::queue_ring waiting for use.
*/
@@ -60,16 +60,6 @@
#include "javascript/fetcher.h"
#include "content/urldb.h"
-/* Define this to turn on verbose fetch logging */
-#undef DEBUG_FETCH_VERBOSE
-
-/** Verbose fetcher logging */
-#ifdef DEBUG_FETCH_VERBOSE
-#define FETCH_LOG(x...) LOG(x...)
-#else
-#define FETCH_LOG(x...)
-#endif
-
/** The maximum number of fetchers that can be added */
#define MAX_FETCHERS 10
@@ -158,8 +148,10 @@ static int get_fetcher_for_scheme(lwc_string *scheme)
static bool fetch_dispatch_job(struct fetch *fetch)
{
RING_REMOVE(queue_ring, fetch);
- FETCH_LOG("Attempting to start fetch %p, fetcher %p, url %s", fetch,
- fetch->fetcher_handle, nsurl_access(fetch->url));
+ NSLOG(fetch, DEBUG,
+ "Attempting to start fetch %p, fetcher %p, url %s", fetch,
+ fetch->fetcher_handle,
+ nsurl_access(fetch->url));
if (!fetchers[fetch->fetcherd].ops.start(fetch->fetcher_handle)) {
RING_INSERT(queue_ring, fetch); /* Put it back on the end of the queue */
@@ -210,25 +202,25 @@ static bool fetch_choose_and_dispatch(void)
static void dump_rings(void)
{
-#ifdef DEBUG_FETCH_VERBOSE
struct fetch *q;
struct fetch *f;
q = queue_ring;
if (q) {
do {
- LOG("queue_ring: %s", nsurl_access(q->url));
+ NSLOG(fetch, DEBUG, "queue_ring: %s",
+ nsurl_access(q->url));
q = q->r_next;
} while (q != queue_ring);
}
f = fetch_ring;
if (f) {
do {
- LOG("fetch_ring: %s", nsurl_access(f->url));
+ NSLOG(fetch, DEBUG, "fetch_ring: %s",
+ nsurl_access(f->url));
f = f->r_next;
} while (f != fetch_ring);
}
-#endif
}
/**
@@ -244,7 +236,10 @@ static bool fetch_dispatch_jobs(void)
RING_GETSIZE(struct fetch, queue_ring, all_queued);
RING_GETSIZE(struct fetch, fetch_ring, all_active);
- FETCH_LOG("queue_ring %i, fetch_ring %i", all_queued, all_active);
+ NSLOG(fetch, DEBUG,
+ "queue_ring %i, fetch_ring %i",
+ all_queued,
+ all_active);
dump_rings();
while ((all_queued != 0) &&
@@ -252,12 +247,14 @@ static bool fetch_dispatch_jobs(void)
fetch_choose_and_dispatch()) {
all_queued--;
all_active++;
- FETCH_LOG("%d queued, %d fetching",
- all_queued, all_active);
+ NSLOG(fetch, DEBUG,
+ "%d queued, %d fetching",
+ all_queued,
+ all_active);
}
- FETCH_LOG("Fetch ring is now %d elements.", all_active);
- FETCH_LOG("Queue ring is now %d elements.", all_queued);
+ NSLOG(fetch, DEBUG, "Fetch ring is now %d elements.", all_active);
+ NSLOG(fetch, DEBUG, "Queue ring is now %d elements.", all_queued);
return (all_active > 0);
}
@@ -267,7 +264,7 @@ static void fetcher_poll(void *unused)
int fetcherd;
if (fetch_dispatch_jobs()) {
- FETCH_LOG("Polling fetchers");
+ NSLOG(fetch, DEBUG, "Polling fetchers");
for (fetcherd = 0; fetcherd < MAX_FETCHERS; fetcherd++) {
if (fetchers[fetcherd].refcount > 0) {
/* fetcher present */
@@ -341,7 +338,10 @@ void fetcher_quit(void)
* the reference count to allow the fetcher to
* be stopped.
*/
- LOG("Fetcher for scheme %s still has %d active users at quit.", lwc_string_data(fetchers[fetcherd].scheme), fetchers[fetcherd].refcount);
+ NSLOG(fetch, INFO,
+ "Fetcher for scheme %s still has %d active users at quit.",
+ lwc_string_data(fetchers[fetcherd].scheme),
+ fetchers[fetcherd].refcount);
fetchers[fetcherd].refcount = 1;
}
@@ -391,12 +391,12 @@ fetch_fdset(fd_set *read_fd_set,
int fetcherd; /* fetcher index */
if (!fetch_dispatch_jobs()) {
- FETCH_LOG("No jobs");
+ NSLOG(fetch, DEBUG, "No jobs");
*maxfd_out = -1;
return NSERROR_OK;
}
- FETCH_LOG("Polling fetchers");
+ NSLOG(fetch, DEBUG, "Polling fetchers");
for (fetcherd = 0; fetcherd < MAX_FETCHERS; fetcherd++) {
if (fetchers[fetcherd].refcount > 0) {
@@ -479,7 +479,7 @@ fetch_start(nsurl *url,
return NSERROR_NO_FETCH_HANDLER;
}
- FETCH_LOG("fetch %p, url '%s'", fetch, nsurl_access(url));
+ NSLOG(fetch, DEBUG, "fetch %p, url '%s'", fetch, nsurl_access(url));
/* construct a new fetch structure */
fetch->callback = callback;
@@ -571,7 +571,7 @@ fetch_start(nsurl *url,
/* Ask the queue to run. */
if (fetch_dispatch_jobs()) {
- FETCH_LOG("scheduling poll");
+ NSLOG(fetch, DEBUG, "scheduling poll");
/* schedule active fetchers to run again in 10ms */
guit->misc->schedule(10, fetcher_poll, NULL);
}
@@ -584,7 +584,8 @@ fetch_start(nsurl *url,
void fetch_abort(struct fetch *f)
{
assert(f);
- FETCH_LOG("fetch %p, fetcher %p, url '%s'", f, f->fetcher_handle,
+ NSLOG(fetch, DEBUG,
+ "fetch %p, fetcher %p, url '%s'", f, f->fetcher_handle,
nsurl_access(f->url));
fetchers[f->fetcherd].ops.abort(f->fetcher_handle);
}
@@ -592,7 +593,10 @@ void fetch_abort(struct fetch *f)
/* exported interface documented in content/fetch.h */
void fetch_free(struct fetch *f)
{
- FETCH_LOG("Freeing fetch %p, fetcher %p", f, f->fetcher_handle);
+ NSLOG(fetch, DEBUG,
+ "Freeing fetch %p, fetcher %p",
+ f,
+ f->fetcher_handle);
fetchers[f->fetcherd].ops.free(f->fetcher_handle);
@@ -718,7 +722,8 @@ void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
free(list->name);
free(list->value);
if (list->file) {
- FETCH_LOG("Freeing rawfile: %s", list->rawfile);
+ NSLOG(fetch, DEBUG,
+ "Freeing rawfile: %s", list->rawfile);
free(list->rawfile);
}
free(list);
@@ -736,8 +741,13 @@ fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
/* exported interface documented in content/fetch.h */
void fetch_remove_from_queues(struct fetch *fetch)
{
- FETCH_LOG("Fetch %p, fetcher %p can be freed",
- fetch, fetch->fetcher_handle);
+ int all_active;
+ int all_queued;
+
+ NSLOG(fetch, DEBUG,
+ "Fetch %p, fetcher %p can be freed",
+ fetch,
+ fetch->fetcher_handle);
/* Go ahead and free the fetch properly now */
if (fetch->fetch_is_active) {
@@ -746,24 +756,19 @@ void fetch_remove_from_queues(struct fetch *fetch)
RING_REMOVE(queue_ring, fetch);
}
-#ifdef DEBUG_FETCH_VERBOSE
- int all_active;
- int all_queued;
RING_GETSIZE(struct fetch, fetch_ring, all_active);
RING_GETSIZE(struct fetch, queue_ring, all_queued);
- LOG("Fetch ring is now %d elements.", all_active);
-
- LOG("Queue ring is now %d elements.", all_queued);
-#endif
+ NSLOG(fetch, DEBUG, "Fetch ring is now %d elements.", all_active);
+ NSLOG(fetch, DEBUG, "Queue ring is now %d elements.", all_queued);
}
/* exported interface documented in content/fetch.h */
void fetch_set_http_code(struct fetch *fetch, long http_code)
{
- FETCH_LOG("Setting HTTP code to %ld", http_code);
+ NSLOG(fetch, DEBUG, "Setting HTTP code to %ld", http_code);
fetch->http_code = http_code;
}
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index 7d0e40c24..a358492ab 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -67,6 +67,21 @@
/** maximum number of X509 certificates in chain for TLS connection */
#define MAX_CERTS 10
+/* the ciphersuites we are willing to use */
+#define CIPHER_LIST \
+ /* disable everything */ \
+ "-ALL:" \
+ /* enable TLSv1.2 PFS suites */ \
+ "EECDH+AES+TLSv1.2:EDH+AES+TLSv1.2:" \
+ /* enable PFS AES GCM suites */ \
+ "EECDH+AESGCM:EDH+AESGCM:" \
+ /* Enable PFS AES CBC suites */ \
+ "EECDH+AES:EDH+AES:" \
+ /* Enable non-PFS fallback suite */ \
+ "AES128-SHA:" \
+ /* Remove any PFS suites using weak DSA key exchange */ \
+ "-DSS"
+
/** SSL certificate info */
struct cert_info {
X509 *cert; /**< Pointer to certificate */
@@ -155,7 +170,8 @@ static void ns_X509_free(X509 *cert)
*/
static bool fetch_curl_initialise(lwc_string *scheme)
{
- LOG("Initialise cURL fetcher for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "Initialise cURL fetcher for %s",
+ lwc_string_data(scheme));
curl_fetchers_registered++;
return true; /* Always succeeds */
}
@@ -171,17 +187,20 @@ static void fetch_curl_finalise(lwc_string *scheme)
struct cache_handle *h;
curl_fetchers_registered--;
- LOG("Finalise cURL fetcher %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "Finalise cURL fetcher %s",
+ lwc_string_data(scheme));
if (curl_fetchers_registered == 0) {
CURLMcode codem;
/* All the fetchers have been finalised. */
- LOG("All cURL fetchers finalised, closing down cURL");
+ NSLOG(netsurf, INFO,
+ "All cURL fetchers finalised, closing down cURL");
curl_easy_cleanup(fetch_blank_curl);
codem = curl_multi_cleanup(fetch_curl_multi);
if (codem != CURLM_OK)
- LOG("curl_multi_cleanup failed: ignoring");
+ NSLOG(netsurf, INFO,
+ "curl_multi_cleanup failed: ignoring");
curl_global_cleanup();
}
@@ -251,7 +270,9 @@ fetch_curl_post_convert(const struct fetch_multipart_data *control)
"application/octet-stream",
CURLFORM_END);
if (code != CURL_FORMADD_OK)
- LOG("curl_formadd: %d (%s)", code, control->name);
+ NSLOG(netsurf, INFO,
+ "curl_formadd: %d (%s)", code,
+ control->name);
} else {
char *mimetype = guit->fetch->mimetype(control->value);
code = curl_formadd(&post, &last,
@@ -262,7 +283,11 @@ fetch_curl_post_convert(const struct fetch_multipart_data *control)
(mimetype != 0 ? mimetype : "text/plain"),
CURLFORM_END);
if (code != CURL_FORMADD_OK)
- LOG("curl_formadd: %d (%s=%s)", code, control->name, control->value);
+ NSLOG(netsurf, INFO,
+ "curl_formadd: %d (%s=%s)",
+ code,
+ control->name,
+ control->value);
free(mimetype);
}
free(leafname);
@@ -273,7 +298,9 @@ fetch_curl_post_convert(const struct fetch_multipart_data *control)
CURLFORM_COPYCONTENTS, control->value,
CURLFORM_END);
if (code != CURL_FORMADD_OK)
- LOG("curl_formadd: %d (%s=%s)", code, control->name, control->value);
+ NSLOG(netsurf, INFO,
+ "curl_formadd: %d (%s=%s)", code,
+ control->name, control->value);
}
}
@@ -321,7 +348,7 @@ fetch_curl_setup(struct fetch *parent_fetch,
fetch->fetch_handle = parent_fetch;
- LOG("fetch %p, url '%s'", fetch, nsurl_access(url));
+ NSLOG(netsurf, INFO, "fetch %p, url '%s'", fetch, nsurl_access(url));
/* construct a new fetch structure */
fetch->curl_handle = NULL;
@@ -543,10 +570,16 @@ fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm)
/* Ensure server rejects the connection if downgraded too far */
SSL_CTX_set_mode(sslctx, SSL_MODE_SEND_FALLBACK_SCSV);
#endif
+ /* Disable TLS1.2 ciphersuites */
+ SSL_CTX_set_cipher_list(sslctx, CIPHER_LIST ":-TLSv1.2");
}
SSL_CTX_set_options(sslctx, options);
+#ifdef SSL_OP_NO_TICKET
+ SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
+#endif
+
return CURLE_OK;
}
@@ -569,6 +602,11 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f)
return code; \
}
+#if LIBCURL_VERSION_NUM >= 0x072f00
+ /* Added in 7.47 */
+ /* Prefer HTTP/2 on encrypted connections */
+ SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+#endif
SETOPT(CURLOPT_URL, nsurl_access(f->url));
SETOPT(CURLOPT_PRIVATE, f);
SETOPT(CURLOPT_WRITEDATA, f);
@@ -634,8 +672,8 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f)
SETOPT(CURLOPT_PROXY, NULL);
}
- /* Disable SSL session ID caching, as some servers can't cope. */
- SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 0);
+ /* Force-enable SSL session ID caching, as some distros are odd. */
+ SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 1);
if (urldb_get_cert_permissions(f->url)) {
/* Disable certificate verification */
@@ -776,7 +814,7 @@ static void fetch_curl_abort(void *vf)
{
struct curl_fetch_info *f = (struct curl_fetch_info *)vf;
assert(f);
- LOG("fetch %p, url '%s'", f, nsurl_access(f->url));
+ NSLOG(netsurf, INFO, "fetch %p, url '%s'", f, nsurl_access(f->url));
if (f->curl_handle) {
f->abort = true;
} else {
@@ -796,7 +834,7 @@ static void fetch_curl_stop(struct curl_fetch_info *f)
CURLMcode codem;
assert(f);
- LOG("fetch %p, url '%s'", f, nsurl_access(f->url));
+ NSLOG(netsurf, INFO, "fetch %p, url '%s'", f, nsurl_access(f->url));
if (f->curl_handle) {
/* remove from curl multi handle */
@@ -864,7 +902,7 @@ static bool fetch_curl_process_headers(struct curl_fetch_info *f)
assert(code == CURLE_OK);
}
http_code = f->http_code;
- LOG("HTTP status code %li", http_code);
+ NSLOG(netsurf, INFO, "HTTP status code %li", http_code);
if (http_code == 304 && !f->post_urlenc && !f->post_multipart) {
/* Not Modified && GET request */
@@ -875,7 +913,7 @@ static bool fetch_curl_process_headers(struct curl_fetch_info *f)
/* handle HTTP redirects (3xx response codes) */
if (300 <= http_code && http_code < 400 && f->location != 0) {
- LOG("FETCH_REDIRECT, '%s'", f->location);
+ NSLOG(netsurf, INFO, "FETCH_REDIRECT, '%s'", f->location);
msg.type = FETCH_REDIRECT;
msg.data.redirect = f->location;
fetch_send_callback(&msg, f->fetch_handle);
@@ -1037,7 +1075,7 @@ static void fetch_curl_done(CURL *curl_handle, CURLcode result)
assert(code == CURLE_OK);
abort_fetch = f->abort;
- LOG("done %s", nsurl_access(f->url));
+ NSLOG(netsurf, INFO, "done %s", nsurl_access(f->url));
if ((abort_fetch == false) &&
(result == CURLE_OK ||
@@ -1082,7 +1120,7 @@ static void fetch_curl_done(CURL *curl_handle, CURLcode result)
memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
} else {
- LOG("Unknown cURL response code %d", result);
+ NSLOG(netsurf, INFO, "Unknown cURL response code %d", result);
error = true;
}
@@ -1146,7 +1184,8 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
&exc_fd_set, &max_fd);
assert(codem == CURLM_OK);
- LOG("Curl file descriptor states (maxfd=%i):", max_fd);
+ NSLOG(netsurf, INFO,
+ "Curl file descriptor states (maxfd=%i):", max_fd);
for (i = 0; i <= max_fd; i++) {
bool read = false;
bool write = false;
@@ -1162,10 +1201,10 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
error = true;
}
if (read || write || error) {
- LOG(" fd %i: %s %s %s", i,
- read ? "read" : " ",
- write ? "write" : " ",
- error ? "error" : " ");
+ NSLOG(netsurf, INFO, " fd %i: %s %s %s", i,
+ read ? "read" : " ",
+ write ? "write" : " ",
+ error ? "error" : " ");
}
}
}
@@ -1174,7 +1213,8 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
do {
codem = curl_multi_perform(fetch_curl_multi, &running);
if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) {
- LOG("curl_multi_perform: %i %s", codem, curl_multi_strerror(codem));
+ NSLOG(netsurf, INFO, "curl_multi_perform: %i %s",
+ codem, curl_multi_strerror(codem));
guit->misc->warning("MiscError", curl_multi_strerror(codem));
return;
}
@@ -1336,7 +1376,7 @@ fetch_curl_header(char *data, size_t size, size_t nmemb, void *_f)
free(f->location);
f->location = malloc(size);
if (!f->location) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return size;
}
SKIP_ST(9);
@@ -1427,17 +1467,17 @@ nserror fetch_curl_register(void)
.finalise = fetch_curl_finalise
};
- LOG("curl_version %s", curl_version());
+ NSLOG(netsurf, INFO, "curl_version %s", curl_version());
code = curl_global_init(CURL_GLOBAL_ALL);
if (code != CURLE_OK) {
- LOG("curl_global_init failed.");
+ NSLOG(netsurf, INFO, "curl_global_init failed.");
return NSERROR_INIT_FAILED;
}
fetch_curl_multi = curl_multi_init();
if (!fetch_curl_multi) {
- LOG("curl_multi_init failed.");
+ NSLOG(netsurf, INFO, "curl_multi_init failed.");
return NSERROR_INIT_FAILED;
}
@@ -1457,6 +1497,13 @@ nserror fetch_curl_register(void)
SETOPT(CURLMOPT_MAXCONNECTS, maxconnects);
SETOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, maxconnects);
SETOPT(CURLMOPT_MAX_HOST_CONNECTIONS, nsoption_int(max_fetchers_per_host));
+
+#if LIBCURL_VERSION_NUM >= 0x072b00
+ /* Added in 7.43.0 */
+ /* Use HTTP/2 multiplexing */
+ SETOPT(CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
+#endif
+
}
#endif
@@ -1465,7 +1512,7 @@ nserror fetch_curl_register(void)
*/
fetch_blank_curl = curl_easy_init();
if (!fetch_blank_curl) {
- LOG("curl_easy_init failed");
+ NSLOG(netsurf, INFO, "curl_easy_init failed");
return NSERROR_INIT_FAILED;
}
@@ -1494,14 +1541,16 @@ nserror fetch_curl_register(void)
SETOPT(CURLOPT_LOW_SPEED_TIME, 180L);
SETOPT(CURLOPT_NOSIGNAL, 1L);
SETOPT(CURLOPT_CONNECTTIMEOUT, nsoption_uint(curl_fetch_timeout));
+ SETOPT(CURLOPT_SSL_CIPHER_LIST, CIPHER_LIST);
if (nsoption_charp(ca_bundle) &&
strcmp(nsoption_charp(ca_bundle), "")) {
- LOG("ca_bundle: '%s'", nsoption_charp(ca_bundle));
+ NSLOG(netsurf, INFO, "ca_bundle: '%s'",
+ nsoption_charp(ca_bundle));
SETOPT(CURLOPT_CAINFO, nsoption_charp(ca_bundle));
}
if (nsoption_charp(ca_path) && strcmp(nsoption_charp(ca_path), "")) {
- LOG("ca_path: '%s'", nsoption_charp(ca_path));
+ NSLOG(netsurf, INFO, "ca_path: '%s'", nsoption_charp(ca_path));
SETOPT(CURLOPT_CAPATH, nsoption_charp(ca_path));
}
@@ -1513,7 +1562,8 @@ nserror fetch_curl_register(void)
curl_with_openssl = false;
}
- LOG("cURL %slinked against openssl", curl_with_openssl ? "" : "not ");
+ NSLOG(netsurf, INFO, "cURL %slinked against openssl",
+ curl_with_openssl ? "" : "not ");
/* cURL initialised okay, register the fetchers */
@@ -1532,19 +1582,21 @@ nserror fetch_curl_register(void)
}
if (fetcher_add(scheme, &fetcher_ops) != NSERROR_OK) {
- LOG("Unable to register cURL fetcher for %s", data->protocols[i]);
+ NSLOG(netsurf, INFO,
+ "Unable to register cURL fetcher for %s",
+ data->protocols[i]);
}
}
return NSERROR_OK;
curl_easy_setopt_failed:
- LOG("curl_easy_setopt failed.");
+ NSLOG(netsurf, INFO, "curl_easy_setopt failed.");
return NSERROR_INIT_FAILED;
#if LIBCURL_VERSION_NUM >= 0x071e00
curl_multi_setopt_failed:
- LOG("curl_multi_setopt failed.");
+ NSLOG(netsurf, INFO, "curl_multi_setopt failed.");
return NSERROR_INIT_FAILED;
#endif
}
diff --git a/content/fetchers/data.c b/content/fetchers/data.c
index cb99e6ff2..5ba021fd3 100644
--- a/content/fetchers/data.c
+++ b/content/fetchers/data.c
@@ -57,14 +57,16 @@ static struct fetch_data_context *ring = NULL;
static bool fetch_data_initialise(lwc_string *scheme)
{
- LOG("fetch_data_initialise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "fetch_data_initialise called for %s",
+ lwc_string_data(scheme));
return true;
}
static void fetch_data_finalise(lwc_string *scheme)
{
- LOG("fetch_data_finalise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "fetch_data_finalise called for %s",
+ lwc_string_data(scheme));
}
static bool fetch_data_can_fetch(const nsurl *url)
@@ -147,7 +149,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
* data must still be there.
*/
- LOG("url: %.140s", c->url);
+ NSLOG(netsurf, INFO, "url: %.140s", c->url);
if (strlen(c->url) < 6) {
/* 6 is the minimum possible length (data:,) */
@@ -259,8 +261,10 @@ static void fetch_data_poll(lwc_string *scheme)
char header[64];
fetch_set_http_code(c->parent_fetch, 200);
- LOG("setting data: MIME type to %s, length to %" PRIsizet,
- c->mimetype, c->datalen);
+ NSLOG(netsurf, INFO,
+ "setting data: MIME type to %s, length to %"PRIsizet,
+ c->mimetype,
+ c->datalen);
/* Any callback can result in the fetch being aborted.
* Therefore, we _must_ check for this after _every_
* call to fetch_data_send_callback().
@@ -296,7 +300,8 @@ static void fetch_data_poll(lwc_string *scheme)
fetch_data_send_callback(&msg, c);
}
} else {
- LOG("Processing of %s failed!", c->url);
+ NSLOG(netsurf, INFO, "Processing of %s failed!",
+ c->url);
/* Ensure that we're unlocked here. If we aren't,
* then fetch_data_process() is broken.
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index b8b4b191f..78757733e 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -276,14 +276,16 @@ static bool fetch_resource_initialise(lwc_string *scheme)
&e->data,
&e->data_len);
if (res == NSERROR_OK) {
- LOG("direct data for %s", fetch_resource_paths[i]);
+ NSLOG(netsurf, INFO, "direct data for %s",
+ fetch_resource_paths[i]);
fetch_resource_path_count++;
} else {
e->redirect_url = guit->fetch->get_resource_url(fetch_resource_paths[i]);
if (e->redirect_url == NULL) {
lwc_string_unref(e->path);
} else {
- LOG("redirect url for %s", fetch_resource_paths[i]);
+ NSLOG(netsurf, INFO, "redirect url for %s",
+ fetch_resource_paths[i]);
fetch_resource_path_count++;
}
}
diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c
index bcb97d2b6..19eb1ca7b 100644
--- a/content/fs_backing_store.c
+++ b/content/fs_backing_store.c
@@ -519,11 +519,12 @@ invalidate_entry(struct store_state *state, struct store_entry *bse)
* This entry cannot be immediately removed as it has
* associated allocation so wait for allocation release.
*/
- LOG("invalidating entry with referenced allocation");
+ NSLOG(netsurf, INFO,
+ "invalidating entry with referenced allocation");
return NSERROR_OK;
}
- LOG("Removing entry for %p", bse);
+ NSLOG(netsurf, INFO, "Removing entry for %p", bse);
/* remove the entry from the index */
ret = remove_store_entry(state, &bse);
@@ -533,12 +534,12 @@ invalidate_entry(struct store_state *state, struct store_entry *bse)
ret = invalidate_element(state, bse, ENTRY_ELEM_META);
if (ret != NSERROR_OK) {
- LOG("Error invalidating metadata element");
+ NSLOG(netsurf, INFO, "Error invalidating metadata element");
}
ret = invalidate_element(state, bse, ENTRY_ELEM_DATA);
if (ret != NSERROR_OK) {
- LOG("Error invalidating data element");
+ NSLOG(netsurf, INFO, "Error invalidating data element");
}
return NSERROR_OK;
@@ -620,8 +621,10 @@ static nserror store_evict(struct store_state *state)
return NSERROR_OK;
}
- LOG("Evicting entries to reduce %"PRIu64" by %"PRIsizet,
- state->total_alloc, state->hysteresis);
+ NSLOG(netsurf, INFO,
+ "Evicting entries to reduce %"PRIu64" by %"PRIsizet,
+ state->total_alloc,
+ state->hysteresis);
/* allocate storage for the list */
elist = malloc(sizeof(entry_ident_t) * state->last_entry);
@@ -658,7 +661,8 @@ static nserror store_evict(struct store_state *state)
free(elist);
- LOG("removed %"PRIsizet" in %d entries", removed, ent);
+ NSLOG(netsurf, INFO, "removed %"PRIsizet" in %d entries", removed,
+ ent);
return ret;
}
@@ -773,7 +777,10 @@ static nserror write_blocks(struct store_state *state)
&state->blocks[elem_idx][bfidx].use_map[0],
BLOCK_USE_MAP_SIZE);
if (wr != BLOCK_USE_MAP_SIZE) {
- LOG("writing block file %d use index on file number %d failed", elem_idx, bfidx);
+ NSLOG(netsurf, INFO,
+ "writing block file %d use index on file number %d failed",
+ elem_idx,
+ bfidx);
goto wr_err;
}
written += wr;
@@ -829,19 +836,21 @@ static nserror set_block_extents(struct store_state *state)
return NSERROR_OK;
}
- LOG("Starting");
+ NSLOG(netsurf, INFO, "Starting");
for (elem_idx = 0; elem_idx < ENTRY_ELEM_COUNT; elem_idx++) {
for (bfidx = 0; bfidx < BLOCK_FILE_COUNT; bfidx++) {
if (state->blocks[elem_idx][bfidx].fd != -1) {
/* ensure block file is correct extent */
ftr = ftruncate(state->blocks[elem_idx][bfidx].fd, 1U << (log2_block_size[elem_idx] + BLOCK_ENTRY_COUNT));
if (ftr == -1) {
- LOG("Truncate failed errno:%d", errno);
+ NSLOG(netsurf, INFO,
+ "Truncate failed errno:%d",
+ errno);
}
}
}
}
- LOG("Complete");
+ NSLOG(netsurf, INFO, "Complete");
state->blocks_opened = false;
@@ -886,7 +895,7 @@ get_store_entry(struct store_state *state, nsurl *url, struct store_entry **bse)
entry_ident_t ident;
unsigned int sei; /* store entry index */
- LOG("url:%s", nsurl_access(url));
+ NSLOG(netsurf, INFO, "url:%s", nsurl_access(url));
/* use the url hash as the entry identifier */
ident = nsurl_hash(url);
@@ -894,13 +903,14 @@ get_store_entry(struct store_state *state, nsurl *url, struct store_entry **bse)
sei = BS_ENTRY_INDEX(ident, state);
if (sei == 0) {
- LOG("Failed to find ident 0x%x in index", ident);
+ NSLOG(netsurf, INFO, "Failed to find ident 0x%x in index",
+ ident);
return NSERROR_NOT_FOUND;
}
if (state->entries[sei].ident != ident) {
/* entry ident did not match */
- LOG("ident did not match entry");
+ NSLOG(netsurf, INFO, "ident did not match entry");
return NSERROR_NOT_FOUND;
}
@@ -975,7 +985,7 @@ set_store_entry(struct store_state *state,
nserror ret;
struct store_entry_element *elem;
- LOG("url:%s", nsurl_access(url));
+ NSLOG(netsurf, INFO, "url:%s", nsurl_access(url));
/* evict entries as required and ensure there is at least one
* new entry available.
@@ -1013,7 +1023,10 @@ set_store_entry(struct store_state *state,
* to see if the old entry is in use and if
* not prefer the newly stored entry instead?
*/
- LOG("Entry index collision trying to replace %x with %x", se->ident, ident);
+ NSLOG(netsurf, INFO,
+ "Entry index collision trying to replace %x with %x",
+ se->ident,
+ ident);
return NSERROR_PERMISSION;
}
}
@@ -1026,7 +1039,8 @@ set_store_entry(struct store_state *state,
/* this entry cannot be removed as it has associated
* allocation.
*/
- LOG("attempt to overwrite entry with in use data");
+ NSLOG(netsurf, INFO,
+ "attempt to overwrite entry with in use data");
return NSERROR_PERMISSION;
}
@@ -1085,7 +1099,7 @@ store_open(struct store_state *state,
fname = store_fname(state, ident, elem_idx);
if (fname == NULL) {
- LOG("filename error");
+ NSLOG(netsurf, INFO, "filename error");
return -1;
}
@@ -1093,13 +1107,14 @@ store_open(struct store_state *state,
if (openflags & O_CREAT) {
ret = netsurf_mkdir_all(fname);
if (ret != NSERROR_OK) {
- LOG("file path \"%s\" could not be created", fname);
+ NSLOG(netsurf, INFO,
+ "file path \"%s\" could not be created", fname);
free(fname);
return -1;
}
}
- LOG("opening %s", fname);
+ NSLOG(netsurf, INFO, "opening %s", fname);
fd = open(fname, openflags, S_IRUSR | S_IWUSR);
free(fname);
@@ -1126,9 +1141,9 @@ build_entrymap(struct store_state *state)
{
unsigned int eloop;
- LOG("Allocating %ld bytes for max of %d buckets",
- (1 << state->ident_bits) * sizeof(entry_index_t),
- 1 << state->ident_bits);
+ NSLOG(netsurf, INFO, "Allocating %"PRIsizet" bytes for max of %d buckets",
+ (1 << state->ident_bits) * sizeof(entry_index_t),
+ 1 << state->ident_bits);
state->addrmap = calloc(1 << state->ident_bits, sizeof(entry_index_t));
if (state->addrmap == NULL) {
@@ -1138,12 +1153,12 @@ build_entrymap(struct store_state *state)
state->total_alloc = 0;
for (eloop = 1; eloop < state->last_entry; eloop++) {
- /*
- LOG("entry:%d ident:0x%08x used:%d",
- eloop,
- BS_ADDRESS(state->entries[eloop].ident, state),
- state->entries[eloop].use_count);
- */
+
+ NSLOG(llcache, DEEPDEBUG,
+ "entry:%d ident:0x%08x used:%d",
+ eloop,
+ BS_ADDRESS(state->entries[eloop].ident, state),
+ state->entries[eloop].use_count);
/* update the address map to point at the entry */
BS_ENTRY_INDEX(state->entries[eloop].ident, state) = eloop;
@@ -1204,10 +1219,12 @@ read_entries(struct store_state *state)
entries_size = (1 << state->entry_bits) * sizeof(struct store_entry);
- LOG("Allocating %"PRIsizet" bytes for max of %d entries of %ld length elements %ld length",
- entries_size, 1 << state->entry_bits,
- sizeof(struct store_entry),
- sizeof(struct store_entry_element));
+ NSLOG(netsurf, INFO,
+ "Allocating %"PRIsizet" bytes for max of %d entries of %"PRIsizet" length elements %"PRIsizet" length",
+ entries_size,
+ 1 << state->entry_bits,
+ sizeof(struct store_entry),
+ sizeof(struct store_entry_element));
state->entries = calloc(1, entries_size);
if (state->entries == NULL) {
@@ -1222,7 +1239,8 @@ read_entries(struct store_state *state)
close(fd);
if (rd > 0) {
state->last_entry = rd / sizeof(struct store_entry);
- LOG("Read %d entries", state->last_entry);
+ NSLOG(netsurf, INFO, "Read %d entries",
+ state->last_entry);
}
} else {
/* could rebuild entries from fs */
@@ -1253,7 +1271,7 @@ read_blocks(struct store_state *state)
return ret;
}
- LOG("Initialising block use map from %s", fname);
+ NSLOG(netsurf, INFO, "Initialising block use map from %s", fname);
fd = open(fname, O_RDWR);
free(fname);
@@ -1265,7 +1283,10 @@ read_blocks(struct store_state *state)
&state->blocks[elem_idx][bfidx].use_map[0],
BLOCK_USE_MAP_SIZE);
if (rd <= 0) {
- LOG("reading block file %d use index on file number %d failed", elem_idx, bfidx);
+ NSLOG(netsurf, INFO,
+ "reading block file %d use index on file number %d failed",
+ elem_idx,
+ bfidx);
goto rd_err;
}
}
@@ -1274,7 +1295,7 @@ read_blocks(struct store_state *state)
close(fd);
} else {
- LOG("Initialising block use map to defaults");
+ NSLOG(netsurf, INFO, "Initialising block use map to defaults");
/* ensure block 0 (invalid sentinel) is skipped */
state->blocks[ENTRY_ELEM_DATA][0].use_map[0] = 1;
state->blocks[ENTRY_ELEM_META][0].use_map[0] = 1;
@@ -1344,7 +1365,7 @@ write_control(struct store_state *state)
return ret;
}
- LOG("writing control file \"%s\"", fname);
+ NSLOG(netsurf, INFO, "writing control file \"%s\"", fname);
ret = netsurf_mkdir_all(fname);
if (ret != NSERROR_OK) {
@@ -1392,7 +1413,7 @@ read_control(struct store_state *state)
return ret;
}
- LOG("opening control file \"%s\"", fname);
+ NSLOG(netsurf, INFO, "opening control file \"%s\"", fname);
fcontrol = fopen(fname, "rb");
@@ -1509,7 +1530,8 @@ initialise(const struct llcache_store_parameters *parameters)
/* read store control and create new if required */
ret = read_control(newstate);
if (ret != NSERROR_OK) {
- LOG("read control failed %s", messages_get_errorcode(ret));
+ NSLOG(netsurf, INFO, "read control failed %s",
+ messages_get_errorcode(ret));
ret = write_control(newstate);
if (ret == NSERROR_OK) {
unlink_entries(newstate);
@@ -1543,6 +1565,7 @@ initialise(const struct llcache_store_parameters *parameters)
ret = build_entrymap(newstate);
if (ret != NSERROR_OK) {
/* that obviously went well */
+ free(newstate->entries);
free(newstate->path);
free(newstate);
return ret;
@@ -1551,6 +1574,8 @@ initialise(const struct llcache_store_parameters *parameters)
ret = read_blocks(newstate);
if (ret != NSERROR_OK) {
/* oh dear */
+ free(newstate->addrmap);
+ free(newstate->entries);
free(newstate->path);
free(newstate);
return ret;
@@ -1558,15 +1583,17 @@ initialise(const struct llcache_store_parameters *parameters)
storestate = newstate;
- LOG("FS backing store init successful");
+ NSLOG(netsurf, INFO, "FS backing store init successful");
- LOG("path:%s limit:%"PRIsizet" hyst:%"PRIsizet" addr:%d entries:%d",
- newstate->path,
- newstate->limit,
- newstate->hysteresis,
- newstate->ident_bits,
- newstate->entry_bits);
- LOG("Using %"PRIu64"/%"PRIsizet, newstate->total_alloc, newstate->limit);
+ NSLOG(netsurf, INFO,
+ "path:%s limit:%"PRIsizet" hyst:%"PRIsizet" addr:%d entries:%d",
+ newstate->path,
+ newstate->limit,
+ newstate->hysteresis,
+ newstate->ident_bits,
+ newstate->entry_bits);
+ NSLOG(netsurf, INFO, "Using %"PRIu64"/%"PRIsizet,
+ newstate->total_alloc, newstate->limit);
return NSERROR_OK;
}
@@ -1605,16 +1632,19 @@ finalise(void)
/* avoid division by zero */
if (op_count > 0) {
- LOG("Cache total/hit/miss/fail (counts) %d/%"PRIsizet"/%"PRIsizet"/%d (100%%/%"PRIsizet"%%/%"PRIsizet"%%/%d%%)",
- op_count,
- storestate->hit_count,
- storestate->miss_count,
- 0,
- (storestate->hit_count * 100) / op_count,
- (storestate->miss_count * 100) / op_count,
- 0);
+ NSLOG(netsurf, INFO,
+ "Cache total/hit/miss/fail (counts) %d/%"PRIsizet"/%"PRIsizet"/%d (100%%/%"PRIsizet"%%/%"PRIsizet"%%/%d%%)",
+ op_count,
+ storestate->hit_count,
+ storestate->miss_count,
+ 0,
+ (storestate->hit_count * 100) / op_count,
+ (storestate->miss_count * 100) / op_count,
+ 0);
}
+ free(storestate->addrmap);
+ free(storestate->entries);
free(storestate->path);
free(storestate);
storestate = NULL;
@@ -1646,7 +1676,7 @@ static nserror store_write_block(struct store_state *state,
state->blocks[elem_idx][bf].fd = store_open(state, bf,
elem_idx + ENTRY_ELEM_COUNT, O_CREAT | O_RDWR);
if (state->blocks[elem_idx][bf].fd == -1) {
- LOG("Open failed errno %d", errno);
+ NSLOG(netsurf, INFO, "Open failed errno %d", errno);
return NSERROR_SAVE_FAILED;
}
@@ -1654,28 +1684,28 @@ static nserror store_write_block(struct store_state *state,
state->blocks_opened = true;
}
- offst = bi << log2_block_size[elem_idx];
+ offst = (unsigned int)bi << log2_block_size[elem_idx];
wr = nsu_pwrite(state->blocks[elem_idx][bf].fd,
bse->elem[elem_idx].data,
bse->elem[elem_idx].size,
offst);
if (wr != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Write failed %"PRIssizet" of %d bytes from %p at 0x%jx block %d errno %d",
- wr,
- bse->elem[elem_idx].size,
- bse->elem[elem_idx].data,
- (uintmax_t)offst,
- bse->elem[elem_idx].block,
- errno);
+ NSLOG(netsurf, INFO,
+ "Write failed %"PRIssizet" of %d bytes from %p at 0x%jx block %d errno %d",
+ wr,
+ bse->elem[elem_idx].size,
+ bse->elem[elem_idx].data,
+ (uintmax_t)offst,
+ bse->elem[elem_idx].block,
+ errno);
return NSERROR_SAVE_FAILED;
}
- LOG("Wrote %"PRIssizet" bytes from %p at 0x%jx block %d",
- wr,
- bse->elem[elem_idx].data,
- (uintmax_t)offst,
- bse->elem[elem_idx].block);
+ NSLOG(netsurf, INFO,
+ "Wrote %"PRIssizet" bytes from %p at 0x%jx block %d", wr,
+ bse->elem[elem_idx].data, (uintmax_t)offst,
+ bse->elem[elem_idx].block);
return NSERROR_OK;
}
@@ -1699,7 +1729,7 @@ static nserror store_write_file(struct store_state *state,
fd = store_open(state, bse->ident, elem_idx, O_CREAT | O_WRONLY);
if (fd < 0) {
perror("");
- LOG("Open failed %d errno %d", fd, errno);
+ NSLOG(netsurf, INFO, "Open failed %d errno %d", fd, errno);
return NSERROR_SAVE_FAILED;
}
@@ -1708,17 +1738,19 @@ static nserror store_write_file(struct store_state *state,
close(fd);
if (wr != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Write failed %"PRIssizet" of %d bytes from %p errno %d",
- wr,
- bse->elem[elem_idx].size,
- bse->elem[elem_idx].data,
- err);
+ NSLOG(netsurf, INFO,
+ "Write failed %"PRIssizet" of %d bytes from %p errno %d",
+ wr,
+ bse->elem[elem_idx].size,
+ bse->elem[elem_idx].data,
+ err);
/** @todo Delete the file? */
return NSERROR_SAVE_FAILED;
}
- LOG("Wrote %"PRIssizet" bytes from %p", wr, bse->elem[elem_idx].data);
+ NSLOG(netsurf, INFO, "Wrote %"PRIssizet" bytes from %p", wr,
+ bse->elem[elem_idx].data);
return NSERROR_OK;
}
@@ -1759,7 +1791,7 @@ store(nsurl *url,
/* set the store entry up */
ret = set_store_entry(storestate, url, elem_idx, data, datalen, &bse);
if (ret != NSERROR_OK) {
- LOG("store entry setting failed");
+ NSLOG(netsurf, INFO, "store entry setting failed");
return ret;
}
@@ -1782,7 +1814,7 @@ static nserror entry_release_alloc(struct store_entry_element *elem)
if ((elem->flags & ENTRY_ELEM_FLAG_HEAP) != 0) {
elem->ref--;
if (elem->ref == 0) {
- LOG("freeing %p", elem->data);
+ NSLOG(netsurf, INFO, "freeing %p", elem->data);
free(elem->data);
elem->flags &= ~ENTRY_ELEM_FLAG_HEAP;
}
@@ -1814,7 +1846,7 @@ static nserror store_read_block(struct store_state *state,
state->blocks[elem_idx][bf].fd = store_open(state, bf,
elem_idx + ENTRY_ELEM_COUNT, O_CREAT | O_RDWR);
if (state->blocks[elem_idx][bf].fd == -1) {
- LOG("Open failed errno %d", errno);
+ NSLOG(netsurf, INFO, "Open failed errno %d", errno);
return NSERROR_SAVE_FAILED;
}
@@ -1822,28 +1854,28 @@ static nserror store_read_block(struct store_state *state,
state->blocks_opened = true;
}
- offst = bi << log2_block_size[elem_idx];
+ offst = (unsigned int)bi << log2_block_size[elem_idx];
rd = nsu_pread(state->blocks[elem_idx][bf].fd,
bse->elem[elem_idx].data,
bse->elem[elem_idx].size,
offst);
if (rd != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Failed reading %"PRIssizet" of %d bytes into %p from 0x%jx block %d errno %d",
- rd,
- bse->elem[elem_idx].size,
- bse->elem[elem_idx].data,
- (uintmax_t)offst,
- bse->elem[elem_idx].block,
- errno);
+ NSLOG(netsurf, INFO,
+ "Failed reading %"PRIssizet" of %d bytes into %p from 0x%jx block %d errno %d",
+ rd,
+ bse->elem[elem_idx].size,
+ bse->elem[elem_idx].data,
+ (uintmax_t)offst,
+ bse->elem[elem_idx].block,
+ errno);
return NSERROR_SAVE_FAILED;
}
- LOG("Read %"PRIssizet" bytes into %p from 0x%jx block %d",
- rd,
- bse->elem[elem_idx].data,
- (uintmax_t)offst,
- bse->elem[elem_idx].block);
+ NSLOG(netsurf, INFO,
+ "Read %"PRIssizet" bytes into %p from 0x%jx block %d", rd,
+ bse->elem[elem_idx].data, (uintmax_t)offst,
+ bse->elem[elem_idx].block);
return NSERROR_OK;
}
@@ -1868,7 +1900,7 @@ static nserror store_read_file(struct store_state *state,
/* separate file in backing store */
fd = store_open(storestate, bse->ident, elem_idx, O_RDONLY);
if (fd < 0) {
- LOG("Open failed %d errno %d", fd, errno);
+ NSLOG(netsurf, INFO, "Open failed %d errno %d", fd, errno);
/** @todo should this invalidate the entry? */
return NSERROR_NOT_FOUND;
}
@@ -1878,8 +1910,10 @@ static nserror store_read_file(struct store_state *state,
bse->elem[elem_idx].data + tot,
bse->elem[elem_idx].size - tot);
if (rd <= 0) {
- LOG("read error returned %"PRIssizet" errno %d",
- rd, errno);
+ NSLOG(netsurf, INFO,
+ "read error returned %"PRIssizet" errno %d",
+ rd,
+ errno);
ret = NSERROR_NOT_FOUND;
break;
}
@@ -1888,7 +1922,8 @@ static nserror store_read_file(struct store_state *state,
close(fd);
- LOG("Read %"PRIsizet" bytes into %p", tot, bse->elem[elem_idx].data);
+ NSLOG(netsurf, INFO, "Read %"PRIsizet" bytes into %p", tot,
+ bse->elem[elem_idx].data);
return ret;
}
@@ -1921,13 +1956,14 @@ fetch(nsurl *url,
/* fetch store entry */
ret = get_store_entry(storestate, url, &bse);
if (ret != NSERROR_OK) {
- LOG("entry not found");
+ NSLOG(netsurf, INFO, "entry not found");
storestate->miss_count++;
return ret;
}
storestate->hit_count++;
- LOG("retrieving cache data for url:%s", nsurl_access(url));
+ NSLOG(netsurf, INFO, "retrieving cache data for url:%s",
+ nsurl_access(url));
/* calculate the entry element index */
if ((bsflags & BACKING_STORE_META) != 0) {
@@ -1942,16 +1978,20 @@ fetch(nsurl *url,
/* use the existing allocation and bump the ref count. */
elem->ref++;
- LOG("Using existing entry (%p) allocation %p refs:%d", bse, elem->data, elem->ref);
+ NSLOG(netsurf, INFO,
+ "Using existing entry (%p) allocation %p refs:%d", bse,
+ elem->data, elem->ref);
} else {
/* allocate from the heap */
elem->data = malloc(elem->size);
if (elem->data == NULL) {
- LOG("Failed to create new heap allocation");
+ NSLOG(netsurf, INFO,
+ "Failed to create new heap allocation");
return NSERROR_NOMEM;
}
- LOG("Created new heap allocation %p", elem->data);
+ NSLOG(netsurf, INFO, "Created new heap allocation %p",
+ elem->data);
/* mark the entry as having a valid heap allocation */
elem->flags |= ENTRY_ELEM_FLAG_HEAP;
@@ -2000,7 +2040,7 @@ static nserror release(nsurl *url, enum backing_store_flags bsflags)
ret = get_store_entry(storestate, url, &bse);
if (ret != NSERROR_OK) {
- LOG("entry not found");
+ NSLOG(netsurf, INFO, "entry not found");
return ret;
}
diff --git a/content/handlers/Makefile b/content/handlers/Makefile
index 2f2da3aed..ea9d0c84d 100644
--- a/content/handlers/Makefile
+++ b/content/handlers/Makefile
@@ -13,4 +13,15 @@ include content/handlers/javascript/Makefile
S_CONTENT += $(addprefix handlers/javascript/,$(S_JAVASCRIPT))
+# HTML content handler sources
+include content/handlers/html/Makefile
+
+S_CONTENT += $(addprefix handlers/html/,$(S_HTML))
+
+# Text content handler sources
+include content/handlers/text/Makefile
+
+S_CONTENT += $(addprefix handlers/text/,$(S_TEXT))
+
+# extend the include search path
INCLUDE_DIRS += content/handlers
diff --git a/content/handlers/css/css.c b/content/handlers/css/css.c
index 997eb5115..93efd6a1b 100644
--- a/content/handlers/css/css.c
+++ b/content/handlers/css/css.c
@@ -136,7 +136,6 @@ nscss_create(const content_handler *handler,
const char *charset = NULL;
const char *xnsbase = NULL;
lwc_string *charset_value = NULL;
- union content_msg_data msg_data;
nserror error;
result = calloc(1, sizeof(nscss_content));
@@ -171,8 +170,7 @@ nscss_create(const content_handler *handler,
xnsbase, charset, result->base.quirks,
nscss_content_done, result);
if (error != NSERROR_OK) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&result->base, NSERROR_NOMEM);
if (charset_value != NULL)
lwc_string_unref(charset_value);
free(result);
@@ -250,13 +248,11 @@ static nserror nscss_create_css_data(struct content_css_data *c,
bool nscss_process_data(struct content *c, const char *data, unsigned int size)
{
nscss_content *css = (nscss_content *) c;
- union content_msg_data msg_data;
css_error error;
error = nscss_process_css_data(&css->data, data, size);
if (error != CSS_OK && error != CSS_NEEDDATA) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_CSS);
}
return (error == CSS_OK || error == CSS_NEEDDATA);
@@ -286,13 +282,11 @@ static css_error nscss_process_css_data(struct content_css_data *c,
bool nscss_convert(struct content *c)
{
nscss_content *css = (nscss_content *) c;
- union content_msg_data msg_data;
css_error error;
error = nscss_convert_css_data(&css->data);
if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_CSS);
return false;
}
@@ -327,9 +321,11 @@ static css_error nscss_convert_css_data(struct content_css_data *c)
const char *url;
if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) {
- LOG("Failed converting %p %s (%d)", c, url, error);
+ NSLOG(netsurf, INFO, "Failed converting %p %s (%d)",
+ c, url, error);
} else {
- LOG("Failed converting %p (%d)", c, error);
+ NSLOG(netsurf, INFO, "Failed converting %p (%d)", c,
+ error);
}
}
@@ -475,7 +471,6 @@ content_type nscss_content_type(void)
*/
void nscss_content_done(struct content_css_data *css, void *pw)
{
- union content_msg_data msg_data;
struct content *c = pw;
uint32_t i;
size_t size;
@@ -484,8 +479,7 @@ void nscss_content_done(struct content_css_data *css, void *pw)
/* Retrieve the size of this sheet */
error = css_stylesheet_size(css->sheet, &size);
if (error != CSS_OK) {
- msg_data.error = "?";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_CSS);
content_set_error(c);
return;
}
@@ -606,7 +600,9 @@ css_error nscss_handle_import(void *pw, css_stylesheet *parent,
nsurl_unref(ns_ref);
#ifdef NSCSS_IMPORT_TRACE
- LOG("Import %d '%s' -> (handle: %p ctx: %p)", c->import_count, lwc_string_data(url), c->imports[c->import_count].c, ctx);
+ NSLOG(netsurf, INFO, "Import %d '%s' -> (handle: %p ctx: %p)",
+ c->import_count, lwc_string_data(url),
+ c->imports[c->import_count].c, ctx);
#endif
c->import_count++;
@@ -629,7 +625,7 @@ nserror nscss_import(hlcache_handle *handle,
css_error error = CSS_OK;
#ifdef NSCSS_IMPORT_TRACE
- LOG("Event %d for %p (%p)", event->type, handle, ctx);
+ NSLOG(netsurf, INFO, "Event %d for %p (%p)", event->type, handle, ctx);
#endif
assert(ctx->css->imports[ctx->index].c == handle);
@@ -639,6 +635,7 @@ nserror nscss_import(hlcache_handle *handle,
error = nscss_import_complete(ctx);
break;
+ case CONTENT_MSG_ERRORCODE:
case CONTENT_MSG_ERROR:
hlcache_handle_release(handle);
ctx->css->imports[ctx->index].c = NULL;
@@ -670,7 +667,8 @@ css_error nscss_import_complete(nscss_import_ctx *ctx)
error = nscss_register_imports(ctx->css);
#ifdef NSCSS_IMPORT_TRACE
- LOG("Destroying import context %p for %d", ctx, ctx->index);
+ NSLOG(netsurf, INFO, "Destroying import context %p for %d", ctx,
+ ctx->index);
#endif
/* No longer need import context */
diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c
index 1ad188cb8..b12e1d9e8 100644
--- a/content/handlers/css/dump.c
+++ b/content/handlers/css/dump.c
@@ -20,6 +20,7 @@
#include <libcss/libcss.h>
#include "css/dump.h"
+#include "css/utils.h"
/**
* Dump a fixed point value to the stream in a textual form.
@@ -112,6 +113,45 @@ static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit)
case CSS_UNIT_KHZ:
fprintf(stream, "kHz");
break;
+ case CSS_UNIT_CAP:
+ fprintf(stream, "cap");
+ break;
+ case CSS_UNIT_CH:
+ fprintf(stream, "ch");
+ break;
+ case CSS_UNIT_IC:
+ fprintf(stream, "ic");
+ break;
+ case CSS_UNIT_REM:
+ fprintf(stream, "rem");
+ break;
+ case CSS_UNIT_LH:
+ fprintf(stream, "lh");
+ break;
+ case CSS_UNIT_RLH:
+ fprintf(stream, "rlh");
+ break;
+ case CSS_UNIT_VH:
+ fprintf(stream, "vh");
+ break;
+ case CSS_UNIT_VW:
+ fprintf(stream, "vw");
+ break;
+ case CSS_UNIT_VI:
+ fprintf(stream, "vi");
+ break;
+ case CSS_UNIT_VB:
+ fprintf(stream, "vb");
+ break;
+ case CSS_UNIT_VMIN:
+ fprintf(stream, "vmin");
+ break;
+ case CSS_UNIT_VMAX:
+ fprintf(stream, "vmax");
+ break;
+ case CSS_UNIT_Q:
+ fprintf(stream, "q");
+ break;
}
}
@@ -783,7 +823,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
}
/* display */
- val = css_computed_display_static(style);
+ val = ns_computed_display_static(style);
switch (val) {
case CSS_DISPLAY_INLINE:
fprintf(stream, "display: inline ");
@@ -1268,7 +1308,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
}
/* min-height */
- val = css_computed_min_height(style, &len1, &unit1);
+ val = ns_computed_min_height(style, &len1, &unit1);
switch (val) {
case CSS_MIN_HEIGHT_SET:
fprintf(stream, "min-height: ");
@@ -1282,7 +1322,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
}
/* min-width */
- val = css_computed_min_width(style, &len1, &unit1);
+ val = ns_computed_min_width(style, &len1, &unit1);
switch (val) {
case CSS_MIN_WIDTH_SET:
fprintf(stream, "min-width: ");
diff --git a/content/handlers/css/hints.c b/content/handlers/css/hints.c
index a96212386..3a15f8e08 100644
--- a/content/handlers/css/hints.c
+++ b/content/handlers/css/hints.c
@@ -748,6 +748,8 @@ static void css_hint_vertical_align_table_cells(
corestring_dom_valign, &attr);
if (err == DOM_NO_ERR && attr != NULL) {
+ hint->data.length.value = 0;
+ hint->data.length.unit = CSS_UNIT_PX;
if (dom_string_caseless_lwc_isequal(attr,
corestring_lwc_top)) {
hint->prop = CSS_PROP_VERTICAL_ALIGN;
@@ -882,6 +884,7 @@ static void css_hint_margin_left_right_align_center(
corestring_dom_align, &attr);
if (exc == DOM_NO_ERR && attr != NULL) {
+ memset(hint, 0, sizeof(*hint) * 2);
if (dom_string_caseless_lwc_isequal(attr,
corestring_lwc_center) ||
dom_string_caseless_lwc_isequal(attr,
@@ -1022,6 +1025,7 @@ static void css_hint_margin_left_right_hr(
corestring_dom_align, &attr);
if (exc == DOM_NO_ERR && attr != NULL) {
+ memset(hint, 0, sizeof(*hint) * 2);
if (dom_string_caseless_lwc_isequal(attr,
corestring_lwc_left)) {
hint->prop = CSS_PROP_MARGIN_LEFT;
@@ -1584,6 +1588,7 @@ css_error node_presentational_hint(void *pw, void *node,
css_hint_width(pw, node);
break;
case DOM_HTML_ELEMENT_TYPE_HR:
+ css_hint_width(pw, node);
css_hint_margin_left_right_hr(pw, node);
break;
case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
@@ -1612,7 +1617,7 @@ css_error node_presentational_hint(void *pw, void *node,
}
#ifdef LOG_STATS
- LOG("Properties with hints: %i", hint_ctx.len);
+ NSLOG(netsurf, INFO, "Properties with hints: %i", hint_ctx.len);
#endif
css_hint_get_hints(hints, nhints);
diff --git a/content/handlers/css/select.c b/content/handlers/css/select.c
index daa3b4087..ee79eb394 100644
--- a/content/handlers/css/select.c
+++ b/content/handlers/css/select.c
@@ -175,20 +175,20 @@ css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
error = css_stylesheet_create(&params, &sheet);
if (error != CSS_OK) {
- LOG("Failed creating sheet: %d", error);
+ NSLOG(netsurf, INFO, "Failed creating sheet: %d", error);
return NULL;
}
error = css_stylesheet_append_data(sheet, data, len);
if (error != CSS_OK && error != CSS_NEEDDATA) {
- LOG("failed appending data: %d", error);
+ NSLOG(netsurf, INFO, "failed appending data: %d", error);
css_stylesheet_destroy(sheet);
return NULL;
}
error = css_stylesheet_data_done(sheet);
if (error != CSS_OK) {
- LOG("failed completing parse: %d", error);
+ NSLOG(netsurf, INFO, "failed completing parse: %d", error);
css_stylesheet_destroy(sheet);
return NULL;
}
@@ -214,7 +214,8 @@ static void nscss_dom_user_data_handler(dom_node_operation operation,
CSS_NODE_CLONED,
NULL, src, dst, data);
if (error != CSS_OK)
- LOG("Failed to clone libcss_node_data.");
+ NSLOG(netsurf, INFO,
+ "Failed to clone libcss_node_data.");
break;
case DOM_NODE_RENAMED:
@@ -222,7 +223,8 @@ static void nscss_dom_user_data_handler(dom_node_operation operation,
CSS_NODE_MODIFIED,
NULL, src, NULL, data);
if (error != CSS_OK)
- LOG("Failed to update libcss_node_data.");
+ NSLOG(netsurf, INFO,
+ "Failed to update libcss_node_data.");
break;
case DOM_NODE_IMPORTED:
@@ -232,11 +234,12 @@ static void nscss_dom_user_data_handler(dom_node_operation operation,
CSS_NODE_DELETED,
NULL, src, NULL, data);
if (error != CSS_OK)
- LOG("Failed to delete libcss_node_data.");
+ NSLOG(netsurf, INFO,
+ "Failed to delete libcss_node_data.");
break;
default:
- LOG("User data operation not handled.");
+ NSLOG(netsurf, INFO, "User data operation not handled.");
assert(0);
}
}
@@ -275,7 +278,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
* element's style */
error = css_computed_style_compose(ctx->parent_style,
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
css_select_results_destroy(styles);
@@ -307,7 +310,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
error = css_computed_style_compose(
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
styles->styles[pseudo_element],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
/* TODO: perhaps this shouldn't be quite so
@@ -346,7 +349,7 @@ css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
/* TODO: Do we really need to compose? Initial style shouldn't
* have any inherited properties. */
error = css_computed_style_compose(parent, partial,
- nscss_compute_font_size, NULL, &composed);
+ nscss_compute_font_size, ctx, &composed);
css_computed_style_destroy(partial);
if (error != CSS_OK) {
css_computed_style_destroy(composed);
@@ -419,14 +422,37 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
FDIV(parent_size.value, FLTTOFIX(1.2));
size->data.length.unit = parent_size.unit;
} else if (size->data.length.unit == CSS_UNIT_EM ||
- size->data.length.unit == CSS_UNIT_EX) {
+ size->data.length.unit == CSS_UNIT_EX ||
+ size->data.length.unit == CSS_UNIT_CAP ||
+ size->data.length.unit == CSS_UNIT_CH ||
+ size->data.length.unit == CSS_UNIT_IC) {
size->data.length.value =
FMUL(size->data.length.value, parent_size.value);
- if (size->data.length.unit == CSS_UNIT_EX) {
+ switch (size->data.length.unit) {
+ case CSS_UNIT_EX:
/* 1ex = 0.6em in NetSurf */
size->data.length.value = FMUL(size->data.length.value,
FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ /* Height of captals. 1cap = 0.9em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ /* Width of '0'. 1ch = 0.4em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ /* Width of U+6C43. 1ic = 1.1em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(1.1));
+ break;
+ default:
+ /* No scaling required for EM. */
+ break;
}
size->data.length.unit = parent_size.unit;
@@ -434,6 +460,25 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
size->data.length.value = FDIV(FMUL(size->data.length.value,
parent_size.value), INTTOFIX(100));
size->data.length.unit = parent_size.unit;
+ } else if (size->data.length.unit == CSS_UNIT_REM) {
+ nscss_select_ctx *ctx = pw;
+ if (parent == NULL) {
+ size->data.length.value = parent_size.value;
+ size->data.length.unit = parent_size.unit;
+ } else {
+ css_computed_font_size(ctx->root_style,
+ &parent_size.value,
+ &size->data.length.unit);
+ size->data.length.value = FMUL(
+ size->data.length.value,
+ parent_size.value);
+ }
+ } else if (size->data.length.unit == CSS_UNIT_RLH) {
+ /** TODO: Convert root element line-height to absolute value. */
+ size->data.length.value = FMUL(size->data.length.value, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ size->data.length.unit = CSS_UNIT_PT;
}
size->status = CSS_FONT_SIZE_DIMENSION;
diff --git a/content/handlers/css/select.h b/content/handlers/css/select.h
index abfb85814..9fa6d3a56 100644
--- a/content/handlers/css/select.h
+++ b/content/handlers/css/select.h
@@ -37,6 +37,7 @@ typedef struct nscss_select_ctx
bool quirks;
struct nsurl *base_url;
lwc_string *universal;
+ const css_computed_style *root_style;
const css_computed_style *parent_style;
} nscss_select_ctx;
diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c
index 5c7cbd9a7..8fe157bd2 100644
--- a/content/handlers/css/utils.c
+++ b/content/handlers/css/utils.c
@@ -27,11 +27,75 @@
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = F_90;
+
+/**
+ * Map viewport-relative length units to either vh or vw.
+ *
+ * Non-viewport-relative units are unchanged.
+ *
+ * \param[in] ctx Length conversion context.
+ * \param[in] unit Unit to map.
+ * \return the mapped unit.
+ */
+static inline css_unit css_utils__fudge_viewport_units(
+ const nscss_len_ctx *ctx,
+ css_unit unit)
+{
+ switch (unit) {
+ case CSS_UNIT_VI:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VW;
+ } else {
+ unit = CSS_UNIT_VH;
+ }
+ break;
+ case CSS_UNIT_VB:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMIN:
+ if (ctx->vh < ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMAX:
+ if (ctx->vh > ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ default: break;
+ }
+
+ return unit;
+}
+
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2pt(css_fixed length, css_unit unit)
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit)
{
/* Length must not be relative */
- assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX);
+ assert(unit != CSS_UNIT_EM &&
+ unit != CSS_UNIT_EX &&
+ unit != CSS_UNIT_CAP &&
+ unit != CSS_UNIT_CH &&
+ unit != CSS_UNIT_IC &&
+ unit != CSS_UNIT_REM &&
+ unit != CSS_UNIT_RLH);
+
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
/* We assume the screen and any other output has the same dpi */
@@ -45,36 +109,50 @@ css_fixed nscss_len2pt(css_fixed length, css_unit unit)
/* 1in = 25.4mm => 1mm = (72/25.4)pt */
case CSS_UNIT_MM: return FMUL(length,
FDIV(F_72, FLTTOFIX(25.4)));
+ /* 1in = 101.6q => 1mm = (72/101.6)pt */
+ case CSS_UNIT_Q: return FMUL(length,
+ FDIV(F_72, FLTTOFIX(101.6)));
case CSS_UNIT_PT: return length;
/* 1pc = 12pt */
case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12));
+ case CSS_UNIT_VH: return FDIV(FMUL(FDIV((length * ctx->vh), F_100),
+ F_72), nscss_screen_dpi);
+ case CSS_UNIT_VW: return FDIV(FMUL(FDIV((length * ctx->vw), F_100),
+ F_72), nscss_screen_dpi);
default: break;
}
return 0;
}
-
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2px(css_fixed length, css_unit unit,
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit,
const css_computed_style *style)
{
/* We assume the screen and any other output has the same dpi */
css_fixed px_per_unit;
- assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX));
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
case CSS_UNIT_EM:
case CSS_UNIT_EX:
+ case CSS_UNIT_CAP:
+ case CSS_UNIT_CH:
+ case CSS_UNIT_IC:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
+ assert(style != NULL);
+
css_computed_font_size(style, &font_size, &font_unit);
/* Convert to points */
- font_size = nscss_len2pt(font_size, font_unit);
+ font_size = nscss_len2pt(ctx, font_size, font_unit);
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
@@ -85,9 +163,22 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
* 1in = 72pt => 1pt = (DPI/72)px */
px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72);
- /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */
- if (unit == CSS_UNIT_EX)
+ /* Scale non-em units to em. We have fixed ratios. */
+ switch (unit) {
+ case CSS_UNIT_EX:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(1.1));
+ break;
+ default: break;
+ }
}
break;
case CSS_UNIT_PX:
@@ -105,6 +196,10 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_MM:
px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4));
break;
+ /* 1in = 101.6q => 1q = (DPI/101.6)px */
+ case CSS_UNIT_Q:
+ px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(101.6));
+ break;
/* 1in = 72pt => 1pt = (DPI/72)px */
case CSS_UNIT_PT:
px_per_unit = FDIV(nscss_screen_dpi, F_72);
@@ -113,6 +208,39 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_PC:
px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6));
break;
+ case CSS_UNIT_REM:
+ {
+ css_fixed font_size = 0;
+ css_unit font_unit = CSS_UNIT_PT;
+
+ assert(ctx->root_style != NULL);
+
+ css_computed_font_size(ctx->root_style,
+ &font_size, &font_unit);
+
+ /* Convert to points */
+ font_size = nscss_len2pt(ctx, font_size, font_unit);
+
+ /* Clamp to configured minimum */
+ if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
+ font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10);
+ }
+
+ /* Convert to pixels (manually, to maximise precision)
+ * 1in = 72pt => 1pt = (DPI/72)px */
+ px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72);
+ break;
+ }
+ /* 1rlh = <user_font_size>pt => 1rlh = (DPI/user_font_size)px */
+ case CSS_UNIT_RLH:
+ px_per_unit = FDIV(nscss_screen_dpi, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ break;
+ case CSS_UNIT_VH:
+ return TRUNCATEFIX((FDIV((length * ctx->vh), F_100) + F_0_5));
+ case CSS_UNIT_VW:
+ return TRUNCATEFIX((FDIV((length * ctx->vw), F_100) + F_0_5));
default:
px_per_unit = 0;
break;
diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h
index 58a5ea6e6..c8f4c82f4 100644
--- a/content/handlers/css/utils.h
+++ b/content/handlers/css/utils.h
@@ -27,23 +27,122 @@
extern css_fixed nscss_screen_dpi;
/**
+ * Length conversion context data.
+ */
+typedef struct nscss_len_ctx {
+ /**
+ * Viewport width in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vw;
+ /**
+ * Viewport height in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vh;
+ /**
+ * Computed style for the document root element.
+ * May be NULL if unit is not rem, or rlh.
+ */
+ const css_computed_style *root_style;
+} nscss_len_ctx;
+
+/**
* Convert an absolute CSS length to points.
*
- * \param[in] length Absolute CSS length.
- * \param[in] unit Unit of the length.
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Absolute CSS length.
+ * \param[in] unit Unit of the length.
* \return length in points
*/
-css_fixed nscss_len2pt(css_fixed length, css_unit unit);
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit);
/**
* Convert a CSS length to pixels.
*
- * \param length Length to convert
- * \param unit Corresponding unit
- * \param style Computed style applying to length. May be NULL if unit is
- * neither em nor ex
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Corresponding unit.
+ * \param[in] style Computed style applying to length.
+ * May be NULL if unit is not em, ex, cap, ch, or ic.
* \return length in pixels
*/
-css_fixed nscss_len2px(css_fixed length, css_unit unit, const css_computed_style *style);
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit,
+ const css_computed_style *style);
+
+
+/**
+ * Temporary helper wrappers for for libcss computed style getter, while
+ * we don't support flexbox related property values.
+ */
+
+static inline uint8_t ns_computed_display(
+ const css_computed_style *style, bool root)
+{
+ uint8_t value = css_computed_display(style, root);
+
+ if (value == CSS_DISPLAY_FLEX) {
+ return CSS_DISPLAY_BLOCK;
+
+ } else if (value == CSS_DISPLAY_INLINE_FLEX) {
+ return CSS_DISPLAY_INLINE_BLOCK;
+ }
+
+ return value;
+}
+
+
+static inline uint8_t ns_computed_display_static(
+ const css_computed_style *style)
+{
+ uint8_t value = css_computed_display_static(style);
+
+ if (value == CSS_DISPLAY_FLEX) {
+ return CSS_DISPLAY_BLOCK;
+
+ } else if (value == CSS_DISPLAY_INLINE_FLEX) {
+ return CSS_DISPLAY_INLINE_BLOCK;
+ }
+
+ return value;
+}
+
+
+static inline uint8_t ns_computed_min_height(
+ const css_computed_style *style,
+ css_fixed *length, css_unit *unit)
+{
+ uint8_t value = css_computed_min_height(style, length, unit);
+
+ if (value == CSS_MIN_HEIGHT_AUTO) {
+ value = CSS_MIN_HEIGHT_SET;
+ *length = 0;
+ *unit = CSS_UNIT_PX;
+ }
+
+ return value;
+}
+
+
+static inline uint8_t ns_computed_min_width(
+ const css_computed_style *style,
+ css_fixed *length, css_unit *unit)
+{
+ uint8_t value = css_computed_min_width(style, length, unit);
+
+ if (value == CSS_MIN_WIDTH_AUTO) {
+ value = CSS_MIN_WIDTH_SET;
+ *length = 0;
+ *unit = CSS_UNIT_PX;
+ }
+
+ return value;
+}
#endif
diff --git a/content/handlers/html/Makefile b/content/handlers/html/Makefile
new file mode 100644
index 000000000..afefba27d
--- /dev/null
+++ b/content/handlers/html/Makefile
@@ -0,0 +1,7 @@
+# HTML content handler sources
+
+S_HTML := box.c box_construct.c box_normalise.c box_textarea.c \
+ font.c form.c imagemap.c layout.c search.c table.c \
+ html.c html_css.c html_css_fetcher.c html_script.c \
+ html_interaction.c html_redraw.c html_redraw_border.c \
+ html_forms.c html_object.c
diff --git a/render/box.c b/content/handlers/html/box.c
index 11a24e797..52cf12413 100644
--- a/render/box.c
+++ b/content/handlers/html/box.c
@@ -41,9 +41,9 @@
#include "desktop/scrollbar.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/box.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
#define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
box->type == BOX_FLOAT_RIGHT)
@@ -62,7 +62,7 @@ static int box_talloc_destructor(struct box *b)
css_computed_style_destroy(b->style);
b->style = NULL;
}
-
+
if (b->styles != NULL) {
css_select_results_destroy(b->styles);
b->styles = NULL;
@@ -112,7 +112,7 @@ static int box_talloc_destructor(struct box *b)
*/
struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, nsurl *href, const char *target,
+ bool style_owned, nsurl *href, const char *target,
const char *title, lwc_string *id, void *context)
{
unsigned int i;
@@ -342,20 +342,27 @@ void box_bounds(struct box *box, struct rect *r)
/**
* Determine if a point lies within a box.
*
- * \param box box to consider
- * \param x coordinate relative to box
- * \param y coordinate relative to box
- * \param physically if function returning true, physically is set true if
- * point is within the box's physical dimensions and false
- * if the point is not within the box's physical dimensions
- * but is in the area defined by the box's descendants.
- * if function returning false, physically is undefined.
+ * \param[in] len_ctx CSS length conversion context to use.
+ * \param[in] box Box to consider
+ * \param[in] x Coordinate relative to box
+ * \param[in] y Coordinate relative to box
+ * \param[out] physically If function returning true, physically is set true
+ * iff point is within the box's physical dimensions and
+ * false if the point is not within the box's physical
+ * dimensions but is in the area defined by the box's
+ * descendants. If function returns false, physically
+ * is undefined.
* \return true if the point is within the box or a descendant box
*
* This is a helper function for box_at_point().
*/
-static bool box_contains_point(struct box *box, int x, int y, bool *physically)
+static bool box_contains_point(
+ const nscss_len_ctx *len_ctx,
+ const struct box *box,
+ int x,
+ int y,
+ bool *physically)
{
css_computed_clip_rect css_rect;
@@ -382,25 +389,25 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
/* Adjust rect to css clip region */
if (css_rect.left_auto == false) {
- r.x0 += FIXTOINT(nscss_len2px(
+ r.x0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.left, css_rect.lunit,
box->style));
}
if (css_rect.top_auto == false) {
- r.y0 += FIXTOINT(nscss_len2px(
+ r.y0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.top, css_rect.tunit,
box->style));
}
if (css_rect.right_auto == false) {
r.x1 = box->border[LEFT].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.right,
css_rect.runit,
box->style));
}
if (css_rect.bottom_auto == false) {
r.y1 = box->border[TOP].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.bottom,
css_rect.bunit,
box->style));
@@ -441,7 +448,7 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
*physically = true;
return true;
}
- if ((box->style && css_computed_overflow_x(box->style) ==
+ if ((box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->descendant_x0 <= x &&
x < box->descendant_x1) {
@@ -449,7 +456,7 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
return true;
}
}
- if ((box->style && css_computed_overflow_y(box->style) ==
+ if ((box->style && css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->descendant_y0 <= y &&
y < box->descendant_y1) {
@@ -659,6 +666,7 @@ skip_children:
/**
* Find the boxes at a point.
*
+ * \param len_ctx CSS length conversion context for document.
* \param box box to search children of
* \param x point to find, in global document coordinates
* \param y point to find, in global document coordinates
@@ -674,13 +682,14 @@ skip_children:
* struct box *box = top_of_document_to_search;
* int box_x = 0, box_y = 0;
*
- * while ((box = box_at_point(box, x, y, &box_x, &box_y))) {
+ * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
* // process box
* }
* \endcode
*/
-struct box *box_at_point(struct box *box, const int x, const int y,
+struct box *box_at_point(const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y)
{
bool skip_children;
@@ -690,7 +699,7 @@ struct box *box_at_point(struct box *box, const int x, const int y,
skip_children = false;
while ((box = box_next_xy(box, box_x, box_y, skip_children))) {
- if (box_contains_point(box, x - *box_x, y - *box_y,
+ if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y,
&physically)) {
*box_x -= scrollbar_get_offset(box->scroll_x);
*box_y -= scrollbar_get_offset(box->scroll_y);
@@ -972,7 +981,7 @@ struct box *box_find_by_id(struct box *box, lwc_string *id)
bool box_visible(struct box *box)
{
/* visibility: hidden */
- if (box->style && css_computed_visibility(box->style) ==
+ if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
return false;
@@ -1031,7 +1040,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
if (box->space)
fprintf(stream, "space ");
if (box->object) {
- fprintf(stream, "(object '%s') ",
+ fprintf(stream, "(object '%s') ",
nsurl_access(hlcache_handle_get_url(box->object)));
}
if (box->iframe) {
@@ -1048,7 +1057,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
if (box->title)
fprintf(stream, " [%s]", box->title);
if (box->id)
- fprintf(stream, " <%s>", lwc_string_data(box->id));
+ fprintf(stream, " ID:%s", lwc_string_data(box->id));
if (box->type == BOX_INLINE || box->type == BOX_INLINE_END)
fprintf(stream, " inline_end %p", box->inline_end);
if (box->float_children)
@@ -1071,6 +1080,13 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
box->col[i].min, box->col[i].max);
fprintf(stream, ")");
}
+ if (box->node != NULL) {
+ dom_string *name;
+ if (dom_node_get_node_name(box->node, &name) == DOM_NO_ERR) {
+ fprintf(stream, " <%s>", dom_string_data(name));
+ dom_string_unref(name);
+ }
+ }
fprintf(stream, "\n");
if (box->list_marker) {
@@ -1148,7 +1164,7 @@ bool box_handle_scrollbars(struct content *c, struct box *box,
if (box->scroll_y == NULL) {
data = malloc(sizeof(struct html_scrollbar_data));
if (data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
guit->misc->warning("NoMemory", 0);
return false;
}
@@ -1169,7 +1185,7 @@ bool box_handle_scrollbars(struct content *c, struct box *box,
if (box->scroll_x == NULL) {
data = malloc(sizeof(struct html_scrollbar_data));
if (data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
guit->misc->warning("NoMemory", 0);
return false;
}
@@ -1190,10 +1206,10 @@ bool box_handle_scrollbars(struct content *c, struct box *box,
visible_width, full_width);
}
}
-
+
if (right && bottom)
scrollbar_make_pair(box->scroll_x, box->scroll_y);
-
+
return true;
}
@@ -1223,4 +1239,3 @@ bool box_hscrollbar_present(const struct box * const box)
return box->padding[LEFT] + box->width + box->padding[RIGHT] +
box->border[RIGHT].width < box->descendant_x1;
}
-
diff --git a/render/box.h b/content/handlers/html/box.h
index 2800d4026..0952b841b 100644
--- a/render/box.h
+++ b/content/handlers/html/box.h
@@ -17,7 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree construction and manipulation (interface).
*
* This stage of rendering converts a tree of dom_nodes (produced by libdom)
@@ -83,14 +84,16 @@
* \endcode
*/
-#ifndef _NETSURF_RENDER_BOX_H_
-#define _NETSURF_RENDER_BOX_H_
+#ifndef NETSURF_HTML_BOX_H
+#define NETSURF_HTML_BOX_H
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <libcss/libcss.h>
+#include "content/handlers/css/utils.h"
+
struct content;
struct box;
struct browser_window;
@@ -319,7 +322,7 @@ extern const char *TARGET_BLANK;
struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, struct nsurl *href, const char *target,
+ bool style_owned, struct nsurl *href, const char *target,
const char *title, lwc_string *id, void *context);
void box_add_child(struct box *parent, struct box *child);
void box_insert_sibling(struct box *box, struct box *new_box);
@@ -328,7 +331,9 @@ void box_free(struct box *box);
void box_free_box(struct box *box);
void box_bounds(struct box *box, struct rect *r);
void box_coords(struct box *box, int *x, int *y);
-struct box *box_at_point(struct box *box, const int x, const int y,
+struct box *box_at_point(
+ const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y);
struct box *box_pick_text_box(struct html_content *html,
int x, int y, int dir, int *dx, int *dy);
@@ -356,6 +361,20 @@ bool box_hscrollbar_present(const struct box *box);
nserror dom_to_box(struct dom_node *n, struct html_content *c,
box_construct_complete_cb cb);
-bool box_normalise_block(struct box *block, struct html_content *c);
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ struct html_content *c);
+
+/**
+ * Check if layout box is a first child.
+ *
+ * \param[in] b Box to check.
+ * \return true iff box is first child.
+ */
+static inline bool box_is_first_child(struct box *b)
+{
+ return (b->parent == NULL || b == b->parent->children);
+}
#endif
diff --git a/render/box_construct.c b/content/handlers/html/box_construct.c
index f2d041385..5650fbf55 100644
--- a/render/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -46,12 +46,14 @@
#include "content/content_protected.h"
#include "css/hints.h"
#include "css/select.h"
+#include "css/utils.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
/**
* Context for box tree construction
@@ -103,7 +105,8 @@ static bool box_construct_element(struct box_construct_ctx *ctx,
static void box_construct_element_after(dom_node *n, html_content *content);
static bool box_construct_text(struct box_construct_ctx *ctx);
static css_select_results * box_get_style(html_content *c,
- const css_computed_style *parent_style, dom_node *n);
+ const css_computed_style *parent_style,
+ const css_computed_style *root_style, dom_node *n);
static void box_text_transform(char *s, unsigned int len,
enum css_text_transform_e tt);
#define BOX_SPECIAL_PARAMS dom_node *n, html_content *content, \
@@ -428,7 +431,8 @@ void convert_xml_to_box(struct box_construct_ctx *ctx)
root.children->parent = &root;
/** \todo Remove box_normalise_block */
- if (box_normalise_block(&root, ctx->content) == false) {
+ if (box_normalise_block(&root, ctx->root_box,
+ ctx->content) == false) {
ctx->cb(ctx->content, false);
} else {
ctx->content->layout = root.children;
@@ -594,6 +598,7 @@ static void box_construct_generate(dom_node *n, html_content *content,
struct box *box, const css_computed_style *style)
{
struct box *gen = NULL;
+ enum css_display_e computed_display;
const css_computed_content_item *c_item;
/* Nothing to generate if the parent box is not a block */
@@ -611,8 +616,10 @@ static void box_construct_generate(dom_node *n, html_content *content,
}
/* create box for this element */
- if (css_computed_display(style, box_is_root(n)) == CSS_DISPLAY_BLOCK) {
- /* currently only support block level elements */
+ computed_display = ns_computed_display(style, box_is_root(n));
+ if (computed_display == CSS_DISPLAY_BLOCK ||
+ computed_display == CSS_DISPLAY_TABLE) {
+ /* currently only support block level boxes */
/** \todo Not wise to drop const from the computed style */
gen = box_create(NULL, (css_computed_style *) style,
@@ -622,7 +629,7 @@ static void box_construct_generate(dom_node *n, html_content *content,
}
/* set box type from computed display */
- gen->type = box_map[css_computed_display(
+ gen->type = box_map[ns_computed_display(
style, box_is_root(n))];
box_add_child(box, gen);
@@ -737,6 +744,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
lwc_string *bgimage_uri;
dom_exception err;
struct box_construct_props props;
+ const css_computed_style *root_style = NULL;
assert(ctx->n != NULL);
@@ -744,12 +752,17 @@ bool box_construct_element(struct box_construct_ctx *ctx,
if (props.containing_block != NULL) {
/* In case the containing block is a pre block, we clear
- * the PRE_STRIP flag since it is not used if we follow
- * the pre with a tag */
+ * the PRE_STRIP flag since it is not used if we follow
+ * the pre with a tag */
props.containing_block->flags &= ~PRE_STRIP;
}
- styles = box_get_style(ctx->content, props.parent_style, ctx->n);
+ if (props.node_is_root == false) {
+ root_style = ctx->root_box->style;
+ }
+
+ styles = box_get_style(ctx->content, props.parent_style, root_style,
+ ctx->n);
if (styles == NULL)
return false;
@@ -828,11 +841,11 @@ bool box_construct_element(struct box_construct_ctx *ctx,
if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE ||
css_computed_position(box->style) ==
CSS_POSITION_FIXED) &&
- (css_computed_display_static(box->style) ==
+ (ns_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE ||
- css_computed_display_static(box->style) ==
+ ns_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE_BLOCK ||
- css_computed_display_static(box->style) ==
+ ns_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE_TABLE)) {
/* Special case for absolute positioning: make absolute inlines
* into inline block so that the boxes are constructed in an
@@ -845,7 +858,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
box->type = BOX_BLOCK;
} else {
/* Normal mapping */
- box->type = box_map[css_computed_display(box->style,
+ box->type = box_map[ns_computed_display(box->style,
props.node_is_root)];
}
@@ -873,7 +886,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
}
- if (box->type == BOX_NONE || (css_computed_display(box->style,
+ if (box->type == BOX_NONE || (ns_computed_display(box->style,
props.node_is_root) == CSS_DISPLAY_NONE &&
props.node_is_root == false)) {
css_select_results_destroy(styles);
@@ -965,7 +978,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
box_add_child(props.inline_container, box);
} else {
- if (css_computed_display(box->style, props.node_is_root) ==
+ if (ns_computed_display(box->style, props.node_is_root) ==
CSS_DISPLAY_LIST_ITEM) {
/* List item: compute marker */
if (box_construct_marker(box, props.title, ctx,
@@ -1317,13 +1330,15 @@ bool box_construct_text(struct box_construct_ctx *ctx)
/**
* Get the style for an element.
*
- * \param c content of type CONTENT_HTML that is being processed
+ * \param c content of type CONTENT_HTML that is being processed
* \param parent_style style at this point in xml tree, or NULL for root
- * \param n node in xml tree
+ * \param root_style root node's style, or NULL for root
+ * \param n node in xml tree
* \return the new style, or NULL on memory exhaustion
*/
css_select_results *box_get_style(html_content *c,
- const css_computed_style *parent_style, dom_node *n)
+ const css_computed_style *parent_style,
+ const css_computed_style *root_style, dom_node *n)
{
dom_string *s;
dom_exception err;
@@ -1355,6 +1370,7 @@ css_select_results *box_get_style(html_content *c,
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
+ ctx.root_style = root_style;
ctx.parent_style = parent_style;
/* Select style for element */
@@ -1556,7 +1572,7 @@ bool box_image(BOX_SPECIAL_PARAMS)
css_unit wunit = CSS_UNIT_PX;
css_unit hunit = CSS_UNIT_PX;
- if (box->style && css_computed_display(box->style,
+ if (box->style && ns_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
@@ -1663,7 +1679,7 @@ bool box_object(BOX_SPECIAL_PARAMS)
dom_node *c;
dom_exception err;
- if (box->style && css_computed_display(box->style,
+ if (box->style && ns_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
@@ -1897,7 +1913,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
bool ok;
if (content->frameset) {
- LOG("Error: multiple framesets in document.");
+ NSLOG(netsurf, INFO, "Error: multiple framesets in document.");
/* Don't convert children */
if (convert_children)
*convert_children = false;
@@ -2053,9 +2069,9 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n,
/* common extension: frameborder="yes|no" to control all children */
err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_no) == 0)
- default_border = false;
+ if (dom_string_caseless_lwc_isequal(s,
+ corestring_lwc_no) == 0)
+ default_border = false;
dom_string_unref(s);
}
@@ -2199,8 +2215,8 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n,
/* copy url */
if (url != NULL) {
- /* no self-references */
- if (nsurl_compare(content->base_url, url,
+ /* no self-references */
+ if (nsurl_compare(content->base_url, url,
NSURL_COMPLETE) == false)
frame->url = url;
url = NULL;
@@ -2313,7 +2329,7 @@ bool box_iframe(BOX_SPECIAL_PARAMS)
struct content_html_iframe *iframe;
int i;
- if (box->style && css_computed_display(box->style,
+ if (box->style && ns_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
@@ -2548,7 +2564,7 @@ bool box_input(BOX_SPECIAL_PARAMS)
corestring_lwc_image)) {
gadget->type = GADGET_IMAGE;
- if (box->style && css_computed_display(box->style,
+ if (box->style && ns_computed_display(box->style,
box_is_root(n)) != CSS_DISPLAY_NONE &&
nsoption_bool(foreground_images) == true) {
dom_string *s;
@@ -2884,7 +2900,7 @@ bool box_embed(BOX_SPECIAL_PARAMS)
dom_string *src;
dom_exception err;
- if (box->style && css_computed_display(box->style,
+ if (box->style && ns_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
@@ -3049,7 +3065,7 @@ bool box_get_attribute(dom_node *n, const char *attribute,
}
-/* exported function documented in render/box.h */
+/* exported function documented in html/box.h */
bool
box_extract_link(const html_content *content,
const dom_string *dsrel,
@@ -3117,6 +3133,3 @@ box_extract_link(const html_content *content,
return true;
}
-
-
-
diff --git a/render/box_normalise.c b/content/handlers/html/box_normalise.c
index 5d36b99d7..7155cb722 100644
--- a/render/box_normalise.c
+++ b/content/handlers/html/box_normalise.c
@@ -19,7 +19,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree normalisation (implementation).
*/
@@ -31,9 +32,9 @@
#include "utils/errors.h"
#include "css/select.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/table.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/table.h"
/* Define to enable box normalise debug */
#undef BOX_NORMALISE_DEBUG
@@ -65,24 +66,38 @@ struct columns {
};
-static bool box_normalise_table(struct box *table, html_content *c);
-static bool box_normalise_table_spans(struct box *table,
- struct span_info *spans, html_content *c);
-static bool box_normalise_table_row_group(struct box *row_group,
+static bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content *c);
+static bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
+ html_content *c);
+static bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content *c);
-static bool box_normalise_table_row(struct box *row,
+static bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
struct columns *col_info,
html_content *c);
static bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column, struct box *cell);
-static bool box_normalise_inline_container(struct box *cont, html_content *c);
+static bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ html_content *c);
/**
* Ensure the box tree is correctly nested by adding and removing nodes.
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
+ * \param root root box of document
* \param c content of boxes
* \return true on success, false on memory exhaustion
*
@@ -100,7 +115,10 @@ static bool box_normalise_inline_container(struct box *cont, html_content *c);
* \endcode
*/
-bool box_normalise_block(struct box *block, html_content *c)
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ html_content *c)
{
struct box *child;
struct box *next_child;
@@ -109,9 +127,12 @@ bool box_normalise_block(struct box *block, html_content *c)
nscss_select_ctx ctx;
assert(block != NULL);
+ assert(root != NULL);
+
+ ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
- LOG("block %p, block->type %u", block, block->type);
+ NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
#endif
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
@@ -119,7 +140,8 @@ bool box_normalise_block(struct box *block, html_content *c)
for (child = block->children; child != NULL; child = next_child) {
#ifdef BOX_NORMALISE_DEBUG
- LOG("child %p, child->type = %d", child, child->type);
+ NSLOG(netsurf, INFO, "child %p, child->type = %d", child,
+ child->type);
#endif
next_child = child->next; /* child may be destroyed */
@@ -127,15 +149,15 @@ bool box_normalise_block(struct box *block, html_content *c)
switch (child->type) {
case BOX_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
- if (box_normalise_inline_container(child, c) == false)
+ if (box_normalise_inline_container(child, root, c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child, c) == false)
+ if (box_normalise_table(child, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -198,7 +220,7 @@ bool box_normalise_block(struct box *block, html_content *c)
block->last = table;
table->parent = block;
- if (box_normalise_table(table, c) == false)
+ if (box_normalise_table(table, root, c) == false)
return false;
break;
default:
@@ -210,7 +232,10 @@ bool box_normalise_block(struct box *block, html_content *c)
}
-bool box_normalise_table(struct box *table, html_content * c)
+bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -222,8 +247,10 @@ bool box_normalise_table(struct box *table, html_content * c)
assert(table != NULL);
assert(table->type == BOX_TABLE);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
- LOG("table %p", table);
+ NSLOG(netsurf, INFO, "table %p", table);
#endif
col_info.num_columns = 1;
@@ -242,7 +269,7 @@ bool box_normalise_table(struct box *table, html_content * c)
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
- if (box_normalise_table_row_group(child,
+ if (box_normalise_table_row_group(child, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -307,7 +334,7 @@ bool box_normalise_table(struct box *table, html_content * c)
table->last = row_group;
row_group->parent = table;
- if (box_normalise_table_row_group(row_group,
+ if (box_normalise_table_row_group(row_group, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -337,7 +364,8 @@ bool box_normalise_table(struct box *table, html_content * c)
struct box *row;
#ifdef BOX_NORMALISE_DEBUG
- LOG("table->children == 0, creating implied row");
+ NSLOG(netsurf, INFO,
+ "table->children == 0, creating implied row");
#endif
assert(table->style != NULL);
@@ -388,18 +416,15 @@ bool box_normalise_table(struct box *table, html_content * c)
table->rows = 1;
}
- if (box_normalise_table_spans(table, col_info.spans, c) == false) {
+ if (box_normalise_table_spans(table, root, col_info.spans, c) == false) {
free(col_info.spans);
return false;
}
free(col_info.spans);
- if (table_calculate_column_types(table) == false)
- return false;
-
#ifdef BOX_NORMALISE_DEBUG
- LOG("table %p done", table);
+ NSLOG(netsurf, INFO, "table %p done", table);
#endif
return true;
@@ -411,12 +436,16 @@ bool box_normalise_table(struct box *table, html_content * c)
* Additionally, generate empty cells.
*
* \param table Table to process
+ * \param root root box of document
* \param spans Array of length table->columns for use in empty cell detection
* \param c Content containing table
* \return True on success, false on memory exhaustion.
*/
-bool box_normalise_table_spans(struct box *table, struct span_info *spans,
+bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
html_content *c)
{
struct box *table_row_group;
@@ -427,10 +456,12 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
unsigned int col;
nscss_select_ctx ctx;
+ ctx.root_style = root->style;
+
/* Clear span data */
memset(spans, 0, table->columns * sizeof(struct span_info));
- /* Scan table, filling in width and height of table cells with
+ /* Scan table, filling in width and height of table cells with
* colspan = 0 and rowspan = 0. Also generate empty cells */
for (table_row_group = table->children;
table_row_group != NULL;
@@ -479,34 +510,34 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
css_computed_style *style;
struct box *cell, *prev;
- /* If it's already zero, then we need
- * to generate an empty cell for the
- * gap in the row that spans as many
- * columns as remain blank.
+ /* If it's already zero, then we need
+ * to generate an empty cell for the
+ * gap in the row that spans as many
+ * columns as remain blank.
*/
assert(table_row->style != NULL);
/* Find width of gap */
while (col < table->columns &&
- spans[col].row_span ==
+ spans[col].row_span ==
0) {
col++;
}
ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks ==
+ ctx.quirks = (c->quirks ==
DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
- style = nscss_get_blank_style(&ctx,
+ style = nscss_get_blank_style(&ctx,
table_row->style);
if (style == NULL)
return false;
- cell = box_create(NULL, style, true,
- table_row->href,
- table_row->target,
+ cell = box_create(NULL, style, true,
+ table_row->href,
+ table_row->target,
NULL, NULL, c->bctx);
if (cell == NULL) {
css_computed_style_destroy(
@@ -523,8 +554,8 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
for (prev = table_row->children;
prev != NULL;
prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
+ if (prev->start_column +
+ prev->columns ==
start)
break;
if (prev->next == NULL)
@@ -539,7 +570,7 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
else
table_row->last = cell;
- cell->next =
+ cell->next =
table_row->children;
table_row->children = cell;
} else {
@@ -570,7 +601,9 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
}
-bool box_normalise_table_row_group(struct box *row_group,
+bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -584,8 +617,10 @@ bool box_normalise_table_row_group(struct box *row_group,
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
- LOG("row_group %p", row_group);
+ NSLOG(netsurf, INFO, "row_group %p", row_group);
#endif
for (child = row_group->children; child != NULL; child = next_child) {
@@ -595,7 +630,7 @@ bool box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_ROW:
/* ok */
group_row_count++;
- if (box_normalise_table_row(child, col_info,
+ if (box_normalise_table_row(child, root, col_info,
c) == false)
return false;
break;
@@ -655,7 +690,7 @@ bool box_normalise_table_row_group(struct box *row_group,
row->parent = row_group;
group_row_count++;
- if (box_normalise_table_row(row, col_info,
+ if (box_normalise_table_row(row, root, col_info,
c) == false)
return false;
break;
@@ -677,7 +712,8 @@ bool box_normalise_table_row_group(struct box *row_group,
if (row_group->children == NULL) {
#ifdef BOX_NORMALISE_DEBUG
- LOG("row_group->children == 0, inserting implied row");
+ NSLOG(netsurf, INFO,
+ "row_group->children == 0, inserting implied row");
#endif
assert(row_group->style != NULL);
@@ -712,14 +748,16 @@ bool box_normalise_table_row_group(struct box *row_group,
row_group->rows = group_row_count;
#ifdef BOX_NORMALISE_DEBUG
- LOG("row_group %p done", row_group);
+ NSLOG(netsurf, INFO, "row_group %p done", row_group);
#endif
return true;
}
-bool box_normalise_table_row(struct box *row,
+bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -733,8 +771,10 @@ bool box_normalise_table_row(struct box *row,
assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
- LOG("row %p", row);
+ NSLOG(netsurf, INFO, "row %p", row);
#endif
for (child = row->children; child != NULL; child = next_child) {
@@ -743,7 +783,7 @@ bool box_normalise_table_row(struct box *row,
switch (child->type) {
case BOX_TABLE_CELL:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
cell = child;
break;
@@ -802,7 +842,7 @@ bool box_normalise_table_row(struct box *row,
row->last = cell;
cell->parent = row;
- if (box_normalise_block(cell, c) == false)
+ if (box_normalise_block(cell, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -828,7 +868,7 @@ bool box_normalise_table_row(struct box *row,
/* Update row spanning details for all columns */
for (i = 0; i < col_info->num_columns; i++) {
- if (col_info->spans[i].row_span != 0 &&
+ if (col_info->spans[i].row_span != 0 &&
col_info->spans[i].auto_row == false) {
/* This cell spans rows, and is not an auto row.
* Reduce number of rows left to span */
@@ -843,7 +883,7 @@ bool box_normalise_table_row(struct box *row,
col_info->num_rows++;
#ifdef BOX_NORMALISE_DEBUG
- LOG("row %p done", row);
+ NSLOG(netsurf, INFO, "row %p done", row);
#endif
return true;
@@ -887,12 +927,12 @@ bool calculate_table_row(struct columns *col_info,
* No other browser supports colspan=0, anyway. */
if (col_span == 0)
col_span = 1;
-
+
cell_end_col = cell_start_col + col_span;
if (col_info->num_columns < cell_end_col) {
/* It appears that this row has more columns than
- * the maximum recorded for the table so far.
+ * the maximum recorded for the table so far.
* Allocate more span records. */
spans = realloc(col_info->spans,
sizeof *spans * (cell_end_col + 1));
@@ -907,7 +947,7 @@ bool calculate_table_row(struct columns *col_info,
col_info->spans[cell_end_col].auto_row = false;
}
- /* This cell may span multiple columns. If it also wants to span
+ /* This cell may span multiple columns. If it also wants to span
* multiple rows, temporarily assume it spans 1 row only. This will
* be fixed up in box_normalise_table_spans() */
for (i = cell_start_col; i < cell_end_col; i++) {
@@ -925,7 +965,10 @@ bool calculate_table_row(struct columns *col_info,
}
-bool box_normalise_inline_container(struct box *cont, html_content * c)
+bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -934,7 +977,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
assert(cont->type == BOX_INLINE_CONTAINER);
#ifdef BOX_NORMALISE_DEBUG
- LOG("cont %p", cont);
+ NSLOG(netsurf, INFO, "cont %p", cont);
#endif
for (child = cont->children; child != NULL; child = next_child) {
@@ -948,7 +991,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
break;
case BOX_INLINE_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
@@ -958,12 +1001,12 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
switch (child->children->type) {
case BOX_BLOCK:
- if (box_normalise_block(child->children,
+ if (box_normalise_block(child->children, root,
c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child->children,
+ if (box_normalise_table(child->children, root,
c) == false)
return false;
break;
@@ -997,7 +1040,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
}
#ifdef BOX_NORMALISE_DEBUG
- LOG("cont %p done", cont);
+ NSLOG(netsurf, INFO, "cont %p done", cont);
#endif
return true;
diff --git a/render/box_textarea.c b/content/handlers/html/box_textarea.c
index 44f5c0b16..c19afbb77 100644
--- a/render/box_textarea.c
+++ b/content/handlers/html/box_textarea.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree treeview box replacement (implementation).
*/
@@ -27,9 +28,11 @@
#include "netsurf/keypress.h"
#include "desktop/textarea.h"
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/font.h"
+#include "html/form_internal.h"
bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
@@ -149,7 +152,9 @@ static void box_textarea_callback(void *data, struct textarea_msg *msg)
break;
default:
- LOG("Drag type %d not handled.", msg->data.drag);
+ NSLOG(netsurf, INFO,
+ "Drag type %d not handled.",
+ msg->data.drag);
/* This is a logic faliure in the
* front end code so abort.
*/
@@ -237,8 +242,16 @@ bool box_textarea_create_textarea(html_content *html,
dom_exception err;
textarea_setup ta_setup;
textarea_flags ta_flags;
- plot_font_style_t fstyle;
+ plot_font_style_t fstyle = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 10 * PLOT_STYLE_SCALE,
+ .weight = 400,
+ .flags = FONTF_NONE,
+ .background = 0,
+ .foreground = 0,
+ };
bool read_only = false;
+ bool disabled = false;
struct form_control *gadget = box->gadget;
const char *text;
@@ -257,6 +270,11 @@ bool box_textarea_create_textarea(html_content *html,
if (err != DOM_NO_ERR)
return false;
+ err = dom_html_text_area_element_get_disabled(
+ textarea, &disabled);
+ if (err != DOM_NO_ERR)
+ return false;
+
/* Get the textarea's initial content */
err = dom_html_text_area_element_get_value(textarea, &dom_text);
if (err != DOM_NO_ERR)
@@ -270,6 +288,11 @@ bool box_textarea_create_textarea(html_content *html,
if (err != DOM_NO_ERR)
return false;
+ err = dom_html_input_element_get_disabled(
+ input, &disabled);
+ if (err != DOM_NO_ERR)
+ return false;
+
if (gadget->type == GADGET_PASSWORD)
ta_flags = TEXTAREA_PASSWORD;
else
@@ -289,13 +312,11 @@ bool box_textarea_create_textarea(html_content *html,
text = "";
}
- if (read_only)
+ if (read_only || disabled)
ta_flags |= TEXTAREA_READONLY;
gadget->data.text.data.gadget = gadget;
- font_plot_style_from_css(gadget->box->style, &fstyle);
-
/* Reset to correct values by layout */
ta_setup.width = 200;
ta_setup.height = 20;
@@ -329,4 +350,3 @@ bool box_textarea_create_textarea(html_content *html,
return true;
}
-
diff --git a/render/box_textarea.h b/content/handlers/html/box_textarea.h
index a7a377076..822fc8b10 100644
--- a/render/box_textarea.h
+++ b/content/handlers/html/box_textarea.h
@@ -16,20 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree treeview box replacement (interface).
*/
-
-
-#ifndef _NETSURF_RENDER_BOX_TEXTAREA_H_
-#define _NETSURF_RENDER_BOX_TEXTAREA_H_
-
-
-#include "render/box.h"
-#include "render/html_internal.h"
+#ifndef NETSURF_HTML_BOX_TEXTAREA_H
+#define NETSURF_HTML_BOX_TEXTAREA_H
struct dom_node;
+struct html_content;
+struct box;
/**
* Create textarea widget for a form element
@@ -38,7 +35,7 @@ struct dom_node;
* \param box box with gadget to be given textarea widget
* \param node DOM node for form element
*/
-bool box_textarea_create_textarea(html_content *html,
+bool box_textarea_create_textarea(struct html_content *html,
struct box *box, struct dom_node *node);
@@ -50,6 +47,6 @@ bool box_textarea_create_textarea(html_content *html,
* \param key keypress
* \return true iff keypress handled
*/
-bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key);
+bool box_textarea_keypress(struct html_content *html, struct box *box, uint32_t key);
#endif
diff --git a/render/font.c b/content/handlers/html/font.c
index 94ef877c7..7ebe16825 100644
--- a/render/font.c
+++ b/content/handlers/html/font.c
@@ -19,23 +19,23 @@
/**
* \file
*
- * Renderer internal font handling implementation.
+ * HTML internal font handling implementation.
*/
#include "utils/nsoption.h"
#include "netsurf/plot_style.h"
#include "css/utils.h"
-#include "render/font.h"
+#include "html/font.h"
/**
* Map a generic CSS font family to a generic plot font family
*
- * \param css Generic CSS font family
+ * \param css Generic CSS font family
* \return Plot font family
*/
-static plot_font_generic_family_t plot_font_generic_family(
- enum css_font_family_e css)
+static plot_font_generic_family_t
+plot_font_generic_family(enum css_font_family_e css)
{
plot_font_generic_family_t plot;
@@ -131,8 +131,10 @@ static plot_font_flags_t plot_font_flags(enum css_font_style_e style,
}
-/* exported function documented in render/font_internal.h */
-void font_plot_style_from_css(const css_computed_style *css,
+/* exported function documented in html/font.h */
+void font_plot_style_from_css(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
plot_font_style_t *fstyle)
{
lwc_string **families;
@@ -142,14 +144,15 @@ void font_plot_style_from_css(const css_computed_style *css,
fstyle->family = plot_font_generic_family(
css_computed_font_family(css, &families));
+ fstyle->families = families;
css_computed_font_size(css, &length, &unit);
- fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit),
- INTTOFIX(FONT_SIZE_SCALE)));
+ fstyle->size = FIXTOINT(FMUL(nscss_len2pt(len_ctx, length, unit),
+ INTTOFIX(PLOT_STYLE_SCALE)));
/* Clamp font size to configured minimum */
- if (fstyle->size < (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10)
- fstyle->size = (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10;
+ if (fstyle->size < (nsoption_int(font_min_size) * PLOT_STYLE_SCALE) / 10)
+ fstyle->size = (nsoption_int(font_min_size) * PLOT_STYLE_SCALE) / 10;
fstyle->weight = plot_font_weight(css_computed_font_weight(css));
fstyle->flags = plot_font_flags(css_computed_font_style(css),
diff --git a/render/font.h b/content/handlers/html/font.h
index fba368a97..5f69ee7d3 100644
--- a/render/font.h
+++ b/content/handlers/html/font.h
@@ -16,26 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- *
+/**
+ * \file
* Internal font handling interfaces.
*
* These functions provide font related services. They all work on
* UTF-8 strings with lengths given.
*/
-#ifndef _NETSURF_RENDER_FONT_H_
-#define _NETSURF_RENDER_FONT_H_
+#ifndef NETSURF_HTML_FONT_H
+#define NETSURF_HTML_FONT_H
struct plot_font_style;
/**
* Populate a font style using data from a computed CSS style
*
- * \param css Computed style to consider
- * \param fstyle Font style to populate
+ * \param len_ctx Length conversion context
+ * \param css Computed style to consider
+ * \param fstyle Font style to populate
*/
-void font_plot_style_from_css(const css_computed_style *css,
+void font_plot_style_from_css(const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
struct plot_font_style *fstyle);
#endif
diff --git a/render/form.c b/content/handlers/html/form.c
index 6eb1b80b8..8ba99d4ab 100644
--- a/render/form.c
+++ b/content/handlers/html/form.c
@@ -52,12 +52,12 @@
#include "desktop/textarea.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
+#include "html/layout.h"
#define MAX_SELECT_HEIGHT 210
#define SELECT_LINE_SPACING 0.2
@@ -96,9 +96,9 @@ static void form_select_menu_clicked(struct form_control *control,
static void form_select_menu_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
-/* exported interface documented in render/form_internal.h */
-struct form *form_new(void *node, const char *action, const char *target,
- form_method method, const char *charset,
+/* exported interface documented in html/form_internal.h */
+struct form *form_new(void *node, const char *action, const char *target,
+ form_method method, const char *charset,
const char *doc_charset)
{
struct form *form;
@@ -146,7 +146,7 @@ struct form *form_new(void *node, const char *action, const char *target,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
void form_free(struct form *form)
{
struct form_control *c, *d;
@@ -165,7 +165,7 @@ void form_free(struct form *form)
free(form);
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
struct form_control *form_new_control(void *node, form_control_type type)
{
struct form_control *control;
@@ -218,7 +218,8 @@ void form_free_control(struct form_control *control)
struct form_control *c;
assert(control != NULL);
- LOG("Control:%p name:%p value:%p initial:%p", control, control->name, control->value, control->initial_value);
+ NSLOG(netsurf, INFO, "Control:%p name:%p value:%p initial:%p",
+ control, control->name, control->value, control->initial_value);
free(control->name);
free(control->value);
free(control->initial_value);
@@ -229,7 +230,9 @@ void form_free_control(struct form_control *control)
for (option = control->data.select.items; option;
option = next) {
next = option->next;
- LOG("select option:%p text:%p value:%p", option, option->text, option->value);
+ NSLOG(netsurf, INFO,
+ "select option:%p text:%p value:%p", option,
+ option->text, option->value);
free(option->text);
free(option->value);
free(option);
@@ -324,7 +327,7 @@ bool form_add_option(struct form_control *control, char *value, char *text,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_successful_controls_dom(struct form *_form,
struct form_control *_submit_button,
struct fetch_multipart_data **successful_controls)
@@ -344,11 +347,11 @@ bool form_successful_controls_dom(struct form *_form,
last_success = &sentinel;
sentinel.next = NULL;
-
+
/** \todo Replace this call with something DOMish */
charset = form_acceptable_charset(_form);
if (charset == NULL) {
- LOG("failed to find charset");
+ NSLOG(netsurf, INFO, "failed to find charset");
return false;
}
@@ -358,22 +361,22 @@ bool form_successful_controls_dom(struct form *_form,
form_encode_item(dom_string_data(i), dom_string_byte_length(i), \
charset, _form->document_charset) \
))
-
+
err = dom_html_form_element_get_elements(form, &form_elements);
-
+
if (err != DOM_NO_ERR) {
- LOG("Could not get form elements");
+ NSLOG(netsurf, INFO, "Could not get form elements");
goto dom_no_memory;
}
-
-
+
+
err = dom_html_collection_get_length(form_elements, &element_count);
-
+
if (err != DOM_NO_ERR) {
- LOG("Could not get form element count");
+ NSLOG(netsurf, INFO, "Could not get form element count");
goto dom_no_memory;
}
-
+
for (index = 0; index < element_count; index++) {
if (form_element != NULL) {
dom_node_unref(form_element);
@@ -402,7 +405,8 @@ bool form_successful_controls_dom(struct form *_form,
err = dom_html_collection_item(form_elements,
index, &form_element);
if (err != DOM_NO_ERR) {
- LOG("Could not retrieve form element %d", index);
+ NSLOG(netsurf, INFO,
+ "Could not retrieve form element %d", index);
goto dom_no_memory;
}
@@ -414,7 +418,7 @@ bool form_successful_controls_dom(struct form *_form,
*/
err = dom_node_get_node_name(form_element, &nodename);
if (err != DOM_NO_ERR) {
- LOG("Could not get node name");
+ NSLOG(netsurf, INFO, "Could not get node name");
goto dom_no_memory;
}
@@ -423,14 +427,16 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_text_area_element *)form_element,
&element_disabled);
if (err != DOM_NO_ERR) {
- LOG("Could not get text area disabled property");
+ NSLOG(netsurf, INFO,
+ "Could not get text area disabled property");
goto dom_no_memory;
}
err = dom_html_text_area_element_get_name(
(dom_html_text_area_element *)form_element,
&inputname);
if (err != DOM_NO_ERR) {
- LOG("Could not get text area name property");
+ NSLOG(netsurf, INFO,
+ "Could not get text area name property");
goto dom_no_memory;
}
} else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
@@ -438,14 +444,16 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_select_element *)form_element,
&element_disabled);
if (err != DOM_NO_ERR) {
- LOG("Could not get select disabled property");
+ NSLOG(netsurf, INFO,
+ "Could not get select disabled property");
goto dom_no_memory;
}
err = dom_html_select_element_get_name(
(dom_html_select_element *)form_element,
&inputname);
if (err != DOM_NO_ERR) {
- LOG("Could not get select name property");
+ NSLOG(netsurf, INFO,
+ "Could not get select name property");
goto dom_no_memory;
}
} else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
@@ -453,14 +461,16 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&element_disabled);
if (err != DOM_NO_ERR) {
- LOG("Could not get input disabled property");
+ NSLOG(netsurf, INFO,
+ "Could not get input disabled property");
goto dom_no_memory;
}
err = dom_html_input_element_get_name(
(dom_html_input_element *)form_element,
&inputname);
if (err != DOM_NO_ERR) {
- LOG("Could not get input name property");
+ NSLOG(netsurf, INFO,
+ "Could not get input name property");
goto dom_no_memory;
}
} else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
@@ -468,34 +478,37 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_button_element *)form_element,
&element_disabled);
if (err != DOM_NO_ERR) {
- LOG("Could not get button disabled property");
+ NSLOG(netsurf, INFO,
+ "Could not get button disabled property");
goto dom_no_memory;
}
err = dom_html_button_element_get_name(
(dom_html_button_element *)form_element,
&inputname);
if (err != DOM_NO_ERR) {
- LOG("Could not get button name property");
+ NSLOG(netsurf, INFO,
+ "Could not get button name property");
goto dom_no_memory;
}
} else {
/* Unknown element type came through! */
- LOG("Unknown element type: %*s",
- (int)dom_string_byte_length(nodename),
- dom_string_data(nodename));
+ NSLOG(netsurf, INFO, "Unknown element type: %*s",
+ (int)dom_string_byte_length(nodename),
+ dom_string_data(nodename));
goto dom_no_memory;
}
if (element_disabled)
continue;
if (inputname == NULL)
continue;
-
+
if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
err = dom_html_text_area_element_get_value(
(dom_html_text_area_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get text area content");
+ NSLOG(netsurf, INFO,
+ "Could not get text area content");
goto dom_no_memory;
}
} else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
@@ -504,13 +517,15 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_select_element *)form_element,
&options);
if (err != DOM_NO_ERR) {
- LOG("Could not get select options collection");
+ NSLOG(netsurf, INFO,
+ "Could not get select options collection");
goto dom_no_memory;
}
err = dom_html_options_collection_get_length(
options, &options_count);
if (err != DOM_NO_ERR) {
- LOG("Could not get select options collection length");
+ NSLOG(netsurf, INFO,
+ "Could not get select options collection length");
goto dom_no_memory;
}
for(option_index = 0; option_index < options_count;
@@ -527,14 +542,17 @@ bool form_successful_controls_dom(struct form *_form,
err = dom_html_options_collection_item(
options, option_index, &option_element);
if (err != DOM_NO_ERR) {
- LOG("Could not get options item %d", option_index);
+ NSLOG(netsurf, INFO,
+ "Could not get options item %d",
+ option_index);
goto dom_no_memory;
}
err = dom_html_option_element_get_selected(
(dom_html_option_element *)option_element,
&selected);
if (err != DOM_NO_ERR) {
- LOG("Could not get option selected property");
+ NSLOG(netsurf, INFO,
+ "Could not get option selected property");
goto dom_no_memory;
}
if (!selected)
@@ -543,27 +561,31 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_option_element *)option_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get option value");
+ NSLOG(netsurf, INFO,
+ "Could not get option value");
goto dom_no_memory;
}
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
- LOG("Could not allocate data for option");
+ NSLOG(netsurf, INFO,
+ "Could not allocate data for option");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = ENCODE_ITEM(inputname);
if (success_new->name == NULL) {
- LOG("Could not encode name for option");
+ NSLOG(netsurf, INFO,
+ "Could not encode name for option");
goto dom_no_memory;
}
success_new->value = ENCODE_ITEM(inputvalue);
if (success_new->value == NULL) {
- LOG("Could not encode value for option");
+ NSLOG(netsurf, INFO,
+ "Could not encode value for option");
goto dom_no_memory;
}
}
@@ -573,7 +595,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_button_element *) form_element,
&inputtype);
if (err != DOM_NO_ERR) {
- LOG("Could not get button element type");
+ NSLOG(netsurf, INFO,
+ "Could not get button element type");
goto dom_no_memory;
}
if (dom_string_caseless_isequal(
@@ -593,7 +616,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_button_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get submit button value");
+ NSLOG(netsurf, INFO,
+ "Could not get submit button value");
goto dom_no_memory;
}
/* Drop through to report successful button */
@@ -610,7 +634,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *) form_element,
&inputtype);
if (err != DOM_NO_ERR) {
- LOG("Could not get input element type");
+ NSLOG(netsurf, INFO,
+ "Could not get input element type");
goto dom_no_memory;
}
if (dom_string_caseless_isequal(
@@ -630,7 +655,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get submit button value");
+ NSLOG(netsurf, INFO,
+ "Could not get submit button value");
goto dom_no_memory;
}
/* Drop through to report the successful button */
@@ -642,67 +668,75 @@ bool form_successful_controls_dom(struct form *_form,
if ((dom_node *)submit_button !=
(dom_node *)form_element)
continue;
-
+
err = dom_node_get_user_data(
form_element,
corestring_dom___ns_key_image_coords_node_data,
&coords);
if (err != DOM_NO_ERR) {
- LOG("Could not get image XY data");
+ NSLOG(netsurf, INFO,
+ "Could not get image XY data");
goto dom_no_memory;
}
if (coords == NULL) {
- LOG("No XY data on the image input");
+ NSLOG(netsurf, INFO,
+ "No XY data on the image input");
goto dom_no_memory;
}
-
+
basename = ENCODE_ITEM(inputname);
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
free(basename);
- LOG("Could not allocate data for image.x");
+ NSLOG(netsurf, INFO,
+ "Could not allocate data for image.x");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = malloc(strlen(basename) + 3);
if (success_new->name == NULL) {
free(basename);
- LOG("Could not allocate name for image.x");
+ NSLOG(netsurf, INFO,
+ "Could not allocate name for image.x");
goto dom_no_memory;
}
success_new->value = malloc(20);
if (success_new->value == NULL) {
free(basename);
- LOG("Could not allocate value for image.x");
+ NSLOG(netsurf, INFO,
+ "Could not allocate value for image.x");
goto dom_no_memory;
}
sprintf(success_new->name, "%s.x", basename);
sprintf(success_new->value, "%d", coords->x);
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
free(basename);
- LOG("Could not allocate data for image.y");
+ NSLOG(netsurf, INFO,
+ "Could not allocate data for image.y");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = malloc(strlen(basename) + 3);
if (success_new->name == NULL) {
free(basename);
- LOG("Could not allocate name for image.y");
+ NSLOG(netsurf, INFO,
+ "Could not allocate name for image.y");
goto dom_no_memory;
}
success_new->value = malloc(20);
if (success_new->value == NULL) {
free(basename);
- LOG("Could not allocate value for image.y");
+ NSLOG(netsurf, INFO,
+ "Could not allocate value for image.y");
goto dom_no_memory;
}
sprintf(success_new->name, "%s.y", basename);
@@ -717,7 +751,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&checked);
if (err != DOM_NO_ERR) {
- LOG("Could not get input element checked");
+ NSLOG(netsurf, INFO,
+ "Could not get input element checked");
goto dom_no_memory;
}
if (!checked)
@@ -726,7 +761,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get input element value");
+ NSLOG(netsurf, INFO,
+ "Could not get input element value");
goto dom_no_memory;
}
if (inputvalue == NULL) {
@@ -741,7 +777,8 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get file value");
+ NSLOG(netsurf, INFO,
+ "Could not get file value");
goto dom_no_memory;
}
err = dom_node_get_user_data(
@@ -749,14 +786,16 @@ bool form_successful_controls_dom(struct form *_form,
corestring_dom___ns_key_file_name_node_data,
&rawfile_temp);
if (err != DOM_NO_ERR) {
- LOG("Could not get file rawname");
+ NSLOG(netsurf, INFO,
+ "Could not get file rawname");
goto dom_no_memory;
}
rawfile_temp = strdup(rawfile_temp != NULL ?
rawfile_temp :
"");
if (rawfile_temp == NULL) {
- LOG("Could not copy file rawname");
+ NSLOG(netsurf, INFO,
+ "Could not copy file rawname");
goto dom_no_memory;
}
/* Fall out to the allocation */
@@ -765,7 +804,8 @@ bool form_successful_controls_dom(struct form *_form,
dom_string_caseless_isequal(
inputtype, corestring_dom_button)) {
/* Skip these */
- LOG("Skipping RESET and BUTTON");
+ NSLOG(netsurf, INFO,
+ "Skipping RESET and BUTTON");
continue;
} else {
/* Everything else is treated as text values */
@@ -773,30 +813,34 @@ bool form_successful_controls_dom(struct form *_form,
(dom_html_input_element *)form_element,
&inputvalue);
if (err != DOM_NO_ERR) {
- LOG("Could not get input value");
+ NSLOG(netsurf, INFO,
+ "Could not get input value");
goto dom_no_memory;
}
/* Fall out to the allocation */
}
}
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
- LOG("Could not allocate data for generic");
+ NSLOG(netsurf, INFO,
+ "Could not allocate data for generic");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = ENCODE_ITEM(inputname);
if (success_new->name == NULL) {
- LOG("Could not encode name for generic");
+ NSLOG(netsurf, INFO,
+ "Could not encode name for generic");
goto dom_no_memory;
}
success_new->value = ENCODE_ITEM(inputvalue);
if (success_new->value == NULL) {
- LOG("Could not encode value for generic");
+ NSLOG(netsurf, INFO,
+ "Could not encode value for generic");
goto dom_no_memory;
}
if (rawfile_temp != NULL) {
@@ -805,7 +849,7 @@ bool form_successful_controls_dom(struct form *_form,
rawfile_temp = NULL;
}
}
-
+
free(charset);
if (form_element != NULL) {
@@ -845,13 +889,13 @@ bool form_successful_controls_dom(struct form *_form,
}
*successful_controls = sentinel.next;
-
+
return true;
-
+
dom_no_memory:
free(charset);
fetch_multipart_data_destroy(sentinel.next);
-
+
if (form_elements != NULL)
dom_html_collection_unref(form_elements);
if (form_element != NULL)
@@ -870,7 +914,7 @@ dom_no_memory:
dom_string_unref(inputtype);
if (rawfile_temp != NULL)
free(rawfile_temp);
-
+
return false;
}
#undef ENCODE_ITEM
@@ -1047,7 +1091,7 @@ char *form_encode_item(const char *item, uint32_t len, const char *charset,
if (err == NSERROR_BAD_ENCODING) {
/* nope, try fallback charset (if any) */
if (fallback) {
- snprintf(cset, sizeof cset,
+ snprintf(cset, sizeof cset,
"%s//TRANSLIT", fallback);
err = utf8_to_enc(item, cset, 0, &ret);
@@ -1078,7 +1122,7 @@ char *form_encode_item(const char *item, uint32_t len, const char *charset,
return ret;
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback callback,
@@ -1089,6 +1133,7 @@ bool form_open_select_menu(void *client_data,
plot_font_style_t fstyle;
int total_height;
struct form_select_menu *menu;
+ html_content *html = (html_content *)c;
/* if the menu is opened for the first time */
@@ -1109,13 +1154,13 @@ bool form_open_select_menu(void *client_data,
box->border[LEFT].width +
box->padding[RIGHT] + box->padding[LEFT];
- font_plot_style_from_css(control->box->style,
+ font_plot_style_from_css(&html->len_ctx, control->box->style,
&fstyle);
menu->f_size = fstyle.size;
menu->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
FMUL(nscss_screen_dpi,
- INTTOFIX(fstyle.size / FONT_SIZE_SCALE)))),
+ INTTOFIX(fstyle.size / PLOT_STYLE_SCALE)))),
F_72));
line_height_with_spacing = menu->line_height +
@@ -1134,7 +1179,7 @@ bool form_open_select_menu(void *client_data,
menu->callback = callback;
if (scrollbar_create(false,
menu->height,
- total_height,
+ total_height,
menu->height,
control,
form_select_menu_scroll_callback,
@@ -1152,7 +1197,7 @@ bool form_open_select_menu(void *client_data,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
void form_free_select_menu(struct form_control *control)
{
if (control->data.select.menu->scrollbar != NULL)
@@ -1162,12 +1207,11 @@ void form_free_select_menu(struct form_control *control)
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_redraw_select_menu(struct form_control *control, int x, int y,
float scale, const struct rect *clip,
const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
struct box *box;
struct form_select_menu *menu = control->data.select.menu;
struct form_option *option;
@@ -1181,26 +1225,28 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
int scroll;
int x_cp, y_cp;
struct rect r;
-
+ struct rect rect;
+ nserror res;
+
box = control->box;
-
+
x_cp = x;
y_cp = y;
width = menu->width;
height = menu->height;
line_height = menu->line_height;
-
+
line_height_with_spacing = line_height +
line_height * SELECT_LINE_SPACING;
scroll = scrollbar_get_offset(menu->scrollbar);
-
+
if (scale != 1.0) {
x *= scale;
y *= scale;
width *= scale;
height *= scale;
scrollbar_width *= scale;
-
+
i = scroll / line_height_with_spacing;
scroll -= i * line_height_with_spacing;
line_height *= scale;
@@ -1208,8 +1254,8 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
scroll *= scale;
scroll += i * line_height_with_spacing;
}
-
-
+
+
x0 = x;
y0 = y;
x1 = x + width - 1;
@@ -1220,12 +1266,20 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
r.y0 = y0;
r.x1 = x1 + 1;
r.y1 = y1 + 1;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
- if (!plot->rectangle(x0, y0, x1, y1 ,plot_style_stroke_darkwbasec))
+ }
+
+ rect.x0 = x0;
+ rect.y0 = y0;
+ rect.x1 = x1;
+ rect.y1 = y1;
+ res = ctx->plot->rectangle(ctx, plot_style_stroke_darkwbasec, &rect);
+ if (res != NSERROR_OK) {
return false;
-
-
+ }
+
x0 = x0 + SELECT_BORDER_WIDTH;
y0 = y0 + SELECT_BORDER_WIDTH;
x1 = x1 - SELECT_BORDER_WIDTH;
@@ -1236,14 +1290,19 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
r.y0 = y0;
r.x1 = x1 + 1;
r.y1 = y1 + 1;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
- if (!plot->rectangle(x0, y0, x1 + 1, y1 + 1,
- plot_style_fill_lightwbasec))
+ }
+
+ res = ctx->plot->rectangle(ctx, plot_style_fill_lightwbasec, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
+
option = control->data.select.items;
item_y = line_height_with_spacing;
-
+
while (item_y < scroll) {
option = option->next;
item_y += line_height_with_spacing;
@@ -1252,36 +1311,46 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
text_pos_offset = y - scroll +
(int) (line_height * (0.75 + SELECT_LINE_SPACING));
text_x = x + (box->border[LEFT].width + box->padding[LEFT]) * scale;
-
+
plot_fstyle_entry.size = menu->f_size;
-
+
while (option && item_y - scroll < height) {
-
- if (option->selected) {
- y2 = y + item_y - scroll;
- y3 = y + item_y + line_height_with_spacing - scroll;
- if (!plot->rectangle(x0, (y0 > y2 ? y0 : y2),
- scrollbar_x + 1,
- (y3 < y1 + 1 ? y3 : y1 + 1),
- &plot_style_fill_selected))
+
+ if (option->selected) {
+ y2 = y + item_y - scroll;
+ y3 = y + item_y + line_height_with_spacing - scroll;
+
+ rect.x0 = x0;
+ rect.y0 = y0 > y2 ? y0 : y2;
+ rect.x1 = scrollbar_x + 1;
+ rect.y1 = y3 < y1 + 1 ? y3 : y1 + 1;
+ res = ctx->plot->rectangle(ctx, &plot_style_fill_selected, &rect);
+ if (res != NSERROR_OK) {
return false;
- }
-
+ }
+ }
+
y2 = text_pos_offset + item_y;
- if (!plot->text(text_x, y2, option->text,
- strlen(option->text), &plot_fstyle_entry))
+ res = ctx->plot->text(ctx,
+ &plot_fstyle_entry,
+ text_x, y2,
+ option->text, strlen(option->text));
+ if (res != NSERROR_OK) {
return false;
-
+ }
+
item_y += line_height_with_spacing;
option = option->next;
}
-
- if (!scrollbar_redraw(menu->scrollbar,
- x_cp + menu->width - SCROLLBAR_WIDTH,
- y_cp,
- clip, scale, ctx))
+
+ res = scrollbar_redraw(menu->scrollbar,
+ x_cp + menu->width - SCROLLBAR_WIDTH,
+ y_cp,
+ clip, scale, ctx);
+ if (res != NSERROR_OK) {
return false;
-
+ }
+
return true;
}
@@ -1299,16 +1368,16 @@ bool form_clip_inside_select_menu(struct form_control *control, float scale,
{
struct form_select_menu *menu = control->data.select.menu;
int width, height;
-
+
width = menu->width;
height = menu->height;
-
+
if (scale != 1.0) {
width *= scale;
height *= scale;
}
-
+
if (clip->x0 >= 0 && clip->x1 <= width &&
clip->y0 >= 0 && clip->y1 <= height)
return true;
@@ -1440,26 +1509,26 @@ nserror form_control_bounding_rect(struct form_control *control, struct rect *r)
/**
* Handle a click on the area of the currently opened select menu.
- *
+ *
* \param control the select menu which received the click
* \param x X coordinate of click
* \param y Y coordinate of click
*/
void form_select_menu_clicked(struct form_control *control, int x, int y)
-{
+{
struct form_select_menu *menu = control->data.select.menu;
struct form_option *option;
html_content *html = (html_content *)menu->c;
- int line_height, line_height_with_spacing;
+ int line_height, line_height_with_spacing;
int item_bottom_y;
int scroll, i;
-
+
scroll = scrollbar_get_offset(menu->scrollbar);
-
+
line_height = menu->line_height;
line_height_with_spacing = line_height +
line_height * SELECT_LINE_SPACING;
-
+
option = control->data.select.items;
item_bottom_y = line_height_with_spacing;
i = 0;
@@ -1468,11 +1537,11 @@ void form_select_menu_clicked(struct form_control *control, int x, int y)
option = option->next;
i++;
}
-
+
if (option != NULL) {
form__select_process_selection(html, control, i);
}
-
+
menu->callback(menu->client_data, 0, 0, menu->width, menu->height);
}
@@ -1484,7 +1553,7 @@ void form_select_menu_clicked(struct form_control *control, int x, int y)
* \param x X coordinate of click
* \param y Y coordinate of click
* \return text for the browser status bar or NULL if the menu has
- * to be closed
+ * to be closed
*/
const char *form_select_mouse_action(struct form_control *control,
browser_mouse_state mouse, int x, int y)
@@ -1493,13 +1562,13 @@ const char *form_select_mouse_action(struct form_control *control,
int x0, y0, x1, y1, scrollbar_x;
const char *status = NULL;
bool multiple = control->data.select.multiple;
-
+
x0 = 0;
y0 = 0;
x1 = menu->width;
y1 = menu->height;
scrollbar_x = x1 - SCROLLBAR_WIDTH;
-
+
if (menu->scroll_capture ||
(x > scrollbar_x && x < x1 && y > y0 && y < y1)) {
/* The scroll is currently capturing all events or the mouse
@@ -1510,25 +1579,25 @@ const char *form_select_mouse_action(struct form_control *control,
scrollbar_mouse_action(menu->scrollbar,
mouse, x, y));
}
-
-
+
+
if (x > x0 && x < scrollbar_x && y > y0 && y < y1) {
/* over option area */
-
+
if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2))
/* button 1 or 2 click */
form_select_menu_clicked(control, x, y);
-
+
if (!(mouse & BROWSER_MOUSE_CLICK_1 && !multiple))
/* anything but a button 1 click over a single select
menu */
status = messages_get(control->data.select.multiple ?
"SelectMClick" : "SelectClick");
-
+
} else if (!(mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)))
/* if not a button 1 or 2 click*/
status = messages_get("SelectClose");
-
+
return status;
}
@@ -1565,13 +1634,13 @@ void form_select_mouse_drag_end(struct form_control *control,
scrollbar_mouse_drag_end(menu->scrollbar, mouse, x, y);
return;
}
-
+
x0 = 0;
y0 = 0;
x1 = menu->width;
y1 = menu->height;
-
-
+
+
if (x > x0 && x < x1 - SCROLLBAR_WIDTH && y > y0 && y < y1)
/* handle drag end above the option area like a regular click */
form_select_menu_clicked(control, x, y);
@@ -1586,13 +1655,13 @@ void form_select_menu_scroll_callback(void *client_data,
struct form_control *control = client_data;
struct form_select_menu *menu = control->data.select.menu;
html_content *html = (html_content *)menu->c;
-
+
switch (scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
menu->callback(menu->client_data,
- 0, 0,
+ 0, 0,
menu->width,
- menu->height);
+ menu->height);
break;
case SCROLLBAR_MSG_SCROLL_START:
{
@@ -1643,10 +1712,10 @@ void form_select_menu_callback(void *client_data,
html_content *html = client_data;
int menu_x, menu_y;
struct box *box;
-
+
box = html->visible_select_menu->box;
box_coords(box, &menu_x, &menu_y);
-
+
menu_x -= box->border[LEFT].width;
menu_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] +
@@ -1733,7 +1802,7 @@ void form_submit(nsurl *page_url, struct browser_window *target,
}
/* Replace query segment */
- error = nsurl_replace_query(action_url, data, &action_query);
+ error = nsurl_replace_query(action_url, data, &action_query);
if (error != NSERROR_OK) {
nsurl_unref(action_query);
free(data);
@@ -1773,12 +1842,12 @@ void form_submit(nsurl *page_url, struct browser_window *target,
break;
case method_POST_MULTIPART:
- browser_window_navigate(target,
- action_url,
+ browser_window_navigate(target,
+ action_url,
page_url,
BW_NAVIGATE_HISTORY,
- NULL,
- success,
+ NULL,
+ success,
NULL);
break;
diff --git a/render/form_internal.h b/content/handlers/html/form_internal.h
index 0ffb6b46c..a77e823b3 100644
--- a/render/form_internal.h
+++ b/content/handlers/html/form_internal.h
@@ -18,11 +18,11 @@
/**
* \file
- * Interface to form handling functions internal to render.
+ * Interface to form handling functions internal to HTML content handler.
*/
-#ifndef _NETSURF_RENDER_FORM_INTERNAL_H_
-#define _NETSURF_RENDER_FORM_INTERNAL_H_
+#ifndef NETSURF_HTML_FORM_INTERNAL_H
+#define NETSURF_HTML_FORM_INTERNAL_H
#include <stdbool.h>
@@ -229,7 +229,7 @@ bool form_successful_controls_dom(struct form *form,
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback redraw_callback,
- struct content *c);
+ struct content *c);
void form_select_menu_callback(void *client_data,
diff --git a/render/html.c b/content/handlers/html/html.c
index 6f7ad6249..f721b98ab 100644
--- a/render/html.c
+++ b/content/handlers/html/html.c
@@ -19,7 +19,7 @@
/**
* \file
- * Content for text/html (implementation).
+ * Implementation of HTML content handling.
*/
#include <assert.h>
@@ -54,12 +54,14 @@
#include "javascript/js.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/layout.h"
-#include "render/search.h"
+#include "html/html.h"
+#include "html/html_save.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/form_internal.h"
+#include "html/imagemap.h"
+#include "html/layout.h"
+#include "html/search.h"
#define CHUNK 4096
@@ -89,8 +91,8 @@ bool fire_dom_event(dom_string *type, dom_node *target,
dom_event_unref(evt);
return false;
}
- LOG("Dispatching '%*s' against %p",
- dom_string_length(type), dom_string_data(type), target);
+ NSLOG(netsurf, INFO, "Dispatching '%*s' against %p",
+ dom_string_length(type), dom_string_data(type), target);
exc = dom_event_target_dispatch_event(target, evt, &result);
if (exc != DOM_NO_ERR) {
result = false;
@@ -111,7 +113,7 @@ static void html_box_convert_done(html_content *c, bool success)
dom_exception exc; /* returned by libdom functions */
dom_node *html;
- LOG("Done XML to box (%p)", c);
+ NSLOG(netsurf, INFO, "Done XML to box (%p)", c);
/* Clean up and report error if unsuccessful or aborted */
if ((success == false) || (c->aborted)) {
@@ -139,9 +141,9 @@ static void html_box_convert_done(html_content *c, bool success)
exc = dom_document_get_document_element(c->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
/** @todo should this call html_object_free_objects(c);
- * like the other error paths
+ * like the other error paths
*/
- LOG("error retrieving html element from dom");
+ NSLOG(netsurf, INFO, "error retrieving html element from dom");
content_broadcast_errorcode(&c->base, NSERROR_DOM);
content_set_error(&c->base);
return;
@@ -150,7 +152,7 @@ static void html_box_convert_done(html_content *c, bool success)
/* extract image maps - can't do this sensibly in dom_to_box */
err = imagemap_extract(c);
if (err != NSERROR_OK) {
- LOG("imagemap extraction failed");
+ NSLOG(netsurf, INFO, "imagemap extraction failed");
html_object_free_objects(c);
content_broadcast_errorcode(&c->base, err);
content_set_error(&c->base);
@@ -443,7 +445,7 @@ static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
c->base.refresh = nsurl_ref(
content_get_url(&c->base));
- content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+ content_broadcast(&c->base, CONTENT_MSG_REFRESH, &msg_data);
return NSERROR_OK;
}
@@ -522,7 +524,8 @@ static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
c->base.refresh = nsurl;
- content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
+ content_broadcast(&c->base, CONTENT_MSG_REFRESH,
+ &msg_data);
c->refresh = true;
}
@@ -567,7 +570,7 @@ static bool html_process_img(html_content *c, dom_node *node)
return success;
}
-/* exported function documented in render/html_internal.h */
+/* exported function documented in html/html_internal.h */
void html_finish_conversion(html_content *htmlc)
{
union content_msg_data msg_data;
@@ -600,14 +603,14 @@ void html_finish_conversion(html_content *htmlc)
}
/* convert dom tree to box tree */
- LOG("DOM to box (%p)", htmlc);
+ NSLOG(netsurf, INFO, "DOM to box (%p)", htmlc);
content_set_status(&htmlc->base, messages_get("Processing"));
msg_data.explicit_status_text = NULL;
- content_broadcast(&htmlc->base, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(&htmlc->base, CONTENT_MSG_STATUS, &msg_data);
exc = dom_document_get_document_element(htmlc->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
- LOG("error retrieving html element from dom");
+ NSLOG(netsurf, INFO, "error retrieving html element from dom");
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
content_set_error(&htmlc->base);
return;
@@ -615,7 +618,7 @@ void html_finish_conversion(html_content *htmlc)
error = dom_to_box(html, htmlc, html_box_convert_done);
if (error != NSERROR_OK) {
- LOG("box conversion failed");
+ NSLOG(netsurf, INFO, "box conversion failed");
dom_node_unref(html);
html_object_free_objects(htmlc);
content_broadcast_errorcode(&htmlc->base, error);
@@ -685,9 +688,11 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw)
msg_data.jscontext = &htmlc->jscontext;
content_broadcast(&htmlc->base,
CONTENT_MSG_GETCTX,
- msg_data);
- LOG("javascript context: %p",
- htmlc->jscontext);
+ &msg_data);
+ NSLOG(netsurf, INFO,
+ "javascript context: %p (htmlc: %p)",
+ htmlc->jscontext,
+ htmlc);
}
if (htmlc->jscontext != NULL) {
js_handle_new_element(htmlc->jscontext,
@@ -705,7 +710,6 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
{
dom_event_target *node;
dom_node_type type;
- dom_string *name;
dom_exception exc;
html_content *htmlc = pw;
@@ -721,16 +725,19 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
exc = dom_node_get_node_type(node, &type);
if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
/* an element node has been modified */
- exc = dom_node_get_node_name(node, &name);
- if ((exc == DOM_NO_ERR) && (name != NULL)) {
+ dom_html_element_type tag_type;
- if (dom_string_caseless_isequal(name,
- corestring_dom_style)) {
- html_css_update_style(htmlc,
- (dom_node *)node);
- }
+ exc = dom_html_element_get_tag_type(node, &tag_type);
+ if (exc != DOM_NO_ERR) {
+ tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
+ }
- dom_string_unref(name);
+ switch (tag_type) {
+ case DOM_HTML_ELEMENT_TYPE_STYLE:
+ html_css_update_style(htmlc, (dom_node *)node);
+ break;
+ default:
+ break;
}
}
dom_node_unref(node);
@@ -764,7 +771,7 @@ dom_event_fetcher(dom_string *type,
dom_default_action_phase phase,
void **pw)
{
- //LOG("type:%s", dom_string_data(type));
+ NSLOG(netsurf, DEEPDEBUG, "type:%s", dom_string_data(type));
if (phase == DOM_DEFAULT_ACTION_END) {
if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) {
@@ -791,22 +798,22 @@ html_document_user_data_handler(dom_node_operation operation,
switch (operation) {
case DOM_NODE_CLONED:
- LOG("Cloned");
+ NSLOG(netsurf, INFO, "Cloned");
break;
case DOM_NODE_RENAMED:
- LOG("Renamed");
+ NSLOG(netsurf, INFO, "Renamed");
break;
case DOM_NODE_IMPORTED:
- LOG("imported");
+ NSLOG(netsurf, INFO, "imported");
break;
case DOM_NODE_ADOPTED:
- LOG("Adopted");
+ NSLOG(netsurf, INFO, "Adopted");
break;
case DOM_NODE_DELETED:
/* This is the only path I expect */
break;
default:
- LOG("User data operation not handled.");
+ NSLOG(netsurf, INFO, "User data operation not handled.");
assert(0);
}
}
@@ -931,7 +938,7 @@ html_create_html_data(html_content *c, const http_parameter *params)
lwc_string_unref(c->universal);
c->universal = NULL;
- LOG("Unable to set user data.");
+ NSLOG(netsurf, INFO, "Unable to set user data.");
return NSERROR_DOM;
}
@@ -993,8 +1000,8 @@ html_create(const content_handler *handler,
static nserror
-html_process_encoding_change(struct content *c,
- const char *data,
+html_process_encoding_change(struct content *c,
+ const char *data,
unsigned int size)
{
html_content *html = (html_content *) c;
@@ -1005,7 +1012,7 @@ html_process_encoding_change(struct content *c,
unsigned long source_size;
/* Retrieve new encoding */
- encoding = dom_hubbub_parser_get_encoding(html->parser,
+ encoding = dom_hubbub_parser_get_encoding(html->parser,
&html->encoding_source);
if (encoding == NULL) {
return NSERROR_NOMEM;
@@ -1065,10 +1072,10 @@ html_process_encoding_change(struct content *c,
/* Reprocess all the data. This is safe because
* the encoding is now specified at parser start which means
- * it cannot be changed again.
+ * it cannot be changed again.
*/
- error = dom_hubbub_parser_parse_chunk(html->parser,
- (const uint8_t *)source_data,
+ error = dom_hubbub_parser_parse_chunk(html->parser,
+ (const uint8_t *)source_data,
source_size);
return libdom_hubbub_error_to_nserror(error);
@@ -1086,8 +1093,8 @@ html_process_data(struct content *c, const char *data, unsigned int size)
dom_hubbub_error dom_ret;
nserror err = NSERROR_OK; /* assume its all going to be ok */
- dom_ret = dom_hubbub_parser_parse_chunk(html->parser,
- (const uint8_t *) data,
+ dom_ret = dom_hubbub_parser_parse_chunk(html->parser,
+ (const uint8_t *) data,
size);
err = libdom_hubbub_error_to_nserror(dom_ret);
@@ -1103,7 +1110,7 @@ html_process_data(struct content *c, const char *data, unsigned int size)
return false;
}
- return true;
+ return true;
}
@@ -1138,11 +1145,11 @@ static bool html_convert(struct content *c)
exc = dom_document_get_quirks_mode(htmlc->document, &htmlc->quirks);
if (exc == DOM_NO_ERR) {
html_css_quirks_stylesheets(htmlc);
- LOG("quirks set to %d", htmlc->quirks);
+ NSLOG(netsurf, INFO, "quirks set to %d", htmlc->quirks);
}
htmlc->base.active--; /* the html fetch is no longer active */
- LOG("%d fetches active", htmlc->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active (%p)", htmlc->base.active, c);
/* The parse cannot be completed here because it may be paused
* untill all the resources being fetched have completed.
@@ -1183,25 +1190,25 @@ html_begin_conversion(html_content *htmlc)
dom_string *node_name = NULL;
dom_hubbub_error error;
- /* The act of completing the parse can result in additional data
- * being flushed through the parser. This may result in new style or
- * script nodes, upon which the conversion depends. Thus, once we
- * have completed the parse, we must check again to see if we can
- * begin the conversion. If we can't, we must stop and wait for the
+ /* The act of completing the parse can result in additional data
+ * being flushed through the parser. This may result in new style or
+ * script nodes, upon which the conversion depends. Thus, once we
+ * have completed the parse, we must check again to see if we can
+ * begin the conversion. If we can't, we must stop and wait for the
* new styles/scripts to be processed. Once they have been processed,
- * we will be called again to begin the conversion for real. Thus,
- * we must also ensure that we don't attempt to complete the parse
+ * we will be called again to begin the conversion for real. Thus,
+ * we must also ensure that we don't attempt to complete the parse
* multiple times, so store a flag to indicate that parsing is
* complete to avoid repeating the completion pointlessly.
*/
if (htmlc->parse_completed == false) {
- LOG("Completing parse");
+ NSLOG(netsurf, INFO, "Completing parse (%p)", htmlc);
/* complete parsing */
error = dom_hubbub_parser_completed(htmlc->parser);
if (error != DOM_HUBBUB_OK) {
- LOG("Parsing failed");
-
- content_broadcast_errorcode(&htmlc->base,
+ NSLOG(netsurf, INFO, "Parsing failed");
+
+ content_broadcast_errorcode(&htmlc->base,
libdom_hubbub_error_to_nserror(error));
return false;
@@ -1210,12 +1217,16 @@ html_begin_conversion(html_content *htmlc)
}
if (html_can_begin_conversion(htmlc) == false) {
+ NSLOG(netsurf, INFO, "Can't begin conversion (%p)", htmlc);
/* We can't proceed (see commentary above) */
return true;
}
/* Give up processing if we've been aborted */
if (htmlc->aborted) {
+ NSLOG(netsurf, INFO, "Conversion aborted (%p) (active: %u)",
+ htmlc, htmlc->base.active);
+ content_set_error(&htmlc->base);
content_broadcast_errorcode(&htmlc->base, NSERROR_STOPPED);
return false;
}
@@ -1234,14 +1245,14 @@ html_begin_conversion(html_content *htmlc)
encoding = dom_hubbub_parser_get_encoding(htmlc->parser,
&htmlc->encoding_source);
if (encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
htmlc->encoding = strdup(encoding);
if (htmlc->encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
@@ -1250,7 +1261,7 @@ html_begin_conversion(html_content *htmlc)
/* locate root element and ensure it is html */
exc = dom_document_get_document_element(htmlc->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
- LOG("error retrieving html element from dom");
+ NSLOG(netsurf, INFO, "error retrieving html element from dom");
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
return false;
}
@@ -1259,8 +1270,8 @@ html_begin_conversion(html_content *htmlc)
if ((exc != DOM_NO_ERR) ||
(node_name == NULL) ||
(!dom_string_caseless_lwc_isequal(node_name,
- corestring_lwc_html))) {
- LOG("root element not html");
+ corestring_lwc_html))) {
+ NSLOG(netsurf, INFO, "root element not html");
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
dom_node_unref(html);
return false;
@@ -1278,11 +1289,11 @@ html_begin_conversion(html_content *htmlc)
/* HTML5 4.10.22.3 step 9 */
nsurl *doc_addr = content_get_url(&htmlc->base);
ns_error = nsurl_join(htmlc->base_url,
- nsurl_access(doc_addr),
+ nsurl_access(doc_addr),
&action);
} else {
- ns_error = nsurl_join(htmlc->base_url,
- f->action,
+ ns_error = nsurl_join(htmlc->base_url,
+ f->action,
&action);
}
@@ -1297,7 +1308,7 @@ html_begin_conversion(html_content *htmlc)
f->action = strdup(nsurl_access(action));
nsurl_unref(action);
if (f->action == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
dom_node_unref(html);
@@ -1308,7 +1319,7 @@ html_begin_conversion(html_content *htmlc)
if (f->document_charset == NULL) {
f->document_charset = strdup(htmlc->encoding);
if (f->document_charset == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
dom_node_unref(html);
return false;
@@ -1354,7 +1365,7 @@ static void html_stop(struct content *c)
html_object_abort_objects(htmlc);
/* If there are no further active fetches and we're still
- * in the READY state, transition to the DONE state. */
+ * in the READY state, transition to the DONE state. */
if (c->status == CONTENT_STATUS_READY && c->active == 0) {
content_set_done(c);
}
@@ -1366,7 +1377,8 @@ static void html_stop(struct content *c)
break;
default:
- LOG("Unexpected status %d", c->status);
+ NSLOG(netsurf, INFO, "Unexpected status %d (%p)", c->status,
+ c);
assert(0);
}
}
@@ -1388,6 +1400,10 @@ static void html_reformat(struct content *c, int width, int height)
htmlc->reflowing = true;
+ htmlc->len_ctx.vw = width;
+ htmlc->len_ctx.vh = height;
+ htmlc->len_ctx.root_style = htmlc->layout->style;
+
layout_document(htmlc, width, height);
layout = htmlc->layout;
@@ -1479,8 +1495,8 @@ static void html_destroy_frameset(struct content_html_frames *frameset)
nsurl_unref(frameset->children[i].url);
frameset->children[i].url = NULL;
}
- if (frameset->children[i].children)
- html_destroy_frameset(&frameset->children[i]);
+ if (frameset->children[i].children)
+ html_destroy_frameset(&frameset->children[i]);
}
talloc_free(frameset->children);
frameset->children = NULL;
@@ -1508,7 +1524,7 @@ static void html_free_layout(html_content *htmlc)
{
if (htmlc->bctx != NULL) {
/* freeing talloc context should let the entire box
- * set be destroyed
+ * set be destroyed
*/
talloc_free(htmlc->bctx);
}
@@ -1523,7 +1539,7 @@ static void html_destroy(struct content *c)
html_content *html = (html_content *) c;
struct form *f, *g;
- LOG("content %p", c);
+ NSLOG(netsurf, INFO, "content %p", c);
/* Destroy forms */
for (f = html->forms; f != NULL; f = g) {
@@ -1563,8 +1579,8 @@ static void html_destroy(struct content *c)
/* Free base target */
if (html->base_target != NULL) {
- free(html->base_target);
- html->base_target = NULL;
+ free(html->base_target);
+ html->base_target = NULL;
}
/* Free frameset */
@@ -1637,7 +1653,7 @@ html_open(struct content *c,
html->drag_owner.no_owner = true;
/* text selection */
- selection_init(&html->sel, html->layout);
+ selection_init(&html->sel, html->layout, &html->len_ctx);
html->selection_type = HTML_SELECTION_NONE;
html->selection_owner.none = true;
@@ -1758,7 +1774,8 @@ html_get_contextual_content(struct content *c, int x, int y,
struct box *next;
int box_x = 0, box_y = 0;
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
/* hidden boxes are ignored */
@@ -1835,7 +1852,8 @@ html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry)
/* TODO: invert order; visit deepest box first */
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
@@ -1912,7 +1930,7 @@ static void html__dom_user_data_handler(dom_node_operation operation,
free(data);
break;
default:
- LOG("User data operation not handled.");
+ NSLOG(netsurf, INFO, "User data operation not handled.");
assert(0);
}
}
@@ -1928,11 +1946,12 @@ static void html__set_file_gadget_filename(struct content *c,
ret = guit->utf8->local_to_utf8(fn, 0, &utf8_fn);
if (ret != NSERROR_OK) {
assert(ret != NSERROR_BAD_ENCODING);
- LOG("utf8 to local encoding conversion failed");
+ NSLOG(netsurf, INFO,
+ "utf8 to local encoding conversion failed");
/* Load was for us - just no memory */
- return;
+ return;
}
-
+
form_gadget_update_value(gadget, utf8_fn);
/* corestring_dom___ns_key_file_name_node_data */
@@ -1945,7 +1964,7 @@ static void html__set_file_gadget_filename(struct content *c,
}
/* Redraw box. */
- html__redraw_a_box(html, file_box);
+ html__redraw_a_box(html, file_box);
}
void html_set_file_gadget_filename(struct hlcache_handle *hl,
@@ -1976,7 +1995,8 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
int box_x = 0, box_y = 0;
/* Scan box tree for boxes that can handle drop */
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
@@ -2080,7 +2100,7 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
if (ret != NSERROR_OK) {
/* bad encoding shouldn't happen */
assert(ret != NSERROR_BAD_ENCODING);
- LOG("local to utf8 encoding failed");
+ NSLOG(netsurf, INFO, "local to utf8 encoding failed");
free(buffer);
guit->misc->warning("NoMemory", NULL);
return true;
@@ -2146,19 +2166,19 @@ html_debug_dump(struct content *c, FILE *f, enum content_debug op)
ret = NSERROR_OK;
} else {
if (htmlc->document == NULL) {
- LOG("No document to dump");
+ NSLOG(netsurf, INFO, "No document to dump");
return NSERROR_DOM;
}
exc = dom_document_get_document_element(htmlc->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
- LOG("Unable to obtain root node");
+ NSLOG(netsurf, INFO, "Unable to obtain root node");
return NSERROR_DOM;
}
ret = libdom_dump_structure(html, f, 0);
- LOG("DOM structure dump returning %d", ret);
+ NSLOG(netsurf, INFO, "DOM structure dump returning %d", ret);
dom_node_unref(html);
}
@@ -2242,7 +2262,8 @@ dom_document *html_get_document(hlcache_handle *h)
* \param h HTML content to retrieve tree from
* \return Pointer to box tree
*
- * \todo This API must die, as must all use of the box tree outside render/
+ * \todo This API must die, as must all use of the box tree outside of
+ * HTML content handler
*/
struct box *html_get_box_tree(hlcache_handle *h)
{
diff --git a/render/html.h b/content/handlers/html/html.h
index b8429fd17..8d1c77992 100644
--- a/render/html.h
+++ b/content/handlers/html/html.h
@@ -16,20 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for text/html (interface).
+/**
+ * \file
+ * Interface to text/html content handler.
*
* These functions should in general be called via the content interface.
*/
-#ifndef _NETSURF_RENDER_HTML_H_
-#define _NETSURF_RENDER_HTML_H_
+#ifndef NETSURF_HTML_HTML_H
+#define NETSURF_HTML_HTML_H
#include <stdbool.h>
-#include <dom/dom.h>
-#include <dom/bindings/hubbub/parser.h>
-
#include "netsurf/types.h"
#include "netsurf/content_type.h"
#include "netsurf/browser_window.h"
@@ -64,6 +62,7 @@ struct html_stylesheet {
bool unused;
};
+
/**
* Container for scripts used by an HTML document
*/
@@ -88,7 +87,9 @@ struct html_script {
};
-/** An object (<img>, <object>, etc.) in a CONTENT_HTML document. */
+/**
+ * An object (img, object, etc. tag) in a CONTENT_HTML document.
+ */
struct content_html_object {
struct content *parent; /**< Parent document */
struct content_html_object *next; /**< Next in chain */
@@ -100,12 +101,10 @@ struct content_html_object {
bool background; /**< This object is a background image. */
};
-struct html_scrollbar_data {
- struct content *c;
- struct box *box;
-};
-/** Frame tree (<frameset>, <frame>) */
+/**
+ * Frame tree (frameset or frame tag)
+ */
struct content_html_frames {
int cols; /** number of columns in frameset */
int rows; /** number of rows in frameset */
@@ -126,9 +125,11 @@ struct content_html_frames {
struct content_html_frames *children; /** [cols * rows] children */
};
-/** Inline frame list (<iframe>) */
+/**
+ * Inline frame list (iframe tag)
+ */
struct content_html_iframe {
- struct box *box;
+ struct box *box;
int margin_width; /** frame margin width */
int margin_height; /** frame margin height */
@@ -140,7 +141,7 @@ struct content_html_iframe {
bool border; /** frame has a border */
colour border_colour; /** frame border colour */
- struct content_html_iframe *next;
+ struct content_html_iframe *next;
};
/* entries in stylesheet_content */
@@ -150,32 +151,46 @@ struct content_html_iframe {
#define STYLESHEET_USER 3 /* user stylesheet */
#define STYLESHEET_START 4 /* start of document stylesheets */
+/**
+ * initialise content handler
+ *
+ * \return NSERROR_OK on success otherwise appropriate error code
+ */
nserror html_init(void);
+/**
+ * redraw a specific box
+ *
+ * used by core browser
+ */
void html_redraw_a_box(struct hlcache_handle *h, struct box *box);
-void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
- browser_mouse_state mouse, int x, int y);
-
-bool text_redraw(const char *utf8_text, size_t utf8_len,
- size_t offset, int space,
- const struct plot_font_style *fstyle,
- int x, int y,
- const struct rect *clip,
- int height,
- float scale,
- bool excluded,
- struct content *c,
- const struct selection *sel,
- struct search_context *search,
- const struct redraw_context *ctx);
-
-dom_document *html_get_document(struct hlcache_handle *h);
-struct box *html_get_box_tree(struct hlcache_handle *h);
+/**
+ * obtain html frame content from handle
+ *
+ * used by core browser
+ */
struct content_html_frames *html_get_frameset(struct hlcache_handle *h);
+
+/**
+ * obtain html iframe content from handle
+ *
+ * used by core browser
+ */
struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
-struct nsurl *html_get_base_url(struct hlcache_handle *h);
+
+/**
+ * obtain html base target from handle
+ *
+ * used by core browser
+ */
const char *html_get_base_target(struct hlcache_handle *h);
+
+/**
+ * set filename on a file gadget
+ *
+ * used by core browser
+ */
void html_set_file_gadget_filename(struct hlcache_handle *hl,
struct form_control *gadget, const char *fn);
@@ -189,8 +204,19 @@ void html_set_file_gadget_filename(struct hlcache_handle *hl,
struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
unsigned int *n);
+/**
+ * Retrieve objects used by HTML document
+ *
+ * \param h Content to retrieve objects from
+ * \param n Pointer to location to receive number of objects
+ * \return Pointer to array of objects
+ */
struct content_html_object *html_get_objects(struct hlcache_handle *h,
unsigned int *n);
+
+/**
+ * get the offset within the docuemnt of a fragment id
+ */
bool html_get_id_offset(struct hlcache_handle *h, lwc_string *frag_id,
int *x, int *y);
diff --git a/render/html_css.c b/content/handlers/html/html_css.c
index 4d5469361..7b2d469c4 100644
--- a/render/html_css.c
+++ b/content/handlers/html/html_css.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Processing for html content css operations.
*/
@@ -37,7 +38,8 @@
#include "css/css.h"
#include "desktop/gui_internal.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
static nsurl *html_default_stylesheet_url;
static nsurl *html_adblock_stylesheet_url;
@@ -103,17 +105,23 @@ html_convert_css_callback(hlcache_handle *css,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("done stylesheet slot %d '%s'", i, nsurl_access(hlcache_handle_get_url(css)));
+ NSLOG(netsurf, INFO, "done stylesheet slot %d '%s'", i,
+ nsurl_access(hlcache_handle_get_url(css)));
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
break;
case CONTENT_MSG_ERROR:
- LOG("stylesheet %s failed: %s", nsurl_access(hlcache_handle_get_url(css)), event->data.error);
+ NSLOG(netsurf, INFO, "stylesheet %s failed: %s",
+ nsurl_access(hlcache_handle_get_url(css)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(css);
s->sheet = NULL;
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
content_add_error(&parent->base, "?", 0);
break;
@@ -150,7 +158,7 @@ html_stylesheet_from_domnode(html_content *c,
exc = dom_node_get_text_content(node, &style);
if ((exc != DOM_NO_ERR) || (style == NULL)) {
- LOG("No text content");
+ NSLOG(netsurf, INFO, "No text content");
return NSERROR_OK;
}
@@ -181,7 +189,7 @@ html_stylesheet_from_domnode(html_content *c,
nsurl_unref(url);
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
return NSERROR_OK;
}
@@ -253,13 +261,14 @@ static bool html_css_process_modified_style(html_content *c,
error = html_stylesheet_from_domnode(c, s->node, &sheet);
if (error != NSERROR_OK) {
- LOG("Failed to update sheet");
+ NSLOG(netsurf, INFO, "Failed to update sheet");
content_broadcast_errorcode(&c->base, error);
return false;
}
if (sheet != NULL) {
- LOG("Updating sheet %p with %p", s->sheet, sheet);
+ NSLOG(netsurf, INFO, "Updating sheet %p with %p", s->sheet,
+ sheet);
if (s->sheet != NULL) {
switch (content_get_status(s->sheet)) {
@@ -268,7 +277,8 @@ static bool html_css_process_modified_style(html_content *c,
default:
hlcache_handle_abort(s->sheet);
c->base.active--;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active",
+ c->base.active);
}
hlcache_handle_release(s->sheet);
}
@@ -313,7 +323,9 @@ bool html_css_update_style(html_content *c, dom_node *style)
s = html_create_style_element(c, style);
}
if (s == NULL) {
- LOG("Could not find or create inline stylesheet for %p", style);
+ NSLOG(netsurf, INFO,
+ "Could not find or create inline stylesheet for %p",
+ style);
return false;
}
@@ -417,7 +429,8 @@ bool html_css_process_link(html_content *htmlc, dom_node *node)
}
dom_string_unref(href);
- LOG("linked stylesheet %i '%s'", htmlc->stylesheet_count, nsurl_access(joined));
+ NSLOG(netsurf, INFO, "linked stylesheet %i '%s'",
+ htmlc->stylesheet_count, nsurl_access(joined));
/* extend stylesheets array to allow for new sheet */
stylesheets = realloc(htmlc->stylesheets,
@@ -452,7 +465,7 @@ bool html_css_process_link(html_content *htmlc, dom_node *node)
htmlc->stylesheet_count++;
htmlc->base.active++;
- LOG("%d fetches active", htmlc->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", htmlc->base.active);
return true;
@@ -461,7 +474,7 @@ no_memory:
return false;
}
-/* exported interface documented in render/html.h */
+/* exported interface documented in html/html.h */
struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
@@ -475,7 +488,7 @@ struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_free_stylesheets(html_content *html)
{
unsigned int i;
@@ -495,7 +508,7 @@ nserror html_css_free_stylesheets(html_content *html)
return NSERROR_OK;
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_quirks_stylesheets(html_content *c)
{
nserror ns_error = NSERROR_OK;
@@ -517,13 +530,13 @@ nserror html_css_quirks_stylesheets(html_content *c)
}
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
}
return ns_error;
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_new_stylesheets(html_content *c)
{
nserror ns_error;
@@ -561,7 +574,7 @@ nserror html_css_new_stylesheets(html_content *c)
}
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
if (nsoption_bool(block_advertisements)) {
@@ -575,7 +588,7 @@ nserror html_css_new_stylesheets(html_content *c)
}
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
}
@@ -588,7 +601,7 @@ nserror html_css_new_stylesheets(html_content *c)
}
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
return ns_error;
}
diff --git a/render/html_css_fetcher.c b/content/handlers/html/html_css_fetcher.c
index 9eda6aeb7..7987ea094 100644
--- a/render/html_css_fetcher.c
+++ b/content/handlers/html/html_css_fetcher.c
@@ -17,6 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * HTML fetcher for CSS objects
+ */
+
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -33,7 +38,7 @@
#include "content/fetch.h"
#include "content/fetchers.h"
-#include "render/html_internal.h"
+#include "html/html_internal.h"
typedef struct html_css_fetcher_item {
uint32_t key;
@@ -51,7 +56,7 @@ typedef struct html_css_fetcher_context {
bool aborted;
bool locked;
-
+
struct html_css_fetcher_context *r_next, *r_prev;
} html_css_fetcher_context;
@@ -61,13 +66,15 @@ static html_css_fetcher_context *ring = NULL;
static bool html_css_fetcher_initialise(lwc_string *scheme)
{
- LOG("html_css_fetcher_initialise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "html_css_fetcher_initialise called for %s",
+ lwc_string_data(scheme));
return true;
}
static void html_css_fetcher_finalise(lwc_string *scheme)
{
- LOG("html_css_fetcher_finalise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "html_css_fetcher_finalise called for %s",
+ lwc_string_data(scheme));
}
static bool html_css_fetcher_can_fetch(const nsurl *url)
@@ -84,7 +91,7 @@ static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
lwc_string *path;
uint32_t key;
html_css_fetcher_item *item, *found = NULL;
-
+
/* format of a x-ns-css URL is:
* x-ns-url:<key>
* Where key is an unsigned 32bit integer
@@ -129,7 +136,7 @@ static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
ctx->item = found;
RING_INSERT(ring, ctx);
-
+
return ctx;
}
@@ -158,14 +165,14 @@ static void html_css_fetcher_abort(void *ctx)
html_css_fetcher_context *c = ctx;
/* To avoid the poll loop having to deal with the fetch context
- * disappearing from under it, we simply flag the abort here.
+ * disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
-static void html_css_fetcher_send_callback(const fetch_msg *msg,
- html_css_fetcher_context *c)
+static void html_css_fetcher_send_callback(const fetch_msg *msg,
+ html_css_fetcher_context *c)
{
c->locked = true;
fetch_send_callback(msg, c->parent_fetch);
@@ -176,16 +183,16 @@ static void html_css_fetcher_poll(lwc_string *scheme)
{
fetch_msg msg;
html_css_fetcher_context *c, *next;
-
+
if (ring == NULL) return;
-
+
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
/* Ignore fetches that have been flagged as locked.
* This allows safe re-entrant calls to this function.
* Re-entrancy can occur if, as a result of a callback,
- * the interested party causes fetch_poll() to be called
+ * the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
@@ -211,26 +218,26 @@ static void html_css_fetcher_poll(lwc_string *scheme)
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
- html_css_fetcher_send_callback(&msg, c);
+ html_css_fetcher_send_callback(&msg, c);
if (c->aborted == false) {
- snprintf(header, sizeof header,
+ snprintf(header, sizeof header,
"Content-Length: %"PRIsizet,
dom_string_byte_length(c->item->data));
msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
+ msg.data.header_or_data.buf =
(const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
html_css_fetcher_send_callback(&msg, c);
}
if (c->aborted == false) {
- snprintf(header, sizeof header,
+ snprintf(header, sizeof header,
"X-NS-Base: %.*s",
(int) nsurl_length(c->item->base_url),
nsurl_access(c->item->base_url));
msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
+ msg.data.header_or_data.buf =
(const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
html_css_fetcher_send_callback(&msg, c);
@@ -238,8 +245,8 @@ static void html_css_fetcher_poll(lwc_string *scheme)
if (c->aborted == false) {
msg.type = FETCH_DATA;
- msg.data.header_or_data.buf =
- (const uint8_t *)
+ msg.data.header_or_data.buf =
+ (const uint8_t *)
dom_string_data(c->item->data);
msg.data.header_or_data.len =
dom_string_byte_length(c->item->data);
@@ -251,9 +258,10 @@ static void html_css_fetcher_poll(lwc_string *scheme)
html_css_fetcher_send_callback(&msg, c);
}
} else {
- LOG("Processing of %s failed!", nsurl_access(c->url));
+ NSLOG(netsurf, INFO, "Processing of %s failed!",
+ nsurl_access(c->url));
- /* Ensure that we're unlocked here. If we aren't,
+ /* Ensure that we're unlocked here. If we aren't,
* then html_css_fetcher_process() is broken.
*/
assert(c->locked == false);
@@ -290,7 +298,7 @@ nserror html_css_fetcher_register(void)
if (lwc_intern_string("x-ns-css", SLEN("x-ns-css"),
&scheme) != lwc_error_ok) {
- LOG("could not intern \"x-ns-css\".");
+ NSLOG(netsurf, INFO, "could not intern \"x-ns-css\".");
return NSERROR_INIT_FAILED;
}
@@ -315,4 +323,3 @@ html_css_fetcher_add_item(dom_string *data, nsurl *base_url, uint32_t *key)
return NSERROR_OK;
}
-
diff --git a/render/html_forms.c b/content/handlers/html/html_forms.c
index 39bc690d9..915eb002f 100644
--- a/render/html_forms.c
+++ b/content/handlers/html/html_forms.c
@@ -16,14 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * HTML form handling implementation
+ */
+
#include "utils/config.h"
#include "utils/corestrings.h"
#include "utils/log.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
-/**
+/**
* process form element from dom
*/
static struct form *
@@ -572,4 +577,3 @@ struct form_control *html_forms_get_control_for_node(struct form *forms,
return ctl;
}
-
diff --git a/render/html_interaction.c b/content/handlers/html/html_interaction.c
index e727a9ffc..648d27467 100644
--- a/render/html_interaction.c
+++ b/content/handlers/html/html_interaction.c
@@ -2,7 +2,7 @@
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -21,7 +21,7 @@
/**
* \file
- * User interaction with a CONTENT_HTML (implementation).
+ * implementation of user interaction with a CONTENT_HTML.
*/
#include <assert.h>
@@ -48,13 +48,13 @@
#include "javascript/js.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/search.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
+#include "html/imagemap.h"
+#include "html/search.h"
/**
* Get pointer shape for given box
@@ -208,7 +208,7 @@ static size_t html_selection_drag_end(struct html_content *html,
if (box) {
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
guit->layout->position(&fstyle, box->text, box->length,
dx, &idx, &pixel_offset);
@@ -289,11 +289,50 @@ html__image_coords_dom_user_data_handler(dom_node_operation operation,
break;
default:
- LOG("User data operation not handled.");
+ NSLOG(netsurf, INFO, "User data operation not handled.");
assert(0);
}
}
+
+/**
+ * End overflow scroll scrollbar drags
+ *
+ * \param scrollbar scrollbar widget
+ * \param mouse state of mouse buttons and modifier keys
+ * \param x coordinate of mouse
+ * \param y coordinate of mouse
+ */
+static void
+html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
+ browser_mouse_state mouse,
+ int x, int y)
+{
+ int scroll_mouse_x, scroll_mouse_y, box_x, box_y;
+ struct html_scrollbar_data *data = scrollbar_get_data(scrollbar);
+ struct box *box;
+
+ box = data->box;
+ box_coords(box, &box_x, &box_y);
+
+ if (scrollbar_is_horizontal(scrollbar)) {
+ scroll_mouse_x = x - box_x;
+ scroll_mouse_y = y - (box_y + box->padding[TOP] +
+ box->height + box->padding[BOTTOM] -
+ SCROLLBAR_WIDTH);
+ scrollbar_mouse_drag_end(scrollbar, mouse,
+ scroll_mouse_x, scroll_mouse_y);
+ } else {
+ scroll_mouse_x = x - (box_x + box->padding[LEFT] +
+ box->width + box->padding[RIGHT] -
+ SCROLLBAR_WIDTH);
+ scroll_mouse_y = y - box_y;
+ scrollbar_mouse_drag_end(scrollbar, mouse,
+ scroll_mouse_x, scroll_mouse_y);
+ }
+}
+
+
/**
* Handle mouse clicks and movements in an HTML content window.
*
@@ -368,7 +407,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
mouse, x - box_x, y - box_y);
if (status != NULL) {
msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
} else {
int width, height;
form_select_get_dimensions(html->visible_select_menu,
@@ -415,7 +454,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
size_t idx;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ box->style, &fstyle);
guit->layout->position(&fstyle,
box->text, box->length,
@@ -459,7 +499,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
}
msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
return;
}
@@ -504,7 +544,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
assert(html->drag_type == HTML_DRAG_NONE);
/* search the box tree for a link, imagemap, form control, or
- * box with scrollbars
+ * box with scrollbars
*/
box = html->layout;
@@ -514,7 +554,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
box_y = box->margin[TOP];
/* descend through visible boxes setting more specific values for:
- * box - deepest box at point
+ * box - deepest box at point
* html_object_box - html object
* html_object_pos_x - html object
* html_object_pos_y - html object
@@ -539,13 +579,13 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
* scrollbar - inside padding box stops decent
* scroll_mouse_x - inside padding box stops decent
* scroll_mouse_y - inside padding box stops decent
- *
+ *
* text_box - text box
* text_box_x - text_box
*/
do {
- if ((box->style != NULL) &&
- (css_computed_visibility(box->style) ==
+ if ((box->style != NULL) &&
+ (css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)) {
continue;
}
@@ -597,8 +637,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
}
pointer = get_pointer_shape(box, false);
-
- if ((box->scroll_x != NULL) ||
+
+ if ((box->scroll_x != NULL) ||
(box->scroll_y != NULL)) {
if (drag_candidate == NULL) {
@@ -613,29 +653,29 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
scrollbar_get_offset(box->scroll_y);
padding_bottom = padding_top + box->padding[TOP] +
box->height + box->padding[BOTTOM];
-
- if ((x > padding_left) &&
+
+ if ((x > padding_left) &&
(x < padding_right) &&
- (y > padding_top) &&
+ (y > padding_top) &&
(y < padding_bottom)) {
/* mouse inside padding box */
-
- if ((box->scroll_y != NULL) &&
+
+ if ((box->scroll_y != NULL) &&
(x > (padding_right -
SCROLLBAR_WIDTH))) {
/* mouse above vertical box scroll */
-
+
scrollbar = box->scroll_y;
scroll_mouse_x = x - (padding_right -
SCROLLBAR_WIDTH);
scroll_mouse_y = y - padding_top;
break;
-
+
} else if ((box->scroll_x != NULL) &&
(y > (padding_bottom -
- SCROLLBAR_WIDTH))) {
+ SCROLLBAR_WIDTH))) {
/* mouse above horizontal box scroll */
-
+
scrollbar = box->scroll_x;
scroll_mouse_x = x - padding_left;
scroll_mouse_y = y - (padding_bottom -
@@ -649,7 +689,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
text_box = box;
text_box_x = box_x;
}
- } while ((box = box_at_point(box, x, y, &box_x, &box_y)) != NULL);
+ } while ((box = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL);
/* use of box_x, box_y, or content below this point is probably a
* mistake; they will refer to the last box returned by box_at_point */
@@ -678,7 +719,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
} else if (mouse & BROWSER_MOUSE_CLICK_1) {
msg_data.select_menu.gadget = gadget;
content_broadcast(c, CONTENT_MSG_SELECTMENU,
- msg_data);
+ &msg_data);
}
break;
case GADGET_CHECKBOX:
@@ -697,6 +738,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
form_radio_set(gadget);
break;
case GADGET_IMAGE:
+ /* This falls through to SUBMIT */
if (mouse & BROWSER_MOUSE_CLICK_1) {
struct image_input_coords *coords, *oldcoords;
/** \todo Find a way to not ignore errors */
@@ -714,7 +756,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
return;
free(oldcoords);
}
- /* drop through */
+ /* Fall through */
case GADGET_SUBMIT:
if (gadget->form) {
snprintf(status_buffer, sizeof status_buffer,
@@ -768,7 +810,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
status = messages_get("FormFile");
if (mouse & BROWSER_MOUSE_CLICK_1) {
msg_data.gadget_click.gadget = gadget;
- content_broadcast(c, CONTENT_MSG_GADGETCLICK, msg_data);
+ content_broadcast(c, CONTENT_MSG_GADGETCLICK,
+ &msg_data);
}
break;
case GADGET_BUTTON:
@@ -782,12 +825,12 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
if (mouse & BROWSER_MOUSE_DRAG_2) {
msg_data.dragsave.type = CONTENT_SAVE_NATIVE;
msg_data.dragsave.content = object;
- content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
+ content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data);
} else if (mouse & BROWSER_MOUSE_DRAG_1) {
msg_data.dragsave.type = CONTENT_SAVE_ORIG;
msg_data.dragsave.content = object;
- content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
+ content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data);
}
/* \todo should have a drag-saving object msg */
@@ -869,7 +912,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
mouse & BROWSER_MOUSE_MOD_1) {
msg_data.savelink.url = url;
msg_data.savelink.title = title;
- content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data);
+ content_broadcast(c, CONTENT_MSG_SAVELINK, &msg_data);
} else if (mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2))
@@ -890,7 +933,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/* if clicking in the main page, remove the selection from any
* text areas */
if (!done) {
-
+
if (click && html->focus_type != HTML_FOCUS_SELF) {
union html_focus_owner fo;
fo.self = true;
@@ -908,8 +951,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
int pixel_offset;
size_t idx;
- font_plot_style_from_css(text_box->style,
- &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ text_box->style, &fstyle);
guit->layout->position(&fstyle,
text_box->text,
@@ -968,7 +1011,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
msg_data.dragsave.content = NULL;
content_broadcast(c,
CONTENT_MSG_DRAGSAVE,
- msg_data);
+ &msg_data);
} else {
if (drag_candidate == NULL) {
browser_window_page_drag_start(
@@ -988,7 +1031,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
msg_data.dragsave.content = NULL;
content_broadcast(c,
CONTENT_MSG_DRAGSAVE,
- msg_data);
+ &msg_data);
} else {
if (drag_candidate == NULL) {
browser_window_page_drag_start(
@@ -1013,10 +1056,10 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
if (!iframe && !html_object_box) {
msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
msg_data.pointer = pointer;
- content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
+ content_broadcast(c, CONTENT_MSG_POINTER, &msg_data);
}
/* fire dom click event */
@@ -1186,7 +1229,7 @@ void html_overflow_scroll_callback(void *client_data,
union content_msg_data msg_data;
html_drag_type drag_type;
union html_drag_owner drag_owner;
-
+
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
@@ -1217,47 +1260,12 @@ void html_overflow_scroll_callback(void *client_data,
html_set_drag_type(html, drag_type, drag_owner, NULL);
msg_data.pointer = BROWSER_POINTER_AUTO;
- content_broadcast(data->c, CONTENT_MSG_POINTER, msg_data);
+ content_broadcast(data->c, CONTENT_MSG_POINTER, &msg_data);
break;
}
}
-/**
- * End overflow scroll scrollbar drags
- *
- * \param scrollbar scrollbar widget
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
- browser_mouse_state mouse, int x, int y)
-{
- int scroll_mouse_x, scroll_mouse_y, box_x, box_y;
- struct html_scrollbar_data *data = scrollbar_get_data(scrollbar);
- struct box *box;
-
- box = data->box;
- box_coords(box, &box_x, &box_y);
-
- if (scrollbar_is_horizontal(scrollbar)) {
- scroll_mouse_x = x - box_x;
- scroll_mouse_y = y - (box_y + box->padding[TOP] +
- box->height + box->padding[BOTTOM] -
- SCROLLBAR_WIDTH);
- scrollbar_mouse_drag_end(scrollbar, mouse,
- scroll_mouse_x, scroll_mouse_y);
- } else {
- scroll_mouse_x = x - (box_x + box->padding[LEFT] +
- box->width + box->padding[RIGHT] -
- SCROLLBAR_WIDTH);
- scroll_mouse_y = y - box_y;
- scrollbar_mouse_drag_end(scrollbar, mouse,
- scroll_mouse_x, scroll_mouse_y);
- }
-}
-
/* Documented in html_internal.h */
void html_set_drag_type(html_content *html, html_drag_type drag_type,
union html_drag_owner drag_owner, const struct rect *rect)
@@ -1292,7 +1300,7 @@ void html_set_drag_type(html_content *html, html_drag_type drag_type,
msg_data.drag.rect = rect;
/* Inform of the content's drag status change */
- content_broadcast((struct content *)html, CONTENT_MSG_DRAG, msg_data);
+ content_broadcast((struct content *)html, CONTENT_MSG_DRAG, &msg_data);
}
/* Documented in html_internal.h */
@@ -1350,7 +1358,7 @@ void html_set_focus(html_content *html, html_focus_type focus_type,
}
/* Inform of the content's drag status change */
- content_broadcast((struct content *)html, CONTENT_MSG_CARET, msg_data);
+ content_broadcast((struct content *)html, CONTENT_MSG_CARET, &msg_data);
}
/* Documented in html_internal.h */
@@ -1426,5 +1434,5 @@ void html_set_selection(html_content *html, html_selection_type selection_type,
/* Inform of the content's selection status change */
content_broadcast((struct content *)html, CONTENT_MSG_SELECTION,
- msg_data);
+ &msg_data);
}
diff --git a/render/html_internal.h b/content/handlers/html/html_internal.h
index fd65707ce..77354c369 100644
--- a/render/html_internal.h
+++ b/content/handlers/html/html_internal.h
@@ -18,19 +18,21 @@
/**
* \file
- * Content for text/html (private data).
+ * Private data for text/html content.
*/
-#ifndef NETSURF_RENDER_HTML_INTERNAL_H_
-#define NETSURF_RENDER_HTML_INTERNAL_H_
+#ifndef NETSURF_HTML_HTML_INTERNAL_H
+#define NETSURF_HTML_HTML_INTERNAL_H
#include <libcss/libcss.h>
+#include <dom/bindings/hubbub/parser.h>
+#include "netsurf/types.h"
#include "content/content_protected.h"
#include "desktop/selection.h"
-#include "render/html.h"
struct gui_layout_table;
+struct scrollbar_msg_data;
typedef enum {
HTML_DRAG_NONE, /** No drag */
@@ -42,12 +44,15 @@ typedef enum {
HTML_DRAG_CONTENT_SCROLL /** Not own; drag in child content */
} html_drag_type;
+/**
+ * For drags we don't own
+ */
union html_drag_owner {
bool no_owner;
struct box *content;
struct scrollbar *scrollbar;
struct box *textarea;
-}; /**< For drags we don't own */
+};
typedef enum {
HTML_SELECTION_NONE, /** No selection */
@@ -55,24 +60,39 @@ typedef enum {
HTML_SELECTION_SELF, /** Selection in this html content */
HTML_SELECTION_CONTENT /** Selection in child content */
} html_selection_type;
+
+/**
+ * For getting at selections in this content or things in this content
+ */
union html_selection_owner {
bool none;
struct box *textarea;
struct box *content;
-}; /**< For getting at selections in this content or things in this content */
+};
typedef enum {
- HTML_FOCUS_SELF, /** Focus is our own */
- HTML_FOCUS_CONTENT, /** Focus belongs to child content */
- HTML_FOCUS_TEXTAREA /** Focus belongs to textarea */
+ HTML_FOCUS_SELF, /**< Focus is our own */
+ HTML_FOCUS_CONTENT, /**< Focus belongs to child content */
+ HTML_FOCUS_TEXTAREA /**< Focus belongs to textarea */
} html_focus_type;
+
+/**
+ * For directing input
+ */
union html_focus_owner {
bool self;
struct box *textarea;
struct box *content;
-}; /**< For directing input */
+};
-/** Data specific to CONTENT_HTML. */
+struct html_scrollbar_data {
+ struct content *c;
+ struct box *box;
+};
+
+/**
+ * Data specific to CONTENT_HTML.
+ */
typedef struct html_content {
struct content base;
@@ -94,6 +114,9 @@ typedef struct html_content {
/** Base target */
char *base_target;
+ /** CSS length conversion context for document. */
+ nscss_len_ctx len_ctx;
+
/** Content has been aborted in the LOADING state */
bool aborted;
@@ -109,7 +132,7 @@ typedef struct html_content {
/* Title element node */
dom_node *title;
- /** A talloc context purely for the render box tree */
+ /** A talloc context purely for the render box tree */
int *bctx;
/** Box tree, or NULL. */
struct box *layout;
@@ -153,7 +176,7 @@ typedef struct html_content {
/** Inline frame information */
struct content_html_iframe *iframe;
- /** Content of type CONTENT_HTML containing this, or NULL if not an
+ /** Content of type CONTENT_HTML containing this, or NULL if not an
* object within a page. */
struct html_content *page;
@@ -254,11 +277,20 @@ bool html_can_begin_conversion(html_content *htmlc);
*/
bool html_begin_conversion(html_content *htmlc);
-/* in render/html_redraw.c */
+/* in html/html_redraw.c */
bool html_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx);
-/* in render/html_interaction.c */
+/* in html/html_redraw_border.c */
+bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
+ int p_width, int p_height, const struct rect *clip, float scale,
+ const struct redraw_context *ctx);
+
+bool html_redraw_inline_borders(struct box *box, struct rect b,
+ const struct rect *clip, float scale, bool first, bool last,
+ const struct redraw_context *ctx);
+
+/* in html/html_interaction.c */
void html_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void html_mouse_action(struct content *c, struct browser_window *bw,
@@ -271,7 +303,7 @@ void html_search(struct content *c, void *context,
void html_search_clear(struct content *c);
-/* in render/html_script.c */
+/* in html/html_script.c */
dom_hubbub_error html_process_script(void *ctx, dom_node *node);
/**
@@ -301,12 +333,12 @@ nserror html_script_free(html_content *htmlc);
*/
nserror html_script_invalidate_ctx(html_content *htmlc);
-/* in render/html_forms.c */
+/* in html/html_forms.c */
struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc);
struct form_control *html_forms_get_control_for_node(struct form *forms,
dom_node *node);
-/* in render/html_css.c */
+/* in html/html_css.c */
nserror html_css_init(void);
void html_css_fini(void);
@@ -327,7 +359,7 @@ bool html_css_update_style(html_content *c, dom_node *style);
nserror html_css_new_selection_context(html_content *c,
css_select_ctx **ret_select_ctx);
-/* in render/html_css_fetcher.c */
+/* in html/html_css_fetcher.c */
/**
* Register the fetcher for the pseudo x-ns-css scheme.
*
@@ -337,7 +369,7 @@ nserror html_css_fetcher_register(void);
nserror html_css_fetcher_add_item(dom_string *data, nsurl *base_url,
uint32_t *key);
-/* in render/html_object.c */
+/* in html/html_object.c */
/**
* Start a fetch for an object required by a page.
@@ -393,5 +425,3 @@ extern struct dom_string *html_dom_string_type;
extern struct dom_string *html_dom_string_src;
#endif
-
-
diff --git a/render/html_object.c b/content/handlers/html/html_object.c
index bc351247c..7eab46647 100644
--- a/render/html_object.c
+++ b/content/handlers/html/html_object.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Processing for html content object operations.
*/
@@ -39,8 +40,9 @@
#include "desktop/scrollbar.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/box.h"
+#include "html/html_internal.h"
/* break reference loop */
static void html_object_refresh(void *p);
@@ -97,6 +99,16 @@ html_object_done(struct box *box,
box->object = object;
+ /* Normalise the box type, now it has been replaced. */
+ switch (box->type) {
+ case BOX_TABLE:
+ box->type = BOX_BLOCK;
+ break;
+ default:
+ /* TODO: Any other box types need mapping? */
+ break;
+ }
+
if (!(box->flags & REPLACE_DIM)) {
/* invalidate parent min, max widths */
for (b = box; b; b = b->parent)
@@ -124,10 +136,10 @@ html_object_callback(hlcache_handle *object,
int x, y;
struct box *box;
- assert(c->base.status != CONTENT_STATUS_ERROR);
-
box = o->box;
- if (box == NULL && event->type != CONTENT_MSG_ERROR) {
+ if (box == NULL &&
+ event->type != CONTENT_MSG_ERROR &&
+ event->type != CONTENT_MSG_ERRORCODE) {
return NSERROR_OK;
}
@@ -160,7 +172,7 @@ html_object_callback(hlcache_handle *object,
case CONTENT_MSG_DONE:
c->base.active--;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
html_object_done(box, object, o->background);
@@ -179,10 +191,11 @@ html_object_callback(hlcache_handle *object,
data.redraw.height = box->height;
data.redraw.full_redraw = true;
- content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
+ content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data);
}
break;
+ case CONTENT_MSG_ERRORCODE:
case CONTENT_MSG_ERROR:
hlcache_handle_release(object);
@@ -190,7 +203,8 @@ html_object_callback(hlcache_handle *object,
if (box != NULL) {
c->base.active--;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active",
+ c->base.active);
content_add_error(&c->base, "?", 0);
html_object_failed(box, c, o->background);
@@ -225,7 +239,8 @@ html_object_callback(hlcache_handle *object,
if (hunit == CSS_UNIT_PCT) {
l = (width - w) * hpos / INTTOFIX(100);
} else {
- l = FIXTOINT(nscss_len2px(hpos, hunit,
+ l = FIXTOINT(nscss_len2px(&c->len_ctx,
+ hpos, hunit,
box->style));
}
@@ -233,7 +248,8 @@ html_object_callback(hlcache_handle *object,
if (vunit == CSS_UNIT_PCT) {
t = (height - h) * vpos / INTTOFIX(100);
} else {
- t = FIXTOINT(nscss_len2px(vpos, vunit,
+ t = FIXTOINT(nscss_len2px(&c->len_ctx,
+ vpos, vunit,
box->style));
}
@@ -278,7 +294,7 @@ html_object_callback(hlcache_handle *object,
data.redraw.object_y += y;
content_broadcast(&c->base,
- CONTENT_MSG_REDRAW, data);
+ CONTENT_MSG_REDRAW, &data);
break;
} else {
@@ -317,7 +333,7 @@ html_object_callback(hlcache_handle *object,
data.redraw.object_y += y + box->padding[TOP];
}
- content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
+ content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data);
}
break;
@@ -356,7 +372,7 @@ html_object_callback(hlcache_handle *object,
msg_data.dragsave.content =
event->data.dragsave.content;
- content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, msg_data);
+ content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, &msg_data);
}
break;
@@ -366,7 +382,7 @@ html_object_callback(hlcache_handle *object,
case CONTENT_MSG_GADGETCLICK:
/* These messages are for browser window layer.
* we're not interested, so pass them on. */
- content_broadcast(&c->base, event->type, event->data);
+ content_broadcast(&c->base, event->type, &event->data);
break;
case CONTENT_MSG_CARET:
@@ -436,39 +452,40 @@ html_object_callback(hlcache_handle *object,
}
if (c->base.status == CONTENT_STATUS_READY &&
- c->base.active == 0 &&
- (event->type == CONTENT_MSG_LOADING ||
- event->type == CONTENT_MSG_DONE ||
- event->type == CONTENT_MSG_ERROR)) {
+ c->base.active == 0 &&
+ (event->type == CONTENT_MSG_LOADING ||
+ event->type == CONTENT_MSG_DONE ||
+ event->type == CONTENT_MSG_ERROR ||
+ event->type == CONTENT_MSG_ERRORCODE)) {
/* all objects have arrived */
content__reformat(&c->base, false, c->base.available_width,
c->base.height);
content_set_done(&c->base);
} else if (nsoption_bool(incremental_reflow) &&
- event->type == CONTENT_MSG_DONE &&
- box != NULL &&
- !(box->flags & REPLACE_DIM) &&
- (c->base.status == CONTENT_STATUS_READY ||
- c->base.status == CONTENT_STATUS_DONE)) {
- /* 1) the configuration option to reflow pages while
- * objects are fetched is set
- * 2) an object is newly fetched & converted,
- * 3) the box's dimensions need to change due to being replaced
- * 4) the object's parent HTML is ready for reformat,
- */
- uint64_t ms_now;
- nsu_getmonotonic_ms(&ms_now);
- if (ms_now > c->base.reformat_time) {
- /* The time since the previous reformat is
- * more than the configured minimum time
- * between reformats so reformat the page to
- * display newly fetched objects
- */
- content__reformat(&c->base,
- false,
- c->base.available_width,
- c->base.height);
- }
+ event->type == CONTENT_MSG_DONE &&
+ box != NULL &&
+ !(box->flags & REPLACE_DIM) &&
+ (c->base.status == CONTENT_STATUS_READY ||
+ c->base.status == CONTENT_STATUS_DONE)) {
+ /* 1) the configuration option to reflow pages while
+ * objects are fetched is set
+ * 2) an object is newly fetched & converted,
+ * 3) the box's dimensions need to change due to being replaced
+ * 4) the object's parent HTML is ready for reformat,
+ */
+ uint64_t ms_now;
+ nsu_getmonotonic_ms(&ms_now);
+ if (ms_now > c->base.reformat_time) {
+ /* The time since the previous reformat is
+ * more than the configured minimum time
+ * between reformats so reformat the page to
+ * display newly fetched objects
+ */
+ content__reformat(&c->base,
+ false,
+ c->base.available_width,
+ c->base.height);
+ }
}
return NSERROR_OK;
@@ -501,7 +518,8 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
/* remove existing object */
if (content_get_status(object->content) != CONTENT_STATUS_DONE) {
c->base.active--;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active",
+ c->base.active);
}
hlcache_handle_release(object->content);
@@ -522,7 +540,7 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url)
for (page = c; page != NULL; page = page->page) {
page->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
page->base.status = CONTENT_STATUS_READY;
}
@@ -605,7 +623,8 @@ nserror html_object_abort_objects(html_content *htmlc)
object->content = NULL;
if (object->box != NULL) {
htmlc->base.active--;
- LOG("%d fetches active", htmlc->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active",
+ htmlc->base.active);
}
break;
@@ -643,7 +662,7 @@ nserror html_object_free_objects(html_content *html)
struct content_html_object *victim = html->object_list;
if (victim->content != NULL) {
- LOG("object %p", victim->content);
+ NSLOG(netsurf, INFO, "object %p", victim->content);
if (content_get_type(victim->content) == CONTENT_HTML) {
guit->misc->schedule(-1, html_object_refresh, victim);
@@ -659,7 +678,7 @@ nserror html_object_free_objects(html_content *html)
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_type permitted_types,
int available_width, int available_height,
@@ -693,7 +712,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_get_url(&c->base), NULL,
html_object_callback, object, &child,
object->permitted_types, &object->content);
- if (error != NSERROR_OK) {
+ if (error != NSERROR_OK) {
free(object);
return error != NSERROR_NOMEM;
}
@@ -705,7 +724,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
c->num_objects++;
if (box != NULL) {
c->base.active++;
- LOG("%d fetches active", c->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
}
return true;
diff --git a/render/html_redraw.c b/content/handlers/html/html_redraw.c
index ae8675671..d05df8753 100644
--- a/render/html_redraw.c
+++ b/content/handlers/html/html_redraw.c
@@ -5,7 +5,7 @@
* Copyright 2005-2006 Adrian Lees <adrianl@users.sourceforge.net>
* Copyright 2006 Rob Kendrick <rjek@netsurf-browser.org>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -53,12 +53,12 @@
#include "desktop/textarea.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/search.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
+#include "html/layout.h"
+#include "html/search.h"
bool html_redraw_debug = false;
@@ -150,16 +150,26 @@ static struct box *html_redraw_find_bg_box(struct box *box)
* \return true iff successful and redraw should proceed
*/
-bool text_redraw(const char *utf8_text, size_t utf8_len,
- size_t offset, int space, const plot_font_style_t *fstyle,
- int x, int y, const struct rect *clip, int height,
- float scale, bool excluded, struct content *c,
- const struct selection *sel, struct search_context *search,
- const struct redraw_context *ctx)
+static bool
+text_redraw(const char *utf8_text,
+ size_t utf8_len,
+ size_t offset,
+ int space,
+ const plot_font_style_t *fstyle,
+ int x,
+ int y,
+ const struct rect *clip,
+ int height,
+ float scale,
+ bool excluded,
+ struct content *c,
+ const struct selection *sel,
+ struct search_context *search,
+ const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
bool highlighted = false;
plot_font_style_t plot_fstyle = *fstyle;
+ nserror res;
/* Need scaled text size to pass to plotters */
plot_fstyle.size *= scale;
@@ -195,7 +205,6 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
int startx, endx;
plot_style_t pstyle_fill_hback = *plot_style_fill_white;
plot_font_style_t fstyle_hback = plot_fstyle;
- nserror res;
if (end_idx > utf8_len) {
/* adjust for trailing space, not present in
@@ -230,19 +239,26 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
}
/* draw any text preceding highlighted portion */
- if (start_idx > 0 &&
- !plot->text(x, y + (int)(height * 0.75 * scale),
- utf8_text, start_idx,
- &plot_fstyle))
+ if ((start_idx > 0) &&
+ (ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ start_idx) != NSERROR_OK))
return false;
pstyle_fill_hback.fill_colour = fstyle->foreground;
/* highlighted portion */
- if (!plot->rectangle(x + startx, y, x + endx,
- y + height * scale,
- &pstyle_fill_hback))
+ r.x0 = x + startx;
+ r.y0 = y;
+ r.x1 = x + endx;
+ r.y1 = y + height * scale;
+ res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
if (start_idx > 0) {
int px0 = max(x + startx, clip->x0);
@@ -253,8 +269,11 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
r.y0 = clip->y0;
r.x1 = px1;
r.y1 = clip->y1;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
+
clip_changed = true;
} else {
text_visible = false;
@@ -267,10 +286,14 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
pstyle_fill_hback.fill_colour);
if (text_visible &&
- !plot->text(x, y + (int)(height * 0.75 * scale),
- utf8_text, endtxt_idx,
- &fstyle_hback))
+ (ctx->plot->text(ctx,
+ &fstyle_hback,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ endtxt_idx) != NSERROR_OK)) {
return false;
+ }
/* draw any text succeeding highlighted portion */
if (endtxt_idx < utf8_len) {
@@ -281,858 +304,43 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
r.y0 = clip->y0;
r.x1 = clip->x1;
r.y1 = clip->y1;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
clip_changed = true;
- if (!plot->text(x, y + (int)
- (height * 0.75 * scale),
- utf8_text, utf8_len,
- &plot_fstyle))
+ res = ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ utf8_len);
+ if (res != NSERROR_OK) {
return false;
+ }
}
}
if (clip_changed &&
- !plot->clip(clip))
+ (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
return false;
- }
- }
-
- if (!highlighted) {
- if (!plot->text(x, y + (int) (height * 0.75 * scale),
- utf8_text, utf8_len,
- &plot_fstyle))
- return false;
- }
- return true;
-}
-
-static plot_style_t plot_style_bdr = {
- .stroke_type = PLOT_OP_TYPE_DASH,
-};
-static plot_style_t plot_style_fillbdr = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_dark = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_light = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_ddark = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_dlight = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-
-/**
- * Draw one border.
- *
- * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT)
- * \param p array of precomputed border vertices
- * \param c colour for border
- * \param style border line style
- * \param thickness border thickness
- * \param rectangular whether border is rectangular
- * \param clip cliping area for redrawing border.
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_border_plot(const int side, const int *p, colour c,
- enum css_border_style_e style, int thickness, bool rectangular,
- const struct rect *clip, const struct redraw_context *ctx)
-{
- const struct plotter_table *plot = ctx->plot;
- int z[8]; /* Vertices of border part */
- unsigned int light = side;
- plot_style_t *plot_style_bdr_in;
- plot_style_t *plot_style_bdr_out;
-
- if (c == NS_TRANSPARENT)
- return true;
-
- plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH;
- plot_style_bdr.stroke_colour = c;
- plot_style_bdr.stroke_width = thickness;
- plot_style_fillbdr.fill_colour = c;
- plot_style_fillbdr_dark.fill_colour = darken_colour(c);
- plot_style_fillbdr_light.fill_colour = lighten_colour(c);
- plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c);
- plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c);
-
- switch (style) {
- case CSS_BORDER_STYLE_DOTTED:
- plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT;
- /* fall through */
- case CSS_BORDER_STYLE_DASHED:
- if (!plot->line((p[0] + p[2]) / 2,
- (p[1] + p[3]) / 2,
- (p[4] + p[6]) / 2,
- (p[5] + p[7]) / 2,
- &plot_style_bdr))
- return false;
- break;
-
- case CSS_BORDER_STYLE_SOLID:
- /* fall through to default */
- default:
- if (rectangular || thickness == 1) {
- int x0, y0, x1, y1;
- if (side == TOP || side == RIGHT) {
- x0 = p[2]; y0 = p[3];
- x1 = p[6]; y1 = p[7];
- x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- x1 + p[4] - p[6] : x1;
- } else {
- x0 = p[6]; y0 = p[7];
- x1 = p[2]; y1 = p[3];
- y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- y1 + p[1] - p[3] : y1;
}
- /* find intersection of clip rectangle and border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- &plot_style_fillbdr))
- return false;
- }
- } else {
- if (!plot->polygon(p, 4, &plot_style_fillbdr))
- return false;
}
- break;
-
- case CSS_BORDER_STYLE_DOUBLE:
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] * 2 + p[2]) / 3;
- z[3] = (p[1] * 2 + p[3]) / 3;
- z[4] = (p[6] * 2 + p[4]) / 3;
- z[5] = (p[7] * 2 + p[5]) / 3;
- z[6] = p[6];
- z[7] = p[7];
- if (!plot->polygon(z, 4, &plot_style_fillbdr))
- return false;
- z[0] = p[2];
- z[1] = p[3];
- z[2] = (p[2] * 2 + p[0]) / 3;
- z[3] = (p[3] * 2 + p[1]) / 3;
- z[4] = (p[4] * 2 + p[6]) / 3;
- z[5] = (p[5] * 2 + p[7]) / 3;
- z[6] = p[4];
- z[7] = p[5];
- if (!plot->polygon(z, 4, &plot_style_fillbdr))
- return false;
- break;
-
- case CSS_BORDER_STYLE_GROOVE:
- light = 3 - light;
- /* fall through */
- case CSS_BORDER_STYLE_RIDGE:
- /* choose correct colours for each part of the border line */
- if (light <= 1) {
- plot_style_bdr_in = &plot_style_fillbdr_dark;
- plot_style_bdr_out = &plot_style_fillbdr_light;
- } else {
- plot_style_bdr_in = &plot_style_fillbdr_light;
- plot_style_bdr_out = &plot_style_fillbdr_dark;
- }
-
- /* Render border */
- if ((rectangular || thickness == 2) && thickness != 1) {
- /* Border made up from two parts and can be plotted
- * with rectangles */
- int x0, y0, x1, y1;
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2;
- x1 = p[6]; y1 = p[7];
- } else {
- x0 = p[6]; y0 = p[7];
- x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2;
- }
- /* find intersection of clip rectangle and border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_in))
- return false;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- x0 = p[2]; y0 = p[3];
- x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2;
- } else {
- x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2;
- x1 = p[2]; y1 = p[3];
- }
- /* find intersection of clip rectangle and border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_out))
- return false;
- }
- } else if (thickness == 1) {
- /* Border made up from one part which can be plotted
- * as a rectangle */
- int x0, y0, x1, y1;
- if (side == TOP || side == RIGHT) {
- x0 = p[2]; y0 = p[3];
- x1 = p[6]; y1 = p[7];
- x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- x1 + p[4] - p[6] : x1;
- /* find intersection of clip rectangle and
- * border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_in))
- return false;
- }
- } else {
- x0 = p[6]; y0 = p[7];
- x1 = p[2]; y1 = p[3];
- y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- y1 + p[1] - p[3] : y1;
- /* find intersection of clip rectangle and
- * border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_out))
- return false;
- }
- }
- } else {
- /* Border made up from two parts and can't be plotted
- * with rectangles */
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] + p[2]) / 2;
- z[3] = (p[1] + p[3]) / 2;
- z[4] = (p[6] + p[4]) / 2;
- z[5] = (p[7] + p[5]) / 2;
- z[6] = p[6];
- z[7] = p[7];
- if (!plot->polygon(z, 4, plot_style_bdr_in))
- return false;
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- if (!plot->polygon(z, 4, plot_style_bdr_out))
- return false;
- }
- break;
-
- case CSS_BORDER_STYLE_INSET:
- light = (light + 2) % 4;
- /* fall through */
- case CSS_BORDER_STYLE_OUTSET:
- /* choose correct colours for each part of the border line */
- switch (light) {
- case 0:
- plot_style_bdr_in = &plot_style_fillbdr_light;
- plot_style_bdr_out = &plot_style_fillbdr_dlight;
- break;
- case 1:
- plot_style_bdr_in = &plot_style_fillbdr_ddark;
- plot_style_bdr_out = &plot_style_fillbdr_dark;
- break;
- case 2:
- plot_style_bdr_in = &plot_style_fillbdr_dark;
- plot_style_bdr_out = &plot_style_fillbdr_ddark;
- break;
- case 3:
- plot_style_bdr_in = &plot_style_fillbdr_dlight;
- plot_style_bdr_out = &plot_style_fillbdr_light;
- break;
- default:
- plot_style_bdr_in = &plot_style_fillbdr;
- plot_style_bdr_out = &plot_style_fillbdr;
- break;
- }
-
- /* Render border */
- if ((rectangular || thickness == 2) && thickness != 1) {
- /* Border made up from two parts and can be plotted
- * with rectangles */
- int x0, y0, x1, y1;
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2;
- x1 = p[6]; y1 = p[7];
- } else {
- x0 = p[6]; y0 = p[7];
- x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2;
- }
- /* find intersection of clip rectangle and border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_in))
- return false;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- x0 = p[2]; y0 = p[3];
- x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2;
- } else {
- x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2;
- x1 = p[2]; y1 = p[3];
- }
- /* find intersection of clip rectangle and border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_out))
- return false;
- }
- } else if (thickness == 1) {
- /* Border made up from one part which can be plotted
- * as a rectangle */
- int x0, y0, x1, y1;
- if (side == TOP || side == RIGHT) {
- x0 = p[2]; y0 = p[3];
- x1 = p[6]; y1 = p[7];
- x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- x1 + p[4] - p[6] : x1;
- /* find intersection of clip rectangle and
- * border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_in))
- return false;
- }
- } else {
- x0 = p[6]; y0 = p[7];
- x1 = p[2]; y1 = p[3];
- y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- y1 + p[1] - p[3] : y1;
- /* find intersection of clip rectangle and
- * border */
- x0 = (clip->x0 > x0) ? clip->x0 : x0;
- y0 = (clip->y0 > y0) ? clip->y0 : y0;
- x1 = (clip->x1 < x1) ? clip->x1 : x1;
- y1 = (clip->y1 < y1) ? clip->y1 : y1;
- if ((x0 < x1) && (y0 < y1)) {
- /* valid clip rectangles only */
- if (!plot->rectangle(x0, y0, x1, y1,
- plot_style_bdr_out))
- return false;
- }
- }
- } else {
- /* Border made up from two parts and can't be plotted
- * with rectangles */
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] + p[2]) / 2;
- z[3] = (p[1] + p[3]) / 2;
- z[4] = (p[6] + p[4]) / 2;
- z[5] = (p[7] + p[5]) / 2;
- z[6] = p[6];
- z[7] = p[7];
- if (!plot->polygon(z, 4, plot_style_bdr_in))
- return false;
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- if (!plot->polygon(z, 4, plot_style_bdr_out))
- return false;
- }
- break;
}
- return true;
-}
-
-
-/**
- * Draw borders for a box.
- *
- * \param box box to draw
- * \param x_parent coordinate of left padding edge of parent of box
- * \param y_parent coordinate of top padding edge of parent of box
- * \param p_width width of padding box
- * \param p_height height of padding box
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
- int p_width, int p_height, const struct rect *clip, float scale,
- const struct redraw_context *ctx)
-{
- unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- int x, y;
- unsigned int i, side;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1 = false;
- bool square_end_2 = false;
-
- x = x_parent + box->x;
- y = y_parent + box->y;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- x *= scale;
- y *= scale;
- }
-
- assert(box->style);
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = x - left; p[1] = y - top; /* A */
- p[2] = x; p[3] = y; /* B */
- p[4] = x + p_width; p[5] = y + p_height; /* C */
- p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
-
- for (i = 0; i != 4; i++) {
- colour col = 0;
- side = sides[i]; /* plot order */
-
- if (box->border[side].width == 0 ||
- nscss_color_is_transparent(box->border[side].c))
- continue;
-
- switch (side) {
- case LEFT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) ==
- false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[5] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- if (!html_redraw_border_plot(side, z, col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip, ctx))
- return false;
- break;
- case RIGHT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) ==
- false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[3] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- if (!html_redraw_border_plot(side, z, col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip, ctx))
- return false;
- break;
- case TOP:
- if (clip->y0 > p[3])
- /* clip rectangle is below border; nothing to
- * plot */
- continue;
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[2] += left;
- square_end_1 = true;
- }
- if (box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[4] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- if (!html_redraw_border_plot(side, z, col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip, ctx))
- return false;
- break;
- case BOTTOM:
- if (clip->y1 < p[5])
- /* clip rectangle is above border; nothing to
- * plot */
- continue;
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[4] += left;
- square_end_1 = true;
- }
- if (box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[2] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- if (!html_redraw_border_plot(side, z, col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip, ctx))
- return false;
- break;
- default:
- assert(side == TOP || side == BOTTOM ||
- side == LEFT || side == RIGHT);
- break;
- }
- }
-
- return true;
-}
-
-
-/**
- * Draw an inline's borders.
- *
- * \param box BOX_INLINE which created the border
- * \param b coordinates of border edge rectangle
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param first true if this is the first rectangle associated with the inline
- * \param last true if this is the last rectangle associated with the inline
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_inline_borders(struct box *box, struct rect b,
- const struct rect *clip, float scale, bool first, bool last,
- const struct redraw_context *ctx)
-{
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- colour col;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1;
- bool square_end_2;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- }
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = b.x0; p[1] = b.y0; /* A */
- p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
- p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
- p[6] = b.x1; p[7] = b.y1; /* D */
-
- assert(box->style);
-
- /* Left */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (left != 0 && first && nscss_color_is_transparent(
- box->border[LEFT].c) == false) {
- col = nscss_color_to_ns(box->border[LEFT].c);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[5] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- if (!html_redraw_border_plot(LEFT, z, col,
- box->border[LEFT].style,
- left, square_end_1 && square_end_2,
- clip, ctx))
- return false;
- }
-
- /* Right */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (right != 0 && last && nscss_color_is_transparent(
- box->border[RIGHT].c) == false) {
- col = nscss_color_to_ns(box->border[RIGHT].c);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[3] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- if (!html_redraw_border_plot(RIGHT, z, col,
- box->border[RIGHT].style,
- right, square_end_1 && square_end_2,
- clip, ctx))
- return false;
- }
-
- /* Top */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (top != 0 && nscss_color_is_transparent(
- box->border[TOP].c) == false) {
- col = nscss_color_to_ns(box->border[TOP].c);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (first && box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[2] += left;
- square_end_1 = true;
- }
-
- if (last && box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[4] -= right;
- square_end_2 = true;
- }
-
- if (!html_redraw_border_plot(TOP, z, col,
- box->border[TOP].style,
- top, square_end_1 && square_end_2,
- clip, ctx))
+ if (!highlighted) {
+ res = ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int) (height * 0.75 * scale),
+ utf8_text,
+ utf8_len);
+ if (res != NSERROR_OK) {
return false;
- }
-
- /* Bottom */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (bottom != 0 && nscss_color_is_transparent(
- box->border[BOTTOM].c) == false) {
- col = nscss_color_to_ns(box->border[BOTTOM].c);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (first && box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[4] += left;
- square_end_1 = true;
- }
-
- if (last && box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[2] -= right;
- square_end_2 = true;
}
-
- if (!html_redraw_border_plot(BOTTOM, z, col,
- box->border[BOTTOM].style,
- bottom, square_end_1 && square_end_2,
- clip, ctx))
- return false;
}
-
return true;
}
@@ -1152,42 +360,85 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b,
static bool html_redraw_checkbox(int x, int y, int width, int height,
bool selected, const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
- double z = width * 0.15;
- if (z == 0)
+ double z;
+ nserror res;
+ struct rect rect;
+
+ z = width * 0.15;
+ if (z == 0) {
z = 1;
+ }
- if (!(plot->rectangle(x, y, x + width, y + height,
- plot_style_fill_wbasec) &&
- plot->line(x, y, x + width, y, plot_style_stroke_darkwbasec) &&
- plot->line(x, y, x, y + height, plot_style_stroke_darkwbasec) &&
- plot->line(x + width, y, x + width, y + height,
- plot_style_stroke_lightwbasec) &&
- plot->line(x, y + height, x + width, y + height,
- plot_style_stroke_lightwbasec)))
+ rect.x0 = x;
+ rect.y0 = y ;
+ rect.x1 = x + width;
+ rect.y1 = y + height;
+ res = ctx->plot->rectangle(ctx, plot_style_fill_wbasec, &rect);
+ if (res != NSERROR_OK) {
return false;
+ }
+
+ /* dark line across top */
+ rect.y1 = y;
+ res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ /* dark line across left */
+ rect.x1 = x;
+ rect.y1 = y + height;
+ res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ /* light line across right */
+ rect.x0 = x + width;
+ rect.x1 = x + width;
+ res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ /* light line across bottom */
+ rect.x0 = x;
+ rect.y0 = y + height;
+ res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
+ if (res != NSERROR_OK) {
+ return false;
+ }
if (selected) {
if (width < 12 || height < 12) {
/* render a solid box instead of a tick */
- if (!plot->rectangle(x + z + z, y + z + z,
- x + width - z, y + height - z,
- plot_style_fill_wblobc))
+ rect.x0 = x + z + z;
+ rect.y0 = y + z + z;
+ rect.x1 = x + width - z;
+ rect.y1 = y + height - z;
+ res = ctx->plot->rectangle(ctx, plot_style_fill_wblobc, &rect);
+ if (res != NSERROR_OK) {
return false;
+ }
} else {
/* render a tick, as it'll fit comfortably */
- if (!(plot->line(x + width - z,
- y + z,
- x + (z * 3),
- y + height - z,
- plot_style_stroke_wblobc) &&
-
- plot->line(x + (z * 3),
- y + height - z,
- x + z + z,
- y + (height / 2),
- plot_style_stroke_wblobc)))
+ rect.x0 = x + width - z;
+ rect.y0 = y + z;
+ rect.x1 = x + (z * 3);
+ rect.y1 = y + height - z;
+ res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ rect.x0 = x + (z * 3);
+ rect.y0 = y + height - z;
+ rect.x1 = x + z + z;
+ rect.y1 = y + (height / 2);
+ res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
+ if (res != NSERROR_OK) {
return false;
+ }
}
}
return true;
@@ -1208,40 +459,52 @@ static bool html_redraw_checkbox(int x, int y, int width, int height,
static bool html_redraw_radio(int x, int y, int width, int height,
bool selected, const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
+ nserror res;
/* plot background of radio button */
- if (!plot->disc(x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1,
- plot_style_fill_wbasec))
+ res = ctx->plot->disc(ctx,
+ plot_style_fill_wbasec,
+ x + width * 0.5,
+ y + height * 0.5,
+ width * 0.5 - 1);
+ if (res != NSERROR_OK) {
return false;
+ }
/* plot dark arc */
- if (!plot->arc(x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1,
- 45,
- 225,
- plot_style_fill_darkwbasec))
+ res = ctx->plot->arc(ctx,
+ plot_style_fill_darkwbasec,
+ x + width * 0.5,
+ y + height * 0.5,
+ width * 0.5 - 1,
+ 45,
+ 225);
+ if (res != NSERROR_OK) {
return false;
+ }
/* plot light arc */
- if (!plot->arc(x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1,
- 225,
- 45,
- plot_style_fill_lightwbasec))
+ res = ctx->plot->arc(ctx,
+ plot_style_fill_lightwbasec,
+ x + width * 0.5,
+ y + height * 0.5,
+ width * 0.5 - 1,
+ 225,
+ 45);
+ if (res != NSERROR_OK) {
return false;
+ }
if (selected) {
/* plot selection blob */
- if (!plot->disc(x + width * 0.5,
- y + height * 0.5,
- width * 0.3 - 1,
- plot_style_fill_wblobc))
+ res = ctx->plot->disc(ctx,
+ plot_style_fill_wblobc,
+ x + width * 0.5,
+ y + height * 0.5,
+ width * 0.3 - 1);
+ if (res != NSERROR_OK) {
return false;
+ }
}
return true;
@@ -1258,12 +521,14 @@ static bool html_redraw_radio(int x, int y, int width, int height,
* \param box box of input
* \param scale scale for redraw
* \param background_colour current background colour
+ * \param len_ctx Length conversion context
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_file(int x, int y, int width, int height,
struct box *box, float scale, colour background_colour,
+ const nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
int text_width;
@@ -1272,13 +537,14 @@ static bool html_redraw_file(int x, int y, int width, int height,
plot_font_style_t fstyle;
nserror res;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
fstyle.background = background_colour;
- if (box->gadget->value)
+ if (box->gadget->value) {
text = box->gadget->value;
- else
+ } else {
text = messages_get("Form_Drop");
+ }
length = strlen(text);
res = guit->layout->width(&fstyle, text, length, &text_width);
@@ -1292,13 +558,21 @@ static bool html_redraw_file(int x, int y, int width, int height,
x = x + 4;
}
- return ctx->plot->text(x, y + height * 0.75, text, length, &fstyle);
+ res = ctx->plot->text(ctx, &fstyle, x, y + height * 0.75, text, length);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ return true;
}
/**
* Plot background images.
*
+ * The reason for the presence of \a background is the backwards compatibility
+ * mess that is backgrounds on &lt;body&gt;. The background will be drawn relative
+ * to \a box, using the background information contained within \a background.
+ *
* \param x coordinate of box
* \param y coordinate of box
* \param box box to draw background image of
@@ -1306,19 +580,17 @@ static bool html_redraw_file(int x, int y, int width, int height,
* \param clip current clip rectangle
* \param background_colour current background colour
* \param background box containing background details (usually \a box)
- * \param ctx current redraw context
+ * \param len_ctx Length conversion context
+ * \param ctx current redraw context
* \return true if successful, false otherwise
- *
- * The reason for the presence of ::background is the backwards compatibility
- * mess that is backgrounds on &lt;body&gt;. The background will be drawn relative
- * to \a box, using the background information contained within \a background.
*/
static bool html_redraw_background(int x, int y, struct box *box, float scale,
const struct rect *clip, colour *background_colour,
- struct box *background, const struct redraw_context *ctx)
+ struct box *background,
+ const nscss_len_ctx *len_ctx,
+ const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
bool repeat_x = false;
bool repeat_y = false;
bool plot_colour = true;
@@ -1336,6 +608,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
};
+ nserror res;
if (ctx->background_images == false)
return true;
@@ -1388,20 +661,20 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
css_computed_background_position(background->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
- x += (width -
+ x += (width -
content_get_width(background->background)) *
scale * FIXTOFLT(hpos) / 100.;
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
background->style)) * scale);
}
if (vunit == CSS_UNIT_PCT) {
- y += (height -
+ y += (height -
content_get_height(background->background)) *
scale * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
background->style)) * scale);
}
}
@@ -1451,10 +724,10 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
/* if the background content is opaque there
* is no need to plot underneath it.
*/
- if ((r.x0 >= r.x1) ||
+ if ((r.x0 >= r.x1) ||
(r.y0 >= r.y1) ||
(nscss_color_is_transparent(bgcol) == false) ||
- ((clip_box->background != NULL) &&
+ ((clip_box->background != NULL) &&
content_get_opaque(clip_box->background)))
continue;
}
@@ -1465,10 +738,12 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
if (nscss_color_is_transparent(bgcol) == false) {
*background_colour = nscss_color_to_ns(bgcol);
pstyle_fill_bg.fill_colour = *background_colour;
- if (plot_colour)
- if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1,
- &pstyle_fill_bg))
+ if (plot_colour) {
+ res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
+ }
}
/* and plot the image */
if (plot_content) {
@@ -1492,8 +767,10 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
struct content_redraw_data bg_data;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
bg_data.x = x;
bg_data.y = y;
@@ -1530,16 +807,17 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
* \param first true if this is the first rectangle associated with the inline
* \param last true if this is the last rectangle associated with the inline
* \param background_colour updated to current background colour if plotted
- * \param ctx current redraw context
+ * \param len_ctx Length conversion context
+ * \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_inline_background(int x, int y, struct box *box,
float scale, const struct rect *clip, struct rect b,
bool first, bool last, colour *background_colour,
+ const nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
struct rect r = *clip;
bool repeat_x = false;
bool repeat_y = false;
@@ -1552,6 +830,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
};
+ nserror res;
plot_content = (box->background != NULL);
@@ -1564,7 +843,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
- * bitmap is not opaque
+ * bitmap is not opaque
*/
plot_colour = !content_get_opaque(box->background);
break;
@@ -1589,15 +868,15 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
x += (b.x1 - b.x0 -
- content_get_width(box->background) *
+ content_get_width(box->background) *
scale) * FIXTOFLT(hpos) / 100.;
- if (!repeat_x && ((hpos < 2 && !first) ||
+ if (!repeat_x && ((hpos < 2 && !first) ||
(hpos > 98 && !last))){
plot_content = false;
}
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
box->style)) * scale);
}
@@ -1606,7 +885,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
content_get_height(box->background) *
scale) * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
box->style)) * scale);
}
}
@@ -1618,10 +897,12 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
*background_colour = nscss_color_to_ns(bgcol);
pstyle_fill_bg.fill_colour = *background_colour;
- if (plot_colour)
- if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1,
- &pstyle_fill_bg))
+ if (plot_colour) {
+ res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
+ }
}
/* and plot the image */
if (plot_content) {
@@ -1644,8 +925,10 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
struct content_redraw_data bg_data;
- if (!plot->clip(&r))
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
return false;
+ }
bg_data.x = x;
bg_data.y = y;
@@ -1678,28 +961,36 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
* \return true if successful, false otherwise
*/
-static bool html_redraw_text_decoration_inline(struct box *box, int x, int y,
- float scale, colour colour, float ratio,
- const struct redraw_context *ctx)
+static bool
+html_redraw_text_decoration_inline(struct box *box,
+ int x, int y,
+ float scale,
+ colour colour,
+ float ratio,
+ const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
struct box *c;
plot_style_t plot_style_box = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = colour,
};
+ nserror res;
+ struct rect rect;
for (c = box->next;
- c && c != box->inline_end;
- c = c->next) {
- if (c->type != BOX_TEXT)
+ c && c != box->inline_end;
+ c = c->next) {
+ if (c->type != BOX_TEXT) {
continue;
- if (!plot->line((x + c->x) * scale,
- (y + c->y + c->height * ratio) * scale,
- (x + c->x + c->width) * scale,
- (y + c->y + c->height * ratio) * scale,
- &plot_style_box))
+ }
+ rect.x0 = (x + c->x) * scale;
+ rect.y0 = (y + c->y + c->height * ratio) * scale;
+ rect.x1 = (x + c->x + c->width) * scale;
+ rect.y1 = (y + c->y + c->height * ratio) * scale;
+ res = ctx->plot->line(ctx, &plot_style_box, &rect);
+ if (res != NSERROR_OK) {
return false;
+ }
}
return true;
}
@@ -1718,28 +1009,34 @@ static bool html_redraw_text_decoration_inline(struct box *box, int x, int y,
* \return true if successful, false otherwise
*/
-static bool html_redraw_text_decoration_block(struct box *box, int x, int y,
- float scale, colour colour, float ratio,
- const struct redraw_context *ctx)
+static bool
+html_redraw_text_decoration_block(struct box *box,
+ int x, int y,
+ float scale,
+ colour colour,
+ float ratio,
+ const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
struct box *c;
plot_style_t plot_style_box = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = colour,
};
+ nserror res;
+ struct rect rect;
/* draw through text descendants */
for (c = box->children; c; c = c->next) {
if (c->type == BOX_TEXT) {
- if (!plot->line((x + c->x) * scale,
- (y + c->y + c->height * ratio) * scale,
- (x + c->x + c->width) * scale,
- (y + c->y + c->height * ratio) * scale,
- &plot_style_box))
+ rect.x0 = (x + c->x) * scale;
+ rect.y0 = (y + c->y + c->height * ratio) * scale;
+ rect.x1 = (x + c->x + c->width) * scale;
+ rect.y1 = (y + c->y + c->height * ratio) * scale;
+ res = ctx->plot->line(ctx, &plot_style_box, &rect);
+ if (res != NSERROR_OK) {
return false;
- } else if (c->type == BOX_INLINE_CONTAINER ||
- c->type == BOX_BLOCK) {
+ }
+ } else if ((c->type == BOX_INLINE_CONTAINER) || (c->type == BOX_BLOCK)) {
if (!html_redraw_text_decoration_block(c,
x + c->x, y + c->y,
scale, colour, ratio, ctx))
@@ -1785,7 +1082,7 @@ static bool html_redraw_text_decoration(struct box *box,
if (!box->inline_end)
return true;
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
+ if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_inline(box,
x_parent, y_parent, scale,
@@ -1793,7 +1090,7 @@ static bool html_redraw_text_decoration(struct box *box,
return false;
} else {
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
+ if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_block(box,
x_parent + box->x,
@@ -1830,7 +1127,7 @@ static bool html_redraw_text_box(const html_content *html, struct box *box,
bool excluded = (box->object != NULL);
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
fstyle.background = current_background_color;
if (!text_redraw(box->text, box->length, box->byte_offset,
@@ -1924,6 +1221,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
int padding_left, padding_top, padding_width, padding_height;
int border_left, border_top, border_right, border_bottom;
struct rect r;
+ struct rect rect;
int x_scrolled, y_scrolled;
struct box *bg_box = NULL;
bool has_x_scroll, has_y_scroll;
@@ -2067,19 +1365,21 @@ bool html_redraw_box(const html_content *html, struct box *box,
}
/* if visibility is hidden render children only */
- if (box->style && css_computed_visibility(box->style) ==
+ if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN) {
- if ((plot->group_start) && (!plot->group_start("hidden box")))
+ if ((ctx->plot->group_start) &&
+ (ctx->plot->group_start(ctx, "hidden box") != NSERROR_OK))
return false;
if (!html_redraw_box_children(html, box, x_parent, y_parent,
&r, scale, current_background_color, ctx))
return false;
- return ((!plot->group_end) || (plot->group_end()));
+ return ((!ctx->plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
}
- if ((plot->group_start) && (!plot->group_start("vis box")))
+ if ((ctx->plot->group_start) &&
+ (ctx->plot->group_start(ctx,"vis box") != NSERROR_OK)) {
return false;
-
+ }
if (box->style != NULL &&
css_computed_position(box->style) ==
@@ -2089,21 +1389,25 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* We have an absolutly positioned box with a clip rect */
if (css_rect.left_auto == false)
r.x0 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.left, css_rect.lunit,
box->style));
if (css_rect.top_auto == false)
r.y0 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.top, css_rect.tunit,
box->style));
if (css_rect.right_auto == false)
r.x1 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.right, css_rect.runit,
box->style));
if (css_rect.bottom_auto == false)
r.y1 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.bottom, css_rect.bunit,
box->style));
@@ -2115,9 +1419,10 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* Nothing to do for invalid rectangles */
if (r.x0 >= r.x1 || r.y0 >= r.y1)
/* not an error */
- return ((!plot->group_end) || (plot->group_end()));
+ return ((!ctx->plot->group_end) ||
+ (ctx->plot->group_end(ctx) == NSERROR_OK));
/* clip to it */
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
} else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
@@ -2130,14 +1435,15 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* no point trying to draw 0-width/height boxes */
if (r.x0 == r.x1 || r.y0 == r.y1)
/* not an error */
- return ((!plot->group_end) || (plot->group_end()));
+ return ((!ctx->plot->group_end) ||
+ (ctx->plot->group_end(ctx) == NSERROR_OK));
/* clip to it */
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
} else {
/* clip box is fine, clip to it */
r = *clip;
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
}
@@ -2191,25 +1497,26 @@ bool html_redraw_box(const html_content *html, struct box *box,
if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
/* plot background */
if (!html_redraw_background(x, y, box, scale, &p,
- &current_background_color, bg_box, ctx))
+ &current_background_color, bg_box,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
}
}
/* borders for block level content and replaced inlines */
- if (box->style && box->type != BOX_TEXT &&
- box->type != BOX_INLINE_END &&
- (box->type != BOX_INLINE || box->object ||
- box->flags & IFRAME || box->flags & REPLACE_DIM ||
- (box->gadget != NULL &&
- (box->gadget->type == GADGET_TEXTAREA ||
- box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD))) &&
- (border_top || border_right ||
- border_bottom || border_left)) {
+ if (box->style &&
+ box->type != BOX_TEXT &&
+ box->type != BOX_INLINE_END &&
+ (box->type != BOX_INLINE || box->object ||
+ box->flags & IFRAME || box->flags & REPLACE_DIM ||
+ (box->gadget != NULL &&
+ (box->gadget->type == GADGET_TEXTAREA ||
+ box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD))) &&
+ (border_top || border_right || border_bottom || border_left)) {
if (!html_redraw_borders(box, x_parent, y_parent,
padding_width, padding_height, &r,
scale, ctx))
@@ -2270,10 +1577,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (!html_redraw_inline_background(
x, y, box, scale, &p, b,
first, false,
- &current_background_color, ctx))
+ &current_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
if (!html_redraw_inline_borders(box, b, &r,
scale, first, false, ctx))
@@ -2302,10 +1610,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* plot background and borders for last rectangle of
* the inline */
if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
- first, true, &current_background_color, ctx))
+ first, true, &current_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
- if (!plot->clip(&r))
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
if (!html_redraw_inline_borders(box, b, &r, scale, first, true,
ctx))
@@ -2330,26 +1639,27 @@ bool html_redraw_box(const html_content *html, struct box *box,
margin_bottom = box->margin[BOTTOM] * scale;
}
/* Content edge -- blue */
- if (!plot->rectangle(x + padding_left,
- y + padding_top,
- x + padding_left + width,
- y + padding_top + height,
- plot_style_content_edge))
+ rect.x0 = x + padding_left;
+ rect.y0 = y + padding_top;
+ rect.x1 = x + padding_left + width;
+ rect.y1 = y + padding_top + height;
+ if (ctx->plot->rectangle(ctx, plot_style_content_edge, &rect) != NSERROR_OK)
return false;
+
/* Padding edge -- red */
- if (!plot->rectangle(x, y,
- x + padding_width, y + padding_height,
- plot_style_padding_edge))
+ rect.x0 = x;
+ rect.y0 = y;
+ rect.x1 = x + padding_width;
+ rect.y1 = y + padding_height;
+ if (ctx->plot->rectangle(ctx, plot_style_padding_edge, &rect) != NSERROR_OK)
return false;
+
/* Margin edge -- yellow */
- if (!plot->rectangle(
- x - border_left - margin_left,
- y - border_top - margin_top,
- x + padding_width + border_right +
- margin_right,
- y + padding_height + border_bottom +
- margin_bottom,
- plot_style_margin_edge))
+ rect.x0 = x - border_left - margin_left;
+ rect.y0 = y - border_top - margin_top;
+ rect.x1 = x + padding_width + border_right + margin_right;
+ rect.y1 = y + padding_height + border_bottom + margin_bottom;
+ if (ctx->plot->rectangle(ctx, plot_style_margin_edge, &rect) != NSERROR_OK)
return false;
}
@@ -2368,8 +1678,10 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
if (clip->y1 < r.y1) r.y1 = clip->y1;
- if (r.x1 <= r.x0 || r.y1 <= r.y0)
- return (!plot->group_end || plot->group_end());
+ if (r.x1 <= r.x0 || r.y1 <= r.y0) {
+ return (!ctx->plot->group_end ||
+ (ctx->plot->group_end(ctx) == NSERROR_OK));
+ }
need_clip = true;
} else if (overflow_x != CSS_OVERFLOW_VISIBLE) {
@@ -2379,8 +1691,10 @@ bool html_redraw_box(const html_content *html, struct box *box,
r.y1 = clip->y1;
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
- if (r.x1 <= r.x0)
- return (!plot->group_end || plot->group_end());
+ if (r.x1 <= r.x0) {
+ return (!ctx->plot->group_end ||
+ (ctx->plot->group_end(ctx) == NSERROR_OK));
+ }
need_clip = true;
} else if (overflow_y != CSS_OVERFLOW_VISIBLE) {
@@ -2390,26 +1704,30 @@ bool html_redraw_box(const html_content *html, struct box *box,
r.y1 = y + padding_height;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->y1 < r.y1) r.y1 = clip->y1;
- if (r.y1 <= r.y0)
- return (!plot->group_end || plot->group_end());
+ if (r.y1 <= r.y0) {
+ return (!ctx->plot->group_end ||
+ (ctx->plot->group_end(ctx) == NSERROR_OK));
+ }
need_clip = true;
}
- if (need_clip && (box->type == BOX_BLOCK ||
- box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->object)) {
- if (!plot->clip(&r))
+ if (need_clip &&
+ (box->type == BOX_BLOCK ||
+ box->type == BOX_INLINE_BLOCK ||
+ box->type == BOX_TABLE_CELL || box->object)) {
+ if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
return false;
}
}
/* text decoration */
- if (box->type != BOX_TEXT && box->style &&
- css_computed_text_decoration(box->style) !=
- CSS_TEXT_DECORATION_NONE)
+ if ((box->type != BOX_TEXT) &&
+ box->style &&
+ css_computed_text_decoration(box->style) != CSS_TEXT_DECORATION_NONE) {
if (!html_redraw_text_decoration(box, x_parent, y_parent,
scale, current_background_color, ctx))
return false;
+ }
if (box->object && width != 0 && height != 0) {
struct content_redraw_data obj_data;
@@ -2439,11 +1757,12 @@ bool html_redraw_box(const html_content *html, struct box *box,
int obj_x = x + padding_left;
nserror res;
- if (!plot->rectangle(x + padding_left,
- y + padding_top,
- x + padding_left + width - 1,
- y + padding_top + height - 1,
- plot_style_broken_object)) {
+ rect.x0 = x + padding_left;
+ rect.y0 = y + padding_top;
+ rect.x1 = x + padding_left + width - 1;
+ rect.y1 = y + padding_top + height - 1;
+ res = ctx->plot->rectangle(ctx, plot_style_broken_object, &rect);
+ if (res != NSERROR_OK) {
return false;
}
@@ -2457,13 +1776,12 @@ bool html_redraw_box(const html_content *html, struct box *box,
obj_x += width / 2 - obj_width / 2;
}
- if (!plot->text(obj_x, y + padding_top + (int)
- (height * 0.75),
- obj, sizeof(obj) - 1,
- plot_fstyle_broken_object))
+ if (ctx->plot->text(ctx,
+ plot_fstyle_broken_object,
+ obj_x, y + padding_top + (int)(height * 0.75),
+ obj, sizeof(obj) - 1) != NSERROR_OK)
return false;
}
-
} else if (box->iframe) {
/* Offset is passed to browser window redraw unscaled */
@@ -2484,7 +1802,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
} else if (box->gadget && box->gadget->type == GADGET_FILE) {
if (!html_redraw_file(x + padding_left, y + padding_top,
width, height, box, scale,
- current_background_color, ctx))
+ current_background_color, &html->len_ctx, ctx))
return false;
} else if (box->gadget &&
@@ -2507,11 +1825,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
- if (!plot->clip(clip))
+ if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
return false;
/* list marker */
- if (box->list_marker)
+ if (box->list_marker) {
if (!html_redraw_box(html, box->list_marker,
x_parent + box->x -
scrollbar_get_offset(box->scroll_x),
@@ -2519,6 +1837,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
scrollbar_get_offset(box->scroll_y),
clip, scale, current_background_color, ctx))
return false;
+ }
/* scrollbars */
if (((box->style && box->type != BOX_BR &&
@@ -2536,11 +1855,11 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (!box_handle_scrollbars((struct content *)html,
box, has_x_scroll, has_y_scroll))
return false;
-
+
if (box->scroll_x != NULL)
scrollbar_redraw(box->scroll_x,
x_parent + box->x,
- y_parent + box->y + box->padding[TOP] +
+ y_parent + box->y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH, clip, scale, ctx);
if (box->scroll_y != NULL)
@@ -2552,11 +1871,12 @@ bool html_redraw_box(const html_content *html, struct box *box,
}
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
- if (!plot->clip(clip))
+ box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) {
+ if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
return false;
+ }
- return ((!plot->group_end) || (plot->group_end()));
+ return ((!plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
}
/**
@@ -2599,18 +1919,16 @@ bool html_redraw(struct content *c, struct content_redraw_data *data,
select_only = form_clip_inside_select_menu(control,
data->scale, clip);
}
-
+
if (!select_only) {
/* clear to background colour */
- result = ctx->plot->clip(clip);
-
+ result = (ctx->plot->clip(ctx, clip) == NSERROR_OK);
+
if (html->background_colour != NS_TRANSPARENT)
pstyle_fill_bg.fill_colour = html->background_colour;
-
- result &= ctx->plot->rectangle(clip->x0, clip->y0,
- clip->x1, clip->y1,
- &pstyle_fill_bg);
-
+
+ result &= (ctx->plot->rectangle(ctx, &pstyle_fill_bg, clip) == NSERROR_OK);
+
result &= html_redraw_box(html, box, data->x, data->y, clip,
data->scale, pstyle_fill_bg.fill_colour, ctx);
}
@@ -2619,7 +1937,7 @@ bool html_redraw(struct content *c, struct content_redraw_data *data,
int menu_x, menu_y;
box = html->visible_select_menu->box;
box_coords(box, &menu_x, &menu_y);
-
+
menu_x -= box->border[LEFT].width;
menu_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] + box->padding[TOP];
diff --git a/content/handlers/html/html_redraw_border.c b/content/handlers/html/html_redraw_border.c
new file mode 100644
index 000000000..0b3d858e6
--- /dev/null
+++ b/content/handlers/html/html_redraw_border.c
@@ -0,0 +1,928 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * Redrawing CONTENT_HTML borders implementation.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "utils/log.h"
+#include "netsurf/plotters.h"
+#include "netsurf/css.h"
+
+#include "html/box.h"
+#include "html/html_internal.h"
+
+
+static plot_style_t plot_style_bdr = {
+ .stroke_type = PLOT_OP_TYPE_DASH,
+};
+static plot_style_t plot_style_fillbdr = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+static plot_style_t plot_style_fillbdr_dark = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+static plot_style_t plot_style_fillbdr_light = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+static plot_style_t plot_style_fillbdr_ddark = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+static plot_style_t plot_style_fillbdr_dlight = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+
+
+static inline nserror
+plot_clipped_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *clip,
+ struct rect *rect)
+{
+ nserror res;
+
+ rect->x0 = (clip->x0 > rect->x0) ? clip->x0 : rect->x0;
+ rect->y0 = (clip->y0 > rect->y0) ? clip->y0 : rect->y0;
+ rect->x1 = (clip->x1 < rect->x1) ? clip->x1 : rect->x1;
+ rect->y1 = (clip->y1 < rect->y1) ? clip->y1 : rect->y1;
+ if ((rect->x0 < rect->x1) && (rect->y0 < rect->y1)) {
+ /* valid clip rectangles only */
+ res = ctx->plot->rectangle(ctx, style, rect);
+ } else {
+ res = NSERROR_OK;
+ }
+ return res;
+}
+
+
+/**
+ * Draw one border.
+ *
+ * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT)
+ * \param p array of precomputed border vertices
+ * \param c colour for border
+ * \param style border line style
+ * \param thickness border thickness
+ * \param rectangular whether border is rectangular
+ * \param clip cliping area for redrawing border.
+ * \param ctx current redraw context
+ * \return NSERROR_OK if successful otherwise appropriate error code
+ */
+static nserror
+html_redraw_border_plot(const int side,
+ const int *p,
+ colour c,
+ enum css_border_style_e style,
+ int thickness,
+ bool rectangular,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ int z[8]; /* Vertices of border part */
+ unsigned int light = side;
+ plot_style_t *plot_style_bdr_in;
+ plot_style_t *plot_style_bdr_out;
+ nserror res = NSERROR_OK;
+ struct rect rect;
+
+ if (c == NS_TRANSPARENT) {
+ return res;
+ }
+
+ plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH;
+ plot_style_bdr.stroke_colour = c;
+ plot_style_bdr.stroke_width = (thickness << PLOT_STYLE_RADIX);
+ plot_style_fillbdr.fill_colour = c;
+ plot_style_fillbdr_dark.fill_colour = darken_colour(c);
+ plot_style_fillbdr_light.fill_colour = lighten_colour(c);
+ plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c);
+ plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c);
+
+ switch (style) {
+ case CSS_BORDER_STYLE_DOTTED:
+ plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT;
+ /* fall through */
+ case CSS_BORDER_STYLE_DASHED:
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = (p[4] + p[6]) / 2;
+ rect.y1 = (p[5] + p[7]) / 2;
+ res = ctx->plot->line(ctx, &plot_style_bdr, &rect);
+ break;
+
+ case CSS_BORDER_STYLE_SOLID:
+ /* fall through to default */
+ default:
+ if (rectangular || thickness == 1) {
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ if ((side == TOP) &&
+ (p[4] - p[6] != 0)) {
+ rect.x1 = p[4];
+ } else {
+ rect.x1 = p[6];
+ }
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ if ((side == LEFT) &&
+ (p[1] - p[3] != 0)) {
+ rect.y1 = p[1];
+ } else {
+ rect.y1 = p[3];
+ }
+ }
+ res = plot_clipped_rectangle(ctx,
+ &plot_style_fillbdr,
+ clip,
+ &rect);
+ } else {
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4);
+ }
+ break;
+
+ case CSS_BORDER_STYLE_DOUBLE:
+ z[0] = p[0];
+ z[1] = p[1];
+ z[2] = (p[0] * 2 + p[2]) / 3;
+ z[3] = (p[1] * 2 + p[3]) / 3;
+ z[4] = (p[6] * 2 + p[4]) / 3;
+ z[5] = (p[7] * 2 + p[5]) / 3;
+ z[6] = p[6];
+ z[7] = p[7];
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
+ if (res == NSERROR_OK) {
+ z[0] = p[2];
+ z[1] = p[3];
+ z[2] = (p[2] * 2 + p[0]) / 3;
+ z[3] = (p[3] * 2 + p[1]) / 3;
+ z[4] = (p[4] * 2 + p[6]) / 3;
+ z[5] = (p[5] * 2 + p[7]) / 3;
+ z[6] = p[4];
+ z[7] = p[5];
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
+ }
+ break;
+
+ case CSS_BORDER_STYLE_GROOVE:
+ light = 3 - light;
+ /* fall through */
+ case CSS_BORDER_STYLE_RIDGE:
+ /* choose correct colours for each part of the border line */
+ if (light <= 1) {
+ plot_style_bdr_in = &plot_style_fillbdr_dark;
+ plot_style_bdr_out = &plot_style_fillbdr_light;
+ } else {
+ plot_style_bdr_in = &plot_style_fillbdr_light;
+ plot_style_bdr_out = &plot_style_fillbdr_dark;
+ }
+
+ /* Render border */
+ if ((rectangular || thickness == 2) && thickness != 1) {
+ /* Border made up from two parts and can be
+ * plotted with rectangles
+ */
+
+ /* First part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = (p[0] + p[2]) / 2;
+ rect.y1 = (p[1] + p[3]) / 2;
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Second part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = (p[6] + p[4]) / 2;
+ rect.y1 = (p[7] + p[5]) / 2;
+ } else {
+ rect.x0 = (p[6] + p[4]) / 2;
+ rect.y0 = (p[7] + p[5]) / 2;
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ } else if (thickness == 1) {
+ /* Border made up from one part which can be
+ * plotted as a rectangle
+ */
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
+ rect.x1 + p[4] - p[6] : rect.x1;
+
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
+ rect.y1 + p[1] - p[3] : rect.y1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ }
+ } else {
+ /* Border made up from two parts and can't be
+ * plotted with rectangles
+ */
+ z[0] = p[0];
+ z[1] = p[1];
+ z[2] = (p[0] + p[2]) / 2;
+ z[3] = (p[1] + p[3]) / 2;
+ z[4] = (p[6] + p[4]) / 2;
+ z[5] = (p[7] + p[5]) / 2;
+ z[6] = p[6];
+ z[7] = p[7];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
+ if (res == NSERROR_OK) {
+ z[0] = p[2];
+ z[1] = p[3];
+ z[6] = p[4];
+ z[7] = p[5];
+ res = ctx->plot->polygon(ctx,
+ plot_style_bdr_out,
+ z,
+ 4);
+ }
+ }
+ break;
+
+ case CSS_BORDER_STYLE_INSET:
+ light = (light + 2) % 4;
+ /* fall through */
+ case CSS_BORDER_STYLE_OUTSET:
+ /* choose correct colours for each part of the border line */
+ switch (light) {
+ case 0:
+ plot_style_bdr_in = &plot_style_fillbdr_light;
+ plot_style_bdr_out = &plot_style_fillbdr_dlight;
+ break;
+ case 1:
+ plot_style_bdr_in = &plot_style_fillbdr_ddark;
+ plot_style_bdr_out = &plot_style_fillbdr_dark;
+ break;
+ case 2:
+ plot_style_bdr_in = &plot_style_fillbdr_dark;
+ plot_style_bdr_out = &plot_style_fillbdr_ddark;
+ break;
+ case 3:
+ plot_style_bdr_in = &plot_style_fillbdr_dlight;
+ plot_style_bdr_out = &plot_style_fillbdr_light;
+ break;
+ default:
+ plot_style_bdr_in = &plot_style_fillbdr;
+ plot_style_bdr_out = &plot_style_fillbdr;
+ break;
+ }
+
+ /* Render border */
+ if ((rectangular || thickness == 2) && thickness != 1) {
+ /* Border made up from two parts and can be
+ * plotted with rectangles
+ */
+
+ /* First part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = (p[0] + p[2]) / 2;
+ rect.y1 = (p[1] + p[3]) / 2;
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Second part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = (p[6] + p[4]) / 2;
+ rect.y1 = (p[7] + p[5]) / 2;
+ } else {
+ rect.x0 = (p[6] + p[4]) / 2;
+ rect.y0 = (p[7] + p[5]) / 2;
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ } else if (thickness == 1) {
+ /* Border made up from one part which can be
+ * plotted as a rectangle
+ */
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
+ rect.x1 + p[4] - p[6] : rect.x1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
+ rect.y1 + p[1] - p[3] : rect.y1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ }
+ } else {
+ /* Border made up from two parts and can't be
+ * plotted with rectangles
+ */
+
+ z[0] = p[0];
+ z[1] = p[1];
+ z[2] = (p[0] + p[2]) / 2;
+ z[3] = (p[1] + p[3]) / 2;
+ z[4] = (p[6] + p[4]) / 2;
+ z[5] = (p[7] + p[5]) / 2;
+ z[6] = p[6];
+ z[7] = p[7];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ z[0] = p[2];
+ z[1] = p[3];
+ z[6] = p[4];
+ z[7] = p[5];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
+ }
+ break;
+ }
+
+ return res;
+}
+
+
+/**
+ * Draw borders for a box.
+ *
+ * \param box box to draw
+ * \param x_parent coordinate of left padding edge of parent of box
+ * \param y_parent coordinate of top padding edge of parent of box
+ * \param p_width width of padding box
+ * \param p_height height of padding box
+ * \param clip cliping area for redrawing border.
+ * \param scale scale for redraw
+ * \param ctx current redraw context
+ * \return true if successful, false otherwise
+ */
+bool
+html_redraw_borders(struct box *box,
+ int x_parent,
+ int y_parent,
+ int p_width,
+ int p_height,
+ const struct rect *clip,
+ float scale,
+ const struct redraw_context *ctx)
+{
+ unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ int x, y;
+ unsigned int i, side;
+ int p[8]; /* Box border vertices */
+ int z[8]; /* Border vertices */
+ bool square_end_1 = false;
+ bool square_end_2 = false;
+ nserror res;
+
+ x = x_parent + box->x;
+ y = y_parent + box->y;
+
+ if (scale != 1.0) {
+ top *= scale;
+ right *= scale;
+ bottom *= scale;
+ left *= scale;
+ x *= scale;
+ y *= scale;
+ }
+
+ assert(box->style);
+
+ /* Calculate border vertices
+ *
+ * A----------------------+
+ * | \ / |
+ * | B--------------+ |
+ * | | | |
+ * | +--------------C |
+ * | / \ |
+ * +----------------------D
+ */
+ p[0] = x - left; p[1] = y - top; /* A */
+ p[2] = x; p[3] = y; /* B */
+ p[4] = x + p_width; p[5] = y + p_height; /* C */
+ p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
+
+ for (i = 0; i != 4; i++) {
+ colour col = 0;
+ side = sides[i]; /* plot order */
+
+ if (box->border[side].width == 0 ||
+ nscss_color_is_transparent(box->border[side].c)) {
+ continue;
+ }
+
+ switch (side) {
+ case LEFT:
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+
+ z[0] = p[0]; z[1] = p[7];
+ z[2] = p[2]; z[3] = p[5];
+ z[4] = p[2]; z[5] = p[3];
+ z[6] = p[0]; z[7] = p[1];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[5] -= top;
+ square_end_1 = true;
+ }
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[3] += bottom;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case RIGHT:
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+
+ z[0] = p[6]; z[1] = p[1];
+ z[2] = p[4]; z[3] = p[3];
+ z[4] = p[4]; z[5] = p[5];
+ z[6] = p[6]; z[7] = p[7];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[3] -= top;
+ square_end_1 = true;
+ }
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[5] += bottom;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case TOP:
+ if (clip->y0 > p[3]) {
+ /* clip rectangle is below border; nothing to
+ * plot
+ */
+ continue;
+ }
+
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+
+ z[0] = p[2]; z[1] = p[3];
+ z[2] = p[0]; z[3] = p[1];
+ z[4] = p[6]; z[5] = p[1];
+ z[6] = p[4]; z[7] = p[3];
+
+ if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[2] += left;
+ square_end_1 = true;
+ }
+ if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[4] -= right;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case BOTTOM:
+ if (clip->y1 < p[5]) {
+ /* clip rectangle is above border; nothing to
+ * plot
+ */
+ continue;
+ }
+
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+
+ z[0] = p[4]; z[1] = p[5];
+ z[2] = p[6]; z[3] = p[7];
+ z[4] = p[0]; z[5] = p[7];
+ z[6] = p[2]; z[7] = p[5];
+
+ if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[4] += left;
+ square_end_1 = true;
+ }
+ if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[2] -= right;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ default:
+ assert(side == TOP || side == BOTTOM ||
+ side == LEFT || side == RIGHT);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Draw an inline's borders.
+ *
+ * \param box BOX_INLINE which created the border
+ * \param b coordinates of border edge rectangle
+ * \param clip cliping area for redrawing border.
+ * \param scale scale for redraw
+ * \param first true if this is the first rectangle associated with the inline
+ * \param last true if this is the last rectangle associated with the inline
+ * \param ctx current redraw context
+ * \return true if successful, false otherwise
+ */
+bool
+html_redraw_inline_borders(struct box *box,
+ struct rect b,
+ const struct rect *clip,
+ float scale,
+ bool first,
+ bool last,
+ const struct redraw_context *ctx)
+{
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ colour col;
+ int p[8]; /* Box border vertices */
+ int z[8]; /* Border vertices */
+ bool square_end_1;
+ bool square_end_2;
+ nserror res;
+
+ if (scale != 1.0) {
+ top *= scale;
+ right *= scale;
+ bottom *= scale;
+ left *= scale;
+ }
+
+ /* Calculate border vertices
+ *
+ * A----------------------+
+ * | \ / |
+ * | B--------------+ |
+ * | | | |
+ * | +--------------C |
+ * | / \ |
+ * +----------------------D
+ */
+ p[0] = b.x0; p[1] = b.y0; /* A */
+ p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
+ p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
+ p[6] = b.x1; p[7] = b.y1; /* D */
+
+ assert(box->style);
+
+ /* Left */
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+ if (left != 0 &&
+ first &&
+ nscss_color_is_transparent(box->border[LEFT].c) == false) {
+ col = nscss_color_to_ns(box->border[LEFT].c);
+
+ z[0] = p[0]; z[1] = p[7];
+ z[2] = p[2]; z[3] = p[5];
+ z[4] = p[2]; z[5] = p[3];
+ z[6] = p[0]; z[7] = p[1];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[5] -= top;
+ square_end_1 = true;
+ }
+
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[3] += bottom;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(LEFT,
+ z,
+ col,
+ box->border[LEFT].style,
+ left,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Right */
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+ if (right != 0 &&
+ last &&
+ nscss_color_is_transparent(box->border[RIGHT].c) == false) {
+ col = nscss_color_to_ns(box->border[RIGHT].c);
+
+ z[0] = p[6]; z[1] = p[1];
+ z[2] = p[4]; z[3] = p[3];
+ z[4] = p[4]; z[5] = p[5];
+ z[6] = p[6]; z[7] = p[7];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[3] -= top;
+ square_end_1 = true;
+ }
+
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[5] += bottom;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(RIGHT,
+ z,
+ col,
+ box->border[RIGHT].style,
+ right,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Top */
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+ if (top != 0 &&
+ nscss_color_is_transparent(box->border[TOP].c) == false) {
+ col = nscss_color_to_ns(box->border[TOP].c);
+
+ z[0] = p[2]; z[1] = p[3];
+ z[2] = p[0]; z[3] = p[1];
+ z[4] = p[6]; z[5] = p[1];
+ z[6] = p[4]; z[7] = p[3];
+
+ if (first &&
+ box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[2] += left;
+ square_end_1 = true;
+ }
+
+ if (last &&
+ box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[4] -= right;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(TOP,
+ z,
+ col,
+ box->border[TOP].style,
+ top,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Bottom */
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+ if (bottom != 0 &&
+ nscss_color_is_transparent(box->border[BOTTOM].c) == false) {
+ col = nscss_color_to_ns(box->border[BOTTOM].c);
+
+ z[0] = p[4]; z[1] = p[5];
+ z[2] = p[6]; z[3] = p[7];
+ z[4] = p[0]; z[5] = p[7];
+ z[6] = p[2]; z[7] = p[5];
+
+ if (first &&
+ box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[4] += left;
+ square_end_1 = true;
+ }
+
+ if (last &&
+ box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[2] -= right;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(BOTTOM,
+ z,
+ col,
+ box->border[BOTTOM].style,
+ bottom,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/content/handlers/html/html_save.h b/content/handlers/html/html_save.h
new file mode 100644
index 000000000..c173922d5
--- /dev/null
+++ b/content/handlers/html/html_save.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to HTML content handler to save documents.
+ *
+ * \todo Investigate altering this API as it is only used for
+ * exporting the html content to disc.
+ */
+
+#ifndef NETSURF_HTML_HTML_SAVE_H
+#define NETSURF_HTML_HTML_SAVE_H
+
+/**
+ * get the dom document of a html content from a handle
+ */
+dom_document *html_get_document(struct hlcache_handle *h);
+
+
+/**
+ * get the render box tree of a html content from a handle
+ */
+struct box *html_get_box_tree(struct hlcache_handle *h);
+
+/**
+ * get the base url of an html content from a handle
+ */
+struct nsurl *html_get_base_url(struct hlcache_handle *h);
+
+#endif
diff --git a/render/html_script.c b/content/handlers/html/html_script.c
index 37b0564d7..80992b9dd 100644
--- a/render/html_script.c
+++ b/content/handlers/html/html_script.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for text/html scripts (implementation).
+/**
+ * \file
+ * implementation of content handling for text/html scripts.
*/
#include <assert.h>
@@ -38,7 +39,8 @@
#include "content/fetch.h"
#include "content/hlcache.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ;
@@ -52,7 +54,7 @@ static script_handler_t *select_script_handler(content_type ctype)
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_exec(html_content *c)
{
unsigned int i;
@@ -96,7 +98,7 @@ nserror html_script_exec(html_content *c)
s->already_started = true;
- }
+ }
}
}
@@ -105,8 +107,8 @@ nserror html_script_exec(html_content *c)
/* create new html script entry */
static struct html_script *
-html_process_new_script(html_content *c,
- dom_string *mimetype,
+html_process_new_script(html_content *c,
+ dom_string *mimetype,
enum html_script_type type)
{
struct html_script *nscript;
@@ -165,18 +167,24 @@ convert_script_async_cb(hlcache_handle *script,
break;
case CONTENT_MSG_DONE:
- LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script)));
+ NSLOG(netsurf, INFO, "script %d done '%s'", i,
+ nsurl_access(hlcache_handle_get_url(script)));
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
break;
case CONTENT_MSG_ERROR:
- LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error);
+ NSLOG(netsurf, INFO, "script %s failed: %s",
+ nsurl_access(hlcache_handle_get_url(script)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
content_add_error(&parent->base, "?", 0);
break;
@@ -218,18 +226,24 @@ convert_script_defer_cb(hlcache_handle *script,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script)));
+ NSLOG(netsurf, INFO, "script %d done '%s'", i,
+ nsurl_access(hlcache_handle_get_url(script)));
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
break;
case CONTENT_MSG_ERROR:
- LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error);
+ NSLOG(netsurf, INFO, "script %s failed: %s",
+ nsurl_access(hlcache_handle_get_url(script)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
content_add_error(&parent->base, "?", 0);
break;
@@ -272,9 +286,10 @@ convert_script_sync_cb(hlcache_handle *script,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script)));
+ NSLOG(netsurf, INFO, "script %d done '%s'", i,
+ nsurl_access(hlcache_handle_get_url(script)));
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
s->already_started = true;
@@ -291,19 +306,23 @@ convert_script_sync_cb(hlcache_handle *script,
/* continue parse */
err = dom_hubbub_parser_pause(parent->parser, false);
if (err != DOM_HUBBUB_OK) {
- LOG("unpause returned 0x%x", err);
- }
+ NSLOG(netsurf, INFO, "unpause returned 0x%x", err);
+ }
break;
case CONTENT_MSG_ERROR:
- LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error);
+ NSLOG(netsurf, INFO, "script %s failed: %s",
+ nsurl_access(hlcache_handle_get_url(script)),
+ event->data.error);
+ /* fall through */
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
- LOG("%d fetches active", parent->base.active);
+ NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
content_add_error(&parent->base, "?", 0);
s->already_started = true;
@@ -311,8 +330,8 @@ convert_script_sync_cb(hlcache_handle *script,
/* continue parse */
err = dom_hubbub_parser_pause(parent->parser, false);
if (err != DOM_HUBBUB_OK) {
- LOG("unpause returned 0x%x", err);
- }
+ NSLOG(netsurf, INFO, "unpause returned 0x%x", err);
+ }
break;
@@ -343,7 +362,6 @@ exec_src_script(html_content *c,
nsurl *joined;
hlcache_child_context child;
struct html_script *nscript;
- union content_msg_data msg_data;
bool async;
bool defer;
enum html_script_type script_type;
@@ -354,21 +372,21 @@ exec_src_script(html_content *c,
/* src url */
ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
if (ns_error != NSERROR_OK) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return DOM_HUBBUB_NOMEM;
}
- LOG("script %i '%s'", c->scripts_count, nsurl_access(joined));
+ NSLOG(netsurf, INFO, "script %i '%s'", c->scripts_count,
+ nsurl_access(joined));
/* there are three ways to process the script tag at this point:
*
* Syncronously pause the parent parse and continue after
* the script has downloaded and executed. (default)
- * Async Start the script downloading and execute it when it
- * becomes available.
- * Defered Start the script downloading and execute it when
- * the page has completed parsing, may be set along
+ * Async Start the script downloading and execute it when it
+ * becomes available.
+ * Defered Start the script downloading and execute it when
+ * the page has completed parsing, may be set along
* with async where it is ignored.
*/
@@ -377,7 +395,7 @@ exec_src_script(html_content *c,
* value or the attribute name itself are valid. However
* various browsers interpret this in various ways the most
* compatible approach is to be liberal and accept any
- * value. Note setting the values to "false" still makes them true!
+ * value. Note setting the values to "false" still makes them true!
*/
exc = dom_element_has_attribute(node, corestring_dom_async, &async);
if (exc != DOM_NO_ERR) {
@@ -390,7 +408,7 @@ exec_src_script(html_content *c,
script_cb = convert_script_async_cb;
} else {
- exc = dom_element_has_attribute(node,
+ exc = dom_element_has_attribute(node,
corestring_dom_defer, &defer);
if (exc != DOM_NO_ERR) {
return DOM_HUBBUB_OK; /* dom error */
@@ -410,8 +428,7 @@ exec_src_script(html_content *c,
nscript = html_process_new_script(c, mimetype, script_type);
if (nscript == NULL) {
nsurl_unref(joined);
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return DOM_HUBBUB_NOMEM;
}
@@ -434,15 +451,15 @@ exec_src_script(html_content *c,
if (ns_error != NSERROR_OK) {
/* @todo Deal with fetch error better. currently assume
- * fetch never became active
+ * fetch never became active
*/
/* mark duff script fetch as already started */
- nscript->already_started = true;
- LOG("Fetch failed with error %d", ns_error);
+ nscript->already_started = true;
+ NSLOG(netsurf, INFO, "Fetch failed with error %d", ns_error);
} else {
/* update base content active fetch count */
- c->base.active++;
- LOG("%d fetches active", c->base.active);
+ c->base.active++;
+ NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
switch (script_type) {
case HTML_SCRIPT_SYNC:
@@ -465,7 +482,6 @@ exec_src_script(html_content *c,
static dom_hubbub_error
exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype)
{
- union content_msg_data msg_data;
dom_string *script;
dom_exception exc; /* returned by libdom functions */
struct lwc_string_s *lwcmimetype;
@@ -482,8 +498,7 @@ exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype)
if (nscript == NULL) {
dom_string_unref(script);
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return DOM_HUBBUB_NOMEM;
}
@@ -526,15 +541,16 @@ html_process_script(void *ctx, dom_node *node)
union content_msg_data msg_data;
msg_data.jscontext = &c->jscontext;
- content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data);
- LOG("javascript context %p ", c->jscontext);
+ content_broadcast(&c->base, CONTENT_MSG_GETCTX, &msg_data);
+ NSLOG(netsurf, INFO, "javascript context %p ", c->jscontext);
if (c->jscontext == NULL) {
/* no context and it could not be created, abort */
return DOM_HUBBUB_OK;
}
}
- LOG("content %p parser %p node %p", c, c->parser, node);
+ NSLOG(netsurf, INFO, "content %p parser %p node %p", c, c->parser,
+ node);
exc = dom_element_get_attribute(node, corestring_dom_type, &mimetype);
if (exc != DOM_NO_ERR || mimetype == NULL) {
@@ -554,7 +570,7 @@ html_process_script(void *ctx, dom_node *node)
return err;
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_free(html_content *html)
{
unsigned int i;
@@ -581,7 +597,7 @@ nserror html_script_free(html_content *html)
return NSERROR_OK;
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_invalidate_ctx(html_content *htmlc)
{
htmlc->jscontext = NULL;
diff --git a/render/imagemap.c b/content/handlers/html/imagemap.c
index 6e2504bdc..5f4dd54b3 100644
--- a/render/imagemap.c
+++ b/content/handlers/html/imagemap.c
@@ -16,8 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * Much of this shamelessly copied from utils/messages.c
+/**
+ * \file
+ * Implementation of HTML image maps
+ *
+ * \todo should this should use the general hashmap instead of its own
*/
#include <assert.h>
@@ -32,9 +35,9 @@
#include "content/content_protected.h"
#include "content/hlcache.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/imagemap.h"
#define HASH_SIZE 31 /* fixed size hash table */
@@ -241,21 +244,35 @@ void imagemap_dump(html_content *c)
map = c->imagemaps[i];
while (map != NULL) {
- LOG("Imagemap: %s", map->key);
+ NSLOG(netsurf, INFO, "Imagemap: %s", map->key);
for (entry = map->list; entry; entry = entry->next) {
switch (entry->type) {
case IMAGEMAP_DEFAULT:
- LOG("\tDefault: %s", nsurl_access(entry->url));
+ NSLOG(netsurf, INFO, "\tDefault: %s",
+ nsurl_access(entry->url));
break;
case IMAGEMAP_RECT:
- LOG("\tRectangle: %s: [(%d,%d),(%d,%d)]", nsurl_access(entry->url), entry->bounds.rect.x0, entry->bounds.rect.y0, entry->bounds.rect.x1, entry->bounds.rect.y1);
+ NSLOG(netsurf, INFO,
+ "\tRectangle: %s: [(%d,%d),(%d,%d)]",
+ nsurl_access(entry->url),
+ entry->bounds.rect.x0,
+ entry->bounds.rect.y0,
+ entry->bounds.rect.x1,
+ entry->bounds.rect.y1);
break;
case IMAGEMAP_CIRCLE:
- LOG("\tCircle: %s: [(%d,%d),%d]", nsurl_access(entry->url), entry->bounds.circle.x, entry->bounds.circle.y, entry->bounds.circle.r);
+ NSLOG(netsurf, INFO,
+ "\tCircle: %s: [(%d,%d),%d]",
+ nsurl_access(entry->url),
+ entry->bounds.circle.x,
+ entry->bounds.circle.y,
+ entry->bounds.circle.r);
break;
case IMAGEMAP_POLY:
- LOG("\tPolygon: %s:", nsurl_access(entry->url));
+ NSLOG(netsurf, INFO,
+ "\tPolygon: %s:",
+ nsurl_access(entry->url));
for (j = 0; j != entry->bounds.poly.num;
j++) {
fprintf(stderr, "(%d,%d) ",
diff --git a/render/imagemap.h b/content/handlers/html/imagemap.h
index 3ae6819da..8e189a072 100644
--- a/render/imagemap.h
+++ b/content/handlers/html/imagemap.h
@@ -16,8 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _NETSURF_RENDER_IMAGEMAP_H_
-#define _NETSURF_RENDER_IMAGEMAP_H_
+/**
+ * \file
+ * Interface to HTML imagemap
+ */
+
+#ifndef NETSURF_HTML_IMAGEMAP_H
+#define NETSURF_HTML_IMAGEMAP_H
#include <dom/dom.h>
diff --git a/render/layout.c b/content/handlers/html/layout.c
index c92089f63..ee1212861 100644
--- a/render/layout.c
+++ b/content/handlers/html/layout.c
@@ -47,6 +47,7 @@
#include "utils/talloc.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
+#include "netsurf/inttypes.h"
#include "netsurf/content.h"
#include "netsurf/browser_window.h"
#include "netsurf/layout.h"
@@ -55,25 +56,78 @@
#include "desktop/scrollbar.h"
#include "desktop/textarea.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/table.h"
-
-
-/* Define to enable layout debugging */
-#undef LAYOUT_DEBUG
+#include "html/html.h"
+#include "html/html_save.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/layout.h"
+#include "html/table.h"
#define AUTO INT_MIN
/* Fixed point percentage (a) of an integer (b), to an integer */
#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
+typedef uint8_t (*css_len_func)(
+ const css_computed_style *style,
+ css_fixed *length, css_unit *unit);
+typedef uint8_t (*css_border_style_func)(
+ const css_computed_style *style);
+typedef uint8_t (*css_border_color_func)(
+ const css_computed_style *style,
+ css_color *color);
+
+/** Array of per-side access functions for computed style margins. */
+static const css_len_func margin_funcs[4] = {
+ [TOP] = css_computed_margin_top,
+ [RIGHT] = css_computed_margin_right,
+ [BOTTOM] = css_computed_margin_bottom,
+ [LEFT] = css_computed_margin_left,
+};
+
+/** Array of per-side access functions for computed style paddings. */
+static const css_len_func padding_funcs[4] = {
+ [TOP] = css_computed_padding_top,
+ [RIGHT] = css_computed_padding_right,
+ [BOTTOM] = css_computed_padding_bottom,
+ [LEFT] = css_computed_padding_left,
+};
+
+/** Array of per-side access functions for computed style border_widths. */
+static const css_len_func border_width_funcs[4] = {
+ [TOP] = css_computed_border_top_width,
+ [RIGHT] = css_computed_border_right_width,
+ [BOTTOM] = css_computed_border_bottom_width,
+ [LEFT] = css_computed_border_left_width,
+};
+
+/** Array of per-side access functions for computed style border styles. */
+static const css_border_style_func border_style_funcs[4] = {
+ [TOP] = css_computed_border_top_style,
+ [RIGHT] = css_computed_border_right_style,
+ [BOTTOM] = css_computed_border_bottom_style,
+ [LEFT] = css_computed_border_left_style,
+};
+
+/** Array of per-side access functions for computed style border colors. */
+static const css_border_color_func border_color_funcs[4] = {
+ [TOP] = css_computed_border_top_color,
+ [RIGHT] = css_computed_border_right_color,
+ [BOTTOM] = css_computed_border_bottom_color,
+ [LEFT] = css_computed_border_left_color,
+};
+
/* forward declaration to break cycles */
-static bool layout_block_context(struct box *block, int viewport_height, html_content *content);
-static void layout_minmax_block(struct box *block, const struct gui_layout_table *font_func);
+static bool layout_block_context(
+ struct box *block,
+ int viewport_height,
+ html_content *content);
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content);
/**
@@ -182,7 +236,9 @@ layout_get_object_dimensions(struct box *box,
* \param width width of containing block
* \return length of indent
*/
-static int layout_text_indent(const css_computed_style *style, int width)
+static int layout_text_indent(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *style, int width)
{
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
@@ -192,7 +248,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
if (unit == CSS_UNIT_PCT) {
return FPCT_OF_INT_TOINT(value, width);
} else {
- return FIXTOINT(nscss_len2px(value, unit, style));
+ return FIXTOINT(nscss_len2px(len_ctx, value, unit, style));
}
}
@@ -200,6 +256,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
/**
* Determine width of margin, borders, and padding on one side of a box.
*
+ * \param len_ctx CSS length conversion context for document
* \param style style to measure
* \param side side of box to measure
* \param margin whether margin width is required
@@ -209,7 +266,8 @@ static int layout_text_indent(const css_computed_style *style, int width)
* \param frac increased by sum of fractional margin and padding
*/
static void
-calculate_mbp_width(const css_computed_style *style,
+calculate_mbp_width(const nscss_len_ctx *len_ctx,
+ const css_computed_style *style,
unsigned int side,
bool margin,
bool border,
@@ -217,35 +275,6 @@ calculate_mbp_width(const css_computed_style *style,
int *fixed,
float *frac)
{
- typedef uint8_t (*len_func)(const css_computed_style *style,
- css_fixed *length, css_unit *unit);
-
- static len_func margin_funcs[4] = {
- css_computed_margin_top,
- css_computed_margin_right,
- css_computed_margin_bottom,
- css_computed_margin_left
- };
- static len_func padding_funcs[4] = {
- css_computed_padding_top,
- css_computed_padding_right,
- css_computed_padding_bottom,
- css_computed_padding_left
- };
- static struct {
- len_func width;
- uint8_t (*style)(const css_computed_style *style);
- } border_funcs[4] = {
- { css_computed_border_top_width,
- css_computed_border_top_style },
- { css_computed_border_right_width,
- css_computed_border_right_style },
- { css_computed_border_bottom_width,
- css_computed_border_bottom_style },
- { css_computed_border_left_width,
- css_computed_border_left_style }
- };
-
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
@@ -260,19 +289,20 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit,
- style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
}
/* border */
if (border) {
- if (border_funcs[side].style(style) !=
+ if (border_style_funcs[side](style) !=
CSS_BORDER_STYLE_NONE) {
- border_funcs[side].width(style, &value, &unit);
+ border_width_funcs[side](style, &value, &unit);
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -282,13 +312,218 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
}
/**
+ * Calculate minimum and maximum width of a table.
+ *
+ * \param table box of type TABLE
+ * \param font_func Font functions
+ * \param content The HTML content we are laying out.
+ * \post table->min_width and table->max_width filled in,
+ * 0 <= table->min_width <= table->max_width
+ */
+static void layout_minmax_table(struct box *table,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
+{
+ unsigned int i, j;
+ int border_spacing_h = 0;
+ int table_min = 0, table_max = 0;
+ int extra_fixed = 0;
+ float extra_frac = 0;
+ struct column *col;
+ struct box *row_group, *row, *cell;
+ enum css_width_e wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ /* check if the widths have already been calculated */
+ if (table->max_width != UNKNOWN_MAX_WIDTH)
+ return;
+
+ if (table_calculate_column_types(&content->len_ctx, table) == false) {
+ NSLOG(netsurf, WARNING,
+ "Could not establish table column types.");
+ return;
+ }
+ col = table->col;
+
+ /* start with 0 except for fixed-width columns */
+ for (i = 0; i != table->columns; i++) {
+ if (col[i].type == COLUMN_WIDTH_FIXED)
+ col[i].min = col[i].max = col[i].width;
+ else
+ col[i].min = col[i].max = 0;
+ }
+
+ /* border-spacing is used in the separated borders model */
+ if (css_computed_border_collapse(table->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
+ css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
+
+ border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+ h, hu, table->style));
+ }
+
+ /* 1st pass: consider cells with colspan 1 only */
+ for (row_group = table->children; row_group; row_group =row_group->next)
+ for (row = row_group->children; row; row = row->next)
+ for (cell = row->children; cell; cell = cell->next) {
+ assert(cell->type == BOX_TABLE_CELL);
+ assert(cell->style);
+ /** TODO: Handle colspan="0" correctly.
+ * It's currently converted to 1 in box normaisation */
+ assert(cell->columns != 0);
+
+ if (cell->columns != 1)
+ continue;
+
+ layout_minmax_block(cell, font_func, content);
+ i = cell->start_column;
+
+ if (col[i].positioned)
+ continue;
+
+ /* update column min, max widths using cell widths */
+ if (col[i].min < cell->min_width)
+ col[i].min = cell->min_width;
+ if (col[i].max < cell->max_width)
+ col[i].max = cell->max_width;
+ }
+
+ /* 2nd pass: cells which span multiple columns */
+ for (row_group = table->children; row_group; row_group =row_group->next)
+ for (row = row_group->children; row; row = row->next)
+ for (cell = row->children; cell; cell = cell->next) {
+ unsigned int flexible_columns = 0;
+ int min = 0, max = 0, fixed_width = 0, extra;
+
+ if (cell->columns == 1)
+ continue;
+
+ layout_minmax_block(cell, font_func, content);
+ i = cell->start_column;
+
+ /* find min width so far of spanned columns, and count
+ * number of non-fixed spanned columns and total fixed width */
+ for (j = 0; j != cell->columns; j++) {
+ min += col[i + j].min;
+ if (col[i + j].type == COLUMN_WIDTH_FIXED)
+ fixed_width += col[i + j].width;
+ else
+ flexible_columns++;
+ }
+ min += (cell->columns - 1) * border_spacing_h;
+
+ /* distribute extra min to spanned columns */
+ if (min < cell->min_width) {
+ if (flexible_columns == 0) {
+ extra = 1 + (cell->min_width - min) /
+ cell->columns;
+ for (j = 0; j != cell->columns; j++) {
+ col[i + j].min += extra;
+ if (col[i + j].max < col[i + j].min)
+ col[i + j].max = col[i + j].min;
+ }
+ } else {
+ extra = 1 + (cell->min_width - min) /
+ flexible_columns;
+ for (j = 0; j != cell->columns; j++) {
+ if (col[i + j].type !=
+ COLUMN_WIDTH_FIXED) {
+ col[i + j].min += extra;
+ if (col[i + j].max <
+ col[i + j].min)
+ col[i + j].max =
+ col[i + j].min;
+ }
+ }
+ }
+ }
+
+ /* find max width so far of spanned columns */
+ for (j = 0; j != cell->columns; j++)
+ max += col[i + j].max;
+ max += (cell->columns - 1) * border_spacing_h;
+
+ /* distribute extra max to spanned columns */
+ if (max < cell->max_width && flexible_columns) {
+ extra = 1 + (cell->max_width - max) / flexible_columns;
+ for (j = 0; j != cell->columns; j++)
+ if (col[i + j].type != COLUMN_WIDTH_FIXED)
+ col[i + j].max += extra;
+ }
+ }
+
+ for (i = 0; i != table->columns; i++) {
+ if (col[i].max < col[i].min) {
+ box_dump(stderr, table, 0, true);
+ assert(0);
+ }
+ table_min += col[i].min;
+ table_max += col[i].max;
+ }
+
+ /* fixed width takes priority, unless it is too narrow */
+ wtype = css_computed_width(table->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
+ int width = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, table->style));
+ if (table_min < width)
+ table_min = width;
+ if (table_max < width)
+ table_max = width;
+ }
+
+ /* add margins, border, padding to min, max widths */
+ calculate_mbp_width(&content->len_ctx,
+ table->style, LEFT, true, true, true,
+ &extra_fixed, &extra_frac);
+ calculate_mbp_width(&content->len_ctx,
+ table->style, RIGHT, true, true, true,
+ &extra_fixed, &extra_frac);
+ if (extra_fixed < 0)
+ extra_fixed = 0;
+ if (extra_frac < 0)
+ extra_frac = 0;
+ if (1.0 <= extra_frac)
+ extra_frac = 0.9;
+ table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac);
+ table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac);
+ table->min_width += (table->columns + 1) * border_spacing_h;
+ table->max_width += (table->columns + 1) * border_spacing_h;
+
+ assert(0 <= table->min_width && table->min_width <= table->max_width);
+}
+
+/**
+ * Helper to check if a box has percentage max width.
+ *
+ * \param[in] b Box to check.
+ * \return true iff box has percnetage max width.
+ */
+static inline bool box_has_percentage_max_width(struct box *b)
+{
+ css_unit unit = CSS_UNIT_PX;
+ enum css_max_width_e type;
+ css_fixed value = 0;
+
+ assert(b != NULL);
+
+ type = css_computed_max_width(b->style, &value, &unit);
+ return ((type == CSS_MAX_WIDTH_SET) && (unit == CSS_UNIT_PCT));
+}
+
+/**
* Calculate minimum and maximum width of a line.
*
* \param first a box in an inline container
@@ -306,7 +541,8 @@ layout_minmax_line(struct box *first,
int *line_max,
bool first_line,
bool *line_has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
int min = 0, max = 0, width, height, fixed;
float frac;
@@ -332,6 +568,7 @@ layout_minmax_line(struct box *first,
for (b = first; b; b = b->next) {
enum css_width_e wtype;
enum css_height_e htype;
+ enum css_box_sizing_e bs;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
@@ -341,9 +578,7 @@ layout_minmax_line(struct box *first,
b->type == BOX_BR || b->type == BOX_TEXT ||
b->type == BOX_INLINE_END);
-#ifdef LAYOUT_DEBUG
- LOG("%p: min %i, max %i", b, min, max);
-#endif
+ NSLOG(layout, DEBUG, "%p: min %i, max %i", b, min, max);
if (b->type == BOX_BR) {
b = b->next;
@@ -353,9 +588,11 @@ layout_minmax_line(struct box *first,
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
assert(b->children);
if (b->children->type == BOX_BLOCK)
- layout_minmax_block(b->children, font_func);
+ layout_minmax_block(b->children, font_func,
+ content);
else
- layout_minmax_table(b->children, font_func);
+ layout_minmax_table(b->children, font_func,
+ content);
b->min_width = b->children->min_width;
b->max_width = b->children->max_width;
if (min < b->min_width)
@@ -365,7 +602,7 @@ layout_minmax_line(struct box *first,
}
if (b->type == BOX_INLINE_BLOCK) {
- layout_minmax_block(b, font_func);
+ layout_minmax_block(b, font_func, content);
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
@@ -376,16 +613,18 @@ layout_minmax_line(struct box *first,
}
assert(b->style);
- font_plot_style_from_css(b->style, &fstyle);
+ font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
if (b->type == BOX_INLINE && !b->object &&
!(b->flags & REPLACE_DIM) &&
!(b->flags & IFRAME)) {
fixed = frac = 0;
- calculate_mbp_width(b->style, LEFT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT, true, true, true,
&fixed, &frac);
if (!b->inline_end)
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -394,7 +633,8 @@ layout_minmax_line(struct box *first,
/* \todo update min width, consider fractional extra */
} else if (b->type == BOX_INLINE_END) {
fixed = frac = 0;
- calculate_mbp_width(b->inline_end->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->inline_end->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -506,16 +746,28 @@ layout_minmax_line(struct box *first,
/* calculate box width */
wtype = css_computed_width(b->style, &value, &unit);
+ bs = css_computed_box_sizing(block->style);
if (wtype == CSS_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
- /*
- b->width = FPCT_OF_INT_TOINT(value, width);
- */
-
width = AUTO;
} else {
- width = FIXTOINT(nscss_len2px(value, unit,
- b->style));
+ width = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
+
+ if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+ fixed = frac = 0;
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
+ false, true, true,
+ &fixed, &frac);
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
+ false, true, true,
+ &fixed, &frac);
+ if (width < fixed) {
+ width = fixed;
+ }
+ }
if (width < 0)
width = 0;
}
@@ -526,7 +778,8 @@ layout_minmax_line(struct box *first,
/* height */
htype = css_computed_height(b->style, &value, &unit);
if (htype == CSS_HEIGHT_SET) {
- height = FIXTOINT(nscss_len2px(value, unit, b->style));
+ height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
} else {
height = AUTO;
}
@@ -541,11 +794,25 @@ layout_minmax_line(struct box *first,
}
fixed = frac = 0;
- calculate_mbp_width(b->style, LEFT, true, true, true,
- &fixed, &frac);
- calculate_mbp_width(b->style, RIGHT, true, true, true,
- &fixed, &frac);
-
+ if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
+ true, false, false,
+ &fixed, &frac);
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
+ true, false, false,
+ &fixed, &frac);
+ } else {
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
+ true, true, true,
+ &fixed, &frac);
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
+ true, true, true,
+ &fixed, &frac);
+ }
if (0 < width + fixed)
width += fixed;
} else if (b->flags & IFRAME) {
@@ -554,23 +821,42 @@ layout_minmax_line(struct box *first,
width = 400;
fixed = frac = 0;
- calculate_mbp_width(b->style, LEFT, true, true, true,
- &fixed, &frac);
- calculate_mbp_width(b->style, RIGHT, true, true, true,
- &fixed, &frac);
+ if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
+ true, false, false,
+ &fixed, &frac);
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
+ true, false, false,
+ &fixed, &frac);
+ } else {
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
+ true, true, true,
+ &fixed, &frac);
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
+ true, true, true,
+ &fixed, &frac);
+ }
if (0 < width + fixed)
width += fixed;
+
} else {
/* form control with no object */
if (width == AUTO)
- width = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
+ width = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ INTTOFIX(1), CSS_UNIT_EM,
+ b->style));
}
- if (min < width)
+ if (min < width && !box_has_percentage_max_width(b))
min = width;
- max += width;
+ if (width > 0)
+ max += width;
*line_has_height = true;
}
@@ -578,7 +864,7 @@ layout_minmax_line(struct box *first,
if (first_line) {
/* todo: handle percentage values properly */
/* todo: handle text-indent interaction with floats */
- int text_indent = layout_text_indent(
+ int text_indent = layout_text_indent(&content->len_ctx,
first->parent->parent->style, 100);
min = (min + text_indent < 0) ? 0 : min + text_indent;
max = (max + text_indent < 0) ? 0 : max + text_indent;
@@ -587,9 +873,7 @@ layout_minmax_line(struct box *first,
*line_min = min;
*line_max = max;
-#ifdef LAYOUT_DEBUG
- LOG("line_min %i, line_max %i", min, max);
-#endif
+ NSLOG(layout, DEBUG, "line_min %i, line_max %i", min, max);
assert(b != first);
assert(0 <= *line_min);
@@ -610,7 +894,8 @@ layout_minmax_line(struct box *first,
static void
layout_minmax_inline_container(struct box *inline_container,
bool *has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int line_min = 0, line_max = 0;
@@ -628,7 +913,8 @@ layout_minmax_inline_container(struct box *inline_container,
for (child = inline_container->children; child; ) {
child = layout_minmax_line(child, &line_min, &line_max,
- first_line, &line_has_height, font_func);
+ first_line, &line_has_height, font_func,
+ content);
if (min < line_min)
min = line_min;
if (max < line_max)
@@ -651,11 +937,14 @@ layout_minmax_inline_container(struct box *inline_container,
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
* \param font_func font functions
+ * \param content The HTML content being layed out.
* \post block->min_width and block->max_width filled in,
* 0 <= block->min_width <= block->max_width
*/
-static void
-layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int min = 0, max = 0;
@@ -667,6 +956,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
enum css_height_e htype = CSS_HEIGHT_AUTO;
css_fixed height = 0;
css_unit hunit = CSS_UNIT_PX;
+ enum css_box_sizing_e bs = CSS_BOX_SIZING_CONTENT_BOX;
bool child_has_height = false;
assert(block->type == BOX_BLOCK ||
@@ -680,6 +970,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
if (block->style != NULL) {
wtype = css_computed_width(block->style, &width, &wunit);
htype = css_computed_height(block->style, &height, &hunit);
+ bs = css_computed_box_sizing(block->style);
}
/* set whether the minimum width is of any interest for this box */
@@ -706,7 +997,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
css_fixed size = INTTOFIX(10);
css_unit unit = CSS_UNIT_EM;
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -719,7 +1011,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -727,7 +1020,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
if (block->object) {
if (content_get_type(block->object) == CONTENT_HTML) {
layout_minmax_block(html_get_box_tree(block->object),
- font_func);
+ font_func, content);
min = html_get_box_tree(block->object)->min_width;
max = html_get_box_tree(block->object)->max_width;
} else {
@@ -744,7 +1037,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
for (child = block->children; child; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
- layout_minmax_block(child, font_func);
+ layout_minmax_block(child, font_func,
+ content);
if (child->flags & HAS_HEIGHT)
child_has_height = true;
break;
@@ -753,7 +1047,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
child->flags |= NEED_MIN;
layout_minmax_inline_container(child,
- &child_has_height, font_func);
+ &child_has_height, font_func,
+ content);
if (child_has_height &&
child ==
child->parent->children) {
@@ -761,7 +1056,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
}
break;
case BOX_TABLE:
- layout_minmax_table(child, font_func);
+ layout_minmax_table(child, font_func,
+ content);
/* todo: fix for zero height tables */
child_has_height = true;
child->flags |= MAKE_HEIGHT;
@@ -799,7 +1095,23 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* fixed width takes priority */
if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
wunit != CSS_UNIT_PCT) {
- min = max = FIXTOINT(nscss_len2px(width, wunit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ width, wunit, block->style));
+ if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+ int border_box_fixed = 0;
+ float border_box_frac = 0;
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
+ false, true, true,
+ &border_box_fixed, &border_box_frac);
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
+ false, true, true,
+ &border_box_fixed, &border_box_frac);
+ if (min < border_box_fixed) {
+ min = max = border_box_fixed;
+ }
+ }
}
if (htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT &&
@@ -811,20 +1123,20 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* add margins, border, padding to min, max widths */
/* Note: we don't know available width here so percentage margin
* and paddings are wrong. */
- if (block->gadget && wtype == CSS_WIDTH_SET &&
- (block->gadget->type == GADGET_SUBMIT ||
- block->gadget->type == GADGET_RESET ||
- block->gadget->type == GADGET_BUTTON)) {
- /* some gadgets with specified width already include border and
- * padding, so just get margin */
- calculate_mbp_width(block->style, LEFT, true, false, false,
+ if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) {
+ /* Border and padding included in width, so just get margin */
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, false, false,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, false, false,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, false, false,
&extra_fixed, &extra_frac);
} else {
- calculate_mbp_width(block->style, LEFT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, true, true,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, true, true,
&extra_fixed, &extra_frac);
}
if (extra_fixed < 0)
@@ -850,12 +1162,12 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/**
- * Under some circumstances, specified dimensions for form elements include
- * borders and padding.
+ * Adjust a specified width or height for the box-sizing property.
+ *
+ * This turns the specified dimension into a content-box dimension.
*
+ * \param len_ctx Length conversion context
* \param box gadget to adjust dimensions of
- * \param percentage whether the gadget has its dimension specified as a
- * percentage
* \param available_width width of containing block
* \param setwidth set true if the dimension to be tweaked is a width,
* else set false for a height
@@ -863,25 +1175,32 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
* updated to new value after consideration of
* gadget properties.
*/
-static void layout_tweak_form_dimensions(struct box *box, bool percentage,
- int available_width, bool setwidth, int *dimension)
+static void layout_handle_box_sizing(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int available_width,
+ bool setwidth,
+ int *dimension)
{
- int fixed = 0;
- float frac = 0;
+ enum css_box_sizing_e bs;
+
+ assert(box && box->style);
- assert(box && box->gadget);
+ bs = css_computed_box_sizing(box->style);
- /* specified gadget widths include borders and padding in some
- * cases */
- if (percentage || box->gadget->type == GADGET_SUBMIT ||
- box->gadget->type == GADGET_RESET ||
- box->gadget->type == GADGET_BUTTON) {
- calculate_mbp_width(box->style, setwidth ? LEFT : TOP,
+ if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+ int orig = *dimension;
+ int fixed = 0;
+ float frac = 0;
+
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? LEFT : TOP,
false, true, true, &fixed, &frac);
- calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM,
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? RIGHT : BOTTOM,
false, true, true, &fixed, &frac);
- *dimension -= frac * available_width + fixed;
- *dimension = *dimension > 0 ? *dimension : 0;
+ orig -= frac * available_width + fixed;
+ *dimension = orig > 0 ? orig : 0;
}
}
@@ -889,6 +1208,7 @@ static void layout_tweak_form_dimensions(struct box *box, bool percentage,
/**
* Calculate width, height, and thickness of margins, paddings, and borders.
*
+ * \param len_ctx Length conversion context
* \param available_width width of containing block
* \param viewport_height height of viewport in pixels or -ve if unknown
* \param box current box
@@ -905,7 +1225,8 @@ static void layout_tweak_form_dimensions(struct box *box, bool percentage,
* \param border filled with border widths, may be NULL
*/
static void
-layout_find_dimensions(int available_width,
+layout_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
struct box *box,
const css_computed_style *style,
@@ -921,7 +1242,6 @@ layout_find_dimensions(int available_width,
{
struct box *containing_block = NULL;
unsigned int i;
- bool percentage;
if (width) {
enum css_width_e wtype;
@@ -935,20 +1255,16 @@ layout_find_dimensions(int available_width,
*width = FPCT_OF_INT_TOINT(
value, available_width);
} else {
- *width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*width = AUTO;
}
- /* specified gadget widths include borders and padding in some
- * cases */
- if (box->gadget && *width != AUTO) {
- percentage = unit == CSS_UNIT_PCT;
-
- layout_tweak_form_dimensions(box, percentage,
- available_width, true, width);
+ if (*width != AUTO) {
+ layout_handle_box_sizing(len_ctx, box, available_width,
+ true, width);
}
}
@@ -1027,20 +1343,16 @@ layout_find_dimensions(int available_width,
*height = AUTO;
}
} else {
- *height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*height = AUTO;
}
- /* specified gadget heights include borders and padding in
- * some cases */
- if (box->gadget && *height != AUTO) {
- percentage = unit == CSS_UNIT_PCT;
-
- layout_tweak_form_dimensions(box, percentage,
- available_width, false, height);
+ if (*height != AUTO) {
+ layout_handle_box_sizing(len_ctx, box, available_width,
+ false, height);
}
}
@@ -1056,21 +1368,17 @@ layout_find_dimensions(int available_width,
*max_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *max_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
*max_width = -1;
}
- /* specified gadget widths include borders and padding in some
- * cases */
- if (box->gadget && *max_width != -1) {
- percentage = unit == CSS_UNIT_PCT;
-
- layout_tweak_form_dimensions(box, percentage,
- available_width, true, max_width);
+ if (*max_width != -1) {
+ layout_handle_box_sizing(len_ctx, box, available_width,
+ true, max_width);
}
}
@@ -1079,28 +1387,24 @@ layout_find_dimensions(int available_width,
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
- type = css_computed_min_width(style, &value, &unit);
+ type = ns_computed_min_width(style, &value, &unit);
if (type == CSS_MIN_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
*min_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *min_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
*min_width = 0;
}
- /* specified gadget widths include borders and padding in some
- * cases */
- if (box->gadget && *min_width != 0) {
- percentage = unit == CSS_UNIT_PCT;
-
- layout_tweak_form_dimensions(box, percentage,
- available_width, true, min_width);
+ if (*min_width != 0) {
+ layout_handle_box_sizing(len_ctx, box, available_width,
+ true, min_width);
}
}
@@ -1116,8 +1420,8 @@ layout_find_dimensions(int available_width,
/* TODO: handle percentage */
*max_height = -1;
} else {
- *max_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1130,15 +1434,15 @@ layout_find_dimensions(int available_width,
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
- type = css_computed_min_height(style, &value, &unit);
+ type = ns_computed_min_height(style, &value, &unit);
if (type == CSS_MIN_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
/* TODO: handle percentage */
*min_height = 0;
} else {
- *min_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1152,32 +1456,16 @@ layout_find_dimensions(int available_width,
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
- switch (i) {
- case TOP:
- type = css_computed_margin_top(style,
- &value, &unit);
- break;
- case RIGHT:
- type = css_computed_margin_right(style,
- &value, &unit);
- break;
- case BOTTOM:
- type = css_computed_margin_bottom(style,
- &value, &unit);
- break;
- case LEFT:
- type = css_computed_margin_left(style,
- &value, &unit);
- break;
- }
+ type = margin_funcs[i](style, &value, &unit);
if (type == CSS_MARGIN_SET) {
if (unit == CSS_UNIT_PCT) {
margin[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- margin[i] = FIXTOINT(nscss_len2px(value,
- unit, style));
+ margin[i] = FIXTOINT(nscss_len2px(
+ len_ctx,
+ value, unit, style));
}
} else {
margin[i] = AUTO;
@@ -1188,29 +1476,14 @@ layout_find_dimensions(int available_width,
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
- switch (i) {
- case TOP:
- css_computed_padding_top(style, &value, &unit);
- break;
- case RIGHT:
- css_computed_padding_right(style, &value,
- &unit);
- break;
- case BOTTOM:
- css_computed_padding_bottom(style, &value,
- &unit);
- break;
- case LEFT:
- css_computed_padding_left(style, &value, &unit);
- break;
- }
+ padding_funcs[i](style, &value, &unit);
if (unit == CSS_UNIT_PCT) {
padding[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- padding[i] = FIXTOINT(nscss_len2px(value, unit,
- style));
+ padding[i] = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -1221,33 +1494,9 @@ layout_find_dimensions(int available_width,
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
- switch (i) {
- case TOP:
- css_computed_border_top_width(style, &value,
- &unit);
- bstyle = css_computed_border_top_style(style);
- css_computed_border_top_color(style, &color);
- break;
- case RIGHT:
- css_computed_border_right_width(style, &value,
- &unit);
- bstyle = css_computed_border_right_style(style);
- css_computed_border_right_color(style, &color);
- break;
- case BOTTOM:
- css_computed_border_bottom_width(style, &value,
- &unit);
- bstyle = css_computed_border_bottom_style(
- style);
- css_computed_border_bottom_color(style, &color);
- break;
- case LEFT:
- css_computed_border_left_width(style, &value,
- &unit);
- bstyle = css_computed_border_left_style(style);
- css_computed_border_left_color(style, &color);
- break;
- }
+ border_width_funcs[i](style, &value, &unit);
+ bstyle = border_style_funcs[i](style);
+ border_color_funcs[i](style, &color);
border[i].style = bstyle;
border[i].c = color;
@@ -1257,8 +1506,8 @@ layout_find_dimensions(int available_width,
/* spec unclear: following Mozilla */
border[i].width = 0;
else
- border[i].width = FIXTOINT(nscss_len2px(value,
- unit, style));
+ border[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
/* Special case for border-collapse: make all borders
* on table/table-row-group/table-row zero width. */
@@ -1276,6 +1525,7 @@ layout_find_dimensions(int available_width,
/**
* Find next block that current margin collapses to.
*
+ * \param len_ctx Length conversion context
* \param box box to start tree-order search from (top margin is included)
* \param block box responsible for current block fromatting context
* \param viewport_height height of viewport in px
@@ -1284,7 +1534,8 @@ layout_find_dimensions(int available_width,
* \return next box that current margin collapses to, or NULL if none.
*/
static struct box*
-layout_next_margin_block(struct box *box,
+layout_next_margin_block(const nscss_len_ctx *len_ctx,
+ struct box *box,
struct box *block,
int viewport_height,
int *max_pos_margin,
@@ -1303,7 +1554,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1326,7 +1578,7 @@ layout_next_margin_block(struct box *box,
css_computed_overflow_y(box->style) !=
CSS_OVERFLOW_VISIBLE) ||
(box->type == BOX_INLINE_CONTAINER &&
- box != box->parent->children)) {
+ !box_is_first_child(box))) {
/* Collapse to this box; return it */
return box;
}
@@ -1377,7 +1629,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1435,9 +1688,7 @@ find_sides(struct box *fl,
{
int fy0, fy1, fx0, fx1;
-#ifdef LAYOUT_DEBUG
- LOG("y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1);
-#endif
+ NSLOG(layout, DEBUG, "y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1);
*left = *right = 0;
for (; fl; fl = fl->next_float) {
@@ -1466,9 +1717,8 @@ find_sides(struct box *fl,
}
}
-#ifdef LAYOUT_DEBUG
- LOG("x0 %i, x1 %i, left %p, right %p", *x0, *x1, *left, *right);
-#endif
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, left %p, right %p", *x0, *x1,
+ *left, *right);
}
@@ -1511,16 +1761,20 @@ layout_solve_width(struct box *box,
/* Find width */
if (width == AUTO) {
- /* any other 'auto' become 0 or the minimum required values */
- if (box->margin[LEFT] == AUTO)
- box->margin[LEFT] = lm;
- if (box->margin[RIGHT] == AUTO)
- box->margin[RIGHT] = rm;
+ int margin_left = box->margin[LEFT];
+ int margin_right = box->margin[RIGHT];
+
+ if (margin_left == AUTO) {
+ margin_left = lm;
+ }
+ if (margin_right == AUTO) {
+ margin_right = rm;
+ }
width = available_width -
- (box->margin[LEFT] + box->border[LEFT].width +
+ (margin_left + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT].width + box->margin[RIGHT]);
+ box->border[RIGHT].width + margin_right);
width = width < 0 ? 0 : width;
auto_width = true;
}
@@ -1538,8 +1792,16 @@ layout_solve_width(struct box *box,
}
/* Width was auto, and unconstrained by min/max width, so we're done */
- if (auto_width)
+ if (auto_width) {
+ /* any other 'auto' become 0 or the minimum required values */
+ if (box->margin[LEFT] == AUTO) {
+ box->margin[LEFT] = lm;
+ }
+ if (box->margin[RIGHT] == AUTO) {
+ box->margin[RIGHT] = rm;
+ }
return width;
+ }
/* Width was not auto, or was constrained by min/max width
* Need to compute left/right margins */
@@ -1604,6 +1866,7 @@ layout_solve_width(struct box *box,
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
+ * \param len_ctx Length conversion context
* \param available_width Max width available in pixels
* \param viewport_height Height of viewport in pixels or -ve if unknown
* \param lm min left margin required to avoid floats in px.
@@ -1616,7 +1879,8 @@ layout_solve_width(struct box *box,
* See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
*/
static void
-layout_block_find_dimensions(int available_width,
+layout_block_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
int lm,
int rm,
@@ -1629,8 +1893,8 @@ layout_block_find_dimensions(int available_width,
struct box_border *border = box->border;
const css_computed_style *style = box->style;
- layout_find_dimensions(available_width, viewport_height, box, style,
- &width, &height, &max_width, &min_width,
+ layout_find_dimensions(len_ctx, available_width, viewport_height, box,
+ style, &width, &height, &max_width, &min_width,
&max_height, &min_height, margin, padding, border);
if (box->object && !(box->flags & REPLACE_DIM) &&
@@ -1783,8 +2047,9 @@ static bool layout_table(struct box *table, int available_width,
memcpy(col, table->col, sizeof(col[0]) * columns);
/* find margins, paddings, and borders for table and cells */
- layout_find_dimensions(available_width, -1, table, style, 0, 0, 0, 0,
- 0, 0, table->margin, table->padding, table->border);
+ layout_find_dimensions(&content->len_ctx, available_width, -1, table,
+ style, 0, 0, 0, 0, 0, 0, table->margin, table->padding,
+ table->border);
for (row_group = table->children; row_group;
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
@@ -1793,9 +2058,11 @@ static bool layout_table(struct box *table, int available_width,
enum css_overflow_e overflow_y;
assert(c->style);
- table_used_border_for_cell(c);
- layout_find_dimensions(available_width, -1,
- c, c->style, 0, 0, 0, 0, 0, 0,
+ table_used_border_for_cell(
+ &content->len_ctx, c);
+ layout_find_dimensions(&content->len_ctx,
+ available_width, -1, c,
+ c->style, 0, 0, 0, 0, 0, 0,
0, c->padding, c->border);
overflow_x = css_computed_overflow_x(c->style);
@@ -1823,8 +2090,10 @@ static bool layout_table(struct box *table, int available_width,
css_computed_border_spacing(style, &h, &hu, &v, &vu);
- border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style));
- border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style));
+ border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+ h, hu, style));
+ border_spacing_v = FIXTOINT(nscss_len2px(&content->len_ctx,
+ v, vu, style));
}
/* find specified table width, or available width if auto-width */
@@ -1834,7 +2103,8 @@ static bool layout_table(struct box *table, int available_width,
table_width = FPCT_OF_INT_TOINT(value, available_width);
} else {
table_width =
- FIXTOINT(nscss_len2px(value, unit, style));
+ FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
/* specified width includes border */
@@ -1912,21 +2182,29 @@ static bool layout_table(struct box *table, int available_width,
} else {
/* This is the minimum height for the table
* (see 17.5.3) */
- min_height = FIXTOINT(nscss_len2px(value, unit, style));
+ min_height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
}
/* calculate width required by cells */
for (i = 0; i != columns; i++) {
-#ifdef LAYOUT_DEBUG
- LOG("table %p, column %u: type %s, width %i, min %i, max %i", table, i, ((const char *[]){
- "UNKNOWN",
- "FIXED",
- "AUTO",
- "PERCENT",
- "RELATIVE"
- })[col[i].type], col[i].width, col[i].min, col[i].max);
-#endif
+
+ NSLOG(layout, DEBUG,
+ "table %p, column %u: type %s, width %i, min %i, max %i",
+ table,
+ i,
+ ((const char *[]){
+ "UNKNOWN",
+ "FIXED",
+ "AUTO",
+ "PERCENT",
+ "RELATIVE",
+ })[col[i].type],
+ col[i].width,
+ col[i].min,
+ col[i].max);
+
if (col[i].positioned) {
positioned_columns++;
@@ -1944,16 +2222,14 @@ static bool layout_table(struct box *table, int available_width,
} else
required_width += col[i].min;
-#ifdef LAYOUT_DEBUG
- LOG("required_width %i", required_width);
-#endif
+ NSLOG(layout, DEBUG, "required_width %i", required_width);
}
required_width += (columns + 1 - positioned_columns) *
border_spacing_h;
-#ifdef LAYOUT_DEBUG
- LOG("width %i, min %i, max %i, auto %i, required %i", table_width, table->min_width, table->max_width, auto_width, required_width);
-#endif
+ NSLOG(layout, DEBUG,
+ "width %i, min %i, max %i, auto %i, required %i", table_width,
+ table->min_width, table->max_width, auto_width, required_width);
if (auto_width < required_width) {
/* table narrower than required width for columns:
@@ -2097,8 +2373,9 @@ static bool layout_table(struct box *table, int available_width,
htype = css_computed_height(row->style, &value, &unit);
if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
- row_height = FIXTOINT(nscss_len2px(value, unit,
- row->style));
+ row_height = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
@@ -2135,8 +2412,9 @@ static bool layout_table(struct box *table, int available_width,
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible, so treat it as a minimum */
- int h = FIXTOINT(nscss_len2px(value,
- unit, c->style));
+ int h = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, c->style));
if (c->height < h)
c->height = h;
}
@@ -2280,12 +2558,16 @@ static bool layout_table(struct box *table, int available_width,
/**
* Manimpulate box height according to CSS min-height and max-height properties
*
+ * \param len_ctx CSS length conversion context for document.
* \param box block to modify with any min-height or max-height
* \param container containing block for absolutely positioned elements, or
* NULL for non absolutely positioned elements.
* \return whether the height has been changed
*/
-static bool layout_apply_minmax_height(struct box *box, struct box *container)
+static bool layout_apply_minmax_height(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ struct box *container)
{
int h;
struct box *containing_block = NULL;
@@ -2344,8 +2626,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h < box->height) {
box->height = h;
updated = true;
@@ -2354,7 +2636,7 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
/* min-height */
- if (css_computed_min_height(box->style, &value, &unit) ==
+ if (ns_computed_min_height(box->style, &value, &unit) ==
CSS_MIN_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
if (containing_block &&
@@ -2374,8 +2656,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h > box->height) {
box->height = h;
updated = true;
@@ -2402,9 +2684,8 @@ static bool layout_block_object(struct box *block)
block->type == BOX_TABLE_CELL);
assert(block->object);
-#ifdef LAYOUT_DEBUG
- LOG("block %p, object %s, width %i", block, hlcache_handle_get_url(block->object), block->width);
-#endif
+ NSLOG(layout, DEBUG, "block %p, object %p, width %i", block,
+ hlcache_handle_get_url(block->object), block->width);
if (content_get_type(block->object) == CONTENT_HTML) {
content_reformat(block->object, false, block->width, 1);
@@ -2419,6 +2700,1211 @@ static bool layout_block_object(struct box *block)
/**
+ * Insert a float into a container.
+ *
+ * \param cont block formatting context block, used to contain float
+ * \param b box to add to float
+ *
+ * This sorts floats in order of descending bottom edges.
+ */
+static void add_float_to_container(struct box *cont, struct box *b)
+{
+ struct box *box = cont->float_children;
+ int b_bottom = b->y + b->height;
+
+ assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
+
+ if (box == NULL) {
+ /* No other float children */
+ b->next_float = NULL;
+ cont->float_children = b;
+ return;
+ } else if (b_bottom >= box->y + box->height) {
+ /* Goes at start of list */
+ b->next_float = cont->float_children;
+ cont->float_children = b;
+ } else {
+ struct box *prev = NULL;
+ while (box != NULL && b_bottom < box->y + box->height) {
+ prev = box;
+ box = box->next_float;
+ }
+ if (prev != NULL) {
+ b->next_float = prev->next_float;
+ prev->next_float = b;
+ }
+ }
+}
+
+
+/**
+ * Split a text box.
+ *
+ * \param content memory pool for any new boxes
+ * \param fstyle style for text in text box
+ * \param split_box box with text to split
+ * \param new_length new length for text in split_box, after splitting
+ * \param new_width new width for text in split_box, after splitting
+ * \return true on success, false on memory exhaustion
+ *
+ * A new box is created and inserted into the box tree after split_box,
+ * containing the text after new_length excluding the initial space character.
+ */
+static bool
+layout_text_box_split(html_content *content,
+ plot_font_style_t *fstyle,
+ struct box *split_box,
+ size_t new_length,
+ int new_width)
+{
+ int space_width = split_box->space;
+ struct box *c2;
+ const struct gui_layout_table *font_func = content->font_func;
+ bool space = (split_box->text[new_length] == ' ');
+ int used_length = new_length + (space ? 1 : 0);
+
+ if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
+ /* We're need to add a space, and we don't know how big
+ * it's to be, OR we have a space of unknown width anyway;
+ * Calculate space width */
+ font_func->width(fstyle, " ", 1, &space_width);
+ }
+
+ if (split_box->space == UNKNOWN_WIDTH)
+ split_box->space = space_width;
+ if (!space)
+ space_width = 0;
+
+ /* Create clone of split_box, c2 */
+ c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
+ if (!c2)
+ return false;
+ c2->flags |= CLONE;
+
+ /* Set remaining text in c2 */
+ c2->text += used_length;
+
+ /* Set c2 according to the remaining text */
+ c2->width -= new_width + space_width;
+ c2->flags &= ~MEASURED; /* width has been estimated */
+ c2->length = split_box->length - used_length;
+
+ /* Update split_box for its reduced text */
+ split_box->width = new_width;
+ split_box->flags |= MEASURED;
+ split_box->length = new_length;
+ split_box->space = space_width;
+
+ /* Insert c2 into box list */
+ c2->next = split_box->next;
+ split_box->next = c2;
+ c2->prev = split_box;
+ if (c2->next)
+ c2->next->prev = c2;
+ else
+ c2->parent->last = c2;
+
+ NSLOG(layout, DEBUG,
+ "split_box %p len: %" PRIsizet " \"%.*s\"",
+ split_box,
+ split_box->length,
+ (int)split_box->length,
+ split_box->text);
+ NSLOG(layout, DEBUG,
+ " new_box %p len: %" PRIsizet " \"%.*s\"",
+ c2,
+ c2->length,
+ (int)c2->length,
+ c2->text);
+
+ return true;
+}
+
+
+/**
+ * Compute dimensions of box, margins, paddings, and borders for a floating
+ * element using shrink-to-fit. Also used for inline-blocks.
+ *
+ * \param len_ctx CSS length conversion context for document.
+ * \param available_width Max width available in pixels
+ * \param style Box's style
+ * \param box Box for which to find dimensions
+ * Box margins, borders, paddings, width and
+ * height are updated.
+ */
+static void
+layout_float_find_dimensions(
+ const nscss_len_ctx *len_ctx,
+ int available_width,
+ const css_computed_style *style,
+ struct box *box)
+{
+ int width, height, max_width, min_width, max_height, min_height;
+ int *margin = box->margin;
+ int *padding = box->padding;
+ struct box_border *border = box->border;
+ enum css_overflow_e overflow_x = css_computed_overflow_x(style);
+ enum css_overflow_e overflow_y = css_computed_overflow_y(style);
+ int scrollbar_width_x =
+ (overflow_x == CSS_OVERFLOW_SCROLL ||
+ overflow_x == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
+ int scrollbar_width_y =
+ (overflow_y == CSS_OVERFLOW_SCROLL ||
+ overflow_y == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
+
+ layout_find_dimensions(len_ctx, available_width, -1, box, style,
+ &width, &height, &max_width, &min_width,
+ &max_height, &min_height, margin, padding, border);
+
+ if (margin[LEFT] == AUTO)
+ margin[LEFT] = 0;
+ if (margin[RIGHT] == AUTO)
+ margin[RIGHT] = 0;
+
+ if (box->gadget == NULL) {
+ padding[RIGHT] += scrollbar_width_y;
+ padding[BOTTOM] += scrollbar_width_x;
+ }
+
+ if (box->object && !(box->flags & REPLACE_DIM) &&
+ content_get_type(box->object) != CONTENT_HTML) {
+ /* Floating replaced element, with intrinsic width or height.
+ * See 10.3.6 and 10.6.2 */
+ layout_get_object_dimensions(box, &width, &height,
+ min_width, max_width, min_height, max_height);
+ } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD ||
+ box->gadget->type == GADGET_FILE ||
+ box->gadget->type == GADGET_TEXTAREA)) {
+ css_fixed size = 0;
+ css_unit unit = CSS_UNIT_EM;
+
+ /* Give sensible dimensions to gadgets, with auto width/height,
+ * that don't shrink to fit contained text. */
+ assert(box->style);
+
+ if (box->gadget->type == GADGET_TEXTBOX ||
+ box->gadget->type == GADGET_PASSWORD ||
+ box->gadget->type == GADGET_FILE) {
+ if (width == AUTO) {
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ if (box->gadget->type == GADGET_FILE &&
+ height == AUTO) {
+ size = FLTTOFIX(1.5);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ }
+ if (box->gadget->type == GADGET_TEXTAREA) {
+ if (width == AUTO) {
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ if (height == AUTO) {
+ size = INTTOFIX(4);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ }
+ } else if (width == AUTO) {
+ /* CSS 2.1 section 10.3.5 */
+ width = min(max(box->min_width, available_width),
+ box->max_width);
+
+ /* width includes margin, borders and padding */
+ if (width == available_width) {
+ width -= box->margin[LEFT] + box->border[LEFT].width +
+ box->padding[LEFT] +
+ box->padding[RIGHT] +
+ box->border[RIGHT].width +
+ box->margin[RIGHT];
+ } else {
+ /* width was obtained from a min_width or max_width
+ * value, so need to use the same method for calculating
+ * mbp as was used in layout_minmax_block() */
+ int fixed = 0;
+ float frac = 0;
+ calculate_mbp_width(len_ctx, box->style, LEFT,
+ true, true, true, &fixed, &frac);
+ calculate_mbp_width(len_ctx, box->style, RIGHT,
+ true, true, true, &fixed, &frac);
+ if (fixed < 0)
+ fixed = 0;
+
+ width -= fixed;
+ }
+
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
+
+ } else {
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
+ width -= scrollbar_width_y;
+ }
+
+ box->width = width;
+ box->height = height;
+
+ if (margin[TOP] == AUTO)
+ margin[TOP] = 0;
+ if (margin[BOTTOM] == AUTO)
+ margin[BOTTOM] = 0;
+}
+
+
+/**
+ * Layout the contents of a float or inline block.
+ *
+ * \param b float or inline block box
+ * \param width available width
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool layout_float(struct box *b, int width, html_content *content)
+{
+ assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
+ b->type == BOX_INLINE_BLOCK);
+ layout_float_find_dimensions(&content->len_ctx, width, b->style, b);
+ if (b->type == BOX_TABLE) {
+ if (!layout_table(b, width, content))
+ return false;
+ if (b->margin[LEFT] == AUTO)
+ b->margin[LEFT] = 0;
+ if (b->margin[RIGHT] == AUTO)
+ b->margin[RIGHT] = 0;
+ if (b->margin[TOP] == AUTO)
+ b->margin[TOP] = 0;
+ if (b->margin[BOTTOM] == AUTO)
+ b->margin[BOTTOM] = 0;
+ } else
+ return layout_block_context(b, -1, content);
+ return true;
+}
+
+
+/**
+ * Position a float in the first available space.
+ *
+ * \param c float box to position
+ * \param width available width
+ * \param cx x coordinate relative to cont to place float right of
+ * \param y y coordinate relative to cont to place float below
+ * \param cont ancestor box which defines horizontal space, for floats
+ */
+static void
+place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
+{
+ int x0, x1, yy;
+ struct box *left;
+ struct box *right;
+
+ yy = y > cont->cached_place_below_level ?
+ y : cont->cached_place_below_level;
+
+ NSLOG(layout, DEBUG,
+ "c %p, width %i, cx %i, y %i, cont %p", c,
+ width, cx, y, cont);
+
+ do {
+ y = yy;
+ x0 = cx;
+ x1 = cx + width;
+ find_sides(cont->float_children, y, y + c->height, &x0, &x1,
+ &left, &right);
+ if (left != 0 && right != 0) {
+ yy = (left->y + left->height <
+ right->y + right->height ?
+ left->y + left->height :
+ right->y + right->height);
+ } else if (left == 0 && right != 0) {
+ yy = right->y + right->height;
+ } else if (left != 0 && right == 0) {
+ yy = left->y + left->height;
+ }
+ } while ((left != 0 || right != 0) && (c->width > x1 - x0));
+
+ if (c->type == BOX_FLOAT_LEFT) {
+ c->x = x0;
+ } else {
+ c->x = x1 - c->width;
+ }
+ c->y = y;
+ cont->cached_place_below_level = y;
+}
+
+
+/**
+ * Calculate line height from a style.
+ */
+static int line_height(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *style)
+{
+ enum css_line_height_e lhtype;
+ css_fixed lhvalue = 0;
+ css_unit lhunit = CSS_UNIT_PX;
+ css_fixed line_height;
+
+ assert(style);
+
+ lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
+ if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
+ /* Normal => use a constant of 1.3 * font-size */
+ lhvalue = FLTTOFIX(1.3);
+ lhtype = CSS_LINE_HEIGHT_NUMBER;
+ }
+
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
+ lhunit == CSS_UNIT_PCT) {
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, CSS_UNIT_EM, style);
+
+ if (lhtype != CSS_LINE_HEIGHT_NUMBER)
+ line_height = FDIV(line_height, F_100);
+ } else {
+ assert(lhunit != CSS_UNIT_PCT);
+
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, lhunit, style);
+ }
+
+ return FIXTOINT(line_height);
+}
+
+
+/**
+ * Position a line of boxes in inline formatting context.
+ *
+ * \param first box at start of line
+ * \param width available width on input, updated with actual width on output
+ * (may be incorrect if the line gets split?)
+ * \param y coordinate of top of line, updated on exit to bottom
+ * \param cx coordinate of left of line relative to cont
+ * \param cy coordinate of top of line relative to cont
+ * \param cont ancestor box which defines horizontal space, for floats
+ * \param indent apply any first-line indent
+ * \param has_text_children at least one TEXT in the inline_container
+ * \param next_box updated to first box for next line, or 0 at end
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool
+layout_line(struct box *first,
+ int *width,
+ int *y,
+ int cx,
+ int cy,
+ struct box *cont,
+ bool indent,
+ bool has_text_children,
+ html_content *content,
+ struct box **next_box)
+{
+ int height, used_height;
+ int x0 = 0;
+ int x1 = *width;
+ int x, h, x_previous;
+ int fy = cy;
+ struct box *left;
+ struct box *right;
+ struct box *b;
+ struct box *split_box = 0;
+ struct box *d;
+ struct box *br_box = 0;
+ bool move_y = false;
+ bool place_below = false;
+ int space_before = 0, space_after = 0;
+ unsigned int inline_count = 0;
+ unsigned int i;
+ const struct gui_layout_table *font_func = content->font_func;
+ plot_font_style_t fstyle;
+
+ NSLOG(layout, DEBUG,
+ "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
+ first,
+ (int)first->length,
+ first->text,
+ *width,
+ *y,
+ cx,
+ cy);
+
+ /* find sides at top of line */
+ x0 += cx;
+ x1 += cx;
+ find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
+ x0 -= cx;
+ x1 -= cx;
+
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
+
+ if (x1 < x0)
+ x1 = x0;
+
+ /* get minimum line height from containing block.
+ * this is the line-height if there are text children and also in the
+ * case of an initially empty text input */
+ if (has_text_children || first->parent->parent->gadget)
+ used_height = height = line_height(&content->len_ctx,
+ first->parent->parent->style);
+ else
+ /* inline containers with no text are usually for layout and
+ * look better with no minimum line-height */
+ used_height = height = 0;
+
+ /* pass 1: find height of line assuming sides at top of line: loop
+ * body executed at least once
+ * keep in sync with the loop in layout_minmax_line() */
+
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+
+
+ for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
+ int min_width, max_width, min_height, max_height;
+
+ assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
+ b->type == BOX_FLOAT_LEFT ||
+ b->type == BOX_FLOAT_RIGHT ||
+ b->type == BOX_BR || b->type == BOX_TEXT ||
+ b->type == BOX_INLINE_END);
+
+
+ NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
+
+
+ if (b->type == BOX_BR)
+ break;
+
+ if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
+ continue;
+ if (b->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED))
+ continue;
+
+ assert(b->style != NULL);
+ font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
+
+ x += space_after;
+
+ if (b->type == BOX_INLINE_BLOCK) {
+ if (b->max_width != UNKNOWN_WIDTH)
+ if (!layout_float(b, *width, content))
+ return false;
+ h = b->border[TOP].width + b->padding[TOP] + b->height +
+ b->padding[BOTTOM] +
+ b->border[BOTTOM].width;
+ if (height < h)
+ height = h;
+ x += b->margin[LEFT] + b->border[LEFT].width +
+ b->padding[LEFT] + b->width +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ space_after = 0;
+ continue;
+ }
+
+ if (b->type == BOX_INLINE) {
+ /* calculate borders, margins, and padding */
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style, 0, 0, 0, 0,
+ 0, 0, b->margin, b->padding, b->border);
+ for (i = 0; i != 4; i++)
+ if (b->margin[i] == AUTO)
+ b->margin[i] = 0;
+ x += b->margin[LEFT] + b->border[LEFT].width +
+ b->padding[LEFT];
+ if (b->inline_end) {
+ b->inline_end->margin[RIGHT] = b->margin[RIGHT];
+ b->inline_end->padding[RIGHT] =
+ b->padding[RIGHT];
+ b->inline_end->border[RIGHT] =
+ b->border[RIGHT];
+ } else {
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ }
+ } else if (b->type == BOX_INLINE_END) {
+ b->width = 0;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
+
+ x += b->padding[RIGHT] + b->border[RIGHT].width +
+ b->margin[RIGHT];
+ continue;
+ }
+
+ if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
+ !(b->flags & REPLACE_DIM)) {
+ /* inline non-replaced, 10.3.1 and 10.6.1 */
+ b->height = line_height(&content->len_ctx,
+ b->style ? b->style :
+ b->parent->parent->style);
+ if (height < b->height)
+ height = b->height;
+
+ if (!b->text) {
+ b->width = 0;
+ space_after = 0;
+ continue;
+ }
+
+ if (b->width == UNKNOWN_WIDTH) {
+ /** \todo handle errors */
+
+ /* If it's a select element, we must use the
+ * width of the widest option text */
+ if (b->parent->parent->gadget &&
+ b->parent->parent->gadget->type
+ == GADGET_SELECT) {
+ int opt_maxwidth = 0;
+ struct form_option *o;
+
+ for (o = b->parent->parent->gadget->
+ data.select.items; o;
+ o = o->next) {
+ int opt_width;
+ font_func->width(&fstyle,
+ o->text,
+ strlen(o->text),
+ &opt_width);
+
+ if (opt_maxwidth < opt_width)
+ opt_maxwidth =opt_width;
+ }
+ b->width = opt_maxwidth;
+ if (nsoption_bool(core_select_menu))
+ b->width += SCROLLBAR_WIDTH;
+ } else {
+ font_func->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
+ }
+ }
+
+ /* If the current text has not been measured (i.e. its
+ * width was estimated after splitting), and it fits on
+ * the line, measure it properly, so next box is placed
+ * correctly. */
+ if (b->text && (x + b->width < x1 - x0) &&
+ !(b->flags & MEASURED) &&
+ b->next) {
+ font_func->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
+ }
+
+ x += b->width;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
+ continue;
+ }
+
+ space_after = 0;
+
+ /* inline replaced, 10.3.2 and 10.6.2 */
+ assert(b->style);
+
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style,
+ &b->width, &b->height,
+ &max_width, &min_width,
+ &max_height, &min_height,
+ NULL, NULL, NULL);
+
+ if (b->object && !(b->flags & REPLACE_DIM)) {
+ layout_get_object_dimensions(b, &b->width, &b->height,
+ min_width, max_width,
+ min_height, max_height);
+ } else if (b->flags & IFRAME) {
+ /* TODO: should we look at the content dimensions? */
+ if (b->width == AUTO)
+ b->width = 400;
+ if (b->height == AUTO)
+ b->height = 300;
+
+ /* We reformat the iframe browser window to new
+ * dimensions in pass 2 */
+ } else {
+ /* form control with no object */
+ if (b->width == AUTO)
+ b->width = FIXTOINT(nscss_len2px(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ if (b->height == AUTO)
+ b->height = FIXTOINT(nscss_len2px(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ }
+
+ /* Reformat object to new box size */
+ if (b->object && content_get_type(b->object) == CONTENT_HTML &&
+ b->width !=
+ content_get_available_width(b->object)) {
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+ enum css_height_e htype = css_computed_height(b->style,
+ &value, &unit);
+
+ content_reformat(b->object, false, b->width, b->height);
+
+ if (htype == CSS_HEIGHT_AUTO)
+ b->height = content_get_height(b->object);
+ }
+
+ if (height < b->height)
+ height = b->height;
+
+ x += b->width;
+ }
+
+ /* find new sides using this height */
+ x0 = cx;
+ x1 = cx + *width;
+ find_sides(cont->float_children, cy, cy + height, &x0, &x1,
+ &left, &right);
+ x0 -= cx;
+ x1 -= cx;
+
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
+
+ if (x1 < x0)
+ x1 = x0;
+
+ space_after = space_before = 0;
+
+ /* pass 2: place boxes in line: loop body executed at least once */
+
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+
+ for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
+
+ NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
+
+ if (b->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED)) {
+ b->x = x + space_after;
+
+ } else if (b->type == BOX_INLINE ||
+ b->type == BOX_INLINE_BLOCK ||
+ b->type == BOX_TEXT ||
+ b->type == BOX_INLINE_END) {
+ assert(b->width != UNKNOWN_WIDTH);
+
+ x_previous = x;
+ x += space_after;
+ b->x = x;
+
+ if ((b->type == BOX_INLINE && !b->inline_end) ||
+ b->type == BOX_INLINE_BLOCK) {
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
+ x = b->x + b->padding[LEFT] + b->width +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ } else if (b->type == BOX_INLINE) {
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
+ x = b->x + b->padding[LEFT] + b->width;
+ } else if (b->type == BOX_INLINE_END) {
+ b->height = b->inline_end->height;
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
+ } else {
+ x += b->width;
+ }
+
+ space_before = space_after;
+ if (b->object || b->flags & REPLACE_DIM ||
+ b->flags & IFRAME)
+ space_after = 0;
+ else if (b->text || b->type == BOX_INLINE_END) {
+ if (b->space == UNKNOWN_WIDTH) {
+ font_plot_style_from_css(
+ &content->len_ctx,
+ b->style, &fstyle);
+ /** \todo handle errors */
+ font_func->width(&fstyle, " ", 1,
+ &b->space);
+ }
+ space_after = b->space;
+ } else {
+ space_after = 0;
+ }
+ split_box = b;
+ move_y = true;
+ inline_count++;
+ } else if (b->type == BOX_BR) {
+ b->x = x;
+ b->width = 0;
+ br_box = b;
+ b = b->next;
+ split_box = 0;
+ move_y = true;
+ break;
+
+ } else {
+ /* float */
+ NSLOG(layout, DEBUG, "float %p", b);
+
+ d = b->children;
+ d->float_children = 0;
+ d->cached_place_below_level = 0;
+ b->float_container = d->float_container = cont;
+
+ if (!layout_float(d, *width, content))
+ return false;
+
+ NSLOG(layout, DEBUG,
+ "%p : %d %d",
+ d,
+ d->margin[TOP],
+ d->border[TOP].width);
+
+ d->x = d->margin[LEFT] + d->border[LEFT].width;
+ d->y = d->margin[TOP] + d->border[TOP].width;
+ b->width = d->margin[LEFT] + d->border[LEFT].width +
+ d->padding[LEFT] + d->width +
+ d->padding[RIGHT] +
+ d->border[RIGHT].width +
+ d->margin[RIGHT];
+ b->height = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
+
+ if (b->width > (x1 - x0) - x)
+ place_below = true;
+ if (d->style && (css_computed_clear(d->style) ==
+ CSS_CLEAR_NONE ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ left == 0 && right == 0)) &&
+ (!place_below ||
+ (left == 0 && right == 0 && x == 0)) &&
+ cy >= cont->clear_level &&
+ cy >= cont->cached_place_below_level) {
+ /* + not cleared or,
+ * cleared and there are no floats to clear
+ * + fits without needing to be placed below or,
+ * this line is empty with no floats
+ * + current y, cy, is below the clear level
+ *
+ * Float affects current line */
+ if (b->type == BOX_FLOAT_LEFT) {
+ b->x = cx + x0;
+ if (b->width > 0)
+ x0 += b->width;
+ left = b;
+ } else {
+ b->x = cx + x1 - b->width;
+ if (b->width > 0)
+ x1 -= b->width;
+ right = b;
+ }
+ b->y = cy;
+ } else {
+ /* cleared or doesn't fit on line */
+ /* place below into next available space */
+ int fcy = (cy > cont->clear_level) ? cy :
+ cont->clear_level;
+ fcy = (fcy > cont->cached_place_below_level) ?
+ fcy :
+ cont->cached_place_below_level;
+ fy = (fy > fcy) ? fy : fcy;
+ fy = (fy == cy) ? fy + height : fy;
+
+ place_float_below(b, *width, cx, fy, cont);
+ fy = b->y;
+ if (d->style && (
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left != 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right != 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ (left != 0 || right != 0)))) {
+ /* to be cleared below existing
+ * floats */
+ if (b->type == BOX_FLOAT_LEFT)
+ b->x = cx;
+ else
+ b->x = cx + *width - b->width;
+
+ fcy = layout_clear(cont->float_children,
+ css_computed_clear(d->style));
+ if (fcy > cont->clear_level)
+ cont->clear_level = fcy;
+ if (b->y < fcy)
+ b->y = fcy;
+ }
+ if (b->type == BOX_FLOAT_LEFT)
+ left = b;
+ else
+ right = b;
+ }
+ add_float_to_container(cont, b);
+
+ split_box = 0;
+ }
+ }
+
+ if (x1 - x0 < x && split_box) {
+ /* the last box went over the end */
+ size_t split = 0;
+ int w;
+ bool no_wrap = css_computed_white_space(
+ split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
+ css_computed_white_space(
+ split_box->style) == CSS_WHITE_SPACE_PRE;
+
+ x = x_previous;
+
+ if (!no_wrap &&
+ (split_box->type == BOX_INLINE ||
+ split_box->type == BOX_TEXT) &&
+ !split_box->object &&
+ !(split_box->flags & REPLACE_DIM) &&
+ !(split_box->flags & IFRAME) &&
+ !split_box->gadget && split_box->text) {
+
+ font_plot_style_from_css(&content->len_ctx,
+ split_box->style, &fstyle);
+ /** \todo handle errors */
+ font_func->split(&fstyle,
+ split_box->text,
+ split_box->length,
+ x1 - x0 - x - space_before,
+ &split,
+ &w);
+ }
+
+ /* split == 0 implies that text can't be split */
+
+ if (split == 0)
+ w = split_box->width;
+
+
+ NSLOG(layout, DEBUG,
+ "splitting: split_box %p \"%.*s\", spilt %zu, w %i, "
+ "left %p, right %p, inline_count %u",
+ split_box,
+ (int)split_box->length,
+ split_box->text,
+ split,
+ w,
+ left,
+ right,
+ inline_count);
+
+ if ((split == 0 || x1 - x0 <= x + space_before + w) &&
+ !left && !right && inline_count == 1) {
+ /* first word of box doesn't fit, but no floats and
+ * first box on line so force in */
+ if (split == 0 || split == split_box->length) {
+ /* only one word in this box, or not text
+ * or white-space:nowrap */
+ b = split_box->next;
+ } else {
+ /* cut off first word for this line */
+ if (!layout_text_box_split(content, &fstyle,
+ split_box, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
+
+ NSLOG(layout, DEBUG, "forcing");
+
+ } else if ((split == 0 || x1 - x0 <= x + space_before + w) &&
+ inline_count == 1) {
+ /* first word of first box doesn't fit, but a float is
+ * taking some of the width so move below it */
+ assert(left || right);
+ used_height = 0;
+ if (left) {
+
+ NSLOG(layout, DEBUG,
+ "cy %i, left->y %i, left->height %i",
+ cy,
+ left->y,
+ left->height);
+
+ used_height = left->y + left->height - cy + 1;
+
+ NSLOG(layout, DEBUG, "used_height %i",
+ used_height);
+
+ }
+ if (right && used_height <
+ right->y + right->height - cy + 1)
+ used_height = right->y + right->height - cy + 1;
+
+ if (used_height < 0)
+ used_height = 0;
+
+ b = split_box;
+
+ NSLOG(layout, DEBUG, "moving below float");
+
+ } else if (split == 0 || x1 - x0 <= x + space_before + w) {
+ /* first word of box doesn't fit so leave box for next
+ * line */
+ b = split_box;
+
+ NSLOG(layout, DEBUG, "leaving for next line");
+
+ } else {
+ /* fit as many words as possible */
+ assert(split != 0);
+
+ NSLOG(layout, DEBUG, "'%.*s' %i %zu %i",
+ (int)split_box->length, split_box->text,
+ x1 - x0, split, w);
+
+ if (split != split_box->length) {
+ if (!layout_text_box_split(content, &fstyle,
+ split_box, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
+
+ NSLOG(layout, DEBUG, "fitting words");
+
+ }
+ move_y = true;
+ }
+
+ /* set positions */
+ switch (css_computed_text_align(first->parent->parent->style)) {
+ case CSS_TEXT_ALIGN_RIGHT:
+ case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
+ x0 = x1 - x;
+ break;
+ case CSS_TEXT_ALIGN_CENTER:
+ case CSS_TEXT_ALIGN_LIBCSS_CENTER:
+ x0 = (x0 + (x1 - x)) / 2;
+ break;
+ case CSS_TEXT_ALIGN_LEFT:
+ case CSS_TEXT_ALIGN_LIBCSS_LEFT:
+ case CSS_TEXT_ALIGN_JUSTIFY:
+ /* leave on left */
+ break;
+ case CSS_TEXT_ALIGN_DEFAULT:
+ /* None; consider text direction */
+ switch (css_computed_direction(first->parent->parent->style)) {
+ case CSS_DIRECTION_LTR:
+ /* leave on left */
+ break;
+ case CSS_DIRECTION_RTL:
+ x0 = x1 - x;
+ break;
+ }
+ break;
+ }
+
+ for (d = first; d != b; d = d->next) {
+ d->flags &= ~NEW_LINE;
+
+ if (d->type == BOX_INLINE_BLOCK &&
+ (css_computed_position(d->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(d->style) ==
+ CSS_POSITION_FIXED)) {
+ /* positioned inline-blocks:
+ * set static position (x,y) only, rest of positioning
+ * is handled later */
+ d->x += x0;
+ d->y = *y;
+ continue;
+ } else if ((d->type == BOX_INLINE &&
+ ((d->object || d->gadget) == false) &&
+ !(d->flags & IFRAME) &&
+ !(d->flags & REPLACE_DIM)) ||
+ d->type == BOX_BR ||
+ d->type == BOX_TEXT ||
+ d->type == BOX_INLINE_END) {
+ /* regular (non-replaced) inlines */
+ d->x += x0;
+ d->y = *y - d->padding[TOP];
+
+ if (d->type == BOX_TEXT && d->height > used_height) {
+ /* text */
+ used_height = d->height;
+ }
+ } else if ((d->type == BOX_INLINE) ||
+ d->type == BOX_INLINE_BLOCK) {
+ /* replaced inlines and inline-blocks */
+ d->x += x0;
+ d->y = *y + d->border[TOP].width + d->margin[TOP];
+ h = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
+ if (used_height < h)
+ used_height = h;
+ }
+ }
+
+ first->flags |= NEW_LINE;
+
+ assert(b != first || (move_y && 0 < used_height && (left || right)));
+
+ /* handle vertical-align by adjusting box y values */
+ /** \todo proper vertical alignment handling */
+ for (d = first; d != b; d = d->next) {
+ if ((d->type == BOX_INLINE && d->inline_end) ||
+ d->type == BOX_BR ||
+ d->type == BOX_TEXT ||
+ d->type == BOX_INLINE_END) {
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+ switch (css_computed_vertical_align(d->style, &value,
+ &unit)) {
+ case CSS_VERTICAL_ALIGN_SUPER:
+ case CSS_VERTICAL_ALIGN_TOP:
+ case CSS_VERTICAL_ALIGN_TEXT_TOP:
+ /* already at top */
+ break;
+ case CSS_VERTICAL_ALIGN_SUB:
+ case CSS_VERTICAL_ALIGN_BOTTOM:
+ case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
+ d->y += used_height - d->height;
+ break;
+ default:
+ case CSS_VERTICAL_ALIGN_BASELINE:
+ d->y += 0.75 * (used_height - d->height);
+ break;
+ }
+ }
+ }
+
+ /* handle clearance for br */
+ if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
+ int clear_y = layout_clear(cont->float_children,
+ css_computed_clear(br_box->style));
+ if (used_height < clear_y - cy)
+ used_height = clear_y - cy;
+ }
+
+ if (move_y)
+ *y += used_height;
+ *next_box = b;
+ *width = x; /* return actual width */
+ return true;
+}
+
+
+/**
+ * Layout lines of text or inline boxes with floats.
+ *
+ * \param box inline container box
+ * \param width horizontal space available
+ * \param cont ancestor box which defines horizontal space, for floats
+ * \param cx box position relative to cont
+ * \param cy box position relative to cont
+ * \param content memory pool for any new boxes
+ * \return true on success, false on memory exhaustion
+ */
+static bool layout_inline_container(struct box *inline_container, int width,
+ struct box *cont, int cx, int cy, html_content *content)
+{
+ bool first_line = true;
+ bool has_text_children;
+ struct box *c, *next;
+ int y = 0;
+ int curwidth,maxwidth = width;
+
+ assert(inline_container->type == BOX_INLINE_CONTAINER);
+
+ NSLOG(layout, DEBUG,
+ "inline_container %p, width %i, cont %p, cx %i, cy %i",
+ inline_container,
+ width,
+ cont,
+ cx,
+ cy);
+
+
+ has_text_children = false;
+ for (c = inline_container->children; c; c = c->next) {
+ bool is_pre = false;
+
+ if (c->style) {
+ enum css_white_space_e whitespace;
+
+ whitespace = css_computed_white_space(c->style);
+
+ is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
+ whitespace == CSS_WHITE_SPACE_PRE_LINE ||
+ whitespace == CSS_WHITE_SPACE_PRE_WRAP);
+ }
+
+ if ((!c->object && !(c->flags & REPLACE_DIM) &&
+ !(c->flags & IFRAME) &&
+ c->text && (c->length || is_pre)) ||
+ c->type == BOX_BR)
+ has_text_children = true;
+ }
+
+ /** \todo fix wrapping so that a box with horizontal scrollbar will
+ * shrink back to 'width' if no word is wider than 'width' (Or just set
+ * curwidth = width and have the multiword lines wrap to the min width)
+ */
+ for (c = inline_container->children; c; ) {
+
+ NSLOG(layout, DEBUG, "c %p", c);
+
+ curwidth = inline_container->width;
+ if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
+ has_text_children, content, &next))
+ return false;
+ maxwidth = max(maxwidth,curwidth);
+ c = next;
+ first_line = false;
+ }
+
+ inline_container->width = maxwidth;
+ inline_container->height = y;
+
+ return true;
+}
+
+
+/**
* Layout a block formatting context.
*
* \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
@@ -2476,7 +3962,8 @@ layout_block_context(struct box *block,
gadget_unit = CSS_UNIT_EM;
gadget_size = INTTOFIX(1);
if (block->height == AUTO)
- block->height = FIXTOINT(nscss_len2px(gadget_size,
+ block->height = FIXTOINT(nscss_len2px(
+ &content->len_ctx, gadget_size,
gadget_unit, block->style));
}
@@ -2540,7 +4027,8 @@ layout_block_context(struct box *block,
/* If we don't know which box the current margin collapses
* through to, find out. Update the pos/neg margin values. */
if (margin_collapse == NULL) {
- margin_collapse = layout_next_margin_block(box, block,
+ margin_collapse = layout_next_margin_block(
+ &content->len_ctx, box, block,
viewport_height,
&max_pos_margin, &max_neg_margin);
/* We have a margin that has not yet been applied. */
@@ -2591,7 +4079,8 @@ layout_block_context(struct box *block,
box->parent->padding[RIGHT] -
x1;
}
- layout_block_find_dimensions(box->parent->width,
+ layout_block_find_dimensions(&content->len_ctx,
+ box->parent->width,
viewport_height, lm, rm, box);
if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) {
layout_block_add_scrollbar(box, RIGHT);
@@ -2649,13 +4138,12 @@ layout_block_context(struct box *block,
}
/* Vertical margin */
- if (((box->type == BOX_BLOCK &&
- (box->flags & HAS_HEIGHT)) ||
- box->type == BOX_TABLE ||
- (box->type == BOX_INLINE_CONTAINER &&
- box != box->parent->children) ||
- margin_collapse == box) &&
- in_margin == true) {
+ if (((box->type == BOX_BLOCK && (box->flags & HAS_HEIGHT)) ||
+ box->type == BOX_TABLE ||
+ (box->type == BOX_INLINE_CONTAINER &&
+ !box_is_first_child(box)) ||
+ margin_collapse == box) &&
+ in_margin == true) {
/* Margin goes above this box. */
cy += max_pos_margin - max_neg_margin;
box->y += max_pos_margin - max_neg_margin;
@@ -2700,9 +4188,7 @@ layout_block_context(struct box *block,
goto advance_to_next_box;
}
-#ifdef LAYOUT_DEBUG
- LOG("box %p, cx %i, cy %i", box, cx, cy);
-#endif
+ NSLOG(layout, DEBUG, "box %p, cx %i, cy %i", box, cx, cy);
/* Layout (except tables). */
if (box->object) {
@@ -2833,8 +4319,9 @@ layout_block_context(struct box *block,
if (box->style &&
css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
- layout_apply_minmax_height(box,
- NULL)) {
+ layout_apply_minmax_height(
+ &content->len_ctx,
+ box, NULL)) {
/* Height altered */
/* Set current cy */
cy += box->height -
@@ -2890,19 +4377,23 @@ layout_block_context(struct box *block,
if (block->style && css_computed_position(block->style) !=
CSS_POSITION_ABSOLUTE) {
/* Block is in normal flow */
- layout_apply_minmax_height(block, NULL);
+ layout_apply_minmax_height(&content->len_ctx, block, NULL);
}
if (block->gadget &&
(block->gadget->type == GADGET_TEXTAREA ||
block->gadget->type == GADGET_PASSWORD ||
block->gadget->type == GADGET_TEXTBOX)) {
+ plot_font_style_t fstyle;
int ta_width = block->padding[LEFT] + block->width +
block->padding[RIGHT];
int ta_height = block->padding[TOP] + block->height +
block->padding[BOTTOM];
+ font_plot_style_from_css(&content->len_ctx,
+ block->style, &fstyle);
+ fstyle.background = NS_TRANSPARENT;
textarea_set_layout(block->gadget->data.text.ta,
- ta_width, ta_height,
+ &fstyle, ta_width, ta_height,
block->padding[TOP], block->padding[RIGHT],
block->padding[BOTTOM], block->padding[LEFT]);
}
@@ -2912,46 +4403,12 @@ layout_block_context(struct box *block,
/**
- * Calculate line height from a style.
- */
-static int line_height(const css_computed_style *style)
-{
- enum css_line_height_e lhtype;
- css_fixed lhvalue = 0;
- css_unit lhunit = CSS_UNIT_PX;
- css_fixed line_height;
-
- assert(style);
-
- lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
- if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
- /* Normal => use a constant of 1.3 * font-size */
- lhvalue = FLTTOFIX(1.3);
- lhtype = CSS_LINE_HEIGHT_NUMBER;
- }
-
- if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
- lhunit == CSS_UNIT_PCT) {
- line_height = nscss_len2px(lhvalue, CSS_UNIT_EM, style);
-
- if (lhtype != CSS_LINE_HEIGHT_NUMBER)
- line_height = FDIV(line_height, F_100);
- } else {
- assert(lhunit != CSS_UNIT_PCT);
-
- line_height = nscss_len2px(lhvalue, lhunit, style);
- }
-
- return FIXTOINT(line_height);
-}
-
-
-/**
* Layout list markers.
*/
static void
layout_lists(struct box *box,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const nscss_len_ctx *len_ctx)
{
struct box *child;
struct box *marker;
@@ -2966,12 +4423,13 @@ layout_lists(struct box *box,
marker->x = -marker->width;
marker->height =
content_get_height(marker->object);
- marker->y = (line_height(marker->style) -
+ marker->y = (line_height(len_ctx,
+ marker->style) -
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH) {
- font_plot_style_from_css(marker->style,
- &fstyle);
+ font_plot_style_from_css(len_ctx,
+ marker->style, &fstyle);
font_func->width(&fstyle,
marker->text,
marker->length,
@@ -2980,7 +4438,8 @@ layout_lists(struct box *box,
}
marker->x = -marker->width;
marker->y = 0;
- marker->height = line_height(marker->style);
+ marker->height = line_height(len_ctx,
+ marker->style);
} else {
marker->x = 0;
marker->y = 0;
@@ -2990,7 +4449,7 @@ layout_lists(struct box *box,
/* Gap between marker and content */
marker->x -= 4;
}
- layout_lists(child, font_func);
+ layout_lists(child, font_func, len_ctx);
}
}
@@ -2999,6 +4458,7 @@ layout_lists(struct box *box,
* Compute box offsets for a relatively or absolutely positioned box with
* respect to a box.
*
+ * \param len_ctx Length conversion context
* \param box box to compute offsets for
* \param containing_block box to compute percentages with respect to
* \param top updated to top offset, or AUTO
@@ -3009,7 +4469,8 @@ layout_lists(struct box *box,
* See CSS 2.1 9.3.2. containing_block must have width and height.
*/
static void
-layout_compute_offsets(struct box *box,
+layout_compute_offsets(const nscss_len_ctx *len_ctx,
+ struct box *box,
struct box *containing_block,
int *top,
int *right,
@@ -3031,7 +4492,8 @@ layout_compute_offsets(struct box *box,
*left = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
- *left = FIXTOINT(nscss_len2px(value, unit, box->style));
+ *left = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*left = AUTO;
@@ -3044,8 +4506,8 @@ layout_compute_offsets(struct box *box,
*right = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
- *right = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ *right = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*right = AUTO;
@@ -3058,7 +4520,8 @@ layout_compute_offsets(struct box *box,
*top = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
- *top = FIXTOINT(nscss_len2px(value, unit, box->style));
+ *top = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*top = AUTO;
@@ -3071,8 +4534,8 @@ layout_compute_offsets(struct box *box,
*bottom = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
- *bottom = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ *bottom = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
}
} else {
*bottom = AUTO;
@@ -3128,22 +4591,26 @@ layout_absolute(struct box *box,
/** \todo inline containers */
}
- layout_compute_offsets(box, containing_block,
+ layout_compute_offsets(&content->len_ctx, box, containing_block,
&top, &right, &bottom, &left);
/* Pass containing block into layout_find_dimensions via the float
* containing block box member. This is unused for absolutely positioned
* boxes because a box can't be floated and absolutely positioned. */
box->float_container = containing_block;
- layout_find_dimensions(available_width, -1, box, box->style,
- &width, &height, &max_width, &min_width,
- 0, 0, margin, padding, border);
+ layout_find_dimensions(&content->len_ctx, available_width, -1,
+ box, box->style, &width, &height,
+ &max_width, &min_width, 0, 0,
+ margin, padding, border);
box->float_container = NULL;
/* 10.3.7 */
-#ifdef LAYOUT_DEBUG
- LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", left, margin[LEFT], border[LEFT].width, padding[LEFT], width, padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, containing_block->width);
-#endif
+ NSLOG(layout, DEBUG,
+ "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
+ left, margin[LEFT], border[LEFT].width, padding[LEFT], width,
+ padding[RIGHT], border[RIGHT].width, margin[RIGHT], right,
+ containing_block->width);
+
if (left == AUTO && width == AUTO && right == AUTO) {
if (margin[LEFT] == AUTO)
@@ -3160,7 +4627,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
+ if (width < min_width) width = min_width;
right = containing_block->width -
left -
@@ -3221,7 +4688,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
- if (min_width > 0 && width < min_width)
+ if (width < min_width)
width = min_width;
left = containing_block->width -
@@ -3255,7 +4722,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
- if (min_width > 0 && width < min_width)
+ if (width < min_width)
width = min_width;
right = containing_block->width -
@@ -3268,7 +4735,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
- if (min_width > 0 && width < min_width)
+ if (width < min_width)
width = min_width;
left = containing_block->width -
@@ -3287,7 +4754,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
- if (min_width > 0 && width < min_width)
+ if (width < min_width)
width = min_width;
} else if (left != AUTO && width != AUTO && right == AUTO) {
@@ -3295,7 +4762,7 @@ layout_absolute(struct box *box,
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
- if (min_width > 0 && width < min_width)
+ if (width < min_width)
width = min_width;
right = containing_block->width -
@@ -3306,9 +4773,11 @@ layout_absolute(struct box *box,
}
}
-#ifdef LAYOUT_DEBUG
- LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", left, margin[LEFT], border[LEFT].width, padding[LEFT], width, padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, containing_block->width);
-#endif
+ NSLOG(layout, DEBUG,
+ "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
+ left, margin[LEFT], border[LEFT].width, padding[LEFT], width,
+ padding[RIGHT], border[RIGHT].width, margin[RIGHT], right,
+ containing_block->width);
box->x = left + margin[LEFT] + border[LEFT].width - cx;
if (containing_block->type == BOX_BLOCK ||
@@ -3340,9 +4809,11 @@ layout_absolute(struct box *box,
}
/* 10.6.4 */
-#ifdef LAYOUT_DEBUG
- LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", top, margin[TOP], border[TOP].width, padding[TOP], height, padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, containing_block->height);
-#endif
+ NSLOG(layout, DEBUG,
+ "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
+ top, margin[TOP], border[TOP].width, padding[TOP], height,
+ padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom,
+ containing_block->height);
if (top == AUTO && height == AUTO && bottom == AUTO) {
top = static_top;
@@ -3428,9 +4899,11 @@ layout_absolute(struct box *box,
}
}
-#ifdef LAYOUT_DEBUG
- LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", top, margin[TOP], border[TOP].width, padding[TOP], height, padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, containing_block->height);
-#endif
+ NSLOG(layout, DEBUG,
+ "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
+ top, margin[TOP], border[TOP].width, padding[TOP], height,
+ padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom,
+ containing_block->height);
box->y = top + margin[TOP] + border[TOP].width - cy;
if (containing_block->type == BOX_BLOCK ||
@@ -3443,7 +4916,7 @@ layout_absolute(struct box *box,
/** \todo Inline ancestors */
}
box->height = height;
- layout_apply_minmax_height(box, containing_block);
+ layout_apply_minmax_height(&content->len_ctx, box, containing_block);
return true;
}
@@ -3520,11 +4993,16 @@ layout_position_absolute(struct box *box,
/**
* Compute a box's relative offset as per CSS 2.1 9.4.3
*
+ * \param len_ctx Length conversion context
* \param box Box to compute relative offsets for.
* \param x Receives relative offset in x.
* \param y Receives relative offset in y.
*/
-static void layout_compute_relative_offset(struct box *box, int *x, int *y)
+static void layout_compute_relative_offset(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int *x,
+ int *y)
{
int left, right, top, bottom;
struct box *containing_block;
@@ -3541,7 +5019,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
containing_block = box->parent;
}
- layout_compute_offsets(box, containing_block,
+ layout_compute_offsets(len_ctx, box, containing_block,
&top, &right, &bottom, &left);
if (left == AUTO && right == AUTO)
@@ -3578,9 +5056,8 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
bottom = -top;
}
-#ifdef LAYOUT_DEBUG
- LOG("left %i, right %i, top %i, bottom %i", left, right, top, bottom);
-#endif
+ NSLOG(layout, DEBUG, "left %i, right %i, top %i, bottom %i", left,
+ right, top, bottom);
*x = left;
*y = top;
@@ -3590,6 +5067,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
/**
* Adjust positions of relatively positioned boxes.
*
+ * \param len_ctx Length conversion context
* \param root box to adjust the position of
* \param fp box which forms the block formatting context for children of
* "root" which are floats
@@ -3601,7 +5079,12 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y)
* box, "fp", for float children of "root"
*/
static void
-layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
+layout_position_relative(
+ const nscss_len_ctx *len_ctx,
+ struct box *root,
+ struct box *fp,
+ int fx,
+ int fy)
{
struct box *box; /* for children of "root" */
struct box *fn; /* for block formatting context box for children of
@@ -3625,7 +5108,8 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* If relatively positioned, get offsets */
if (box->style && css_computed_position(box->style) ==
CSS_POSITION_RELATIVE)
- layout_compute_relative_offset(box, &x, &y);
+ layout_compute_relative_offset(
+ len_ctx, box, &x, &y);
else
x = y = 0;
@@ -3661,7 +5145,7 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
}
/* recurse first */
- layout_position_relative(box, fn, fnx, fny);
+ layout_position_relative(len_ctx, box, fn, fnx, fny);
/* Ignore things we're not interested in. */
if (!box->style || (box->style &&
@@ -3687,1334 +5171,10 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
}
-/* exported function documented in render/layout.h */
-bool layout_document(html_content *content, int width, int height)
-{
- bool ret;
- struct box *doc = content->layout;
- const struct gui_layout_table *font_func = content->font_func;
-
- layout_minmax_block(doc, font_func);
-
- layout_block_find_dimensions(width, height, 0, 0, doc);
- doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
- doc->y = doc->margin[TOP] + doc->border[TOP].width;
- width -= doc->margin[LEFT] + doc->border[LEFT].width +
- doc->padding[LEFT] + doc->padding[RIGHT] +
- doc->border[RIGHT].width + doc->margin[RIGHT];
- if (width < 0) {
- width = 0;
- }
- doc->width = width;
-
- ret = layout_block_context(doc, height, content);
-
- /* make <html> and <body> fill available height */
- if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
- doc->border[BOTTOM].width + doc->margin[BOTTOM] <
- height) {
- doc->height = height - (doc->y + doc->padding[TOP] +
- doc->padding[BOTTOM] +
- doc->border[BOTTOM].width +
- doc->margin[BOTTOM]);
- if (doc->children)
- doc->children->height = doc->height -
- (doc->children->margin[TOP] +
- doc->children->border[TOP].width +
- doc->children->padding[TOP] +
- doc->children->padding[BOTTOM] +
- doc->children->border[BOTTOM].width +
- doc->children->margin[BOTTOM]);
- }
-
- layout_lists(doc, font_func);
- layout_position_absolute(doc, doc, 0, 0, content);
- layout_position_relative(doc, doc, 0, 0);
-
- layout_calculate_descendant_bboxes(doc);
-
- return ret;
-}
-
-
-/**
- * Insert a float into a container.
- *
- * \param cont block formatting context block, used to contain float
- * \param b box to add to float
- *
- * This sorts floats in order of descending bottom edges.
- */
-static void add_float_to_container(struct box *cont, struct box *b)
-{
- struct box *box = cont->float_children;
- int b_bottom = b->y + b->height;
-
- assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
-
- if (box == NULL) {
- /* No other float children */
- b->next_float = NULL;
- cont->float_children = b;
- return;
- } else if (b_bottom >= box->y + box->height) {
- /* Goes at start of list */
- b->next_float = cont->float_children;
- cont->float_children = b;
- } else {
- struct box *prev = NULL;
- while (box != NULL && b_bottom < box->y + box->height) {
- prev = box;
- box = box->next_float;
- }
- if (prev != NULL) {
- b->next_float = prev->next_float;
- prev->next_float = b;
- }
- }
-}
-
-
-/**
- * Split a text box.
- *
- * \param content memory pool for any new boxes
- * \param fstyle style for text in text box
- * \param split_box box with text to split
- * \param new_length new length for text in split_box, after splitting
- * \param new_width new width for text in split_box, after splitting
- * \return true on success, false on memory exhaustion
- *
- * A new box is created and inserted into the box tree after split_box,
- * containing the text after new_length excluding the initial space character.
- */
-static bool
-layout_text_box_split(html_content *content,
- plot_font_style_t *fstyle,
- struct box *split_box,
- size_t new_length,
- int new_width)
-{
- int space_width = split_box->space;
- struct box *c2;
- const struct gui_layout_table *font_func = content->font_func;
- bool space = (split_box->text[new_length] == ' ');
- int used_length = new_length + (space ? 1 : 0);
-
- if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
- /* We're need to add a space, and we don't know how big
- * it's to be, OR we have a space of unknown width anyway;
- * Calculate space width */
- font_func->width(fstyle, " ", 1, &space_width);
- }
-
- if (split_box->space == UNKNOWN_WIDTH)
- split_box->space = space_width;
- if (!space)
- space_width = 0;
-
- /* Create clone of split_box, c2 */
- c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
- if (!c2)
- return false;
- c2->flags |= CLONE;
-
- /* Set remaining text in c2 */
- c2->text += used_length;
-
- /* Set c2 according to the remaining text */
- c2->width -= new_width + space_width;
- c2->flags &= ~MEASURED; /* width has been estimated */
- c2->length = split_box->length - used_length;
-
- /* Update split_box for its reduced text */
- split_box->width = new_width;
- split_box->flags |= MEASURED;
- split_box->length = new_length;
- split_box->space = space_width;
-
- /* Insert c2 into box list */
- c2->next = split_box->next;
- split_box->next = c2;
- c2->prev = split_box;
- if (c2->next)
- c2->next->prev = c2;
- else
- c2->parent->last = c2;
-#ifdef LAYOUT_DEBUG
- LOG("split_box %p len: %u \"%.*s\"", split_box, split_box->length, split_box->length, split_box->text);
- LOG(" new_box %p len: %u \"%.*s\"", c2, c2->length, c2->length, c2->text);
-#endif
- return true;
-}
-
-
-/**
- * Compute dimensions of box, margins, paddings, and borders for a floating
- * element using shrink-to-fit. Also used for inline-blocks.
- *
- * \param available_width Max width available in pixels
- * \param style Box's style
- * \param box Box for which to find dimensions
- * Box margins, borders, paddings, width and
- * height are updated.
- */
-static void
-layout_float_find_dimensions(int available_width,
- const css_computed_style *style,
- struct box *box)
-{
- int width, height, max_width, min_width, max_height, min_height;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- enum css_overflow_e overflow_x = css_computed_overflow_x(style);
- enum css_overflow_e overflow_y = css_computed_overflow_y(style);
- int scrollbar_width_x =
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
- int scrollbar_width_y =
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
-
- layout_find_dimensions(available_width, -1, box, style, &width, &height,
- &max_width, &min_width, &max_height, &min_height,
- margin, padding, border);
-
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
-
- if (box->gadget == NULL) {
- padding[RIGHT] += scrollbar_width_y;
- padding[BOTTOM] += scrollbar_width_x;
- }
-
- if (box->object && !(box->flags & REPLACE_DIM) &&
- content_get_type(box->object) != CONTENT_HTML) {
- /* Floating replaced element, with intrinsic width or height.
- * See 10.3.6 and 10.6.2 */
- layout_get_object_dimensions(box, &width, &height,
- min_width, max_width, min_height, max_height);
- } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE ||
- box->gadget->type == GADGET_TEXTAREA)) {
- css_fixed size = 0;
- css_unit unit = CSS_UNIT_EM;
-
- /* Give sensible dimensions to gadgets, with auto width/height,
- * that don't shrink to fit contained text. */
- assert(box->style);
-
- if (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- if (box->gadget->type == GADGET_FILE &&
- height == AUTO) {
- size = FLTTOFIX(1.5);
- height = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- }
- if (box->gadget->type == GADGET_TEXTAREA) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- if (height == AUTO) {
- size = INTTOFIX(4);
- height = FIXTOINT(nscss_len2px(size, unit,
- box->style));
- }
- }
- } else if (width == AUTO) {
- /* CSS 2.1 section 10.3.5 */
- width = min(max(box->min_width, available_width),
- box->max_width);
-
- /* width includes margin, borders and padding */
- if (width == available_width) {
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] +
- box->padding[RIGHT] +
- box->border[RIGHT].width +
- box->margin[RIGHT];
- } else {
- /* width was obtained from a min_width or max_width
- * value, so need to use the same method for calculating
- * mbp as was used in layout_minmax_block() */
- int fixed = 0;
- float frac = 0;
- calculate_mbp_width(box->style, LEFT, true, true, true,
- &fixed, &frac);
- calculate_mbp_width(box->style, RIGHT, true, true, true,
- &fixed, &frac);
- if (fixed < 0)
- fixed = 0;
-
- width -= fixed;
- }
-
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
-
- } else {
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
- width -= scrollbar_width_y;
- }
-
- box->width = width;
- box->height = height;
-
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
-}
-
-
-/**
- * Layout the contents of a float or inline block.
- *
- * \param b float or inline block box
- * \param width available width
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool layout_float(struct box *b, int width, html_content *content)
-{
- assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
- b->type == BOX_INLINE_BLOCK);
- layout_float_find_dimensions(width, b->style, b);
- if (b->type == BOX_TABLE) {
- if (!layout_table(b, width, content))
- return false;
- if (b->margin[LEFT] == AUTO)
- b->margin[LEFT] = 0;
- if (b->margin[RIGHT] == AUTO)
- b->margin[RIGHT] = 0;
- if (b->margin[TOP] == AUTO)
- b->margin[TOP] = 0;
- if (b->margin[BOTTOM] == AUTO)
- b->margin[BOTTOM] = 0;
- } else
- return layout_block_context(b, -1, content);
- return true;
-}
-
-
-/**
- * Position a float in the first available space.
- *
- * \param c float box to position
- * \param width available width
- * \param cx x coordinate relative to cont to place float right of
- * \param y y coordinate relative to cont to place float below
- * \param cont ancestor box which defines horizontal space, for floats
- */
-static void
-place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
-{
- int x0, x1, yy;
- struct box *left;
- struct box *right;
-
- yy = y > cont->cached_place_below_level ?
- y : cont->cached_place_below_level;
-
-#ifdef LAYOUT_DEBUG
- LOG("c %p, width %i, cx %i, y %i, cont %p", c, width, cx, y, cont);
-#endif
-
- do {
- y = yy;
- x0 = cx;
- x1 = cx + width;
- find_sides(cont->float_children, y, y + c->height, &x0, &x1,
- &left, &right);
- if (left != 0 && right != 0) {
- yy = (left->y + left->height <
- right->y + right->height ?
- left->y + left->height :
- right->y + right->height);
- } else if (left == 0 && right != 0) {
- yy = right->y + right->height;
- } else if (left != 0 && right == 0) {
- yy = left->y + left->height;
- }
- } while ((left != 0 || right != 0) && (c->width > x1 - x0));
-
- if (c->type == BOX_FLOAT_LEFT) {
- c->x = x0;
- } else {
- c->x = x1 - c->width;
- }
- c->y = y;
- cont->cached_place_below_level = y;
-}
-
-
-/**
- * Position a line of boxes in inline formatting context.
- *
- * \param first box at start of line
- * \param width available width on input, updated with actual width on output
- * (may be incorrect if the line gets split?)
- * \param y coordinate of top of line, updated on exit to bottom
- * \param cx coordinate of left of line relative to cont
- * \param cy coordinate of top of line relative to cont
- * \param cont ancestor box which defines horizontal space, for floats
- * \param indent apply any first-line indent
- * \param has_text_children at least one TEXT in the inline_container
- * \param next_box updated to first box for next line, or 0 at end
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool
-layout_line(struct box *first,
- int *width,
- int *y,
- int cx,
- int cy,
- struct box *cont,
- bool indent,
- bool has_text_children,
- html_content *content,
- struct box **next_box)
-{
- int height, used_height;
- int x0 = 0;
- int x1 = *width;
- int x, h, x_previous;
- int fy = cy;
- struct box *left;
- struct box *right;
- struct box *b;
- struct box *split_box = 0;
- struct box *d;
- struct box *br_box = 0;
- bool move_y = false;
- bool place_below = false;
- int space_before = 0, space_after = 0;
- unsigned int inline_count = 0;
- unsigned int i;
- const struct gui_layout_table *font_func = content->font_func;
- plot_font_style_t fstyle;
-
-#ifdef LAYOUT_DEBUG
- LOG("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i", first, (int)first->length, first->text, *width, *y, cx, cy);
-#endif
-
- /* find sides at top of line */
- x0 += cx;
- x1 += cx;
- find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
- x0 -= cx;
- x1 -= cx;
-
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- /* get minimum line height from containing block.
- * this is the line-height if there are text children and also in the
- * case of an initially empty text input */
- if (has_text_children || first->parent->parent->gadget)
- used_height = height =
- line_height(first->parent->parent->style);
- else
- /* inline containers with no text are usually for layout and
- * look better with no minimum line-height */
- used_height = height = 0;
-
- /* pass 1: find height of line assuming sides at top of line: loop
- * body executed at least once
- * keep in sync with the loop in layout_minmax_line() */
-#ifdef LAYOUT_DEBUG
- LOG("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-#endif
-
- for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
- int min_width, max_width, min_height, max_height;
-
- assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_FLOAT_LEFT ||
- b->type == BOX_FLOAT_RIGHT ||
- b->type == BOX_BR || b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END);
-
-#ifdef LAYOUT_DEBUG
- LOG("pass 1: b %p, x %i", b, x);
-#endif
-
- if (b->type == BOX_BR)
- break;
-
- if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
- continue;
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED))
- continue;
-
- assert(b->style != NULL);
- font_plot_style_from_css(b->style, &fstyle);
-
- x += space_after;
-
- if (b->type == BOX_INLINE_BLOCK) {
- if (b->max_width != UNKNOWN_WIDTH)
- if (!layout_float(b, *width, content))
- return false;
- h = b->border[TOP].width + b->padding[TOP] + b->height +
- b->padding[BOTTOM] +
- b->border[BOTTOM].width;
- if (height < h)
- height = h;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- space_after = 0;
- continue;
- }
-
- if (b->type == BOX_INLINE) {
- /* calculate borders, margins, and padding */
- layout_find_dimensions(*width, -1, b, b->style, 0, 0,
- 0, 0, 0, 0, b->margin, b->padding,
- b->border);
- for (i = 0; i != 4; i++)
- if (b->margin[i] == AUTO)
- b->margin[i] = 0;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT];
- if (b->inline_end) {
- b->inline_end->margin[RIGHT] = b->margin[RIGHT];
- b->inline_end->padding[RIGHT] =
- b->padding[RIGHT];
- b->inline_end->border[RIGHT] =
- b->border[RIGHT];
- } else {
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- }
- } else if (b->type == BOX_INLINE_END) {
- b->width = 0;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
-
- x += b->padding[RIGHT] + b->border[RIGHT].width +
- b->margin[RIGHT];
- continue;
- }
-
- if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
- !(b->flags & REPLACE_DIM)) {
- /* inline non-replaced, 10.3.1 and 10.6.1 */
- b->height = line_height(b->style ? b->style :
- b->parent->parent->style);
- if (height < b->height)
- height = b->height;
-
- if (!b->text) {
- b->width = 0;
- space_after = 0;
- continue;
- }
-
- if (b->width == UNKNOWN_WIDTH) {
- /** \todo handle errors */
-
- /* If it's a select element, we must use the
- * width of the widest option text */
- if (b->parent->parent->gadget &&
- b->parent->parent->gadget->type
- == GADGET_SELECT) {
- int opt_maxwidth = 0;
- struct form_option *o;
-
- for (o = b->parent->parent->gadget->
- data.select.items; o;
- o = o->next) {
- int opt_width;
- font_func->width(&fstyle,
- o->text,
- strlen(o->text),
- &opt_width);
-
- if (opt_maxwidth < opt_width)
- opt_maxwidth =opt_width;
- }
- b->width = opt_maxwidth;
- if (nsoption_bool(core_select_menu))
- b->width += SCROLLBAR_WIDTH;
- } else {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
- }
-
- /* If the current text has not been measured (i.e. its
- * width was estimated after splitting), and it fits on
- * the line, measure it properly, so next box is placed
- * correctly. */
- if (b->text && (x + b->width < x1 - x0) &&
- !(b->flags & MEASURED) &&
- b->next) {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
-
- x += b->width;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
- continue;
- }
-
- space_after = 0;
-
- /* inline replaced, 10.3.2 and 10.6.2 */
- assert(b->style);
-
- layout_find_dimensions(*width, -1, b, b->style,
- &b->width, &b->height, &max_width, &min_width,
- &max_height, &min_height, NULL, NULL, NULL);
-
- if (b->object && !(b->flags & REPLACE_DIM)) {
- layout_get_object_dimensions(b, &b->width, &b->height,
- min_width, max_width,
- min_height, max_height);
- } else if (b->flags & IFRAME) {
- /* TODO: should we look at the content dimensions? */
- if (b->width == AUTO)
- b->width = 400;
- if (b->height == AUTO)
- b->height = 300;
-
- /* We reformat the iframe browser window to new
- * dimensions in pass 2 */
- } else {
- /* form control with no object */
- if (b->width == AUTO)
- b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
- if (b->height == AUTO)
- b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
- }
-
- /* Reformat object to new box size */
- if (b->object && content_get_type(b->object) == CONTENT_HTML &&
- b->width !=
- content_get_available_width(b->object)) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- enum css_height_e htype = css_computed_height(b->style,
- &value, &unit);
-
- content_reformat(b->object, false, b->width, b->height);
-
- if (htype == CSS_HEIGHT_AUTO)
- b->height = content_get_height(b->object);
- }
-
- if (height < b->height)
- height = b->height;
-
- x += b->width;
- }
-
- /* find new sides using this height */
- x0 = cx;
- x1 = cx + *width;
- find_sides(cont->float_children, cy, cy + height, &x0, &x1,
- &left, &right);
- x0 -= cx;
- x1 -= cx;
-
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- space_after = space_before = 0;
-
- /* pass 2: place boxes in line: loop body executed at least once */
-#ifdef LAYOUT_DEBUG
- LOG("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-#endif
-
- for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
-#ifdef LAYOUT_DEBUG
- LOG("pass 2: b %p, x %i", b, x);
-#endif
-
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED)) {
- b->x = x + space_after;
-
- } else if (b->type == BOX_INLINE ||
- b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END) {
- assert(b->width != UNKNOWN_WIDTH);
-
- x_previous = x;
- x += space_after;
- b->x = x;
-
- if ((b->type == BOX_INLINE && !b->inline_end) ||
- b->type == BOX_INLINE_BLOCK) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else if (b->type == BOX_INLINE) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width;
- } else if (b->type == BOX_INLINE_END) {
- b->height = b->inline_end->height;
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else {
- x += b->width;
- }
-
- space_before = space_after;
- if (b->object || b->flags & REPLACE_DIM ||
- b->flags & IFRAME)
- space_after = 0;
- else if (b->text || b->type == BOX_INLINE_END) {
- if (b->space == UNKNOWN_WIDTH) {
- font_plot_style_from_css(b->style,
- &fstyle);
- /** \todo handle errors */
- font_func->width(&fstyle, " ", 1,
- &b->space);
- }
- space_after = b->space;
- } else {
- space_after = 0;
- }
- split_box = b;
- move_y = true;
- inline_count++;
- } else if (b->type == BOX_BR) {
- b->x = x;
- b->width = 0;
- br_box = b;
- b = b->next;
- split_box = 0;
- move_y = true;
- break;
-
- } else {
- /* float */
-#ifdef LAYOUT_DEBUG
- LOG("float %p", b);
-#endif
-
- d = b->children;
- d->float_children = 0;
- d->cached_place_below_level = 0;
- b->float_container = d->float_container = cont;
-
- if (!layout_float(d, *width, content))
- return false;
-
-#ifdef LAYOUT_DEBUG
- LOG("%p : %d %d", d, d->margin[TOP], d->border[TOP].width);
-#endif
-
- d->x = d->margin[LEFT] + d->border[LEFT].width;
- d->y = d->margin[TOP] + d->border[TOP].width;
- b->width = d->margin[LEFT] + d->border[LEFT].width +
- d->padding[LEFT] + d->width +
- d->padding[RIGHT] +
- d->border[RIGHT].width +
- d->margin[RIGHT];
- b->height = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
-
- if (b->width > (x1 - x0) - x)
- place_below = true;
- if (d->style && (css_computed_clear(d->style) ==
- CSS_CLEAR_NONE ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- left == 0 && right == 0)) &&
- (!place_below ||
- (left == 0 && right == 0 && x == 0)) &&
- cy >= cont->clear_level &&
- cy >= cont->cached_place_below_level) {
- /* + not cleared or,
- * cleared and there are no floats to clear
- * + fits without needing to be placed below or,
- * this line is empty with no floats
- * + current y, cy, is below the clear level
- *
- * Float affects current line */
- if (b->type == BOX_FLOAT_LEFT) {
- b->x = cx + x0;
- if (b->width > 0)
- x0 += b->width;
- left = b;
- } else {
- b->x = cx + x1 - b->width;
- if (b->width > 0)
- x1 -= b->width;
- right = b;
- }
- b->y = cy;
- } else {
- /* cleared or doesn't fit on line */
- /* place below into next available space */
- int fcy = (cy > cont->clear_level) ? cy :
- cont->clear_level;
- fcy = (fcy > cont->cached_place_below_level) ?
- fcy :
- cont->cached_place_below_level;
- fy = (fy > fcy) ? fy : fcy;
- fy = (fy == cy) ? fy + height : fy;
-
- place_float_below(b, *width, cx, fy, cont);
- fy = b->y;
- if (d->style && (
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- (left != 0 || right != 0)))) {
- /* to be cleared below existing
- * floats */
- if (b->type == BOX_FLOAT_LEFT)
- b->x = cx;
- else
- b->x = cx + *width - b->width;
-
- fcy = layout_clear(cont->float_children,
- css_computed_clear(d->style));
- if (fcy > cont->clear_level)
- cont->clear_level = fcy;
- if (b->y < fcy)
- b->y = fcy;
- }
- if (b->type == BOX_FLOAT_LEFT)
- left = b;
- else
- right = b;
- }
- add_float_to_container(cont, b);
-
- split_box = 0;
- }
- }
-
- if (x1 - x0 < x && split_box) {
- /* the last box went over the end */
- size_t split = 0;
- int w;
- bool no_wrap = css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
- css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_PRE;
-
- x = x_previous;
-
- if (!no_wrap &&
- (split_box->type == BOX_INLINE ||
- split_box->type == BOX_TEXT) &&
- !split_box->object &&
- !(split_box->flags & REPLACE_DIM) &&
- !(split_box->flags & IFRAME) &&
- !split_box->gadget && split_box->text) {
-
- font_plot_style_from_css(split_box->style, &fstyle);
- /** \todo handle errors */
- font_func->split(&fstyle,
- split_box->text,
- split_box->length,
- x1 - x0 - x - space_before,
- &split,
- &w);
- }
-
- /* split == 0 implies that text can't be split */
-
- if (split == 0)
- w = split_box->width;
-
-#ifdef LAYOUT_DEBUG
- LOG("splitting: split_box %p \"%.*s\", spilt %zu, w %i, ""left %p, right %p, inline_count %u", split_box, (int)split_box->length, split_box->text, split, w, left, right, inline_count);
-#endif
-
- if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- !left && !right && inline_count == 1) {
- /* first word of box doesn't fit, but no floats and
- * first box on line so force in */
- if (split == 0 || split == split_box->length) {
- /* only one word in this box, or not text
- * or white-space:nowrap */
- b = split_box->next;
- } else {
- /* cut off first word for this line */
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-#ifdef LAYOUT_DEBUG
- LOG("forcing");
-#endif
- } else if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- inline_count == 1) {
- /* first word of first box doesn't fit, but a float is
- * taking some of the width so move below it */
- assert(left || right);
- used_height = 0;
- if (left) {
-#ifdef LAYOUT_DEBUG
- LOG("cy %i, left->y %i, left->height %i", cy, left->y, left->height);
-#endif
- used_height = left->y + left->height - cy + 1;
-#ifdef LAYOUT_DEBUG
- LOG("used_height %i", used_height);
-#endif
- }
- if (right && used_height <
- right->y + right->height - cy + 1)
- used_height = right->y + right->height - cy + 1;
-
- if (used_height < 0)
- used_height = 0;
-
- b = split_box;
-#ifdef LAYOUT_DEBUG
- LOG("moving below float");
-#endif
- } else if (split == 0 || x1 - x0 <= x + space_before + w) {
- /* first word of box doesn't fit so leave box for next
- * line */
- b = split_box;
-#ifdef LAYOUT_DEBUG
- LOG("leaving for next line");
-#endif
- } else {
- /* fit as many words as possible */
- assert(split != 0);
-#ifdef LAYOUT_DEBUG
- LOG("'%.*s' %i %zu %i", (int)split_box->length, split_box->text, x1 - x0, split, w);
-#endif
- if (split != split_box->length) {
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-#ifdef LAYOUT_DEBUG
- LOG("fitting words");
-#endif
- }
- move_y = true;
- }
-
- /* set positions */
- switch (css_computed_text_align(first->parent->parent->style)) {
- case CSS_TEXT_ALIGN_RIGHT:
- case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
- x0 = x1 - x;
- break;
- case CSS_TEXT_ALIGN_CENTER:
- case CSS_TEXT_ALIGN_LIBCSS_CENTER:
- x0 = (x0 + (x1 - x)) / 2;
- break;
- case CSS_TEXT_ALIGN_LEFT:
- case CSS_TEXT_ALIGN_LIBCSS_LEFT:
- case CSS_TEXT_ALIGN_JUSTIFY:
- /* leave on left */
- break;
- case CSS_TEXT_ALIGN_DEFAULT:
- /* None; consider text direction */
- switch (css_computed_direction(first->parent->parent->style)) {
- case CSS_DIRECTION_LTR:
- /* leave on left */
- break;
- case CSS_DIRECTION_RTL:
- x0 = x1 - x;
- break;
- }
- break;
- }
-
- for (d = first; d != b; d = d->next) {
- d->flags &= ~NEW_LINE;
-
- if (d->type == BOX_INLINE_BLOCK &&
- (css_computed_position(d->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(d->style) ==
- CSS_POSITION_FIXED)) {
- /* positioned inline-blocks:
- * set static position (x,y) only, rest of positioning
- * is handled later */
- d->x += x0;
- d->y = *y;
- continue;
- } else if ((d->type == BOX_INLINE &&
- ((d->object || d->gadget) == false) &&
- !(d->flags & IFRAME) &&
- !(d->flags & REPLACE_DIM)) ||
- d->type == BOX_BR ||
- d->type == BOX_TEXT ||
- d->type == BOX_INLINE_END) {
- /* regular (non-replaced) inlines */
- d->x += x0;
- d->y = *y - d->padding[TOP];
-
- if (d->type == BOX_TEXT && d->height > used_height) {
- /* text */
- used_height = d->height;
- }
- } else if ((d->type == BOX_INLINE) ||
- d->type == BOX_INLINE_BLOCK) {
- /* replaced inlines and inline-blocks */
- d->x += x0;
- d->y = *y + d->border[TOP].width + d->margin[TOP];
- h = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
- if (used_height < h)
- used_height = h;
- }
- }
-
- first->flags |= NEW_LINE;
-
- assert(b != first || (move_y && 0 < used_height && (left || right)));
-
- /* handle vertical-align by adjusting box y values */
- /** \todo proper vertical alignment handling */
- for (d = first; d != b; d = d->next) {
- if ((d->type == BOX_INLINE && d->inline_end) ||
- d->type == BOX_BR ||
- d->type == BOX_TEXT ||
- d->type == BOX_INLINE_END) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- switch (css_computed_vertical_align(d->style, &value,
- &unit)) {
- case CSS_VERTICAL_ALIGN_SUPER:
- case CSS_VERTICAL_ALIGN_TOP:
- case CSS_VERTICAL_ALIGN_TEXT_TOP:
- /* already at top */
- break;
- case CSS_VERTICAL_ALIGN_SUB:
- case CSS_VERTICAL_ALIGN_BOTTOM:
- case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- d->y += used_height - d->height;
- break;
- default:
- case CSS_VERTICAL_ALIGN_BASELINE:
- d->y += 0.75 * (used_height - d->height);
- break;
- }
- }
- }
-
- /* handle clearance for br */
- if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
- int clear_y = layout_clear(cont->float_children,
- css_computed_clear(br_box->style));
- if (used_height < clear_y - cy)
- used_height = clear_y - cy;
- }
-
- if (move_y)
- *y += used_height;
- *next_box = b;
- *width = x; /* return actual width */
- return true;
-}
-
-
-/* exported function documented in render/layout.h */
-bool layout_inline_container(struct box *inline_container, int width,
- struct box *cont, int cx, int cy, html_content *content)
-{
- bool first_line = true;
- bool has_text_children;
- struct box *c, *next;
- int y = 0;
- int curwidth,maxwidth = width;
-
- assert(inline_container->type == BOX_INLINE_CONTAINER);
-
-#ifdef LAYOUT_DEBUG
- LOG("inline_container %p, width %i, cont %p, cx %i, cy %i", inline_container, width, cont, cx, cy);
-#endif
-
- has_text_children = false;
- for (c = inline_container->children; c; c = c->next) {
- bool is_pre = false;
-
- if (c->style) {
- enum css_white_space_e whitespace;
-
- whitespace = css_computed_white_space(c->style);
-
- is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
- whitespace == CSS_WHITE_SPACE_PRE_LINE ||
- whitespace == CSS_WHITE_SPACE_PRE_WRAP);
- }
-
- if ((!c->object && !(c->flags & REPLACE_DIM) &&
- !(c->flags & IFRAME) &&
- c->text && (c->length || is_pre)) ||
- c->type == BOX_BR)
- has_text_children = true;
- }
-
- /** \todo fix wrapping so that a box with horizontal scrollbar will
- * shrink back to 'width' if no word is wider than 'width' (Or just set
- * curwidth = width and have the multiword lines wrap to the min width)
- */
- for (c = inline_container->children; c; ) {
-#ifdef LAYOUT_DEBUG
- LOG("c %p", c);
-#endif
- curwidth = inline_container->width;
- if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
- has_text_children, content, &next))
- return false;
- maxwidth = max(maxwidth,curwidth);
- c = next;
- first_line = false;
- }
-
- inline_container->width = maxwidth;
- inline_container->height = y;
-
- return true;
-}
-
-
-/* exported function documented in render/layout.h */
-void
-layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
-{
- unsigned int i, j;
- int border_spacing_h = 0;
- int table_min = 0, table_max = 0;
- int extra_fixed = 0;
- float extra_frac = 0;
- struct column *col = table->col;
- struct box *row_group, *row, *cell;
- enum css_width_e wtype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- /* check if the widths have already been calculated */
- if (table->max_width != UNKNOWN_MAX_WIDTH)
- return;
-
- /* start with 0 except for fixed-width columns */
- for (i = 0; i != table->columns; i++) {
- if (col[i].type == COLUMN_WIDTH_FIXED)
- col[i].min = col[i].max = col[i].width;
- else
- col[i].min = col[i].max = 0;
- }
-
- /* border-spacing is used in the separated borders model */
- if (css_computed_border_collapse(table->style) ==
- CSS_BORDER_COLLAPSE_SEPARATE) {
- css_fixed h = 0, v = 0;
- css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
-
- css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
-
- border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
- }
-
- /* 1st pass: consider cells with colspan 1 only */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
- /** TODO: Handle colspan="0" correctly.
- * It's currently converted to 1 in box normaisation */
- assert(cell->columns != 0);
-
- if (cell->columns != 1)
- continue;
-
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
-
- if (col[i].positioned)
- continue;
-
- /* update column min, max widths using cell widths */
- if (col[i].min < cell->min_width)
- col[i].min = cell->min_width;
- if (col[i].max < cell->max_width)
- col[i].max = cell->max_width;
- }
-
- /* 2nd pass: cells which span multiple columns */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- unsigned int flexible_columns = 0;
- int min = 0, max = 0, fixed_width = 0, extra;
-
- if (cell->columns == 1)
- continue;
-
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
-
- /* find min width so far of spanned columns, and count
- * number of non-fixed spanned columns and total fixed width */
- for (j = 0; j != cell->columns; j++) {
- min += col[i + j].min;
- if (col[i + j].type == COLUMN_WIDTH_FIXED)
- fixed_width += col[i + j].width;
- else
- flexible_columns++;
- }
- min += (cell->columns - 1) * border_spacing_h;
-
- /* distribute extra min to spanned columns */
- if (min < cell->min_width) {
- if (flexible_columns == 0) {
- extra = 1 + (cell->min_width - min) /
- cell->columns;
- for (j = 0; j != cell->columns; j++) {
- col[i + j].min += extra;
- if (col[i + j].max < col[i + j].min)
- col[i + j].max = col[i + j].min;
- }
- } else {
- extra = 1 + (cell->min_width - min) /
- flexible_columns;
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type !=
- COLUMN_WIDTH_FIXED) {
- col[i + j].min += extra;
- if (col[i + j].max <
- col[i + j].min)
- col[i + j].max =
- col[i + j].min;
- }
- }
- }
- }
-
- /* find max width so far of spanned columns */
- for (j = 0; j != cell->columns; j++)
- max += col[i + j].max;
- max += (cell->columns - 1) * border_spacing_h;
-
- /* distribute extra max to spanned columns */
- if (max < cell->max_width && flexible_columns) {
- extra = 1 + (cell->max_width - max) / flexible_columns;
- for (j = 0; j != cell->columns; j++)
- if (col[i + j].type != COLUMN_WIDTH_FIXED)
- col[i + j].max += extra;
- }
- }
-
- for (i = 0; i != table->columns; i++) {
- if (col[i].max < col[i].min) {
- box_dump(stderr, table, 0, true);
- assert(0);
- }
- table_min += col[i].min;
- table_max += col[i].max;
- }
-
- /* fixed width takes priority, unless it is too narrow */
- wtype = css_computed_width(table->style, &value, &unit);
- if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
- int width = FIXTOINT(nscss_len2px(value, unit, table->style));
- if (table_min < width)
- table_min = width;
- if (table_max < width)
- table_max = width;
- }
-
- /* add margins, border, padding to min, max widths */
- calculate_mbp_width(table->style, LEFT, true, true, true,
- &extra_fixed, &extra_frac);
- calculate_mbp_width(table->style, RIGHT, true, true, true,
- &extra_fixed, &extra_frac);
- if (extra_fixed < 0)
- extra_fixed = 0;
- if (extra_frac < 0)
- extra_frac = 0;
- if (1.0 <= extra_frac)
- extra_frac = 0.9;
- table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac);
- table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac);
- table->min_width += (table->columns + 1) * border_spacing_h;
- table->max_width += (table->columns + 1) * border_spacing_h;
-
- assert(0 <= table->min_width && table->min_width <= table->max_width);
-}
-
-
/**
* Find a box's bounding box relative to itself, i.e. the box's border edge box
*
+ * \param len_ctx Length conversion context
* \param box box find bounding box of
* \param desc_x0 updated to left of box's bbox
* \param desc_y0 updated to top of box's bbox
@@ -5022,9 +5182,11 @@ layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
* \param desc_y1 updated to bottom of box's bbox
*/
static void
-layout_get_box_bbox(struct box *box,
- int *desc_x0, int *desc_y0,
- int *desc_x1, int *desc_y1)
+layout_get_box_bbox(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int *desc_x0, int *desc_y0,
+ int *desc_x1, int *desc_y1)
{
*desc_x0 = -box->border[LEFT].width;
*desc_y0 = -box->border[TOP].width;
@@ -5044,7 +5206,8 @@ layout_get_box_bbox(struct box *box,
int text_height;
css_computed_font_size(box->style, &font_size, &font_unit);
- text_height = nscss_len2px(font_size, font_unit, box->style);
+ text_height = nscss_len2px(len_ctx, font_size, font_unit,
+ box->style);
text_height = FIXTOINT(text_height * 3 / 4);
*desc_y0 = (*desc_y0 < -text_height) ? *desc_y0 : -text_height;
}
@@ -5054,16 +5217,19 @@ layout_get_box_bbox(struct box *box,
/**
* Apply changes to box descendant_[xy][01] values due to given child.
*
- * \param box box to update
- * \param child a box, which may affect box's descendant bbox
- * \param off_x offset to apply to child->x coord to treat as child of box
- * \param off_y offset to apply to child->y coord to treat as child of box
+ * \param len_ctx Length conversion context
+ * \param box box to update
+ * \param child a box, which may affect box's descendant bbox
+ * \param off_x offset to apply to child->x coord to treat as child of box
+ * \param off_y offset to apply to child->y coord to treat as child of box
*/
static void
-layout_update_descendant_bbox(struct box *box,
- struct box *child,
- int off_x,
- int off_y)
+layout_update_descendant_bbox(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ struct box *child,
+ int off_x,
+ int off_y)
{
int child_desc_x0, child_desc_y0, child_desc_x1, child_desc_y1;
@@ -5083,7 +5249,8 @@ layout_update_descendant_bbox(struct box *box,
}
/* Get child's border edge */
- layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
+ layout_get_box_bbox(len_ctx, child,
+ &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
if (overflow_x == CSS_OVERFLOW_VISIBLE &&
@@ -5116,8 +5283,16 @@ layout_update_descendant_bbox(struct box *box,
}
-/* exported function documented in render/layout.h */
-void layout_calculate_descendant_bboxes(struct box *box)
+/**
+ * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
+ * and inform iframe browser windows of their size and position.
+ *
+ * \param len_ctx Length conversion context
+ * \param box tree of boxes to update
+ */
+static void layout_calculate_descendant_bboxes(
+ const nscss_len_ctx *len_ctx,
+ struct box *box)
{
struct box *child;
@@ -5126,7 +5301,8 @@ void layout_calculate_descendant_bboxes(struct box *box)
/* assert((box->width >= 0) && (box->height >= 0)); */
/* Initialise box's descendant box to border edge box */
- layout_get_box_bbox(box, &box->descendant_x0, &box->descendant_y0,
+ layout_get_box_bbox(len_ctx, box,
+ &box->descendant_x0, &box->descendant_y0,
&box->descendant_x1, &box->descendant_y1);
/* Extend it to contain HTML contents if box is replaced */
@@ -5159,7 +5335,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_update_descendant_bbox(box, child,
+ layout_update_descendant_bbox(len_ctx, box, child,
box->x, box->y);
if (child == box->inline_end)
@@ -5177,7 +5353,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
if (box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_HIDDEN &&
@@ -5185,22 +5361,73 @@ void layout_calculate_descendant_bboxes(struct box *box)
CSS_OVERFLOW_HIDDEN)
continue;
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
}
for (child = box->float_children; child; child = child->next_float) {
assert(child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT);
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
}
if (box->list_marker) {
child = box->list_marker;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
+
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
+ }
+}
- layout_update_descendant_bbox(box, child, 0, 0);
+
+/* exported function documented in html/layout.h */
+bool layout_document(html_content *content, int width, int height)
+{
+ bool ret;
+ struct box *doc = content->layout;
+ const struct gui_layout_table *font_func = content->font_func;
+
+ layout_minmax_block(doc, font_func, content);
+
+ layout_block_find_dimensions(&content->len_ctx,
+ width, height, 0, 0, doc);
+ doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
+ doc->y = doc->margin[TOP] + doc->border[TOP].width;
+ width -= doc->margin[LEFT] + doc->border[LEFT].width +
+ doc->padding[LEFT] + doc->padding[RIGHT] +
+ doc->border[RIGHT].width + doc->margin[RIGHT];
+ if (width < 0) {
+ width = 0;
}
+ doc->width = width;
+
+ ret = layout_block_context(doc, height, content);
+
+ /* make <html> and <body> fill available height */
+ if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width + doc->margin[BOTTOM] <
+ height) {
+ doc->height = height - (doc->y + doc->padding[TOP] +
+ doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width +
+ doc->margin[BOTTOM]);
+ if (doc->children)
+ doc->children->height = doc->height -
+ (doc->children->margin[TOP] +
+ doc->children->border[TOP].width +
+ doc->children->padding[TOP] +
+ doc->children->padding[BOTTOM] +
+ doc->children->border[BOTTOM].width +
+ doc->children->margin[BOTTOM]);
+ }
+
+ layout_lists(doc, font_func, &content->len_ctx);
+ layout_position_absolute(doc, doc, 0, 0, content);
+ layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
+
+ layout_calculate_descendant_bboxes(&content->len_ctx, doc);
+
+ return ret;
}
diff --git a/render/layout.h b/content/handlers/html/layout.h
index 78a30028e..0811e81de 100644
--- a/render/layout.h
+++ b/content/handlers/html/layout.h
@@ -18,15 +18,15 @@
/**
* \file
- * HTML layout (interface).
+ * interface to HTML layout.
*
* The main interface to the layout code is layout_document(), which takes a
* normalized box tree and assigns coordinates and dimensions to the boxes, and
* also adds boxes to the tree (eg. when formatting lines of text).
*/
-#ifndef _NETSURF_RENDER_LAYOUT_H_
-#define _NETSURF_RENDER_LAYOUT_H_
+#ifndef NETSURF_HTML_LAYOUT_H
+#define NETSURF_HTML_LAYOUT_H
struct box;
struct html_content;
@@ -42,35 +42,4 @@ struct gui_layout_table;
*/
bool layout_document(struct html_content *content, int width, int height);
-/**
- * Layout lines of text or inline boxes with floats.
- *
- * \param box inline container box
- * \param width horizontal space available
- * \param cont ancestor box which defines horizontal space, for floats
- * \param cx box position relative to cont
- * \param cy box position relative to cont
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-bool layout_inline_container(struct box *box, int width, struct box *cont, int cx, int cy, struct html_content *content);
-
-/**
- * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
- * and inform iframe browser windows of their size and position.
- *
- * \param box tree of boxes to update
- */
-void layout_calculate_descendant_bboxes(struct box *box);
-
-/**
- * Calculate minimum and maximum width of a table.
- *
- * \param table box of type TABLE
- * \param font_func Font functions
- * \post table->min_width and table->max_width filled in,
- * 0 <= table->min_width <= table->max_width
- */
-void layout_minmax_table(struct box *table, const struct gui_layout_table *font_func);
-
#endif
diff --git a/render/search.c b/content/handlers/html/search.c
index 4af6706a0..9ba2957e4 100644
--- a/render/search.c
+++ b/content/handlers/html/search.c
@@ -17,7 +17,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
/**
* \file
* Free text search (core)
@@ -38,11 +38,11 @@
#include "netsurf/misc.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/search.h"
-#include "render/textplain.h"
+#include "text/textplain.h"
+#include "html/box.h"
+#include "html/html.h"
+#include "html/html_internal.h"
+#include "html/search.h"
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
@@ -128,7 +128,7 @@ static void free_matches(struct search_context *context)
{
struct list_entry *a;
struct list_entry *b;
-
+
a = context->found->next;
/* empty the list before clearing and deleting the
@@ -179,11 +179,11 @@ static const char *find_pattern(const char *string, int s_len,
if (p < pattern || *p == '*') {
char ch;
- /* skip any further asterisks; one is the same as many
+ /* skip any further asterisks; one is the same as many
*/
do p++; while (p < ep && *p == '*');
- /* if we're at the end of the pattern, yes, it matches
+ /* if we're at the end of the pattern, yes, it matches
*/
if (p >= ep) break;
@@ -193,7 +193,7 @@ static const char *find_pattern(const char *string, int s_len,
ch = *p;
if (ch != '#') {
- /* scan forwards until we find a match for
+ /* scan forwards until we find a match for
this char */
if (!case_sens) ch = toupper(ch);
while (s < es) {
@@ -206,7 +206,7 @@ static const char *find_pattern(const char *string, int s_len,
}
if (s < es) {
- /* remember where we are in case the match
+ /* remember where we are in case the match
fails; we may then resume */
if (top < (int)NOF_ELEMENTS(context)) {
context[top].ss = ss;
@@ -538,7 +538,7 @@ static void search_text(const char *string, int string_len,
msg_data.scroll.y0 = bounds.y0;
msg_data.scroll.x1 = bounds.x1;
msg_data.scroll.y1 = bounds.y1;
- content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data);
+ content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data);
}
@@ -571,7 +571,7 @@ void search_step(struct search_context *context, search_flags_t flags,
msg_data.scroll.area = false;
msg_data.scroll.x0 = 0;
msg_data.scroll.y0 = 0;
- content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data);
+ content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data);
return;
}
search_text(string, string_len, context, flags);
@@ -621,13 +621,14 @@ void search_show_all(bool all, struct search_context *context)
if (!a->sel)
continue;
- selection_init(a->sel, html->layout);
+ selection_init(a->sel, html->layout,
+ &html->len_ctx);
} else {
a->sel = selection_create(context->c, false);
if (!a->sel)
continue;
- selection_init(a->sel, NULL);
+ selection_init(a->sel, NULL, NULL);
}
selection_set_start(a->sel, a->start_idx);
diff --git a/render/search.h b/content/handlers/html/search.h
index 79d1ee3d3..5c9408e3e 100644
--- a/render/search.h
+++ b/content/handlers/html/search.h
@@ -16,8 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _NETSURF_RENDER_SEARCH_H_
-#define _NETSURF_RENDER_SEARCH_H_
+/**
+ * \file
+ * Interface to HTML searching.
+ */
+
+#ifndef NETSURF_HTML_SEARCH_H
+#define NETSURF_HTML_SEARCH_H
#include <ctype.h>
#include <string.h>
diff --git a/render/table.c b/content/handlers/html/table.c
index acf00c70e..5609e8f29 100644
--- a/render/table.c
+++ b/content/handlers/html/table.c
@@ -17,8 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Table processing and layout (implementation).
+/**
+ * \file
+ * implementation of HTML table processing and layout.
*/
#include <assert.h>
@@ -28,8 +29,8 @@
#include "utils/talloc.h"
#include "css/utils.h"
-#include "render/box.h"
-#include "render/table.h"
+#include "html/box.h"
+#include "html/table.h"
/* Define to enable verbose table debug */
#undef TABLE_DEBUG
@@ -45,31 +46,57 @@ struct border {
css_unit unit; /**< border-width units */
};
-static void table_used_left_border_for_cell(struct box *cell);
-static void table_used_top_border_for_cell(struct box *cell);
-static void table_used_right_border_for_cell(struct box *cell);
-static void table_used_bottom_border_for_cell(struct box *cell);
-static bool table_border_is_more_eyecatching(const struct border *a,
- box_type a_src, const struct border *b, box_type b_src);
-static void table_cell_top_process_table(struct box *table, struct border *a,
+static void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src);
+static void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ struct border *a,
box_type *a_src);
-static bool table_cell_top_process_group(struct box *cell, struct box *group,
- struct border *a, box_type *a_src);
-static bool table_cell_top_process_row(struct box *cell, struct box *row,
- struct border *a, box_type *a_src);
/**
* Determine the column width types for a table.
*
- * \param table box of type BOX_TABLE
+ * \param len_ctx Length conversion context
+ * \param table box of type BOX_TABLE
* \return true on success, false on memory exhaustion
*
* The table->col array is allocated and type and width are filled in for each
* column.
*/
-bool table_calculate_column_types(struct box *table)
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table)
{
unsigned int i, j;
struct column *col;
@@ -104,12 +131,12 @@ bool table_calculate_column_types(struct box *table)
continue;
i = cell->start_column;
- if (css_computed_position(cell->style) !=
+ if (css_computed_position(cell->style) !=
CSS_POSITION_ABSOLUTE &&
- css_computed_position(cell->style) !=
+ css_computed_position(cell->style) !=
CSS_POSITION_FIXED) {
col[i].positioned = false;
- }
+ }
type = css_computed_width(cell->style, &value, &unit);
@@ -117,8 +144,8 @@ bool table_calculate_column_types(struct box *table)
if (col[i].type != COLUMN_WIDTH_FIXED &&
type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = FIXTOINT(nscss_len2px(value, unit,
- cell->style));
+ col[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
@@ -155,7 +182,7 @@ bool table_calculate_column_types(struct box *table)
for (j = i; j < i + cell->columns; j++) {
col[j].positioned = false;
}
-
+
/* count column types in spanned cells */
for (j = 0; j != cell->columns; j++) {
if (col[i + j].type == COLUMN_WIDTH_FIXED) {
@@ -181,8 +208,8 @@ bool table_calculate_column_types(struct box *table)
if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
fixed_columns + unknown_columns ==
cell->columns) {
- int width = (FIXTOFLT(nscss_len2px(value, unit,
- cell->style)) - fixed_width) /
+ int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit,
+ cell->style)) - fixed_width) /
unknown_columns;
if (width < 0)
width = 0;
@@ -219,13 +246,14 @@ bool table_calculate_column_types(struct box *table)
#ifdef TABLE_DEBUG
for (i = 0; i != table->columns; i++)
- LOG("table %p, column %u: type %s, width %i", table, i, ((const char *[]){
+ NSLOG(netsurf, INFO,
+ "table %p, column %u: type %s, width %i", table, i, ((const char *[]){
"UNKNOWN",
"FIXED",
"AUTO",
"PERCENT",
- "RELATIVE"
- })[col[i].type], col[i].width);
+ "RELATIVE",
+ })[col[i].type], col[i].width);
#endif
return true;
@@ -234,75 +262,82 @@ bool table_calculate_column_types(struct box *table)
/**
* Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*
* \post \a cell's border array is populated
*/
-void table_used_border_for_cell(struct box *cell)
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
int side;
assert(cell->type == BOX_TABLE_CELL);
- if (css_computed_border_collapse(cell->style) ==
+ if (css_computed_border_collapse(cell->style) ==
CSS_BORDER_COLLAPSE_SEPARATE) {
css_fixed width = 0;
css_unit unit = CSS_UNIT_PX;
/* Left border */
- cell->border[LEFT].style =
+ cell->border[LEFT].style =
css_computed_border_left_style(cell->style);
css_computed_border_left_color(cell->style,
&cell->border[LEFT].c);
css_computed_border_left_width(cell->style, &width, &unit);
- cell->border[LEFT].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Top border */
- cell->border[TOP].style =
+ cell->border[TOP].style =
css_computed_border_top_style(cell->style);
css_computed_border_top_color(cell->style,
&cell->border[TOP].c);
css_computed_border_top_width(cell->style, &width, &unit);
- cell->border[TOP].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Right border */
- cell->border[RIGHT].style =
+ cell->border[RIGHT].style =
css_computed_border_right_style(cell->style);
css_computed_border_right_color(cell->style,
&cell->border[RIGHT].c);
css_computed_border_right_width(cell->style, &width, &unit);
- cell->border[RIGHT].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Bottom border */
- cell->border[BOTTOM].style =
+ cell->border[BOTTOM].style =
css_computed_border_bottom_style(cell->style);
css_computed_border_bottom_color(cell->style,
&cell->border[BOTTOM].c);
css_computed_border_bottom_width(cell->style, &width, &unit);
- cell->border[BOTTOM].width =
- FIXTOINT(nscss_len2px(width, unit, cell->style));
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
} else {
/* Left border */
- table_used_left_border_for_cell(cell);
+ table_used_left_border_for_cell(len_ctx, cell);
/* Top border */
- table_used_top_border_for_cell(cell);
+ table_used_top_border_for_cell(len_ctx, cell);
/* Right border */
- table_used_right_border_for_cell(cell);
+ table_used_right_border_for_cell(len_ctx, cell);
/* Bottom border */
- table_used_bottom_border_for_cell(cell);
+ table_used_bottom_border_for_cell(len_ctx, cell);
}
- /* Finally, ensure that any borders configured as
+ /* Finally, ensure that any borders configured as
* hidden or none have zero width. (c.f. layout_find_dimensions) */
for (side = 0; side != 4; side++) {
if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN ||
- cell->border[side].style ==
+ cell->border[side].style ==
CSS_BORDER_STYLE_NONE)
cell->border[side].width = 0;
}
@@ -315,9 +350,12 @@ void table_used_border_for_cell(struct box *cell)
/**
* Calculate used values of border-left-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_left_border_for_cell(struct box *cell)
+void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -328,7 +366,7 @@ void table_used_left_border_for_cell(struct box *cell)
a.style = css_computed_border_left_style(cell->style);
a.color = css_computed_border_left_color(cell->style, &a.c);
css_computed_border_left_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -341,10 +379,10 @@ void table_used_left_border_for_cell(struct box *cell)
/* Spanned from a previous row in current row group */
for (row = cell->parent; row != NULL; row = row->prev) {
- for (prev = row->children; prev != NULL;
+ for (prev = row->children; prev != NULL;
prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
+ if (prev->start_column +
+ prev->columns ==
cell->start_column)
break;
}
@@ -361,11 +399,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_right_style(prev->style);
b.color = css_computed_border_right_color(prev->style, &b.c);
css_computed_border_right_width(prev->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, prev->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, prev->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -383,12 +422,13 @@ void table_used_left_border_for_cell(struct box *cell)
row->style, &b.c);
css_computed_border_left_width(
row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(&a, a_src,
- &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -402,11 +442,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_left_style(group->style);
b.color = css_computed_border_left_color(group->style, &b.c);
css_computed_border_left_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -415,11 +456,12 @@ void table_used_left_border_for_cell(struct box *cell)
b.style = css_computed_border_left_style(table->style);
b.color = css_computed_border_left_color(table->style, &b.c);
css_computed_border_left_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -428,16 +470,19 @@ void table_used_left_border_for_cell(struct box *cell)
/* a now contains the used left border for the cell */
cell->border[LEFT].style = a.style;
cell->border[LEFT].c = a.c;
- cell->border[LEFT].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[LEFT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-top-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_top_border_for_cell(struct box *cell)
+void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -448,7 +493,7 @@ void table_used_top_border_for_cell(struct box *cell)
a.style = css_computed_border_top_style(cell->style);
css_computed_border_top_color(cell->style, &a.c);
css_computed_border_top_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -456,18 +501,18 @@ void table_used_top_border_for_cell(struct box *cell)
b.style = css_computed_border_top_style(row->style);
css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
if (row->prev != NULL) {
/* Consider row(s) above */
- while (table_cell_top_process_row(cell, row->prev,
+ while (table_cell_top_process_row(len_ctx, cell, row->prev,
&a, &a_src) == false) {
if (row->prev->prev == NULL) {
/* Consider row group */
@@ -488,26 +533,29 @@ void table_used_top_border_for_cell(struct box *cell)
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
if (group->prev == NULL) {
/* Top border of table */
- table_cell_top_process_table(group->parent, &a, &a_src);
+ table_cell_top_process_table(len_ctx,
+ group->parent, &a, &a_src);
} else {
/* Process previous group(s) */
- while (table_cell_top_process_group(cell, group->prev,
+ while (table_cell_top_process_group(len_ctx,
+ cell, group->prev,
&a, &a_src) == false) {
if (group->prev->prev == NULL) {
/* Top border of table */
- table_cell_top_process_table(
- group->parent,
+ table_cell_top_process_table(len_ctx,
+ group->parent,
&a, &a_src);
break;
} else {
@@ -520,16 +568,19 @@ void table_used_top_border_for_cell(struct box *cell)
/* a now contains the used top border for the cell */
cell->border[TOP].style = a.style;
cell->border[TOP].c = a.c;
- cell->border[TOP].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[TOP].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-right-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_right_border_for_cell(struct box *cell)
+void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -540,11 +591,11 @@ void table_used_right_border_for_cell(struct box *cell)
a.style = css_computed_border_right_style(cell->style);
css_computed_border_right_color(cell->style, &a.c);
css_computed_border_right_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
- if (cell->next != NULL || cell->start_column + cell->columns !=
+ if (cell->next != NULL || cell->start_column + cell->columns !=
cell->parent->parent->parent->columns) {
/* Cell is not at right edge of table -- no right border */
a.style = CSS_BORDER_STYLE_NONE;
@@ -564,12 +615,13 @@ void table_used_right_border_for_cell(struct box *cell)
row->style, &b.c);
css_computed_border_right_width(
row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(&a, a_src,
- &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -582,13 +634,14 @@ void table_used_right_border_for_cell(struct box *cell)
/* Row group -- consider its right border */
b.style = css_computed_border_right_style(group->style);
b.color = css_computed_border_right_color(group->style, &b.c);
- css_computed_border_right_width(group->style,
+ css_computed_border_right_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -596,13 +649,14 @@ void table_used_right_border_for_cell(struct box *cell)
/* The table itself -- consider its right border */
b.style = css_computed_border_right_style(table->style);
b.color = css_computed_border_right_color(table->style, &b.c);
- css_computed_border_right_width(table->style,
+ css_computed_border_right_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -611,16 +665,19 @@ void table_used_right_border_for_cell(struct box *cell)
/* a now contains the used right border for the cell */
cell->border[RIGHT].style = a.style;
cell->border[RIGHT].c = a.c;
- cell->border[RIGHT].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[RIGHT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-bottom-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_bottom_border_for_cell(struct box *cell)
+void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -631,7 +688,7 @@ void table_used_bottom_border_for_cell(struct box *cell)
a.style = css_computed_border_bottom_style(cell->style);
css_computed_border_bottom_color(cell->style, &a.c);
css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(a.width, a.unit, cell->style);
+ a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -655,11 +712,12 @@ void table_used_bottom_border_for_cell(struct box *cell)
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -667,13 +725,14 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* Row group -- consider its bottom border */
b.style = css_computed_border_bottom_style(group->style);
b.color = css_computed_border_bottom_color(group->style, &b.c);
- css_computed_border_bottom_width(group->style,
+ css_computed_border_bottom_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -681,13 +740,14 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* The table itself -- consider its bottom border */
b.style = css_computed_border_bottom_style(table->style);
b.color = css_computed_border_bottom_color(table->style, &b.c);
- css_computed_border_bottom_width(table->style,
+ css_computed_border_bottom_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
}
}
@@ -695,21 +755,26 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* a now contains the used bottom border for the cell */
cell->border[BOTTOM].style = a.style;
cell->border[BOTTOM].c = a.c;
- cell->border[BOTTOM].width =
- FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+ cell->border[BOTTOM].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Determine if a border style is more eyecatching than another
*
- * \param a Reference border style
- * \param a_src Source of \a a
- * \param b Candidate border style
- * \param b_src Source of \a b
+ * \param len_ctx Length conversion context
+ * \param a Reference border style
+ * \param a_src Source of \a a
+ * \param b Candidate border style
+ * \param b_src Source of \a b
* \return True if \a b is more eyecatching than \a a
*/
-bool table_border_is_more_eyecatching(const struct border *a,
- box_type a_src, const struct border *b, box_type b_src)
+bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src)
{
css_fixed awidth, bwidth;
int impact = 0;
@@ -726,12 +791,12 @@ bool table_border_is_more_eyecatching(const struct border *a,
return true;
/* 3a -- wider borders beat narrow ones */
- /* The widths must be absolute, which will be the case
+ /* The widths must be absolute, which will be the case
* if they've come from a computed style. */
assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
- awidth = nscss_len2px(a->width, a->unit, NULL);
- bwidth = nscss_len2px(b->width, b->unit, NULL);
+ awidth = nscss_len2px(len_ctx, a->width, a->unit, NULL);
+ bwidth = nscss_len2px(len_ctx, b->width, b->unit, NULL);
if (awidth < bwidth)
return true;
@@ -740,27 +805,27 @@ bool table_border_is_more_eyecatching(const struct border *a,
/* 3b -- sort by style */
switch (a->style) {
- case CSS_BORDER_STYLE_DOUBLE: impact++;
- case CSS_BORDER_STYLE_SOLID: impact++;
- case CSS_BORDER_STYLE_DASHED: impact++;
- case CSS_BORDER_STYLE_DOTTED: impact++;
- case CSS_BORDER_STYLE_RIDGE: impact++;
- case CSS_BORDER_STYLE_OUTSET: impact++;
- case CSS_BORDER_STYLE_GROOVE: impact++;
- case CSS_BORDER_STYLE_INSET: impact++;
+ case CSS_BORDER_STYLE_DOUBLE: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_SOLID: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_DASHED: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_DOTTED: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_RIDGE: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_OUTSET: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_GROOVE: impact++; /* Fall through */
+ case CSS_BORDER_STYLE_INSET: impact++; /* Fall through */
default:
break;
}
switch (b->style) {
- case CSS_BORDER_STYLE_DOUBLE: impact--;
- case CSS_BORDER_STYLE_SOLID: impact--;
- case CSS_BORDER_STYLE_DASHED: impact--;
- case CSS_BORDER_STYLE_DOTTED: impact--;
- case CSS_BORDER_STYLE_RIDGE: impact--;
- case CSS_BORDER_STYLE_OUTSET: impact--;
- case CSS_BORDER_STYLE_GROOVE: impact--;
- case CSS_BORDER_STYLE_INSET: impact--;
+ case CSS_BORDER_STYLE_DOUBLE: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_SOLID: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_DASHED: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_DOTTED: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_RIDGE: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_OUTSET: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_GROOVE: impact--; /* Fall through */
+ case CSS_BORDER_STYLE_INSET: impact--; /* Fall through */
default:
break;
}
@@ -773,22 +838,22 @@ bool table_border_is_more_eyecatching(const struct border *a,
/* 4a -- sort by origin */
impact = 0;
- switch (a_src) {
- case BOX_TABLE_CELL: impact++;
- case BOX_TABLE_ROW: impact++;
- case BOX_TABLE_ROW_GROUP: impact++;
/** \todo COL/COL_GROUP */
- case BOX_TABLE: impact++;
+ switch (a_src) {
+ case BOX_TABLE_CELL: impact++; /* Fall through */
+ case BOX_TABLE_ROW: impact++; /* Fall through */
+ case BOX_TABLE_ROW_GROUP: impact++; /* Fall through */
+ case BOX_TABLE: impact++; /* Fall through */
default:
break;
}
- switch (b_src) {
- case BOX_TABLE_CELL: impact--;
- case BOX_TABLE_ROW: impact--;
- case BOX_TABLE_ROW_GROUP: impact--;
/** \todo COL/COL_GROUP */
- case BOX_TABLE: impact--;
+ switch (b_src) {
+ case BOX_TABLE_CELL: impact--; /* Fall through */
+ case BOX_TABLE_ROW: impact--; /* Fall through */
+ case BOX_TABLE_ROW_GROUP: impact--; /* Fall through */
+ case BOX_TABLE: impact--; /* Fall through */
default:
break;
}
@@ -810,14 +875,18 @@ bool table_border_is_more_eyecatching(const struct border *a,
/**
* Process a table
*
- * \param table Table to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param table Table to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-void table_cell_top_process_table(struct box *table, struct border *a,
+void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
box_type *a_src)
{
struct border b;
@@ -827,11 +896,11 @@ void table_cell_top_process_table(struct box *table, struct border *a,
b.style = css_computed_border_top_style(table->style);
b.color = css_computed_border_top_color(table->style, &b.c);
css_computed_border_top_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -840,17 +909,22 @@ void table_cell_top_process_table(struct box *table, struct border *a,
/**
* Process a group
*
- * \param cell Cell being considered
- * \param group Group to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param cell Cell being considered
+ * \param group Group to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
* \return true if group has non-empty rows, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-bool table_cell_top_process_group(struct box *cell, struct box *group,
- struct border *a, box_type *a_src)
+bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -859,11 +933,11 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
b.style = css_computed_border_bottom_style(group->style);
b.color = css_computed_border_bottom_color(group->style, &b.c);
css_computed_border_bottom_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -872,7 +946,7 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/* Process rows in group, starting with last */
struct box *row = group->last;
- while (table_cell_top_process_row(cell, row,
+ while (table_cell_top_process_row(len_ctx, cell, row,
a, a_src) == false) {
if (row->prev == NULL) {
return false;
@@ -885,11 +959,12 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -903,17 +978,22 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/**
* Process a row
*
- * \param cell Cell being considered
- * \param row Row to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \param cell Cell being considered
+ * \param row Row to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
* \return true if row has cells, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
-bool table_cell_top_process_row(struct box *cell, struct box *row,
- struct border *a, box_type *a_src)
+bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -922,11 +1002,11 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -936,18 +1016,19 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
b.style = css_computed_border_top_style(row->style);
b.color = css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, row->style);
+ b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
- if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
return false;
} else {
- /* Process cells that are directly above the cell being
+ /* Process cells that are directly above the cell being
* considered. They may not be in this row, but in one of the
* rows above it in the case where rowspan > 1. */
struct box *c;
@@ -974,13 +1055,13 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
c->style, &b.c);
css_computed_border_bottom_width(c->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit,
- c->style);
+ b.width = nscss_len2px(len_ctx,
+ b.width, b.unit, c->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
- if (table_border_is_more_eyecatching(a, *a_src,
- &b, b_src)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -997,4 +1078,3 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
return true;
}
-
diff --git a/render/table.h b/content/handlers/html/table.h
index ecd3043b5..11ab653c6 100644
--- a/render/table.h
+++ b/content/handlers/html/table.h
@@ -17,18 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Table processing and layout (interface).
+/**
+ * \file
+ * Interface to HTML table processing and layout.
*/
-#ifndef _NETSURF_RENDER_TABLE_H_
-#define _NETSURF_RENDER_TABLE_H_
+#ifndef NETSURF_HTML_TABLE_H
+#define NETSURF_HTML_TABLE_H
#include <stdbool.h>
struct box;
-bool table_calculate_column_types(struct box *table);
-void table_used_border_for_cell(struct box *cell);
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table);
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
#endif
diff --git a/content/handlers/image/bmp.c b/content/handlers/image/bmp.c
index 5970f8b16..48a37fb24 100644
--- a/content/handlers/image/bmp.c
+++ b/content/handlers/image/bmp.c
@@ -68,8 +68,7 @@ static void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state)
}
static nserror nsbmp_create_bmp_data(nsbmp_content *bmp)
-{
- union content_msg_data msg_data;
+{
bmp_bitmap_callback_vt bmp_bitmap_callbacks = {
.bitmap_create = nsbmp_bitmap_create,
.bitmap_destroy = guit->bitmap->destroy,
@@ -79,8 +78,7 @@ static nserror nsbmp_create_bmp_data(nsbmp_content *bmp)
bmp->bmp = calloc(sizeof(struct bmp_image), 1);
if (bmp->bmp == NULL) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&bmp->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&bmp->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
@@ -123,7 +121,6 @@ static bool nsbmp_convert(struct content *c)
{
nsbmp_content *bmp = (nsbmp_content *) c;
bmp_result res;
- union content_msg_data msg_data;
uint32_t swidth;
const char *data;
unsigned long size;
@@ -138,13 +135,11 @@ static bool nsbmp_convert(struct content *c)
case BMP_OK:
break;
case BMP_INSUFFICIENT_MEMORY:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
case BMP_INSUFFICIENT_DATA:
case BMP_DATA_ERROR:
- msg_data.error = messages_get("BadBMP");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_BMP_ERROR);
return false;
}
@@ -199,8 +194,12 @@ static bool nsbmp_redraw(struct content *c, struct content_redraw_data *data,
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- bmp->bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx,
+ bmp->bitmap,
+ data->x, data->y,
+ data->width, data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
diff --git a/content/handlers/image/gif.c b/content/handlers/image/gif.c
index c4f039490..253265caa 100644
--- a/content/handlers/image/gif.c
+++ b/content/handlers/image/gif.c
@@ -72,7 +72,6 @@ static void *nsgif_bitmap_create(int width, int height)
static nserror nsgif_create_gif_data(nsgif_content *c)
{
- union content_msg_data msg_data;
gif_bitmap_callback_vt gif_bitmap_callbacks = {
.bitmap_create = nsgif_bitmap_create,
.bitmap_destroy = guit->bitmap->destroy,
@@ -85,8 +84,7 @@ static nserror nsgif_create_gif_data(nsgif_content *c)
/* Initialise our data structure */
c->gif = calloc(sizeof(gif_animation), 1);
if (c->gif == NULL) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
gif_create(c->gif, &gif_bitmap_callbacks);
@@ -231,14 +229,13 @@ static void nsgif_animate(void *p)
data.redraw.object_width = gif->base.width;
data.redraw.object_height = gif->base.height;
- content_broadcast(&gif->base, CONTENT_MSG_REDRAW, data);
+ content_broadcast(&gif->base, CONTENT_MSG_REDRAW, &data);
}
static bool nsgif_convert(struct content *c)
{
nsgif_content *gif = (nsgif_content *) c;
int res;
- union content_msg_data msg_data;
const char *data;
unsigned long size;
char *title;
@@ -251,17 +248,18 @@ static bool nsgif_convert(struct content *c)
res = gif_initialise(gif->gif, size, (unsigned char *) data);
if (res != GIF_OK && res != GIF_WORKING &&
res != GIF_INSUFFICIENT_FRAME_DATA) {
+ nserror error = NSERROR_UNKNOWN;
switch (res) {
case GIF_FRAME_DATA_ERROR:
case GIF_INSUFFICIENT_DATA:
case GIF_DATA_ERROR:
- msg_data.error = messages_get("BadGIF");
+ error = NSERROR_GIF_ERROR;
break;
case GIF_INSUFFICIENT_MEMORY:
- msg_data.error = messages_get("NoMemory");
+ error = NSERROR_NOMEM;
break;
}
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, error);
return false;
}
} while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA);
@@ -269,8 +267,7 @@ static bool nsgif_convert(struct content *c)
/* Abort on bad GIFs */
if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) ||
(gif->gif->height == 0)) {
- msg_data.error = messages_get("BadGIF");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_GIF_ERROR);
return false;
}
diff --git a/content/handlers/image/ico.c b/content/handlers/image/ico.c
index b14ea7fe1..85aab9f64 100644
--- a/content/handlers/image/ico.c
+++ b/content/handlers/image/ico.c
@@ -66,7 +66,6 @@ static void *nsico_bitmap_create(int width, int height, unsigned int bmp_state)
static nserror nsico_create_ico_data(nsico_content *c)
{
- union content_msg_data msg_data;
bmp_bitmap_callback_vt bmp_bitmap_callbacks = {
.bitmap_create = nsico_bitmap_create,
.bitmap_destroy = guit->bitmap->destroy,
@@ -76,8 +75,7 @@ static nserror nsico_create_ico_data(nsico_content *c)
c->ico = calloc(sizeof(ico_collection), 1);
if (c->ico == NULL) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
ico_collection_create(c->ico, &bmp_bitmap_callbacks);
@@ -122,7 +120,6 @@ static bool nsico_convert(struct content *c)
nsico_content *ico = (nsico_content *) c;
struct bmp_image *bmp;
bmp_result res;
- union content_msg_data msg_data;
const char *data;
unsigned long size;
char *title;
@@ -137,13 +134,11 @@ static bool nsico_convert(struct content *c)
case BMP_OK:
break;
case BMP_INSUFFICIENT_MEMORY:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
case BMP_INSUFFICIENT_DATA:
case BMP_DATA_ERROR:
- msg_data.error = messages_get("BadICO");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_ICO_ERROR);
return false;
}
@@ -165,7 +160,7 @@ static bool nsico_convert(struct content *c)
bmp = ico_find(ico->ico, 255, 255);
if (bmp == NULL) {
/* return error */
- LOG("Failed to select icon");
+ NSLOG(netsurf, INFO, "Failed to select icon");
return false;
}
@@ -188,7 +183,7 @@ static bool nsico_redraw(struct content *c, struct content_redraw_data *data,
bmp = ico_find(ico->ico, data->width, data->height);
if (bmp == NULL) {
/* return error */
- LOG("Failed to select icon");
+ NSLOG(netsurf, INFO, "Failed to select icon");
return false;
}
@@ -197,7 +192,7 @@ static bool nsico_redraw(struct content *c, struct content_redraw_data *data,
if (bmp_decode(bmp) != BMP_OK) {
return false;
} else {
- LOG("Decoding bitmap");
+ NSLOG(netsurf, INFO, "Decoding bitmap");
guit->bitmap->modified(bmp->bitmap);
}
@@ -260,7 +255,7 @@ static void *nsico_get_internal(const struct content *c, void *context)
bmp = ico_find(ico->ico, 16, 16);
if (bmp == NULL) {
/* return error */
- LOG("Failed to select icon");
+ NSLOG(netsurf, INFO, "Failed to select icon");
return NULL;
}
diff --git a/content/handlers/image/image.c b/content/handlers/image/image.c
index e7cc9218f..675fdd691 100644
--- a/content/handlers/image/image.c
+++ b/content/handlers/image/image.c
@@ -137,9 +137,9 @@ bool image_bitmap_plot(struct bitmap *bitmap,
fill_style.stroke_type = PLOT_OP_TYPE_NONE;
fill_style.fill_type = PLOT_OP_TYPE_SOLID;
- return ctx->plot->rectangle(area.x0, area.y0,
- area.x1, area.y1,
- &fill_style);
+ return (ctx->plot->rectangle(ctx,
+ &fill_style,
+ &area) == NSERROR_OK);
} else if ((fill_style.fill_colour & 0xff000000) == 0) {
/* transparent pixel used as spacer, skip it */
@@ -154,6 +154,10 @@ bool image_bitmap_plot(struct bitmap *bitmap,
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx,
+ bitmap,
+ data->x, data->y,
+ data->width, data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
diff --git a/content/handlers/image/image_cache.c b/content/handlers/image/image_cache.c
index 02107f75f..a1de01da5 100644
--- a/content/handlers/image/image_cache.c
+++ b/content/handlers/image/image_cache.c
@@ -256,11 +256,12 @@ static void image_cache__free_bitmap(struct image_cache_entry_s *centry)
{
if (centry->bitmap != NULL) {
#ifdef IMAGE_CACHE_VERBOSE
- LOG("Freeing bitmap %p size %d age %d redraw count %d",
- centry->bitmap,
- centry->bitmap_size,
- image_cache->current_age - centry->bitmap_age,
- centry->redraw_count);
+ NSLOG(netsurf, INFO,
+ "Freeing bitmap %p size %d age %d redraw count %d",
+ centry->bitmap,
+ centry->bitmap_size,
+ image_cache->current_age - centry->bitmap_age,
+ centry->redraw_count);
#endif
guit->bitmap->destroy(centry->bitmap);
centry->bitmap = NULL;
@@ -281,7 +282,7 @@ static void image_cache__free_bitmap(struct image_cache_entry_s *centry)
static void image_cache__free_entry(struct image_cache_entry_s *centry)
{
#ifdef IMAGE_CACHE_VERBOSE
- LOG("freeing %p ", centry);
+ NSLOG(netsurf, INFO, "freeing %p ", centry);
#endif
if (centry->redraw_count == 0) {
@@ -331,7 +332,7 @@ static void image_cache__background_update(void *p)
icache->current_age += icache->params.bg_clean_time;
#ifdef IMAGE_CACHE_VERBOSE
- LOG("Cache age %ds", icache->current_age / 1000);
+ NSLOG(netsurf, INFO, "Cache age %ds", icache->current_age / 1000);
#endif
image_cache__clean(icache);
@@ -383,13 +384,16 @@ bool image_cache_speculate(struct content *c)
if ((image_cache->total_bitmap_size < image_cache->params.limit) &&
(c->size <= image_cache->params.speculative_small)) {
#ifdef IMAGE_CACHE_VERBOSE
- LOG("content size (%d) is smaller than minimum (%d)", c->size, SPECULATE_SMALL);
+ NSLOG(netsurf, INFO,
+ "content size (%d) is smaller than minimum (%d)",
+ c->size,
+ SPECULATE_SMALL);
#endif
decision = true;
}
#ifdef IMAGE_CACHE_VERBOSE
- LOG("returning %d", decision);
+ NSLOG(netsurf, INFO, "returning %d", decision);
#endif
return decision;
}
@@ -422,8 +426,10 @@ image_cache_init(const struct image_cache_parameters *image_cache_parameters)
image_cache__background_update,
image_cache);
- LOG("Image cache initialised with a limit of %" PRIsizet " hysteresis of %"PRIsizet,
- image_cache->params.limit, image_cache->params.hysteresis);
+ NSLOG(netsurf, INFO,
+ "Image cache initialised with a limit of %"PRIsizet" hysteresis of %"PRIsizet,
+ image_cache->params.limit,
+ image_cache->params.hysteresis);
return NSERROR_OK;
}
@@ -435,8 +441,8 @@ nserror image_cache_fini(void)
guit->misc->schedule(-1, image_cache__background_update, image_cache);
- LOG("Size at finish %" PRIsizet " (in %d)",
- image_cache->total_bitmap_size, image_cache->bitmap_count);
+ NSLOG(netsurf, INFO, "Size at finish %"PRIsizet" (in %d)",
+ image_cache->total_bitmap_size, image_cache->bitmap_count);
while (image_cache->entries != NULL) {
image_cache__free_entry(image_cache->entries);
@@ -446,11 +452,13 @@ nserror image_cache_fini(void)
image_cache->miss_count +
image_cache->fail_count;
- LOG("Age %ds", image_cache->current_age / 1000);
- LOG("Peak size %" PRIsizet " (in %d)",
- image_cache->max_bitmap_size, image_cache->max_bitmap_size_count);
- LOG("Peak image count %d (size %" PRIsizet ")",
- image_cache->max_bitmap_count, image_cache->max_bitmap_count_size);
+ NSLOG(netsurf, INFO, "Age %ds", image_cache->current_age / 1000);
+ NSLOG(netsurf, INFO, "Peak size %"PRIsizet" (in %d)",
+ image_cache->max_bitmap_size,
+ image_cache->max_bitmap_size_count);
+ NSLOG(netsurf, INFO, "Peak image count %d (size %"PRIsizet")",
+ image_cache->max_bitmap_count,
+ image_cache->max_bitmap_count_size);
if (op_count > 0) {
uint64_t op_size;
@@ -459,35 +467,39 @@ nserror image_cache_fini(void)
image_cache->miss_size +
image_cache->fail_size;
- LOG("Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
- op_count,
- image_cache->hit_count,
- image_cache->miss_count,
- image_cache->fail_count,
- (image_cache->hit_count * 100) / op_count,
- (image_cache->miss_count * 100) / op_count,
- (image_cache->fail_count * 100) / op_count);
- LOG("Cache total/hit/miss/fail (size) %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64" (100%%/%"PRId64"%%/%"PRId64"%%/%"PRId64"%%)",
- op_size,
- image_cache->hit_size,
- image_cache->miss_size,
- image_cache->fail_size,
- (image_cache->hit_size * 100) / op_size,
- (image_cache->miss_size * 100) / op_size,
- (image_cache->fail_size * 100) / op_size);
+ NSLOG(netsurf, INFO,
+ "Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
+ op_count,
+ image_cache->hit_count,
+ image_cache->miss_count,
+ image_cache->fail_count,
+ (image_cache->hit_count * 100) / op_count,
+ (image_cache->miss_count * 100) / op_count,
+ (image_cache->fail_count * 100) / op_count);
+ NSLOG(netsurf, INFO,
+ "Cache total/hit/miss/fail (size) %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64" (100%%/%"PRId64"%%/%"PRId64"%%/%"PRId64"%%)",
+ op_size,
+ image_cache->hit_size,
+ image_cache->miss_size,
+ image_cache->fail_size,
+ (image_cache->hit_size * 100) / op_size,
+ (image_cache->miss_size * 100) / op_size,
+ (image_cache->fail_size * 100) / op_size);
}
- LOG("Total images never rendered: %d (includes %d that were converted)",
- image_cache->total_unrendered,
- image_cache->specultive_miss_count);
+ NSLOG(netsurf, INFO,
+ "Total images never rendered: %d (includes %d that were converted)",
+ image_cache->total_unrendered,
+ image_cache->specultive_miss_count);
- LOG("Total number of excessive conversions: %d (from %d images converted more than once)",
- image_cache->total_extra_conversions,
- image_cache->total_extra_conversions_count);
+ NSLOG(netsurf, INFO,
+ "Total number of excessive conversions: %d (from %d images converted more than once)",
+ image_cache->total_extra_conversions,
+ image_cache->total_extra_conversions_count);
- LOG("Bitmap of size %d had most (%d) conversions",
- image_cache->peak_conversions_size,
- image_cache->peak_conversions);
+ NSLOG(netsurf, INFO, "Bitmap of size %d had most (%d) conversions",
+ image_cache->peak_conversions_size,
+ image_cache->peak_conversions);
free(image_cache);
@@ -519,7 +531,8 @@ nserror image_cache_add(struct content *content,
centry->bitmap_size = content->width * content->height * 4;
}
- LOG("centry %p, content %p, bitmap %p", centry, content, bitmap);
+ NSLOG(netsurf, INFO, "centry %p, content %p, bitmap %p", centry,
+ content, bitmap);
centry->convert = convert;
@@ -558,7 +571,8 @@ nserror image_cache_remove(struct content *content)
/* get the cache entry */
centry = image_cache__find(content);
if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", content);
+ NSLOG(netsurf, INFO,
+ "Could not find cache entry for content (%p)", content);
return NSERROR_NOT_FOUND;
}
@@ -622,7 +636,7 @@ case chr : \
FMTCHR('b', PRIssizet, params.hysteresis);
FMTCHR('c', PRIssizet, total_bitmap_size);
FMTCHR('d', "d", bitmap_count);
- FMTCHR('e', "d", current_age / 1000);
+ FMTCHR('e', "u", current_age / 1000);
FMTCHR('f', PRIssizet, max_bitmap_size);
FMTCHR('g', "d", max_bitmap_size_count);
FMTCHR('h', "d", max_bitmap_count);
@@ -631,7 +645,7 @@ case chr : \
case 'j':
slen += snprintf(string + slen, size - slen,
- "%d", pct?100:op_count);
+ "%u", pct?100:op_count);
break;
FMTPCHR('k', "d", hit_count, op_count);
@@ -651,7 +665,7 @@ case chr : \
FMTCHR('t', "d", specultive_miss_count);
FMTCHR('u', "d", total_extra_conversions);
FMTCHR('v', "d", total_extra_conversions_count);
- FMTCHR('w', "d", peak_conversions_size);
+ FMTCHR('w', "u", peak_conversions_size);
FMTCHR('x', "d", peak_conversions);
@@ -674,8 +688,11 @@ case chr : \
}
/* exported interface documented in image_cache.h */
-int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
- const char *fmt)
+int
+image_cache_snentryf(char *string,
+ size_t size,
+ unsigned int entryn,
+ const char *fmt)
{
struct image_cache_entry_s *centry;
size_t slen = 0; /* current output string length */
@@ -692,7 +709,7 @@ int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
switch (fmt[fmtc]) {
case 'e':
slen += snprintf(string + slen, size - slen,
- "%d", entryn);
+ "%u", entryn);
break;
case 'r':
@@ -788,7 +805,8 @@ bool image_cache_redraw(struct content *c,
/* get the cache entry */
centry = image_cache__find(c);
if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", c);
+ NSLOG(netsurf, INFO,
+ "Could not find cache entry for content (%p)", c);
return false;
}
@@ -827,7 +845,8 @@ void image_cache_destroy(struct content *content)
/* get the cache entry */
centry = image_cache__find(content);
if (centry == NULL) {
- LOG("Could not find cache entry for content (%p)", content);
+ NSLOG(netsurf, INFO,
+ "Could not find cache entry for content (%p)", content);
} else {
image_cache__free_entry(centry);
}
diff --git a/content/handlers/image/jpeg.c b/content/handlers/image/jpeg.c
index 5ae9e70cd..123a0bf70 100644
--- a/content/handlers/image/jpeg.c
+++ b/content/handlers/image/jpeg.c
@@ -142,7 +142,7 @@ static void nsjpeg_term_source(j_decompress_ptr cinfo)
static void nsjpeg_error_log(j_common_ptr cinfo)
{
cinfo->err->format_message(cinfo, nsjpeg_error_buffer);
- LOG("%s", nsjpeg_error_buffer);
+ NSLOG(netsurf, INFO, "%s", nsjpeg_error_buffer);
}
@@ -156,7 +156,7 @@ static void nsjpeg_error_exit(j_common_ptr cinfo)
jmp_buf *setjmp_buffer = (jmp_buf *) cinfo->client_data;
cinfo->err->format_message(cinfo, nsjpeg_error_buffer);
- LOG("%s", nsjpeg_error_buffer);
+ NSLOG(netsurf, INFO, "%s", nsjpeg_error_buffer);
longjmp(*setjmp_buffer, 1);
}
@@ -214,7 +214,12 @@ jpeg_cache_convert(struct content *c)
jpeg_read_header(&cinfo, TRUE);
/* set output processing parameters */
- cinfo.out_color_space = JCS_RGB;
+ if (cinfo.jpeg_color_space == JCS_CMYK ||
+ cinfo.jpeg_color_space == JCS_YCCK) {
+ cinfo.out_color_space = JCS_CMYK;
+ } else {
+ cinfo.out_color_space = JCS_RGB;
+ }
cinfo.dct_method = JDCT_ISLOW;
/* commence the decompression, output parameters now valid */
@@ -248,22 +253,42 @@ jpeg_cache_convert(struct content *c)
rowstride * cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, scanlines, 1);
+ if (cinfo.out_color_space == JCS_CMYK) {
+ int i;
+ for (i = width - 1; 0 <= i; i--) {
+ /* Trivial inverse CMYK -> RGBA */
+ const int c = scanlines[0][i * 4 + 0];
+ const int m = scanlines[0][i * 4 + 1];
+ const int y = scanlines[0][i * 4 + 2];
+ const int k = scanlines[0][i * 4 + 3];
+
+ const int ck = c * k;
+ const int mk = m * k;
+ const int yk = y * k;
+
+#define DIV255(x) ((x) + 1 + ((x) >> 8)) >> 8
+ scanlines[0][i * 4 + 0] = DIV255(ck);
+ scanlines[0][i * 4 + 1] = DIV255(mk);
+ scanlines[0][i * 4 + 2] = DIV255(yk);
+ scanlines[0][i * 4 + 3] = 0xff;
+#undef DIV255
+ }
+ } else {
#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4
-{
- /* Missmatch between configured libjpeg pixel format and
- * NetSurf pixel format. Convert to RGBA */
- int i;
- for (i = width - 1; 0 <= i; i--) {
- int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED];
- int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN];
- int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE];
- scanlines[0][i * 4 + 0] = r;
- scanlines[0][i * 4 + 1] = g;
- scanlines[0][i * 4 + 2] = b;
- scanlines[0][i * 4 + 3] = 0xff;
- }
-}
+ /* Missmatch between configured libjpeg pixel format and
+ * NetSurf pixel format. Convert to RGBA */
+ int i;
+ for (i = width - 1; 0 <= i; i--) {
+ int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED];
+ int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN];
+ int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE];
+ scanlines[0][i * 4 + 0] = r;
+ scanlines[0][i * 4 + 1] = g;
+ scanlines[0][i * 4 + 2] = b;
+ scanlines[0][i * 4 + 3] = 0xff;
+ }
#endif
+ }
} while (cinfo.output_scanline != cinfo.output_height);
guit->bitmap->modified(bitmap);
@@ -301,7 +326,7 @@ static bool nsjpeg_convert(struct content *c)
jpeg_destroy_decompress(&cinfo);
msg_data.error = nsjpeg_error_buffer;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
diff --git a/content/handlers/image/nssprite.c b/content/handlers/image/nssprite.c
index c902fc3e2..269c24356 100644
--- a/content/handlers/image/nssprite.c
+++ b/content/handlers/image/nssprite.c
@@ -16,9 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for image/x-riscos-sprite (librosprite implementation).
- *
+/**
+ * \file
+ * librosprite implementation for content image/x-riscos-sprite
*/
#include <stdbool.h>
@@ -48,14 +48,14 @@ typedef struct nssprite_content {
#define ERRCHK(x) do { \
rosprite_error err = x; \
if (err == ROSPRITE_EOF) { \
- LOG("Got ROSPRITE_EOF when loading sprite file"); \
- return false; \
+ NSLOG(netsurf, INFO, "Got ROSPRITE_EOF when loading sprite file"); \
+ goto ro_sprite_error; \
} else if (err == ROSPRITE_BADMODE) { \
- LOG("Got ROSPRITE_BADMODE when loading sprite file"); \
- return false; \
+ NSLOG(netsurf, INFO, "Got ROSPRITE_BADMODE when loading sprite file"); \
+ goto ro_sprite_error; \
} else if (err == ROSPRITE_OK) { \
} else { \
- return false; \
+ goto ro_sprite_error; \
} \
} while(0)
@@ -95,9 +95,8 @@ static nserror nssprite_create(const content_handler *handler,
static bool nssprite_convert(struct content *c)
{
nssprite_content *nssprite = (nssprite_content *) c;
- union content_msg_data msg_data;
- struct rosprite_mem_context* ctx;
+ struct rosprite_mem_context* ctx = NULL;
const char *data;
unsigned long size;
@@ -118,14 +117,12 @@ static bool nssprite_convert(struct content *c)
nssprite->bitmap = guit->bitmap->create(sprite->width, sprite->height, BITMAP_NEW);
if (!nssprite->bitmap) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
uint32_t* imagebuf = (uint32_t *)guit->bitmap->get_buffer(nssprite->bitmap);
if (!imagebuf) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
unsigned char *spritebuf = (unsigned char *)sprite->image;
@@ -163,6 +160,14 @@ static bool nssprite_convert(struct content *c)
content_set_status(c, ""); /* Done: update status bar */
return true;
+
+ro_sprite_error:
+ if (ctx != NULL) {
+ rosprite_destroy_mem_context(ctx);
+ }
+ content_broadcast_errorcode(c, NSERROR_SPRITE_ERROR);
+
+ return false;
}
@@ -185,19 +190,28 @@ static void nssprite_destroy(struct content *c)
* Redraw a CONTENT_SPRITE.
*/
-static bool nssprite_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx)
+static bool
+nssprite_redraw(struct content *c,
+ struct content_redraw_data *data,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
{
nssprite_content *nssprite = (nssprite_content *) c;
bitmap_flags_t flags = BITMAPF_NONE;
- if (data->repeat_x)
+ if (data->repeat_x) {
flags |= BITMAPF_REPEAT_X;
- if (data->repeat_y)
+ }
+ if (data->repeat_y) {
flags |= BITMAPF_REPEAT_Y;
+ }
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- nssprite->bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx,
+ nssprite->bitmap,
+ data->x, data->y,
+ data->width, data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
diff --git a/content/handlers/image/png.c b/content/handlers/image/png.c
index 0baf411bf..7a4ce3010 100644
--- a/content/handlers/image/png.c
+++ b/content/handlers/image/png.c
@@ -74,7 +74,7 @@ enum nspng_cberr {
*/
static void nspng_warning(png_structp png_ptr, png_const_charp warning_message)
{
- LOG("%s", warning_message);
+ NSLOG(netsurf, INFO, "%s", warning_message);
}
/**
@@ -82,7 +82,7 @@ static void nspng_warning(png_structp png_ptr, png_const_charp warning_message)
*/
static void nspng_error(png_structp png_ptr, png_const_charp error_message)
{
- LOG("%s", error_message);
+ NSLOG(netsurf, INFO, "%s", error_message);
longjmp(png_jmpbuf(png_ptr), CBERR_LIBPNG);
}
@@ -175,10 +175,8 @@ static void info_callback(png_structp png_s, png_infop info)
png_c->rowbytes = png_get_rowbytes(png_s, info);
png_c->interlace = (interlace == PNG_INTERLACE_ADAM7);
- LOG("size %li * %li, rowbytes %" PRIsizet,
- (unsigned long)width,
- (unsigned long)height,
- png_c->rowbytes);
+ NSLOG(netsurf, INFO, "size %li * %li, rowbytes %"PRIsizet,
+ (unsigned long)width, (unsigned long)height, png_c->rowbytes);
}
static void row_callback(png_structp png_s, png_bytep new_row,
@@ -240,14 +238,11 @@ static void end_callback(png_structp png_s, png_infop info)
static nserror nspng_create_png_data(nspng_content *png_c)
{
- union content_msg_data msg_data;
-
png_c->bitmap = NULL;
png_c->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png_c->png == NULL) {
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&png_c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
@@ -257,19 +252,17 @@ static nserror nspng_create_png_data(nspng_content *png_c)
if (png_c->info == NULL) {
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&png_c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
if (setjmp(png_jmpbuf(png_c->png))) {
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
- LOG("Failed to set callbacks");
+ NSLOG(netsurf, INFO, "Failed to set callbacks");
png_c->png = NULL;
png_c->info = NULL;
- msg_data.error = messages_get("PNGError");
- content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&png_c->base, NSERROR_PNG_ERROR);
return NSERROR_NOMEM;
}
@@ -323,7 +316,6 @@ static bool nspng_process_data(struct content *c, const char *data,
unsigned int size)
{
nspng_content *png_c = (nspng_content *)c;
- union content_msg_data msg_data;
volatile bool ret = true;
if (png_c->no_process_data) {
@@ -356,14 +348,14 @@ static bool nspng_process_data(struct content *c, const char *data,
* up png conversion and signal the content
* error
*/
- LOG("Fatal PNG error during header, error content");
+ NSLOG(netsurf, INFO,
+ "Fatal PNG error during header, error content");
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
png_c->png = NULL;
png_c->info = NULL;
- msg_data.error = messages_get("PNGError");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_PNG_ERROR);
ret = false;
diff --git a/content/handlers/image/rsvg.c b/content/handlers/image/rsvg.c
index 1bf4b4403..2ba1b49f5 100644
--- a/content/handlers/image/rsvg.c
+++ b/content/handlers/image/rsvg.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content handler for image/svg using librsvg (implementation).
+/**
+ * \file
+ * implementation of content handler for image/svg using librsvg.
*
* SVG files are rendered to a NetSurf bitmap by creating a Cairo rendering
* surface (content_rsvg_data.cs) over the bitmap's data, creating a Cairo
@@ -38,6 +39,8 @@
#include <librsvg/rsvg-cairo.h>
#endif
+#include <nsutils/endian.h>
+
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
@@ -61,17 +64,14 @@ typedef struct rsvg_content {
static nserror rsvg_create_svg_data(rsvg_content *c)
{
- union content_msg_data msg_data;
-
c->rsvgh = NULL;
c->cs = NULL;
c->ct = NULL;
c->bitmap = NULL;
if ((c->rsvgh = rsvg_handle_new()) == NULL) {
- LOG("rsvg_handle_new() returned NULL.");
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO, "rsvg_handle_new() returned NULL.");
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
@@ -114,14 +114,13 @@ static bool rsvg_process_data(struct content *c, const char *data,
unsigned int size)
{
rsvg_content *d = (rsvg_content *) c;
- union content_msg_data msg_data;
GError *err = NULL;
if (rsvg_handle_write(d->rsvgh, (const guchar *)data, (gsize)size,
&err) == FALSE) {
- LOG("rsvg_handle_write returned an error: %s", err->message);
- msg_data.error = err->message;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO,
+ "rsvg_handle_write returned an error: %s", err->message);
+ content_broadcast_errorcode(c, NSERROR_SVG_ERROR);
return false;
}
@@ -142,15 +141,21 @@ static inline void rsvg_argb_to_abgr(uint8_t *pixels,
int width, int height, size_t rowstride)
{
uint8_t *p = pixels;
+ int boff = 0, roff = 2;
+
+ if (endian_host_is_le() == false) {
+ boff = 1;
+ roff = 3;
+ }
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
/* Swap R and B */
- const uint8_t r = p[x+3];
+ const uint8_t r = p[4*x+roff];
- p[x+3] = p[x];
+ p[4*x+roff] = p[4*x+boff];
- p[x] = r;
+ p[4*x+boff] = r;
}
p += rowstride;
@@ -160,14 +165,13 @@ static inline void rsvg_argb_to_abgr(uint8_t *pixels,
static bool rsvg_convert(struct content *c)
{
rsvg_content *d = (rsvg_content *) c;
- union content_msg_data msg_data;
RsvgDimensionData rsvgsize;
GError *err = NULL;
if (rsvg_handle_close(d->rsvgh, &err) == FALSE) {
- LOG("rsvg_handle_close returned an error: %s", err->message);
- msg_data.error = err->message;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO,
+ "rsvg_handle_close returned an error: %s", err->message);
+ content_broadcast_errorcode(c, NSERROR_SVG_ERROR);
return false;
}
@@ -183,9 +187,9 @@ static bool rsvg_convert(struct content *c)
if ((d->bitmap = guit->bitmap->create(c->width, c->height,
BITMAP_NEW)) == NULL) {
- LOG("Failed to create bitmap for rsvg render.");
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO,
+ "Failed to create bitmap for rsvg render.");
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
@@ -194,16 +198,16 @@ static bool rsvg_convert(struct content *c)
CAIRO_FORMAT_ARGB32,
c->width, c->height,
guit->bitmap->get_rowstride(d->bitmap))) == NULL) {
- LOG("Failed to create Cairo image surface for rsvg render.");
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO,
+ "Failed to create Cairo image surface for rsvg render.");
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
if ((d->ct = cairo_create(d->cs)) == NULL) {
- LOG("Failed to create Cairo drawing context for rsvg render.");
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ NSLOG(netsurf, INFO,
+ "Failed to create Cairo drawing context for rsvg render.");
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
@@ -234,8 +238,12 @@ static bool rsvg_redraw(struct content *c, struct content_redraw_data *data,
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- rsvgcontent->bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx,
+ rsvgcontent->bitmap,
+ data->x, data->y,
+ data->width, data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
static void rsvg_destroy(struct content *c)
diff --git a/content/handlers/image/svg.c b/content/handlers/image/svg.c
index 94c485822..51260733d 100644
--- a/content/handlers/image/svg.c
+++ b/content/handlers/image/svg.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for image/svg (implementation).
+/**
+ * \file
+ * implementation of content for image/svg using libsvgtiny.
*/
#include <assert.h>
@@ -48,8 +49,6 @@ typedef struct svg_content {
static nserror svg_create_svg_data(svg_content *c)
{
- union content_msg_data msg_data;
-
c->diagram = svgtiny_create();
if (c->diagram == NULL)
goto no_memory;
@@ -60,8 +59,7 @@ static nserror svg_create_svg_data(svg_content *c)
return NSERROR_OK;
no_memory:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return NSERROR_NOMEM;
}
@@ -154,18 +152,25 @@ static void svg_reformat(struct content *c, int width, int height)
* Redraw a CONTENT_SVG.
*/
-static bool svg_redraw_internal(struct content *c, int x, int y,
- int width, int height, const struct rect *clip,
- const struct redraw_context *ctx, float scale,
- colour background_colour)
+static bool
+svg_redraw_internal(struct content *c,
+ int x,
+ int y,
+ int width,
+ int height,
+ const struct rect *clip,
+ const struct redraw_context *ctx,
+ float scale,
+ colour background_colour)
{
svg_content *svg = (svg_content *) c;
float transform[6];
struct svgtiny_diagram *diagram = svg->diagram;
- bool ok;
int px, py;
unsigned int i;
plot_font_style_t fstyle = *plot_style_font;
+ plot_style_t pstyle;
+ nserror res;
assert(diagram);
@@ -183,14 +188,18 @@ static bool svg_redraw_internal(struct content *c, int x, int y,
for (i = 0; i != diagram->shape_count; i++) {
if (diagram->shape[i].path) {
- ok = ctx->plot->path(diagram->shape[i].path,
+ pstyle.stroke_width = plot_style_int_to_fixed(
+ diagram->shape[i].stroke);
+ pstyle.stroke_colour = BGR(diagram->shape[i].stroke);
+ pstyle.fill_colour = BGR(diagram->shape[i].fill);
+ res = ctx->plot->path(ctx,
+ &pstyle,
+ diagram->shape[i].path,
diagram->shape[i].path_length,
- BGR(diagram->shape[i].fill),
- diagram->shape[i].stroke_width,
- BGR(diagram->shape[i].stroke),
transform);
- if (!ok)
+ if (res != NSERROR_OK) {
return false;
+ }
} else if (diagram->shape[i].text) {
px = transform[0] * diagram->shape[i].text_x +
@@ -202,14 +211,16 @@ static bool svg_redraw_internal(struct content *c, int x, int y,
fstyle.background = 0xffffff;
fstyle.foreground = 0x000000;
- fstyle.size = (8 * FONT_SIZE_SCALE) * scale;
-
- ok = ctx->plot->text(px, py,
- diagram->shape[i].text,
- strlen(diagram->shape[i].text),
- &fstyle);
- if (!ok)
+ fstyle.size = (8 * PLOT_STYLE_SCALE) * scale;
+
+ res = ctx->plot->text(ctx,
+ &fstyle,
+ px, py,
+ diagram->shape[i].text,
+ strlen(diagram->shape[i].text));
+ if (res != NSERROR_OK) {
return false;
+ }
}
}
diff --git a/content/handlers/javascript/duktape/Console.bnd b/content/handlers/javascript/duktape/Console.bnd
index 734f0035a..c4c0c8399 100644
--- a/content/handlers/javascript/duktape/Console.bnd
+++ b/content/handlers/javascript/duktape/Console.bnd
@@ -34,7 +34,7 @@ write_log_entry(duk_context *ctx, unsigned int group, char logtype)
/* spcs... pfx strs... */
duk_concat(ctx, duk_get_top(ctx));
/* str */
- LOG("%s", duk_safe_to_string(ctx, 0));
+ NSLOG(netsurf, INFO, "%s", duk_safe_to_string(ctx, 0));
}
%};
@@ -110,7 +110,7 @@ method Console::time()
return 0;
if (!duk_is_string(ctx, 0)) {
- duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
+ return duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
}
duk_set_top(ctx, 1);
@@ -136,7 +136,7 @@ method Console::timeEnd()
return 0;
if (!duk_is_string(ctx, 0)) {
- duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
+ return duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
}
duk_set_top(ctx, 1);
diff --git a/content/handlers/javascript/duktape/Document.bnd b/content/handlers/javascript/duktape/Document.bnd
index 8658aec45..5de724538 100644
--- a/content/handlers/javascript/duktape/Document.bnd
+++ b/content/handlers/javascript/duktape/Document.bnd
@@ -14,7 +14,7 @@ prologue Document()
#include "utils/libdom.h"
#include "utils/utils.h"
#include "content/hlcache.h"
-#include "render/html_internal.h"
+#include "html/html_internal.h"
#include "content/urldb.h"
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
@@ -41,11 +41,12 @@ method Document::write()
corestring_dom___ns_key_html_content_data,
&htmlc);
if ((err != DOM_NO_ERR) || (htmlc == NULL)) {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
+ NSLOG(netsurf, INFO,
+ "error getting htmlc. parent node:%p htmlc:%p",
+ priv->parent.node, htmlc);
return 0;
} else if (htmlc->parser == NULL) {
- LOG("error; no parser for htmlc: %p", htmlc);
+ NSLOG(netsurf, INFO, "error; no parser for htmlc: %p", htmlc);
return 0;
}
@@ -74,11 +75,12 @@ method Document::writeln()
corestring_dom___ns_key_html_content_data,
&htmlc);
if ((err != DOM_NO_ERR) || (htmlc == NULL)) {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
+ NSLOG(netsurf, INFO,
+ "error getting htmlc. parent node:%p htmlc:%p",
+ priv->parent.node, htmlc);
return 0;
} else if (htmlc->parser == NULL) {
- LOG("error; no parser for htmlc: %p", htmlc);
+ NSLOG(netsurf, INFO, "error; no parser for htmlc: %p", htmlc);
return 0;
}
@@ -311,8 +313,9 @@ getter Document::cookie()
return 1;
}
} else {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
+ NSLOG(netsurf, INFO,
+ "error getting htmlc. parent node:%p htmlc:%p",
+ priv->parent.node, htmlc);
}
return 0;
%}
diff --git a/content/handlers/javascript/duktape/Element.bnd b/content/handlers/javascript/duktape/Element.bnd
index d34e8c1eb..f7e33545f 100644
--- a/content/handlers/javascript/duktape/Element.bnd
+++ b/content/handlers/javascript/duktape/Element.bnd
@@ -183,7 +183,7 @@ getter Element::childElementCount()
element = NULL;
}
}
- LOG("I found %u of them", jsret);
+ NSLOG(netsurf, INFO, "I found %u of them", jsret);
duk_push_uint(ctx, jsret);
return 1;
%}
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
index 92e2ac83e..d1f9e50d7 100644
--- a/content/handlers/javascript/duktape/EventTarget.bnd
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -173,7 +173,8 @@ method EventTarget::addEventListener()
exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
&ev_ty_s);
if (exc != DOM_NO_ERR) {
- LOG("Oh dear, failed to create dom_string in addEventListener()");
+ NSLOG(netsurf, INFO,
+ "Oh dear, failed to create dom_string in addEventListener()");
return 0;
}
dukky_register_event_listener_for(
diff --git a/content/handlers/javascript/duktape/Location.bnd b/content/handlers/javascript/duktape/Location.bnd
index ca7e90509..a731730de 100644
--- a/content/handlers/javascript/duktape/Location.bnd
+++ b/content/handlers/javascript/duktape/Location.bnd
@@ -40,7 +40,7 @@ method Location::reload()
if (priv_win->win != NULL) {
browser_window_reload(priv_win->win, false);
} else {
- LOG("failed to get browser context");
+ NSLOG(netsurf, INFO, "failed to get browser context");
}
return 0;
%}
@@ -54,7 +54,7 @@ method Location::assign()
duk_pop(ctx);
if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
+ NSLOG(netsurf, INFO, "failed to get browser context");
return 0;
}
@@ -83,7 +83,7 @@ method Location::replace()
duk_pop(ctx);
if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
+ NSLOG(netsurf, INFO, "failed to get browser context");
return 0;
}
@@ -131,7 +131,7 @@ setter Location::href()
duk_pop(ctx);
if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
+ NSLOG(netsurf, INFO, "failed to get browser context");
return 0;
}
diff --git a/content/handlers/javascript/duktape/Makefile b/content/handlers/javascript/duktape/Makefile
index fce79def5..2a5c2e742 100644
--- a/content/handlers/javascript/duktape/Makefile
+++ b/content/handlers/javascript/duktape/Makefile
@@ -4,7 +4,7 @@
# Included by javascript/Makefile
#
-content/handlers/javascript/dukky.c: $(OBJROOT)/duktape/binding.h
+content/handlers/javascript/duktape/dukky.c: $(OBJROOT)/duktape/binding.h
BINDINGS := $(wildcard content/handlers/javascript/duktape/*.bnd)
diff --git a/content/handlers/javascript/duktape/Window.bnd b/content/handlers/javascript/duktape/Window.bnd
index 489587899..98ba39df8 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -15,8 +15,8 @@ class Window {
#include "utils/nsurl.h"
#include "netsurf/browser_window.h"
#include "content/hlcache.h"
-#include "render/html.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
%};
};
@@ -25,9 +25,10 @@ init Window(struct browser_window *win, struct html_content *htmlc)
/* element window */
priv->win = win;
priv->htmlc = htmlc;
- LOG("win=%p htmlc=%p", priv->win, priv->htmlc);
+ NSLOG(netsurf, INFO, "win=%p htmlc=%p", priv->win, priv->htmlc);
- LOG("URL is %s", nsurl_access(browser_window_get_url(priv->win)));
+ NSLOG(netsurf, INFO,
+ "URL is %s", nsurl_access(browser_window_access_url(priv->win)));
%}
prototype Window()
@@ -72,8 +73,7 @@ getter Window::console()
if (duk_is_undefined(ctx, -1)) {
duk_pop(ctx);
if (dukky_create_object(ctx, PROTO_NAME(CONSOLE), 0) != DUK_EXEC_SUCCESS) {
- duk_error(ctx, DUK_ERR_ERROR, "Unable to create console object");
- return 0;
+ return duk_error(ctx, DUK_ERR_ERROR, "Unable to create console object");
}
duk_dup(ctx, -1);
duk_put_prop_string(ctx, -3, MAGIC(Console));
@@ -91,8 +91,7 @@ getter Window::location()
duk_push_pointer(ctx, llcache_handle_get_url(priv->htmlc->base.llcache));
if (dukky_create_object(ctx, PROTO_NAME(LOCATION), 1) != DUK_EXEC_SUCCESS) {
- duk_error(ctx, DUK_ERR_ERROR, "Unable to create location object");
- return 0;
+ return duk_error(ctx, DUK_ERR_ERROR, "Unable to create location object");
}
duk_dup(ctx, -1);
duk_put_prop_string(ctx, -3, MAGIC(Location));
@@ -110,10 +109,9 @@ getter Window::navigator()
if (dukky_create_object(ctx,
PROTO_NAME(NAVIGATOR),
0) != DUK_EXEC_SUCCESS) {
- duk_error(ctx,
+ return duk_error(ctx,
DUK_ERR_ERROR,
"Unable to create navigator object");
- return 0;
}
duk_dup(ctx, -1);
duk_put_prop_string(ctx, -3, MAGIC(Navigator));
@@ -141,6 +139,6 @@ method Window::alert()
%{
duk_size_t msg_len;
const char *msg = duk_safe_to_lstring(ctx, 0, &msg_len);
- LOG("JS ALERT: %*s", (int)msg_len, msg);
+ NSLOG(netsurf, INFO, "JS ALERT: %*s", (int)msg_len, msg);
return 0;
%}
diff --git a/content/handlers/javascript/duktape/duk_config.h b/content/handlers/javascript/duktape/duk_config.h
index f9c95ae33..7ee0b13ba 100644
--- a/content/handlers/javascript/duktape/duk_config.h
+++ b/content/handlers/javascript/duktape/duk_config.h
@@ -1,16 +1,18 @@
/*
* duk_config.h configuration header generated by genconfig.py.
*
- * Git commit: 17e3d86cf8b4788bd0d37658f833ab440ce43a1c
- * Git describe: v1.6.0
- * Git branch: HEAD
+ * Git commit: external
+ * Git describe: external
+ * Git branch: external
*
* Supported platforms:
* - Mac OSX, iPhone, Darwin
+ * - Orbis
* - OpenBSD
* - Generic BSD
* - Atari ST TOS
* - AmigaOS
+ * - Durango (XboxOne)
* - Windows
* - Flashplayer (Crossbridge)
* - QNX
@@ -18,6 +20,8 @@
* - Emscripten
* - Linux
* - Solaris
+ * - AIX
+ * - HPUX
* - Generic POSIX
* - Cygwin
* - Generic UNIX
@@ -60,20 +64,24 @@
*/
/* DLL build detection */
-#if defined(DUK_OPT_DLL_BUILD)
-#define DUK_F_DLL_BUILD
-#elif defined(DUK_OPT_NO_DLL_BUILD)
-#undef DUK_F_DLL_BUILD
-#else
/* not configured for DLL build */
#undef DUK_F_DLL_BUILD
-#endif
/* Apple OSX, iOS */
#if defined(__APPLE__)
#define DUK_F_APPLE
#endif
+/* FreeBSD */
+#if defined(__FreeBSD__) || defined(__FreeBSD)
+#define DUK_F_FREEBSD
+#endif
+
+/* Orbis (PS4) variant */
+#if defined(DUK_F_FREEBSD) && defined(__ORBIS__)
+#define DUK_F_ORBIS
+#endif
+
/* OpenBSD */
#if defined(__OpenBSD__) || defined(__OpenBSD)
#define DUK_F_OPENBSD
@@ -84,11 +92,6 @@
#define DUK_F_NETBSD
#endif
-/* FreeBSD */
-#if defined(__FreeBSD__) || defined(__FreeBSD)
-#define DUK_F_FREEBSD
-#endif
-
/* BSD variant */
#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \
defined(__bsdi__) || defined(__DragonFly__)
@@ -126,6 +129,11 @@
#endif
#endif
+/* Durango (Xbox One) */
+#if defined(_DURANGO) || defined(_XBOX_ONE)
+#define DUK_F_DURANGO
+#endif
+
/* Windows, both 32-bit and 64-bit */
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \
defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
@@ -170,6 +178,28 @@
/* illumos / Solaris */
#if defined(__sun) && defined(__SVR4)
#define DUK_F_SUN
+#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550)
+#define DUK_F_OLD_SOLARIS
+/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms
+ * are processed before architectures, so this happens before the
+ * DUK_F_X86/DUK_F_X64 detection is emitted.
+ */
+#include <sys/isa_defs.h>
+#endif
+#endif
+
+/* AIX */
+#if defined(_AIX)
+/* defined(__xlc__) || defined(__IBMC__): works but too wide */
+#define DUK_F_AIX
+#endif
+
+/* HPUX */
+#if defined(__hpux)
+#define DUK_F_HPUX
+#if defined(__ia64)
+#define DUK_F_HPUX_ITANIUM
+#endif
#endif
/* POSIX */
@@ -188,17 +218,6 @@
#define DUK_F_UNIX
#endif
-/* stdint.h not available */
-#if defined(DUK_F_WINDOWS) && defined(_MSC_VER)
-#if (_MSC_VER < 1700)
-/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */
-#define DUK_F_NO_STDINT_H
-#endif
-#endif
-#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC))
-#define DUK_F_NO_STDINT_H
-#endif
-
/* C++ */
#undef DUK_F_CPP
#if defined(__cplusplus)
@@ -208,6 +227,9 @@
/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers),
* define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32.
* https://sites.google.com/site/x32abi/
+ *
+ * With DUK_F_OLD_SOLARIS the <sys/isa_defs.h> header must be included
+ * before this.
*/
#if defined(__amd64__) || defined(__amd64) || \
defined(__x86_64__) || defined(__x86_64) || \
@@ -230,9 +252,9 @@
#endif
/* ARM */
-#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM)
+#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(__aarch64__)
#define DUK_F_ARM
-#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__)
+#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__)
#define DUK_F_ARM64
#else
#define DUK_F_ARM32
@@ -334,6 +356,10 @@
#define DUK_F_VBCC
#endif
+#if defined(ANDROID) || defined(__ANDROID__)
+#define DUK_F_ANDROID
+#endif
+
/* Atari Mint */
#if defined(__MINT__)
#define DUK_F_MINT
@@ -380,6 +406,20 @@
#define DUK_JMPBUF_TYPE jmp_buf
#define DUK_SETJMP(jb) _setjmp((jb))
#define DUK_LONGJMP(jb) _longjmp((jb), 1)
+#elif defined(DUK_F_ORBIS)
+/* --- Orbis --- */
+/* Orbis = PS4 */
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_S
+/* no parsing (not an error) */
+#define DUK_USE_DATE_FMT_STRFTIME
+#include <sys/types.h>
+#include <machine/endian.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define DUK_USE_OS_STRING "orbis"
#elif defined(DUK_F_OPENBSD)
/* --- OpenBSD --- */
/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */
@@ -436,7 +476,7 @@
#define DUK_USE_DATE_PRS_STRPTIME
#define DUK_USE_DATE_FMT_STRFTIME
#include <time.h>
-#ifndef UINTPTR_MAX
+#if !defined(UINTPTR_MAX)
#define UINTPTR_MAX UINT_MAX
#endif
#else
@@ -449,8 +489,13 @@
#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC))
#define DUK_USE_BYTEORDER 3
#endif
-#elif defined(DUK_F_WINDOWS)
-/* --- Windows --- */
+#elif defined(DUK_F_DURANGO)
+/* --- Durango (XboxOne) --- */
+/* Durango = XboxOne
+ * Configuration is nearly identical to Windows, except for
+ * DUK_USE_DATE_TZO_WINDOWS.
+ */
+
/* Initial fix: disable secure CRT related warnings when compiling Duktape
* itself (must be defined before including Windows headers). Don't define
* for user code including duktape.h.
@@ -459,10 +504,9 @@
#define _CRT_SECURE_NO_WARNINGS
#endif
-/* Windows 32-bit and 64-bit are currently the same. */
/* MSVC does not have sys/param.h */
#define DUK_USE_DATE_NOW_WINDOWS
-#define DUK_USE_DATE_TZO_WINDOWS
+#define DUK_USE_DATE_TZO_WINDOWS_NO_DST
/* Note: PRS and FMT are intentionally left undefined for now. This means
* there is no platform specific date parsing/formatting but there is still
* the ISO 8601 standard format.
@@ -474,6 +518,64 @@
#include <windows.h>
#endif
+#define DUK_USE_OS_STRING "durango"
+
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 1
+#endif
+#elif defined(DUK_F_WINDOWS)
+/* --- Windows --- */
+/* Windows version can't obviously be determined at compile time,
+ * but _WIN32_WINNT indicates the minimum version targeted:
+ * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx
+ */
+
+/* Initial fix: disable secure CRT related warnings when compiling Duktape
+ * itself (must be defined before including Windows headers). Don't define
+ * for user code including duktape.h.
+ */
+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/* Windows 32-bit and 64-bit are currently the same. */
+/* MSVC does not have sys/param.h */
+
+#if defined(DUK_COMPILING_DUKTAPE)
+/* Only include when compiling Duktape to avoid polluting application build
+ * with a lot of unnecessary defines.
+ */
+#include <windows.h>
+#endif
+
+/* GetSystemTimePreciseAsFileTime() available from Windows 8:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx
+ */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS)
+/* User forced provider. */
+#else
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+#define DUK_USE_DATE_NOW_WINDOWS_SUBMS
+#else
+#define DUK_USE_DATE_NOW_WINDOWS
+#endif
+#endif
+
+#define DUK_USE_DATE_TZO_WINDOWS
+
+/* Note: PRS and FMT are intentionally left undefined for now. This means
+ * there is no platform specific date parsing/formatting but there is still
+ * the ISO 8601 standard format.
+ */
+
+/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for
+ * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
+ */
+#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \
+ defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC
+#endif
+
#define DUK_USE_OS_STRING "windows"
/* On Windows, assume we're little endian. Even Itanium which has a
@@ -518,6 +620,10 @@
#define DUK_USE_OS_STRING "qnx"
#elif defined(DUK_F_TINSPIRE)
/* --- TI-Nspire --- */
+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE /* e.g. strptime */
+#endif
+
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
#define DUK_USE_DATE_TZO_GMTIME_R
#define DUK_USE_DATE_PRS_STRPTIME
@@ -531,13 +637,13 @@
#elif defined(DUK_F_EMSCRIPTEN)
/* --- Emscripten --- */
#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
-#ifndef _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE /* e.g. getdate_r */
#endif
-#ifndef _XOPEN_SOURCE
+#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE /* e.g. strptime */
#endif
#endif /* DUK_COMPILING_DUKTAPE */
@@ -562,13 +668,13 @@
#elif defined(DUK_F_LINUX)
/* --- Linux --- */
#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
-#ifndef _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE /* e.g. getdate_r */
#endif
-#ifndef _XOPEN_SOURCE
+#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE /* e.g. strptime */
#endif
#endif /* DUK_COMPILING_DUKTAPE */
@@ -589,6 +695,10 @@
#define DUK_USE_DATE_PRS_STRPTIME
#define DUK_USE_DATE_FMT_STRFTIME
+#if 0 /* XXX: safe condition? */
+#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME
+#endif
+
#define DUK_USE_OS_STRING "linux"
#elif defined(DUK_F_SUN)
/* --- Solaris --- */
@@ -598,12 +708,50 @@
#define DUK_USE_DATE_FMT_STRFTIME
#include <sys/types.h>
+#if defined(DUK_F_OLD_SOLARIS)
+/* Old Solaris with no endian.h, stdint.h */
+#define DUK_F_NO_STDINT_H
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#else /* DUK_F_OLD_SOLARIS */
#include <ast/endian.h>
+#endif /* DUK_F_OLD_SOLARIS */
+
#include <sys/param.h>
#include <sys/time.h>
#include <time.h>
#define DUK_USE_OS_STRING "solaris"
+#elif defined(DUK_F_AIX)
+/* --- AIX --- */
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_R
+#define DUK_USE_DATE_PRS_STRPTIME
+#define DUK_USE_DATE_FMT_STRFTIME
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define DUK_USE_OS_STRING "aix"
+#elif defined(DUK_F_HPUX)
+/* --- HPUX --- */
+#define DUK_F_NO_STDINT_H
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_R
+#define DUK_USE_DATE_PRS_STRPTIME
+#define DUK_USE_DATE_FMT_STRFTIME
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define DUK_USE_OS_STRING "hpux"
#elif defined(DUK_F_POSIX)
/* --- Generic POSIX --- */
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
@@ -743,7 +891,7 @@
#define DUK_USE_ARCH_STRING "arm32"
/* Byte order varies, so rely on autodetect. */
#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
+#define DUK_USE_ALIGN_BY 8
#endif
#define DUK_USE_PACKED_TVAL
#define DUK_F_PACKED_TVAL_PROVIDED
@@ -760,12 +908,8 @@
/* --- MIPS 32-bit --- */
#define DUK_USE_ARCH_STRING "mips32"
/* MIPS byte order varies so rely on autodetection. */
-/* Based on 'make checkalign' there are no alignment requirements on
- * Linux MIPS except for doubles, which need align by 4. Alignment
- * requirements vary based on target though.
- */
#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
+#define DUK_USE_ALIGN_BY 8
#endif
#define DUK_USE_PACKED_TVAL
#define DUK_F_PACKED_TVAL_PROVIDED
@@ -773,9 +917,6 @@
/* --- MIPS 64-bit --- */
#define DUK_USE_ARCH_STRING "mips64"
/* MIPS byte order varies so rely on autodetection. */
-/* Good default is a bit arbitrary because alignment requirements
- * depend on target. See https://github.com/svaarala/duktape/issues/102.
- */
#if !defined(DUK_USE_ALIGN_BY)
#define DUK_USE_ALIGN_BY 8
#endif
@@ -887,6 +1028,11 @@
#define DUK_USE_BRANCH_HINTS
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_unpredictable)
+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x))
+#endif
+#endif
#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
#define DUK_NOINLINE __attribute__((noinline))
@@ -894,6 +1040,9 @@
#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
#endif
+/* DUK_HOT */
+/* DUK_COLD */
+
#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
* compiling Duktape or the application.
@@ -995,6 +1144,7 @@
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
#endif
+/* XXX: equivalent of clang __builtin_unpredictable? */
#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \
defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101)
@@ -1003,6 +1153,12 @@
#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
#endif
+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \
+ defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300)
+#define DUK_HOT __attribute__((hot))
+#define DUK_COLD __attribute__((cold))
+#endif
+
#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
* compiling Duktape or the application.
@@ -1181,6 +1337,18 @@
#define DUK_SNPRINTF _snprintf
#define DUK_VSNPRINTF _vsnprintf
#endif
+
+/* Avoid warning when doing DUK_UNREF(some_function). */
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+#pragma warning(disable: 4100 4101 4550 4551)
+#define DUK_UNREF(x)
+#else
+#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0)
+#endif
+
+/* Older versions of MSVC don't support the LL/ULL suffix. */
+#define DUK_U64_CONSTANT(x) x##ui64
+#define DUK_I64_CONSTANT(x) x##i64
#elif defined(DUK_F_EMSCRIPTEN)
/* --- Emscripten --- */
#define DUK_NORETURN(decl) decl __attribute__((noreturn))
@@ -1194,6 +1362,11 @@
#define DUK_USE_BRANCH_HINTS
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_unpredictable)
+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x))
+#endif
+#endif
#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
#define DUK_NOINLINE __attribute__((noinline))
@@ -1401,10 +1574,16 @@
#if defined(DUK_F_X86) || defined(DUK_F_X32) || \
defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \
defined(DUK_F_BCC) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 32))
+ (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \
+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
+ defined(DUK_F_HPUX)) && defined(_ILP32)) || \
+ defined(DUK_F_ARM32)
#define DUK_F_32BIT_PTRS
#elif defined(DUK_F_X64) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 64))
+ (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \
+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
+ defined(DUK_F_HPUX)) && defined(_LP64)) || \
+ defined(DUK_F_ARM64)
#define DUK_F_64BIT_PTRS
#else
/* not sure, not needed with C99 anyway */
@@ -1607,13 +1786,16 @@ typedef unsigned long long duk_uint64_t;
typedef signed long long duk_int64_t;
#endif
#endif
-#if !defined(DUK_F_HAVE_64BIT) && \
- (defined(DUK_F_MINGW) || defined(DUK_F_MSVC))
-/* Both MinGW and MSVC have a 64-bit type. */
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW)
#define DUK_F_HAVE_64BIT
typedef unsigned long duk_uint64_t;
typedef signed long duk_int64_t;
#endif
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC)
+#define DUK_F_HAVE_64BIT
+typedef unsigned __int64 duk_uint64_t;
+typedef signed __int64 duk_int64_t;
+#endif
#if !defined(DUK_F_HAVE_64BIT)
/* cannot detect 64-bit type, not always needed so don't error */
#endif
@@ -1821,10 +2003,10 @@ typedef duk_uint_fast16_t duk_small_uint_fast_t;
#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN
#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX
-/* Boolean values are represented with the platform 'int'. */
-typedef duk_small_int_t duk_bool_t;
-#define DUK_BOOL_MIN DUK_SMALL_INT_MIN
-#define DUK_BOOL_MAX DUK_SMALL_INT_MAX
+/* Boolean values are represented with the platform 'unsigned int'. */
+typedef duk_small_uint_t duk_bool_t;
+#define DUK_BOOL_MIN DUK_SMALL_UINT_MIN
+#define DUK_BOOL_MAX DUK_SMALL_UINT_MAX
/* Index values must have at least 32-bit signed range. */
typedef duk_int_t duk_idx_t;
@@ -1893,7 +2075,10 @@ typedef double duk_double_t;
#endif
#endif
-/* Type for public API calls. */
+/* Type used in public API declarations and user code. Typedef maps to
+ * 'struct duk_hthread' like the 'duk_hthread' typedef which is used
+ * exclusively in internals.
+ */
typedef struct duk_hthread duk_context;
/* Check whether we should use 64-bit integers or not.
@@ -1912,6 +2097,11 @@ typedef struct duk_hthread duk_context;
* Fill-ins for platform, architecture, and compiler
*/
+/* An abort()-like primitive is needed by the default fatal error handler. */
+#if !defined(DUK_ABORT)
+#define DUK_ABORT abort
+#endif
+
#if !defined(DUK_SETJMP)
#define DUK_JMPBUF_TYPE jmp_buf
#define DUK_SETJMP(jb) setjmp((jb))
@@ -1925,17 +2115,6 @@ typedef struct duk_hthread duk_context;
#define DUK_LONGJMP(jb) siglongjmp((jb), 1)
#endif
-typedef FILE duk_file;
-#if !defined(DUK_STDIN)
-#define DUK_STDIN stdin
-#endif
-#if !defined(DUK_STDOUT)
-#define DUK_STDOUT stdout
-#endif
-#if !defined(DUK_STDERR)
-#define DUK_STDERR stderr
-#endif
-
/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h
* (which is unfortunately named). May sometimes need replacement, e.g.
* some compilers don't handle zero length or NULL correctly in realloc().
@@ -2002,12 +2181,6 @@ typedef FILE duk_file;
#if !defined(DUK_STRNCMP)
#define DUK_STRNCMP strncmp
#endif
-#if !defined(DUK_PRINTF)
-#define DUK_PRINTF printf
-#endif
-#if !defined(DUK_FPRINTF)
-#define DUK_FPRINTF fprintf
-#endif
#if !defined(DUK_SPRINTF)
#define DUK_SPRINTF sprintf
#endif
@@ -2028,46 +2201,9 @@ typedef FILE duk_file;
#if !defined(DUK_VSSCANF)
#define DUK_VSSCANF vsscanf
#endif
-#if !defined(DUK_FOPEN)
-#define DUK_FOPEN fopen
-#endif
-#if !defined(DUK_FCLOSE)
-#define DUK_FCLOSE fclose
-#endif
-#if !defined(DUK_FREAD)
-#define DUK_FREAD fread
-#endif
-#if !defined(DUK_FWRITE)
-#define DUK_FWRITE fwrite
-#endif
-#if !defined(DUK_FSEEK)
-#define DUK_FSEEK fseek
-#endif
-#if !defined(DUK_FTELL)
-#define DUK_FTELL ftell
-#endif
-#if !defined(DUK_FFLUSH)
-#define DUK_FFLUSH fflush
-#endif
-#if !defined(DUK_FPUTC)
-#define DUK_FPUTC fputc
-#endif
#if !defined(DUK_MEMZERO)
#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n))
#endif
-#if !defined(DUK_ABORT)
-#define DUK_ABORT abort
-#endif
-#if !defined(DUK_EXIT)
-#define DUK_EXIT exit
-#endif
-
-#if !defined(DUK_DOUBLE_2TO32)
-#define DUK_DOUBLE_2TO32 4294967296.0
-#endif
-#if !defined(DUK_DOUBLE_2TO31)
-#define DUK_DOUBLE_2TO31 2147483648.0
-#endif
#if !defined(DUK_DOUBLE_INFINITY)
#undef DUK_USE_COMPUTED_INFINITY
@@ -2076,7 +2212,8 @@ typedef FILE duk_file;
#define DUK_DOUBLE_INFINITY (__builtin_inf())
#elif defined(INFINITY)
#define DUK_DOUBLE_INFINITY ((double) INFINITY)
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \
+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX)
#define DUK_DOUBLE_INFINITY (1.0 / 0.0)
#else
/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity.
@@ -2092,7 +2229,8 @@ typedef FILE duk_file;
#undef DUK_USE_COMPUTED_NAN
#if defined(NAN)
#define DUK_DOUBLE_NAN NAN
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \
+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX)
#define DUK_DOUBLE_NAN (0.0 / 0.0)
#else
/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN.
@@ -2141,6 +2279,9 @@ typedef FILE duk_file;
* To be safe, use replacements.
*/
#define DUK_F_USE_REPL_ALL
+#elif defined(DUK_F_AIX)
+/* Older versions may be missing isnan(), etc. */
+#define DUK_F_USE_REPL_ALL
#endif
#if defined(DUK_F_USE_REPL_ALL)
@@ -2176,29 +2317,6 @@ typedef FILE duk_file;
#undef DUK_F_USE_REPL_ALL
#endif
-/* Some math functions are C99 only. This is also an issue with some
- * embedded environments using uclibc where uclibc has been configured
- * not to provide some functions. For now, use replacements whenever
- * using uclibc.
- */
-#undef DUK_USE_MATH_FMIN
-#undef DUK_USE_MATH_FMAX
-#undef DUK_USE_MATH_ROUND
-#if defined(DUK_F_UCLIBC)
-/* uclibc may be missing these */
-#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)
-/* vbcc + AmigaOS may be missing these */
-#elif defined(DUK_F_MINT)
-/* mint clib is missing these */
-#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11)
-/* build is not C99 or C++11, play it safe */
-#else
-/* C99 or C++11, no known issues */
-#define DUK_USE_MATH_FMIN
-#define DUK_USE_MATH_FMAX
-#define DUK_USE_MATH_ROUND
-#endif
-
/* These functions don't currently need replacement but are wrapped for
* completeness. Because these are used as function pointers, they need
* to be defined as concrete C functions (not macros).
@@ -2206,12 +2324,6 @@ typedef FILE duk_file;
#if !defined(DUK_FABS)
#define DUK_FABS fabs
#endif
-#if !defined(DUK_FMIN)
-#define DUK_FMIN fmin
-#endif
-#if !defined(DUK_FMAX)
-#define DUK_FMAX fmax
-#endif
#if !defined(DUK_FLOOR)
#define DUK_FLOOR floor
#endif
@@ -2255,13 +2367,43 @@ typedef FILE duk_file;
#define DUK_SQRT sqrt
#endif
+/* The functions below exist only in C99/C++11 or later and need a workaround
+ * for platforms that don't include them. MSVC isn't detected as C99, but
+ * these functions also exist in MSVC 2013 and later so include a clause for
+ * that too. Android doesn't have log2; disable all of these for Android.
+ */
+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \
+ !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT)
+#if !defined(DUK_CBRT)
+#define DUK_CBRT cbrt
+#endif
+#if !defined(DUK_LOG2)
+#define DUK_LOG2 log2
+#endif
+#if !defined(DUK_LOG10)
+#define DUK_LOG10 log10
+#endif
+#if !defined(DUK_TRUNC)
+#define DUK_TRUNC trunc
+#endif
+#endif /* DUK_F_C99 etc */
+
/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics,
- * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround.
- * (This might be a wider problem; if so, generalize the define name.)
+ * see test-bug-netbsd-math-pow.js. MinGW has similar (but different)
+ * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds
+ * for these targets.
+ */
+#undef DUK_USE_POW_WORKAROUNDS
+#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW)
+#define DUK_USE_POW_WORKAROUNDS
+#endif
+
+/* Similar workarounds for atan2() semantics issues. MinGW issues are
+ * documented in test-bug-mingw-math-issues.js.
*/
-#undef DUK_USE_POW_NETBSD_WORKAROUND
-#if defined(DUK_F_NETBSD)
-#define DUK_USE_POW_NETBSD_WORKAROUND
+#undef DUK_USE_ATAN2_WORKAROUNDS
+#if defined(DUK_F_MINGW)
+#define DUK_USE_ATAN2_WORKAROUNDS
#endif
/* Rely as little as possible on compiler behavior for NaN comparison,
@@ -2304,25 +2446,6 @@ typedef FILE duk_file;
* byte order for doubles is referred to as "mixed endian".
*/
-/* For custom platforms allow user to define byteorder explicitly.
- * Since endianness headers are not standardized, this is a useful
- * workaround for custom platforms for which endianness detection
- * is not directly supported. Perhaps custom hardware is used and
- * user cannot submit upstream patches.
- */
-#if defined(DUK_OPT_FORCE_BYTEORDER)
-#undef DUK_USE_BYTEORDER
-#if (DUK_OPT_FORCE_BYTEORDER == 1)
-#define DUK_USE_BYTEORDER 1
-#elif (DUK_OPT_FORCE_BYTEORDER == 2)
-#define DUK_USE_BYTEORDER 2
-#elif (DUK_OPT_FORCE_BYTEORDER == 3)
-#define DUK_USE_BYTEORDER 3
-#else
-#error invalid DUK_OPT_FORCE_BYTEORDER value
-#endif
-#endif /* DUK_OPT_FORCE_BYTEORDER */
-
/* GCC and Clang provide endianness defines as built-in predefines, with
* leading and trailing double underscores (e.g. __BYTE_ORDER__). See
* output of "make gccpredefs" and "make clangpredefs". Clang doesn't
@@ -2425,18 +2548,6 @@ typedef FILE duk_file;
#define DUK_USE_ALIGN_BY 8
#endif
-/* User forced alignment to 4 or 8. */
-#if defined(DUK_OPT_FORCE_ALIGN)
-#undef DUK_USE_ALIGN_BY
-#if (DUK_OPT_FORCE_ALIGN == 4)
-#define DUK_USE_ALIGN_BY 4
-#elif (DUK_OPT_FORCE_ALIGN == 8)
-#define DUK_USE_ALIGN_BY 8
-#else
-#error invalid DUK_OPT_FORCE_ALIGN value
-#endif
-#endif
-
/* Compiler specific hackery needed to force struct size to match aligment,
* see e.g. duk_hbuffer.h.
*
@@ -2479,9 +2590,8 @@ typedef FILE duk_file;
#endif
#if !defined(DUK_CAUSE_SEGFAULT)
-/* This is optionally used by panic handling to cause the program to segfault
- * (instead of e.g. abort()) on panic. Valgrind will then indicate the C
- * call stack leading to the panic.
+/* This can be used for testing; valgrind will then indicate the C call stack
+ * leading to the call site.
*/
#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0)
#endif
@@ -2489,7 +2599,8 @@ typedef FILE duk_file;
/* Macro for suppressing warnings for potentially unreferenced variables.
* The variables can be actually unreferenced or unreferenced in some
* specific cases only; for instance, if a variable is only debug printed,
- * it is unreferenced when debug printing is disabled.
+ * it is unreferenced when debug printing is disabled. May cause warnings
+ * for volatile arguments.
*/
#define DUK_UNREF(x) do { (void) (x); } while (0)
#endif
@@ -2517,6 +2628,9 @@ typedef FILE duk_file;
#if !defined(DUK_UNLIKELY)
#define DUK_UNLIKELY(x) (x)
#endif
+#if !defined(DUK_UNPREDICTABLE)
+#define DUK_UNPREDICTABLE(x) (x)
+#endif
#if !defined(DUK_NOINLINE)
#define DUK_NOINLINE /*nop*/
@@ -2528,6 +2642,13 @@ typedef FILE duk_file;
#define DUK_ALWAYS_INLINE /*nop*/
#endif
+#if !defined(DUK_HOT)
+#define DUK_HOT /*nop*/
+#endif
+#if !defined(DUK_COLD)
+#define DUK_COLD /*nop*/
+#endif
+
#if !defined(DUK_EXTERNAL_DECL)
#define DUK_EXTERNAL_DECL extern
#endif
@@ -2604,6 +2725,13 @@ typedef FILE duk_file;
#undef DUK_USE_GCC_PRAGMAS
#endif
+#if !defined(DUK_U64_CONSTANT)
+#define DUK_U64_CONSTANT(x) x##ULL
+#endif
+#if !defined(DUK_I64_CONSTANT)
+#define DUK_I64_CONSTANT(x) x##LL
+#endif
+
/* Workaround for GH-323: avoid inlining control when compiling from
* multiple sources, as it causes compiler portability trouble.
*/
@@ -2656,14 +2784,6 @@ typedef FILE duk_file;
#undef DUK_F_PACKED_TVAL_POSSIBLE
#endif /* DUK_F_PACKED_TVAL_PROVIDED */
-
-/* Feature option forcing. */
-#if defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#define DUK_USE_PACKED_TVAL
-#endif
/* Object property allocation layout has implications for memory and code
* footprint and generated code size/speed. The best layout also depends
* on whether the platform has alignment requirements or benefits from
@@ -2694,852 +2814,200 @@ typedef FILE duk_file;
#endif
/*
- * Feature option handling
+ * Autogenerated defaults
*/
-#if !defined(DUK_USE_ALIGN_BY)
-#if defined(DUK_OPT_FORCE_ALIGN)
-#define DUK_USE_ALIGN_BY DUK_OPT_FORCE_ALIGN
-#else
-#define DUK_USE_ALIGN_BY 8
-#endif
-#endif
-
-#if defined(DUK_OPT_ASSERTIONS)
-#define DUK_USE_ASSERTIONS
-#elif defined(DUK_OPT_NO_ASSERTIONS)
-#undef DUK_USE_ASSERTIONS
-#else
+#define DUK_USE_ARRAY_BUILTIN
+#define DUK_USE_ARRAY_FASTPATH
+#define DUK_USE_ARRAY_PROP_FASTPATH
#undef DUK_USE_ASSERTIONS
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
#define DUK_USE_AUGMENT_ERROR_CREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_CREATE
-#else
-#define DUK_USE_AUGMENT_ERROR_CREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_AUGMENT_ERROR_THROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_THROW
-#else
#define DUK_USE_AUGMENT_ERROR_THROW
-#endif
-
-#if defined(DUK_OPT_BROWSER_LIKE)
-#define DUK_USE_BROWSER_LIKE
-#elif defined(DUK_OPT_NO_BROWSER_LIKE)
-#undef DUK_USE_BROWSER_LIKE
-#else
-#define DUK_USE_BROWSER_LIKE
-#endif
-
-#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT)
-#define DUK_USE_BUFFEROBJECT_SUPPORT
-#elif defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT)
-#undef DUK_USE_BUFFEROBJECT_SUPPORT
-#else
+#define DUK_USE_AVOID_PLATFORM_FUNCPTRS
+#define DUK_USE_BASE64_FASTPATH
+#define DUK_USE_BOOLEAN_BUILTIN
#define DUK_USE_BUFFEROBJECT_SUPPORT
-#endif
-
-#if defined(DUK_OPT_BUFLEN16)
-#define DUK_USE_BUFLEN16
-#elif defined(DUK_OPT_NO_BUFLEN16)
-#undef DUK_USE_BUFLEN16
-#else
#undef DUK_USE_BUFLEN16
-#endif
-
-#if defined(DUK_OPT_BYTECODE_DUMP_SUPPORT)
#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#elif defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT)
-#undef DUK_USE_BYTECODE_DUMP_SUPPORT
-#else
-#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_COMMONJS_MODULES)
-#define DUK_USE_COMMONJS_MODULES
-#elif defined(DUK_OPT_NO_COMMONJS_MODULES)
-#undef DUK_USE_COMMONJS_MODULES
-#else
+#define DUK_USE_CACHE_ACTIVATION
+#define DUK_USE_CACHE_CATCHER
+#define DUK_USE_CALLSTACK_LIMIT 10000
#define DUK_USE_COMMONJS_MODULES
-#endif
-
-#if defined(DUK_OPT_CPP_EXCEPTIONS)
-#define DUK_USE_CPP_EXCEPTIONS
-#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS)
-#undef DUK_USE_CPP_EXCEPTIONS
-#else
+#define DUK_USE_COMPILER_RECLIMIT 2500
+#define DUK_USE_COROUTINE_SUPPORT
#undef DUK_USE_CPP_EXCEPTIONS
-#endif
-
-#if defined(DUK_OPT_DATAPTR16)
-#define DUK_USE_DATAPTR16
-#elif defined(DUK_OPT_NO_DATAPTR16)
-#undef DUK_USE_DATAPTR16
-#else
#undef DUK_USE_DATAPTR16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_DEC16)
-#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr))
-#else
#undef DUK_USE_DATAPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_ENC16)
-#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr))
-#else
#undef DUK_USE_DATAPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_DDDPRINT)
-#define DUK_USE_DDDPRINT
-#elif defined(DUK_OPT_NO_DDDPRINT)
-#undef DUK_USE_DDDPRINT
-#else
-#undef DUK_USE_DDDPRINT
-#endif
-
-#if defined(DUK_OPT_DDPRINT)
-#define DUK_USE_DDPRINT
-#elif defined(DUK_OPT_NO_DDPRINT)
-#undef DUK_USE_DDPRINT
-#else
-#undef DUK_USE_DDPRINT
-#endif
-
-#if defined(DUK_OPT_DEBUG)
-#define DUK_USE_DEBUG
-#elif defined(DUK_OPT_NO_DEBUG)
-#undef DUK_USE_DEBUG
-#else
+#define DUK_USE_DATE_BUILTIN
+#undef DUK_USE_DATE_FORMAT_STRING
+#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET
+#undef DUK_USE_DATE_GET_NOW
+#undef DUK_USE_DATE_PARSE_STRING
+#undef DUK_USE_DATE_PRS_GETDATE
#undef DUK_USE_DEBUG
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_DUMPHEAP)
-#define DUK_USE_DEBUGGER_DUMPHEAP
-#elif defined(DUK_OPT_NO_DEBUGGER_DUMPHEAP)
-#undef DUK_USE_DEBUGGER_DUMPHEAP
-#else
#undef DUK_USE_DEBUGGER_DUMPHEAP
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING)
-#define DUK_USE_DEBUGGER_FWD_LOGGING
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_LOGGING)
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#else
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT)
-#define DUK_USE_DEBUGGER_FWD_PRINTALERT
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_PRINTALERT)
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#else
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_INSPECT)
-#define DUK_USE_DEBUGGER_INSPECT
-#elif defined(DUK_OPT_NO_DEBUGGER_INSPECT)
#undef DUK_USE_DEBUGGER_INSPECT
-#else
-#undef DUK_USE_DEBUGGER_INSPECT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT)
-#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#elif defined(DUK_OPT_NO_DEBUGGER_PAUSE_UNCAUGHT)
-#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#else
#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_SUPPORT)
-#define DUK_USE_DEBUGGER_SUPPORT
-#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT)
-#undef DUK_USE_DEBUGGER_SUPPORT
-#else
#undef DUK_USE_DEBUGGER_SUPPORT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_THROW_NOTIFY)
#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY)
-#undef DUK_USE_DEBUGGER_THROW_NOTIFY
-#else
-#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
-#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#elif defined(DUK_OPT_NO_DEBUGGER_TRANSPORT_TORTURE)
-#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#else
#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#endif
-
-#if defined(DUK_OPT_DEBUG_BUFSIZE)
-#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE
-#else
#define DUK_USE_DEBUG_BUFSIZE 65536L
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
+#define DUK_USE_DEBUG_LEVEL 0
+#undef DUK_USE_DEBUG_WRITE
#define DUK_USE_DOUBLE_LINKED_HEAP
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_DOUBLE_LINKED_HEAP
-#else
-#define DUK_USE_DOUBLE_LINKED_HEAP
-#endif
-
-#if defined(DUK_OPT_DPRINT)
-#define DUK_USE_DPRINT
-#elif defined(DUK_OPT_NO_DPRINT)
-#undef DUK_USE_DPRINT
-#else
-#undef DUK_USE_DPRINT
-#endif
-
-#if defined(DUK_OPT_DPRINT_COLORS)
-#define DUK_USE_DPRINT_COLORS
-#elif defined(DUK_OPT_NO_DPRINT_COLORS)
-#undef DUK_USE_DPRINT_COLORS
-#else
-#undef DUK_USE_DPRINT_COLORS
-#endif
-
-#if defined(DUK_OPT_DPRINT_RDTSC)
-#define DUK_USE_DPRINT_RDTSC
-#elif defined(DUK_OPT_NO_DPRINT_RDTSC)
-#undef DUK_USE_DPRINT_RDTSC
-#else
-#undef DUK_USE_DPRINT_RDTSC
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRCREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRCREATE
-#else
+#define DUK_USE_DUKTAPE_BUILTIN
+#define DUK_USE_ENCODING_BUILTINS
#define DUK_USE_ERRCREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRTHROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRTHROW
-#else
#define DUK_USE_ERRTHROW
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_PROTO_PROPERTY)
+#define DUK_USE_ES6
#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#elif defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY)
-#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#else
-#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_SETPROTOTYPEOF)
#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#elif defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF)
-#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#else
-#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#endif
-
-#if defined(DUK_OPT_ES6_PROXY)
#define DUK_USE_ES6_PROXY
-#elif defined(DUK_OPT_NO_ES6_PROXY)
-#undef DUK_USE_ES6_PROXY
-#else
-#define DUK_USE_ES6_PROXY
-#endif
-
-#if defined(DUK_OPT_ES6_REGEXP_BRACES)
-#define DUK_USE_ES6_REGEXP_BRACES
-#elif defined(DUK_OPT_NO_ES6_REGEXP_BRACES)
-#undef DUK_USE_ES6_REGEXP_BRACES
-#else
-#define DUK_USE_ES6_REGEXP_BRACES
-#endif
-
+#define DUK_USE_ES6_REGEXP_SYNTAX
+#define DUK_USE_ES6_UNICODE_ESCAPE
+#define DUK_USE_ES7
+#define DUK_USE_ES7_EXP_OPERATOR
+#define DUK_USE_ES8
+#define DUK_USE_ES9
+#define DUK_USE_ESBC_LIMITS
+#define DUK_USE_ESBC_MAX_BYTES 2147418112L
+#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L
+#undef DUK_USE_EXEC_FUN_LOCAL
#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS)
-/* Enabled with debug/assertions just so that any issues can be caught. */
-#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#endif
-
+#undef DUK_USE_EXEC_PREFER_SIZE
+#define DUK_USE_EXEC_REGCONST_OPTIMIZE
#undef DUK_USE_EXEC_TIMEOUT_CHECK
-#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK)
-#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata))
-#endif
-
+#undef DUK_USE_EXPLICIT_NULL_INIT
#undef DUK_USE_EXTSTR_FREE
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE)
-#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr))
-#endif
-
#undef DUK_USE_EXTSTR_INTERN_CHECK
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK)
-#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len))
-#endif
-
-/* Support for 48-bit signed integer duk_tval with transparent semantics. */
#undef DUK_USE_FASTINT
-#if defined(DUK_OPT_FASTINT)
-#if !defined(DUK_F_HAVE_64BIT)
-#error DUK_OPT_FASTINT requires 64-bit integer type support at the moment
-#endif
-#define DUK_USE_FASTINT
-#endif
-
-#if defined(DUK_OPT_FILE_IO)
-#define DUK_USE_FILE_IO
-#elif defined(DUK_OPT_NO_FILE_IO)
-#undef DUK_USE_FILE_IO
-#else
-#define DUK_USE_FILE_IO
-#endif
-
-#if defined(DUK_OPT_FUNCPTR16)
-#define DUK_USE_FUNCPTR16
-#elif defined(DUK_OPT_NO_FUNCPTR16)
-#undef DUK_USE_FUNCPTR16
-#else
+#define DUK_USE_FAST_REFCOUNT_DEFAULT
+#undef DUK_USE_FATAL_HANDLER
+#define DUK_USE_FATAL_MAXLEN 128
+#define DUK_USE_FINALIZER_SUPPORT
+#undef DUK_USE_FINALIZER_TORTURE
#undef DUK_USE_FUNCPTR16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_DEC16)
-#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr))
-#else
#undef DUK_USE_FUNCPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_ENC16)
-#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr))
-#else
#undef DUK_USE_FUNCPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_GC_TORTURE)
-#define DUK_USE_GC_TORTURE
-#elif defined(DUK_OPT_NO_GC_TORTURE)
-#undef DUK_USE_GC_TORTURE
-#else
+#define DUK_USE_FUNCTION_BUILTIN
+#define DUK_USE_FUNC_FILENAME_PROPERTY
+#define DUK_USE_FUNC_NAME_PROPERTY
#undef DUK_USE_GC_TORTURE
-#endif
-
-#if defined(DUK_OPT_HEAPPTR16)
-#define DUK_USE_HEAPPTR16
-#elif defined(DUK_OPT_NO_HEAPPTR16)
+#undef DUK_USE_GET_MONOTONIC_TIME
+#undef DUK_USE_GET_RANDOM_DOUBLE
+#undef DUK_USE_GLOBAL_BINDING
+#define DUK_USE_GLOBAL_BUILTIN
#undef DUK_USE_HEAPPTR16
-#else
-#undef DUK_USE_HEAPPTR16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_DEC16)
-#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr))
-#else
#undef DUK_USE_HEAPPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_ENC16)
-#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr))
-#else
#undef DUK_USE_HEAPPTR_ENC16
-#endif
-
-/* For now, hash part is dropped if and only if 16-bit object fields are used. */
+#define DUK_USE_HEX_FASTPATH
+#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2
+#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9
+#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16
+#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8
+#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16
+#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8
#define DUK_USE_HOBJECT_HASH_PART
-#if defined(DUK_OPT_OBJSIZES16)
-#undef DUK_USE_HOBJECT_HASH_PART
-#endif
-
-#if defined(DUK_OPT_HSTRING_CLEN)
-#define DUK_USE_HSTRING_CLEN
-#elif defined(DUK_OPT_NO_HSTRING_CLEN)
-#undef DUK_USE_HSTRING_CLEN
-#else
+#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8
+#define DUK_USE_HSTRING_ARRIDX
#define DUK_USE_HSTRING_CLEN
-#endif
-
-#if defined(DUK_OPT_EXTERNAL_STRINGS)
-#define DUK_USE_HSTRING_EXTDATA
-#elif defined(DUK_OPT_NO_EXTERNAL_STRINGS)
#undef DUK_USE_HSTRING_EXTDATA
-#else
-#undef DUK_USE_HSTRING_EXTDATA
-#endif
-
-#if defined(DUK_OPT_INTERRUPT_COUNTER)
-#define DUK_USE_INTERRUPT_COUNTER
-#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER)
-#undef DUK_USE_INTERRUPT_COUNTER
-#else
+#define DUK_USE_HSTRING_LAZY_CLEN
+#define DUK_USE_HTML_COMMENTS
+#define DUK_USE_IDCHAR_FASTPATH
+#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR
#undef DUK_USE_INTERRUPT_COUNTER
-#endif
-
-#if defined(DUK_OPT_JC)
-#define DUK_USE_JC
-#elif defined(DUK_OPT_NO_JC)
-#undef DUK_USE_JC
-#else
+#undef DUK_USE_INTERRUPT_DEBUG_FIXUP
#define DUK_USE_JC
-#endif
-
-#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH)
-#define DUK_USE_JSON_STRINGIFY_FASTPATH
-#elif defined(DUK_OPT_NO_JSON_STRINGIFY_FASTPATH)
-#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#else
+#define DUK_USE_JSON_BUILTIN
+#define DUK_USE_JSON_DECNUMBER_FASTPATH
+#define DUK_USE_JSON_DECSTRING_FASTPATH
+#define DUK_USE_JSON_DEC_RECLIMIT 1000
+#define DUK_USE_JSON_EATWHITE_FASTPATH
+#define DUK_USE_JSON_ENC_RECLIMIT 1000
+#define DUK_USE_JSON_QUOTESTRING_FASTPATH
#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#endif
-
-#if defined(DUK_OPT_JX)
+#define DUK_USE_JSON_SUPPORT
#define DUK_USE_JX
-#elif defined(DUK_OPT_NO_JX)
-#undef DUK_USE_JX
-#else
-#define DUK_USE_JX
-#endif
-
-#if defined(DUK_OPT_LIGHTFUNC_BUILTINS)
-#define DUK_USE_LIGHTFUNC_BUILTINS
-#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS)
-#undef DUK_USE_LIGHTFUNC_BUILTINS
-#else
+#define DUK_USE_LEXER_SLIDING_WINDOW
#undef DUK_USE_LIGHTFUNC_BUILTINS
-#endif
-
-#if defined(DUK_OPT_MARK_AND_SWEEP)
-#define DUK_USE_MARK_AND_SWEEP
-#elif defined(DUK_OPT_NO_MARK_AND_SWEEP)
-#undef DUK_USE_MARK_AND_SWEEP
-#else
-#define DUK_USE_MARK_AND_SWEEP
-#endif
-
-#if defined(DUK_OPT_MS_STRINGTABLE_RESIZE)
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#elif defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE)
-#undef DUK_USE_MS_STRINGTABLE_RESIZE
-#else
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER)
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#else
+#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256
+#define DUK_USE_MATH_BUILTIN
+#define DUK_USE_NATIVE_CALL_RECLIMIT 1000
#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER)
#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#else
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#else
#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#else
#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_SOURCE_PROPERTY)
#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#else
-#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_STMT)
-#define DUK_USE_NONSTD_FUNC_STMT
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_STMT)
-#undef DUK_USE_NONSTD_FUNC_STMT
-#else
#define DUK_USE_NONSTD_FUNC_STMT
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#else
#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029)
#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#elif defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029)
-#undef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#else
-#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#endif
-
-#if defined(DUK_OPT_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#elif defined(DUK_OPT_NO_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#undef DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#else
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#else
#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_STRING_FROMCHARCODE_32BIT)
#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#elif defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT)
-#undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#else
-#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#endif
-
-#if defined(DUK_OPT_OBJSIZES16)
-#define DUK_USE_OBJSIZES16
-#elif defined(DUK_OPT_NO_OBJSIZES16)
-#undef DUK_USE_OBJSIZES16
-#else
+#define DUK_USE_NUMBER_BUILTIN
+#define DUK_USE_OBJECT_BUILTIN
#undef DUK_USE_OBJSIZES16
-#endif
-
-#if defined(DUK_OPT_OCTAL_SUPPORT)
-#define DUK_USE_OCTAL_SUPPORT
-#elif defined(DUK_OPT_NO_OCTAL_SUPPORT)
-#undef DUK_USE_OCTAL_SUPPORT
-#else
-#define DUK_USE_OCTAL_SUPPORT
-#endif
-
-#if defined(DUK_OPT_PACKED_TVAL)
-#define DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#else
-/* Already provided above */
-#endif
-
-#undef DUK_USE_PANIC_ABORT
-#if !defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_ABORT
-#endif
-
-#undef DUK_USE_PANIC_HANDLER
-#if defined(DUK_OPT_PANIC_HANDLER)
-#define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg))
-#endif
-
-#undef DUK_USE_PANIC_SEGFAULT
-#if defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_SEGFAULT
-#endif
-
-#if defined(DUK_OPT_PARANOID_ERRORS)
-#define DUK_USE_PARANOID_ERRORS
-#elif defined(DUK_OPT_NO_PARANOID_ERRORS)
-#undef DUK_USE_PARANOID_ERRORS
-#else
#undef DUK_USE_PARANOID_ERRORS
-#endif
-
-#if defined(DUK_OPT_PC2LINE)
#define DUK_USE_PC2LINE
-#elif defined(DUK_OPT_NO_PC2LINE)
-#undef DUK_USE_PC2LINE
-#else
-#define DUK_USE_PC2LINE
-#endif
-
-#if defined(DUK_OPT_REFCOUNT16)
-#define DUK_USE_REFCOUNT16
-#elif defined(DUK_OPT_NO_REFCOUNT16)
-#undef DUK_USE_REFCOUNT16
-#else
+#define DUK_USE_PERFORMANCE_BUILTIN
+#undef DUK_USE_PREFER_SIZE
+#undef DUK_USE_PROMISE_BUILTIN
+#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
#undef DUK_USE_REFCOUNT16
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
-#define DUK_USE_REFERENCE_COUNTING
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_REFERENCE_COUNTING
-#else
+#define DUK_USE_REFCOUNT32
#define DUK_USE_REFERENCE_COUNTING
-#endif
-
-#if defined(DUK_OPT_REGEXP_CANON_WORKAROUND)
-#define DUK_USE_REGEXP_CANON_WORKAROUND
-#elif defined(DUK_OPT_NO_REGEXP_CANON_WORKAROUND)
+#define DUK_USE_REFLECT_BUILTIN
+#define DUK_USE_REGEXP_CANON_BITMAP
#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#else
-#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#endif
-
-#if defined(DUK_OPT_REGEXP_SUPPORT)
-#define DUK_USE_REGEXP_SUPPORT
-#elif defined(DUK_OPT_NO_REGEXP_SUPPORT)
-#undef DUK_USE_REGEXP_SUPPORT
-#else
+#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000
+#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000
#define DUK_USE_REGEXP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_CLONE)
-#define DUK_USE_ROM_GLOBAL_CLONE
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_CLONE)
-#undef DUK_USE_ROM_GLOBAL_CLONE
-#else
#undef DUK_USE_ROM_GLOBAL_CLONE
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_INHERIT)
-#define DUK_USE_ROM_GLOBAL_INHERIT
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_INHERIT)
#undef DUK_USE_ROM_GLOBAL_INHERIT
-#else
-#undef DUK_USE_ROM_GLOBAL_INHERIT
-#endif
-
-#if defined(DUK_OPT_ROM_OBJECTS)
-#define DUK_USE_ROM_OBJECTS
-#elif defined(DUK_OPT_NO_ROM_OBJECTS)
-#undef DUK_USE_ROM_OBJECTS
-#else
#undef DUK_USE_ROM_OBJECTS
-#endif
-
-#if defined(DUK_OPT_ROM_STRINGS)
-#define DUK_USE_ROM_STRINGS
-#elif defined(DUK_OPT_NO_ROM_STRINGS)
-#undef DUK_USE_ROM_STRINGS
-#else
+#define DUK_USE_ROM_PTRCOMP_FIRST 63488L
#undef DUK_USE_ROM_STRINGS
-#endif
-
-#if defined(DUK_OPT_SECTION_B)
-#define DUK_USE_SECTION_B
-#elif defined(DUK_OPT_NO_SECTION_B)
-#undef DUK_USE_SECTION_B
-#else
#define DUK_USE_SECTION_B
-#endif
-
-#if defined(DUK_OPT_SELF_TESTS)
-#define DUK_USE_SELF_TESTS
-#elif defined(DUK_OPT_NO_SELF_TESTS)
#undef DUK_USE_SELF_TESTS
-#else
-#undef DUK_USE_SELF_TESTS
-#endif
-
-#if defined(DUK_OPT_SHUFFLE_TORTURE)
-#define DUK_USE_SHUFFLE_TORTURE
-#elif defined(DUK_OPT_NO_SHUFFLE_TORTURE)
-#undef DUK_USE_SHUFFLE_TORTURE
-#else
+#define DUK_USE_SHEBANG_COMMENTS
#undef DUK_USE_SHUFFLE_TORTURE
-#endif
-
-#if defined(DUK_OPT_SOURCE_NONBMP)
#define DUK_USE_SOURCE_NONBMP
-#elif defined(DUK_OPT_NO_SOURCE_NONBMP)
-#undef DUK_USE_SOURCE_NONBMP
-#else
-#define DUK_USE_SOURCE_NONBMP
-#endif
-
-#if defined(DUK_OPT_STRHASH16)
-#define DUK_USE_STRHASH16
-#elif defined(DUK_OPT_NO_STRHASH16)
-#undef DUK_USE_STRHASH16
-#else
#undef DUK_USE_STRHASH16
-#endif
-
-#if defined(DUK_OPT_STRICT_DECL)
-#define DUK_USE_STRICT_DECL
-#elif defined(DUK_OPT_NO_STRICT_DECL)
-#undef DUK_USE_STRICT_DECL
-#else
+#undef DUK_USE_STRHASH_DENSE
+#define DUK_USE_STRHASH_SKIP_SHIFT 5
#define DUK_USE_STRICT_DECL
-#endif
-
-#if defined(DUK_OPT_STRICT_UTF8_SOURCE)
-#define DUK_USE_STRICT_UTF8_SOURCE
-#elif defined(DUK_OPT_NO_STRICT_UTF8_SOURCE)
-#undef DUK_USE_STRICT_UTF8_SOURCE
-#else
#undef DUK_USE_STRICT_UTF8_SOURCE
-#endif
-
-#if defined(DUK_OPT_STRLEN16)
-#define DUK_USE_STRLEN16
-#elif defined(DUK_OPT_NO_STRLEN16)
+#define DUK_USE_STRING_BUILTIN
#undef DUK_USE_STRLEN16
-#else
-#undef DUK_USE_STRLEN16
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-#define DUK_USE_STRTAB_CHAIN
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN_SIZE
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-/* Low memory algorithm: separate chaining using arrays, fixed size hash */
-#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE
-#endif
-
-#undef DUK_USE_STRTAB_PROBE
-#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE))
-#define DUK_USE_STRTAB_PROBE
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_TAILCALL
-#else
+#define DUK_USE_STRTAB_GROW_LIMIT 17
+#define DUK_USE_STRTAB_MAXSIZE 268435456L
+#define DUK_USE_STRTAB_MINSIZE 1024
+#undef DUK_USE_STRTAB_PTRCOMP
+#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255
+#define DUK_USE_STRTAB_SHRINK_LIMIT 6
+#undef DUK_USE_STRTAB_TORTURE
+#undef DUK_USE_SYMBOL_BUILTIN
#define DUK_USE_TAILCALL
-#endif
-
-#if defined(DUK_OPT_TARGET_INFO)
-#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO
-#else
#define DUK_USE_TARGET_INFO "unknown"
-#endif
-
-#if defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_TRACEBACKS
-#elif defined(DUK_OPT_NO_TRACEBACKS)
-#undef DUK_USE_TRACEBACKS
-#else
#define DUK_USE_TRACEBACKS
-#endif
-
-#if defined(DUK_OPT_TRACEBACK_DEPTH)
-#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH
-#else
-#define DUK_USE_TRACEBACK_DEPTH 10
-#endif
-
-#if defined(DUK_OPT_DECLARE)
-#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE
-#else
+#define DUK_USE_TRACEBACK_DEPTH 10
#define DUK_USE_USER_DECLARE() /* no user declarations */
-#endif
-
-/* User provided InitJS. */
-#undef DUK_USE_USER_INITJS
-#if defined(DUK_OPT_USER_INITJS)
-#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS)
-#endif
-
-#if defined(DUK_OPT_VERBOSE_ERRORS)
-#define DUK_USE_VERBOSE_ERRORS
-#elif defined(DUK_OPT_NO_VERBOSE_ERRORS)
-#undef DUK_USE_VERBOSE_ERRORS
-#else
+#define DUK_USE_VALSTACK_GROW_SHIFT 2
+#define DUK_USE_VALSTACK_LIMIT 1000000L
+#define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2
+#define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4
+#undef DUK_USE_VALSTACK_UNSAFE
#define DUK_USE_VERBOSE_ERRORS
-#endif
-
-#if defined(DUK_OPT_VOLUNTARY_GC)
-#define DUK_USE_VOLUNTARY_GC
-#elif defined(DUK_OPT_NO_VOLUNTARY_GC)
-#undef DUK_USE_VOLUNTARY_GC
-#else
+#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
#define DUK_USE_VOLUNTARY_GC
-#endif
-
-#if defined(DUK_OPT_ZERO_BUFFER_DATA)
#define DUK_USE_ZERO_BUFFER_DATA
-#elif defined(DUK_OPT_NO_ZERO_BUFFER_DATA)
-#undef DUK_USE_ZERO_BUFFER_DATA
-#else
-#define DUK_USE_ZERO_BUFFER_DATA
-#endif
-
-/*
- * Autogenerated defaults
- */
-
-#define DUK_USE_AVOID_PLATFORM_FUNCPTRS
-#define DUK_USE_BASE64_FASTPATH
-#define DUK_USE_BUILTIN_INITJS
-#define DUK_USE_COMPILER_RECLIMIT 2500
-#undef DUK_USE_DATE_FORMAT_STRING
-#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET
-#undef DUK_USE_DATE_GET_NOW
-#undef DUK_USE_DATE_PARSE_STRING
-#undef DUK_USE_DATE_PRS_GETDATE
-#define DUK_USE_ESBC_LIMITS
-#define DUK_USE_ESBC_MAX_BYTES 2147418112L
-#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L
-#undef DUK_USE_EXEC_FUN_LOCAL
-#undef DUK_USE_EXPLICIT_NULL_INIT
-#define DUK_USE_FAST_REFCOUNT_DEFAULT
-#define DUK_USE_HEX_FASTPATH
-#define DUK_USE_IDCHAR_FASTPATH
-#undef DUK_USE_INTERRUPT_DEBUG_FIXUP
-#define DUK_USE_JSON_DECNUMBER_FASTPATH
-#define DUK_USE_JSON_DECSTRING_FASTPATH
-#define DUK_USE_JSON_DEC_RECLIMIT 1000
-#define DUK_USE_JSON_EATWHITE_FASTPATH
-#define DUK_USE_JSON_ENC_RECLIMIT 1000
-#define DUK_USE_JSON_QUOTESTRING_FASTPATH
-#define DUK_USE_LEXER_SLIDING_WINDOW
-#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE
-#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256
-#define DUK_USE_MATH_BUILTIN
-#define DUK_USE_NATIVE_CALL_RECLIMIT 1000
-#undef DUK_USE_PANIC_EXIT
-#undef DUK_USE_PREFER_SIZE
-#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
-#undef DUK_USE_REFZERO_FINALIZER_TORTURE
-#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000
-#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000
-#define DUK_USE_ROM_PTRCOMP_FIRST 63488L
-#undef DUK_USE_STRHASH_DENSE
-#define DUK_USE_STRHASH_SKIP_SHIFT 5
-#undef DUK_USE_VALSTACK_UNSAFE
-#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
/*
- * Alternative customization header
- *
- * If you want to modify the final DUK_USE_xxx flags directly (without
- * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H
- * and tweak the final flags there.
+ * Fixups
*/
-#if defined(DUK_OPT_HAVE_CUSTOM_H)
#include "duk_custom.h"
-#endif
/*
* You may add overriding #define/#undef directives below for
@@ -3562,21 +3030,25 @@ typedef FILE duk_file;
#if defined(DUK_USE_DATE_GET_NOW)
/* External provider already defined. */
#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday()
#elif defined(DUK_USE_DATE_NOW_TIME)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time()
#elif defined(DUK_USE_DATE_NOW_WINDOWS)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows()
+#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms()
#else
#error no provider for DUK_USE_DATE_GET_NOW()
#endif
#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET)
/* External provider already defined. */
-#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
+#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d))
#elif defined(DUK_USE_DATE_TZO_WINDOWS)
#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d))
+#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d))
#else
#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET()
#endif
@@ -3600,184 +3072,17 @@ typedef FILE duk_file;
/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */
#endif
-#endif /* DUK_COMPILING_DUKTAPE */
-
-/*
- * Checks for config option consistency (DUK_USE_xxx)
- */
-
-#if defined(DUK_USE_32BIT_PTRS)
-#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS
-#endif
-#if defined(DUK_USE_ALIGN_4)
-#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4
-#endif
-#if defined(DUK_USE_ALIGN_8)
-#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8
-#endif
-#if defined(DUK_USE_BYTEORDER_FORCED)
-#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED
-#endif
-#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16)
-#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16)
-#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER)
-#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
-#endif
-#if defined(DUK_USE_DEEP_C_STACK)
-#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK
-#endif
-#if defined(DUK_USE_DOUBLE_BE)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE
-#endif
-#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE)
-#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME)
-#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_LE)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE
-#endif
-#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE)
-#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME)
-#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_ME)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME
-#endif
-#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE)
-#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE)
-#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined)
-#endif
-#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG)
-#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing)
-#endif
-#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS)
-#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing)
-#endif
-#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS)
-#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing)
-#endif
-#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER)
-#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
-#endif
-#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA)
-#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing)
-#endif
-#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA)
-#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing)
-#endif
-#if defined(DUK_USE_FULL_TVAL)
-#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL
-#endif
-#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16)
-#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16)
-#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
-#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
-#endif
-#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG)
-#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined)
-#endif
-#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16)
-#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16)
-#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_INTEGER_BE)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE
-#endif
-#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE)
-#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME)
-#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_LE)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE
-#endif
-#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE)
-#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME)
-#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_ME)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME
-#endif
-#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE)
-#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE)
-#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined)
-#endif
-#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST)
-#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST
-#endif
-#if defined(DUK_USE_PACKED_TVAL_POSSIBLE)
-#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE
-#endif
-#if defined(DUK_USE_RDTSC)
-#error unsupported config option used (option has been removed): DUK_USE_RDTSC
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT)
-#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined)
-#endif
-#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_SETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_SETJMP
-#endif
-#if defined(DUK_USE_SIGSETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP
-#endif
-#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN)
-#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing)
-#endif
-#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
-#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined)
-#endif
-#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
-#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
-#endif
-#if defined(DUK_USE_UNDERSCORE_SETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+/* External provider already defined. */
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime()
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc()
+#else
+/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */
#endif
-#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus)
-#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler
-#endif
+#endif /* DUK_COMPILING_DUKTAPE */
/*
* Convert DUK_USE_BYTEORDER, from whatever source, into currently used
diff --git a/content/handlers/javascript/duktape/duk_custom.h b/content/handlers/javascript/duktape/duk_custom.h
index 1f98b7825..2ff931793 100644
--- a/content/handlers/javascript/duktape/duk_custom.h
+++ b/content/handlers/javascript/duktape/duk_custom.h
@@ -28,6 +28,7 @@
#undef DUK_USE_DATE_PARSE_STRING
#endif
+#define DUK_USE_FASTINT
#define DUK_USE_REGEXP_CANON_WORKAROUND
/* Required for execution timeout checking */
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 4a6b9c398..8cfeb3985 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -48,7 +48,7 @@
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
-static duk_ret_t dukky_populate_object(duk_context *ctx)
+static duk_ret_t dukky_populate_object(duk_context *ctx, void *udata)
{
/* ... obj args protoname nargs */
int nargs = duk_get_int(ctx, -1);
@@ -61,7 +61,8 @@ static duk_ret_t dukky_populate_object(duk_context *ctx)
duk_get_prop(ctx, -2);
/* ... obj args prototab {proto/undefined} */
if (duk_is_undefined(ctx, -1)) {
- LOG("RuhRoh, couldn't find a prototype, HTMLUnknownElement it is");
+ NSLOG(netsurf, INFO,
+ "RuhRoh, couldn't find a prototype, HTMLUnknownElement it is");
duk_pop(ctx);
duk_push_string(ctx, PROTO_NAME(HTMLUNKNOWNELEMENT));
duk_get_prop(ctx, -2);
@@ -77,7 +78,7 @@ static duk_ret_t dukky_populate_object(duk_context *ctx)
/* ... initfn obj[proto] args prototab proto */
duk_pop_2(ctx);
/* ... initfn obj[proto] args */
- LOG("Call the init function");
+ NSLOG(netsurf, INFO, "Call the init function");
duk_call(ctx, nargs + 1);
return 1; /* The object */
}
@@ -85,7 +86,7 @@ static duk_ret_t dukky_populate_object(duk_context *ctx)
duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args)
{
duk_ret_t ret;
- LOG("name=%s nargs=%d", name+2, args);
+ NSLOG(netsurf, INFO, "name=%s nargs=%d", name + 2, args);
/* ... args */
duk_push_object(ctx);
/* ... args obj */
@@ -103,10 +104,10 @@ duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args)
/* ... obj args name */
duk_push_int(ctx, args);
/* ... obj args name nargs */
- if ((ret = duk_safe_call(ctx, dukky_populate_object, args + 3, 1))
+ if ((ret = duk_safe_call(ctx, dukky_populate_object, NULL, args + 3, 1))
!= DUK_EXEC_SUCCESS)
return ret;
- LOG("created");
+ NSLOG(netsurf, INFO, "created");
return DUK_EXEC_SUCCESS;
}
@@ -143,10 +144,10 @@ dukky_push_node_stacked(duk_context *ctx)
/* ... nodeptr klass nodes obj nodeptr klass */
duk_push_int(ctx, 1);
/* ... nodeptr klass nodes obj nodeptr klass 1 */
- if (duk_safe_call(ctx, dukky_populate_object, 4, 1)
+ if (duk_safe_call(ctx, dukky_populate_object, NULL, 4, 1)
!= DUK_EXEC_SUCCESS) {
duk_set_top(ctx, top_at_fail);
- LOG("Boo and also hiss");
+ NSLOG(netsurf, INFO, "Boo and also hiss");
return false;
}
/* ... nodeptr klass nodes node */
@@ -384,13 +385,14 @@ dukky_push_node_klass(duk_context *ctx, struct dom_node *node)
err = dom_node_get_namespace(node, &namespace);
if (err != DOM_NO_ERR) {
/* Feck it, element */
- LOG("dom_node_get_namespace() failed");
+ NSLOG(netsurf, INFO,
+ "dom_node_get_namespace() failed");
duk_push_string(ctx, PROTO_NAME(ELEMENT));
break;
}
if (namespace == NULL) {
/* No namespace, -> element */
- LOG("no namespace");
+ NSLOG(netsurf, INFO, "no namespace");
duk_push_string(ctx, PROTO_NAME(ELEMENT));
break;
}
@@ -474,8 +476,7 @@ dukky_push_node(duk_context *ctx, struct dom_node *node)
static duk_ret_t
dukky_bad_constructor(duk_context *ctx)
{
- duk_error(ctx, DUK_ERR_ERROR, "Bad constructor");
- return 0;
+ return duk_error(ctx, DUK_ERR_ERROR, "Bad constructor");
}
void
@@ -562,7 +563,7 @@ nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
duk_context *ctx;
jscontext *ret = calloc(1, sizeof(*ret));
*jsctx = NULL;
- LOG("Creating new duktape javascript context");
+ NSLOG(netsurf, INFO, "Creating new duktape javascript context");
if (ret == NULL) return NSERROR_NOMEM;
ctx = ret->ctx = duk_create_heap(
dukky_alloc_function,
@@ -585,7 +586,7 @@ nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
void js_destroycontext(jscontext *ctx)
{
- LOG("Destroying duktape javascript context");
+ NSLOG(netsurf, INFO, "Destroying duktape javascript context");
duk_destroy_heap(ctx->ctx);
free(ctx);
}
@@ -594,7 +595,9 @@ jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
{
assert(ctx != NULL);
/* Pop any active thread off */
- LOG("Yay, new compartment, win_priv=%p, doc_priv=%p", win_priv, doc_priv);
+ NSLOG(netsurf, INFO,
+ "Yay, new compartment, win_priv=%p, doc_priv=%p", win_priv,
+ doc_priv);
duk_set_top(ctx->ctx, 0);
duk_push_thread(ctx->ctx);
ctx->thread = duk_require_context(ctx->ctx, -1);
@@ -624,7 +627,7 @@ jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
return (jsobject *)ctx;
}
-static duk_ret_t eval_top_string(duk_context *ctx)
+static duk_ret_t eval_top_string(duk_context *ctx, void *udata)
{
duk_eval(ctx);
return 0;
@@ -654,21 +657,23 @@ bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
duk_push_lstring(CTX, txt, txtlen);
(void) nsu_getmonotonic_ms(&ctx->exec_start_time);
- if (duk_safe_call(CTX, eval_top_string, 1, 1) == DUK_EXEC_ERROR) {
+ if (duk_safe_call(CTX, eval_top_string, NULL, 1, 1) == DUK_EXEC_ERROR) {
duk_get_prop_string(CTX, 0, "name");
duk_get_prop_string(CTX, 0, "message");
duk_get_prop_string(CTX, 0, "fileName");
duk_get_prop_string(CTX, 0, "lineNumber");
duk_get_prop_string(CTX, 0, "stack");
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, 1),
- duk_safe_to_string(CTX, 2));
- LOG(" was at: %s line %s", duk_safe_to_string(CTX, 3),
- duk_safe_to_string(CTX, 4));
- LOG(" Stack trace: %s", duk_safe_to_string(CTX, 5));
+ NSLOG(netsurf, INFO, "Uncaught error in JS: %s: %s",
+ duk_safe_to_string(CTX, 1), duk_safe_to_string(CTX, 2));
+ NSLOG(netsurf, INFO, " was at: %s line %s",
+ duk_safe_to_string(CTX, 3), duk_safe_to_string(CTX, 4));
+ NSLOG(netsurf, INFO, " Stack trace: %s",
+ duk_safe_to_string(CTX, 5));
return false;
}
if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
- LOG("Returning %s", duk_get_boolean(CTX, 0) ? "true" : "false");
+ NSLOG(netsurf, INFO, "Returning %s",
+ duk_get_boolean(CTX, 0) ? "true" : "false");
return duk_get_boolean(CTX, 0);
}
@@ -783,7 +788,8 @@ bool dukky_get_current_value_of_event_handler(duk_context *ctx,
/* ... node fullhandlersrc filename */
if (duk_pcompile(ctx, DUK_COMPILE_FUNCTION) != 0) {
/* ... node err */
- LOG("Unable to proceed with handler, could not compile");
+ NSLOG(netsurf, INFO,
+ "Unable to proceed with handler, could not compile");
duk_pop_2(ctx);
return false;
}
@@ -817,29 +823,27 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_get_memory_functions(ctx, &funcs);
jsctx = funcs.udata;
- LOG("WOOP WOOP, An event:");
+ NSLOG(netsurf, INFO, "WOOP WOOP, An event:");
exc = dom_event_get_type(evt, &name);
if (exc != DOM_NO_ERR) {
- LOG("Unable to find the event name");
+ NSLOG(netsurf, INFO, "Unable to find the event name");
return;
}
- LOG("Event's name is %*s",
- dom_string_length(name), dom_string_data(name));
+ NSLOG(netsurf, INFO, "Event's name is %*s", dom_string_length(name),
+ dom_string_data(name));
exc = dom_event_get_event_phase(evt, &phase);
if (exc != DOM_NO_ERR) {
- LOG("Unable to get event phase");
+ NSLOG(netsurf, INFO, "Unable to get event phase");
return;
}
- LOG("Event phase is: %s (%d)",
- phase == DOM_CAPTURING_PHASE ? "capturing" :
- phase == DOM_AT_TARGET ? "at-target" :
- phase == DOM_BUBBLING_PHASE ? "bubbling" :
- "unknown", (int)phase);
+ NSLOG(netsurf, INFO, "Event phase is: %s (%d)",
+ phase == DOM_CAPTURING_PHASE ? "capturing" : phase == DOM_AT_TARGET ? "at-target" : phase == DOM_BUBBLING_PHASE ? "bubbling" : "unknown",
+ (int)phase);
exc = dom_event_get_current_target(evt, &targ);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
- LOG("Unable to find the event target");
+ NSLOG(netsurf, INFO, "Unable to find the event target");
return;
}
@@ -853,7 +857,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
dom_node_unref(targ);
- LOG("Unable to push JS node representation?!");
+ NSLOG(netsurf, INFO,
+ "Unable to push JS node representation?!");
return;
}
/* ... node */
@@ -869,21 +874,26 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... err */
- LOG("OH NOES! An error running a callback. Meh.");
+ NSLOG(netsurf, INFO,
+ "OH NOES! An error running a callback. Meh.");
exc = dom_event_stop_immediate_propagation(evt);
if (exc != DOM_NO_ERR)
- LOG("WORSE! could not stop propagation");
+ NSLOG(netsurf, INFO,
+ "WORSE! could not stop propagation");
duk_get_prop_string(ctx, -1, "name");
duk_get_prop_string(ctx, -2, "message");
duk_get_prop_string(ctx, -3, "fileName");
duk_get_prop_string(ctx, -4, "lineNumber");
duk_get_prop_string(ctx, -5, "stack");
/* ... err name message fileName lineNumber stack */
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
- duk_safe_to_string(ctx, -4));
- LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
- duk_safe_to_string(ctx, -2));
- LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+ NSLOG(netsurf, INFO, "Uncaught error in JS: %s: %s",
+ duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ NSLOG(netsurf, INFO, " was at: %s line %s",
+ duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ NSLOG(netsurf, INFO, " Stack trace: %s",
+ duk_safe_to_string(ctx, -1));
duk_pop_n(ctx, 6);
/* ... */
@@ -963,21 +973,27 @@ handle_extras:
if (duk_pcall_method(ctx, 1) != 0) {
/* Failed to run the method */
/* ... copy handler err */
- LOG("OH NOES! An error running a callback. Meh.");
+ NSLOG(netsurf, INFO,
+ "OH NOES! An error running a callback. Meh.");
exc = dom_event_stop_immediate_propagation(evt);
if (exc != DOM_NO_ERR)
- LOG("WORSE! could not stop propagation");
+ NSLOG(netsurf, INFO,
+ "WORSE! could not stop propagation");
duk_get_prop_string(ctx, -1, "name");
duk_get_prop_string(ctx, -2, "message");
duk_get_prop_string(ctx, -3, "fileName");
duk_get_prop_string(ctx, -4, "lineNumber");
duk_get_prop_string(ctx, -5, "stack");
/* ... err name message fileName lineNumber stack */
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
- duk_safe_to_string(ctx, -4));
- LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
- duk_safe_to_string(ctx, -2));
- LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+ NSLOG(netsurf, INFO, "Uncaught error in JS: %s: %s",
+ duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ NSLOG(netsurf, INFO,
+ " was at: %s line %s",
+ duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ NSLOG(netsurf, INFO, " Stack trace: %s",
+ duk_safe_to_string(ctx, -1));
duk_pop_n(ctx, 7);
/* ... copy */
@@ -1035,11 +1051,12 @@ void dukky_register_event_listener_for(duk_context *ctx,
exc = dom_event_target_add_event_listener(
ele, name, listen, capture);
if (exc != DOM_NO_ERR) {
- LOG("Unable to register listener for %p.%*s",
- ele, dom_string_length(name), dom_string_data(name));
+ NSLOG(netsurf, INFO,
+ "Unable to register listener for %p.%*s", ele,
+ dom_string_length(name), dom_string_data(name));
} else {
- LOG("have registered listener for %p.%*s",
- ele, dom_string_length(name), dom_string_data(name));
+ NSLOG(netsurf, INFO, "have registered listener for %p.%*s",
+ ele, dom_string_length(name), dom_string_data(name));
}
dom_event_listener_unref(listen);
}
@@ -1206,7 +1223,8 @@ bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, s
dom_event *evt;
dom_event_target *body;
- LOG("Event: %s (doc=%p, target=%p)", type, doc, target);
+ NSLOG(netsurf, INFO, "Event: %s (doc=%p, target=%p)", type, doc,
+ target);
/** @todo Make this more generic, this only handles load and only
* targetting the window, so that we actually stand a chance of
@@ -1277,18 +1295,22 @@ bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, s
if (duk_pcall_method(CTX, 1) != 0) {
/* Failed to run the handler */
/* ... err */
- LOG("OH NOES! An error running a handler. Meh.");
+ NSLOG(netsurf, INFO,
+ "OH NOES! An error running a handler. Meh.");
duk_get_prop_string(CTX, -1, "name");
duk_get_prop_string(CTX, -2, "message");
duk_get_prop_string(CTX, -3, "fileName");
duk_get_prop_string(CTX, -4, "lineNumber");
duk_get_prop_string(CTX, -5, "stack");
/* ... err name message fileName lineNumber stack */
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, -5),
- duk_safe_to_string(CTX, -4));
- LOG(" was at: %s line %s", duk_safe_to_string(CTX, -3),
- duk_safe_to_string(CTX, -2));
- LOG(" Stack trace: %s", duk_safe_to_string(CTX, -1));
+ NSLOG(netsurf, INFO, "Uncaught error in JS: %s: %s",
+ duk_safe_to_string(CTX, -5),
+ duk_safe_to_string(CTX, -4));
+ NSLOG(netsurf, INFO, " was at: %s line %s",
+ duk_safe_to_string(CTX, -3),
+ duk_safe_to_string(CTX, -2));
+ NSLOG(netsurf, INFO, " Stack trace: %s",
+ duk_safe_to_string(CTX, -1));
duk_pop_n(CTX, 6);
/* ... */
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index b5809aa08..435e0c305 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -26,11 +26,13 @@
#define DUKKY_H
#ifdef JS_DEBUG
-# define JS_LOG(format, args...) LOG(format , ##args)
+# define JS_LOG(format, args...) NSLOG(netsurf, INFO, format , ##args)
#else
# define JS_LOG(format, ...) ((void) 0)
#endif
+#define LOG(format, args...) NSLOG(netsurf, INFO, format , ##args)
+
duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args);
duk_bool_t dukky_push_node_stacked(duk_context *ctx);
duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node);
diff --git a/content/handlers/javascript/duktape/duktape.c b/content/handlers/javascript/duktape/duktape.c
index b64383b11..dbebee282 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,10 +1,10 @@
/* Omit from static analysis. */
#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 1.6.0.
+ * Single source autogenerated distributable for Duktape 2.2.1.
*
- * Git commit 17e3d86cf8b4788bd0d37658f833ab440ce43a1c (v1.6.0).
- * Git branch HEAD.
+ * Git commit external (external).
+ * Git branch external.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -18,7 +18,7 @@
*
* (http://opensource.org/licenses/MIT)
*
-* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
+* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -38,6 +38,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
/* AUTHORS.rst */
/*
* ===============
@@ -71,6 +72,23 @@
* * Ren\u00e9 Hollander <rene@rene8888.at>
* * Julien Hamaide (https://github.com/crazyjul)
* * Sebastian G\u00f6tte (https://github.com/jaseg)
+* * Tomasz Magulski (https://github.com/magul)
+* * \D. Bohdan (https://github.com/dbohdan)
+* * Ond\u0159ej Jirman (https://github.com/megous)
+* * Sa\u00fal Ibarra Corretg\u00e9 <saghul@gmail.com>
+* * Jeremy HU <huxingyi@msn.com>
+* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+* * Harold Brenes (https://github.com/harold-b)
+* * Oliver Crow (https://github.com/ocrow)
+* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski)
+* * Brett Vickers (https://github.com/beevik)
+* * Dominik Okwieka (https://github.com/okitec)
+* * Remko Tron\u00e7on (https://el-tramo.be)
+* * Romero Malaquias (rbsm@ic.ufal.br)
+* * Michael Drake <michael.drake@codethink.co.uk>
+* * Steven Don (https://github.com/shdon)
+* * Simon Stone (https://github.com/sstone1)
+* * \J. McC. (https://github.com/jmhmccr)
*
* Other contributions
* ===================
@@ -108,12 +126,21 @@
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
* * Laurent Zubiaur (https://github.com/lzubiaur)
-* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+* * Neil Kolban (https://github.com/nkolban)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala@iki.fi``) and I'll fix the omission.
*/
-#line 1 "duk_internal.h"
+
+/*
+ * Replacements for missing platform functions.
+ *
+ * Unlike the originals, fpclassify() and signbit() replacements don't
+ * work on any floating point types, only doubles. The C typing here
+ * mimics the standard prototypes.
+ */
+
+/* #include duk_internal.h */
/*
* Top-level include file to be used for all (internal) source files.
*
@@ -121,7 +148,7 @@
* have not been designed to be individually included.
*/
-#ifndef DUK_INTERNAL_H_INCLUDED
+#if !defined(DUK_INTERNAL_H_INCLUDED)
#define DUK_INTERNAL_H_INCLUDED
/*
@@ -143,9 +170,7 @@
/*
* User declarations, e.g. prototypes for user functions used by Duktape
- * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro
- * value calls a user function, it needs to be declared for Duktape
- * compilation to avoid warnings.
+ * macros.
*/
DUK_USE_USER_DECLARE()
@@ -159,8 +184,432 @@ DUK_USE_USER_DECLARE()
* dependencies.
*/
-#line 1 "duk_replacements.h"
-#ifndef DUK_REPLACEMENTS_H_INCLUDED
+/* #include duk_dblunion.h */
+/*
+ * Union to access IEEE double memory representation, indexes for double
+ * memory representation, and some macros for double manipulation.
+ *
+ * Also used by packed duk_tval. Use a union for bit manipulation to
+ * minimize aliasing issues in practice. The C99 standard does not
+ * guarantee that this should work, but it's a very widely supported
+ * practice for low level manipulation.
+ *
+ * IEEE double format summary:
+ *
+ * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
+ * A B C D E F G H
+ *
+ * s sign bit
+ * eee... exponent field
+ * fff... fraction
+ *
+ * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
+ *
+ * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
+ * signaling NaN when the highest bit of the mantissa is zero, and a quiet
+ * NaN when the highest bit is set.
+ *
+ * At least three memory layouts are relevant here:
+ *
+ * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
+ * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
+ * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME
+ *
+ * ARM is a special case: ARM double values are in mixed/cross endian
+ * format while ARM duk_uint64_t values are in standard little endian
+ * format (H G F E D C B A). When a double is read as a duk_uint64_t
+ * from memory, the register will contain the (logical) value
+ * E F G H A B C D. This requires some special handling below.
+ *
+ * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
+ * the logical (big endian) order:
+ *
+ * byte order duk_uint8_t duk_uint16_t duk_uint32_t
+ * BE 01234567 0123 01
+ * LE 76543210 3210 10
+ * ME (ARM) 32107654 1032 01
+ *
+ * Some processors may alter NaN values in a floating point load+store.
+ * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
+ * quiet one. This is catastrophic when NaN space is used in packed
+ * duk_tval values. See: misc/clang_aliasing.c.
+ */
+
+#if !defined(DUK_DBLUNION_H_INCLUDED)
+#define DUK_DBLUNION_H_INCLUDED
+
+/*
+ * Union for accessing double parts, also serves as packed duk_tval
+ */
+
+union duk_double_union {
+ double d;
+ float f[2];
+#if defined(DUK_USE_64BIT_OPS)
+ duk_uint64_t ull[1];
+#endif
+ duk_uint32_t ui[2];
+ duk_uint16_t us[4];
+ duk_uint8_t uc[8];
+#if defined(DUK_USE_PACKED_TVAL)
+ void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
+#endif
+};
+
+typedef union duk_double_union duk_double_union;
+
+/*
+ * Indexes of various types with respect to big endian (logical) layout
+ */
+
+#if defined(DUK_USE_DOUBLE_LE)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0
+#endif
+#define DUK_DBL_IDX_UI0 1
+#define DUK_DBL_IDX_UI1 0
+#define DUK_DBL_IDX_US0 3
+#define DUK_DBL_IDX_US1 2
+#define DUK_DBL_IDX_US2 1
+#define DUK_DBL_IDX_US3 0
+#define DUK_DBL_IDX_UC0 7
+#define DUK_DBL_IDX_UC1 6
+#define DUK_DBL_IDX_UC2 5
+#define DUK_DBL_IDX_UC3 4
+#define DUK_DBL_IDX_UC4 3
+#define DUK_DBL_IDX_UC5 2
+#define DUK_DBL_IDX_UC6 1
+#define DUK_DBL_IDX_UC7 0
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#elif defined(DUK_USE_DOUBLE_BE)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0
+#endif
+#define DUK_DBL_IDX_UI0 0
+#define DUK_DBL_IDX_UI1 1
+#define DUK_DBL_IDX_US0 0
+#define DUK_DBL_IDX_US1 1
+#define DUK_DBL_IDX_US2 2
+#define DUK_DBL_IDX_US3 3
+#define DUK_DBL_IDX_UC0 0
+#define DUK_DBL_IDX_UC1 1
+#define DUK_DBL_IDX_UC2 2
+#define DUK_DBL_IDX_UC3 3
+#define DUK_DBL_IDX_UC4 4
+#define DUK_DBL_IDX_UC5 5
+#define DUK_DBL_IDX_UC6 6
+#define DUK_DBL_IDX_UC7 7
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#elif defined(DUK_USE_DOUBLE_ME)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
+#endif
+#define DUK_DBL_IDX_UI0 0
+#define DUK_DBL_IDX_UI1 1
+#define DUK_DBL_IDX_US0 1
+#define DUK_DBL_IDX_US1 0
+#define DUK_DBL_IDX_US2 3
+#define DUK_DBL_IDX_US3 2
+#define DUK_DBL_IDX_UC0 3
+#define DUK_DBL_IDX_UC1 2
+#define DUK_DBL_IDX_UC2 1
+#define DUK_DBL_IDX_UC3 0
+#define DUK_DBL_IDX_UC4 7
+#define DUK_DBL_IDX_UC5 6
+#define DUK_DBL_IDX_UC6 5
+#define DUK_DBL_IDX_UC7 4
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#else
+#error internal error
+#endif
+
+/*
+ * Helper macros for reading/writing memory representation parts, used
+ * by duk_numconv.c and duk_tval.h.
+ */
+
+#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
+ (u)->d = (v); \
+ } while (0)
+
+#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
+ } while (0)
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
+ } while (0)
+#else
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
+ } while (0)
+#endif
+#else /* DUK_USE_64BIT_OPS */
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
+ } while (0)
+#endif /* DUK_USE_64BIT_OPS */
+
+#define DUK_DBLUNION_SET_LOW32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
+ } while (0)
+
+#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
+#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
+#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_SET_UINT64(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
+ } while (0)
+#define DUK_DBLUNION_GET_UINT64(u) \
+ ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
+ ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
+#else
+#define DUK_DBLUNION_SET_UINT64(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
+ } while (0)
+#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
+#endif
+#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
+#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
+#endif /* DUK_USE_64BIT_OPS */
+
+/*
+ * Double NaN manipulation macros related to NaN normalization needed when
+ * using the packed duk_tval representation. NaN normalization is necessary
+ * to keep double values compatible with the duk_tval format.
+ *
+ * When packed duk_tval is used, the NaN space is used to store pointers
+ * and other tagged values in addition to NaNs. Actual NaNs are normalized
+ * to a specific quiet NaN. The macros below are used by the implementation
+ * to check and normalize NaN values when they might be created. The macros
+ * are essentially NOPs when the non-packed duk_tval representation is used.
+ *
+ * A FULL check is exact and checks all bits. A NOTFULL check is used by
+ * the packed duk_tval and works correctly for all NaNs except those that
+ * begin with 0x7ff0. Since the 'normalized NaN' values used with packed
+ * duk_tval begin with 0x7ff8, the partial check is reliable when packed
+ * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
+ * quiet NaN regardless of its remaining lower bits.
+ *
+ * The ME variant below is specifically for ARM byte order, which has the
+ * feature that while doubles have a mixed byte order (32107654), unsigned
+ * long long values has a little endian byte order (76543210). When writing
+ * a logical double value through a ULL pointer, the 32-bit words need to be
+ * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
+ * This is not full ARM support but suffices for some environments.
+ */
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+/* Macros for 64-bit ops + mixed endian doubles. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
+#else
+/* Macros for 64-bit ops + big/little endian doubles. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
+#endif
+#else /* DUK_USE_64BIT_OPS */
+/* Macros for no 64-bit ops, any endianness. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
+ (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
+ (u)->ui[DUK_DBL_IDX_UI1] != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#endif /* DUK_USE_64BIT_OPS */
+
+#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
+ (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
+ } while (0)
+
+#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
+ /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
+ ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
+ (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
+
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
+ /* E == 0x7ff, F == 8 => normalized NaN */ \
+ ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
+
+#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
+ if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
+ DUK__DBLUNION_SET_NAN_FULL((u)); \
+ } \
+ } while (0)
+
+#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
+ if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
+ DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
+ } \
+ } while (0)
+
+/* Concrete macros for NaN handling used by the implementation internals.
+ * Chosen so that they match the duk_tval representation: with a packed
+ * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
+ * these are essentially NOPs.
+ */
+
+#if defined(DUK_USE_PACKED_TVAL)
+#if defined(DUK_USE_FULL_TVAL)
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
+#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
+#else
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
+#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
+#endif
+#define DUK_DBLUNION_IS_NORMALIZED(u) \
+ (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
+ DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
+#else /* DUK_USE_PACKED_TVAL */
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
+#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
+#define DUK_DBLUNION_SET_NAN(u) do { \
+ /* in non-packed representation we don't care about which NaN is used */ \
+ (u)->d = DUK_DOUBLE_NAN; \
+ } while (0)
+#endif /* DUK_USE_PACKED_TVAL */
+
+#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
+#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
+#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
+
+#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
+#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
+#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
+
+/* XXX: native 64-bit byteswaps when available */
+
+/* 64-bit byteswap, same operation independent of target endianness. */
+#define DUK_DBLUNION_BSWAP64(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp2; \
+ (u)->ui[1] = duk__bswaptmp1; \
+ } while (0)
+
+/* Byteswap an IEEE double in the duk_double_union from host to network
+ * order. For a big endian target this is a no-op.
+ */
+#if defined(DUK_USE_DOUBLE_LE)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp2; \
+ (u)->ui[1] = duk__bswaptmp1; \
+ } while (0)
+#elif defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp1; \
+ (u)->ui[1] = duk__bswaptmp2; \
+ } while (0)
+#elif defined(DUK_USE_DOUBLE_BE)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
+#else
+#error internal error, double endianness insane
+#endif
+
+/* Reverse operation is the same. */
+#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
+
+/* Some sign bit helpers. */
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
+#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
+#else
+#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
+#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
+#endif
+
+#endif /* DUK_DBLUNION_H_INCLUDED */
+/* #include duk_replacements.h */
+#if !defined(DUK_REPLACEMENTS_H_INCLUDED)
#define DUK_REPLACEMENTS_H_INCLUDED
#if !defined(DUK_SINGLE_FILE)
@@ -170,6 +619,8 @@ DUK_INTERNAL_DECL double duk_computed_infinity;
#if defined(DUK_USE_COMPUTED_NAN)
DUK_INTERNAL_DECL double duk_computed_nan;
#endif
+#endif /* !DUK_SINGLE_FILE */
+
#if defined(DUK_USE_REPL_FPCLASSIFY)
DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
#endif
@@ -185,10 +636,9 @@ DUK_INTERNAL_DECL int duk_repl_isnan(double x);
#if defined(DUK_USE_REPL_ISINF)
DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#endif
-#endif /* !DUK_SINGLE_FILE */
#endif /* DUK_REPLACEMENTS_H_INCLUDED */
-#line 1 "duk_jmpbuf.h"
+/* #include duk_jmpbuf.h */
/*
* Wrapper for jmp_buf.
*
@@ -199,7 +649,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x);
* http://en.wikipedia.org/wiki/Setjmp.h#Member_types
*/
-#ifndef DUK_JMPBUF_H_INCLUDED
+#if !defined(DUK_JMPBUF_H_INCLUDED)
#define DUK_JMPBUF_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
@@ -213,7 +663,7 @@ struct duk_jmpbuf {
#endif
#endif /* DUK_JMPBUF_H_INCLUDED */
-#line 1 "duk_exception.h"
+/* #include duk_exception.h */
/*
* Exception for Duktape internal throws when C++ exceptions are used
* for long control transfers.
@@ -222,7 +672,7 @@ struct duk_jmpbuf {
* that user code would accidentally catch this exception.
*/
-#ifndef DUK_EXCEPTION_H_INCLUDED
+#if !defined(DUK_EXCEPTION_H_INCLUDED)
#define DUK_EXCEPTION_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
@@ -232,12 +682,12 @@ class duk_internal_exception {
#endif
#endif /* DUK_EXCEPTION_H_INCLUDED */
-#line 1 "duk_forwdecl.h"
+/* #include duk_forwdecl.h */
/*
* Forward declarations for all Duktape structures.
*/
-#ifndef DUK_FORWDECL_H_INCLUDED
+#if !defined(DUK_FORWDECL_H_INCLUDED)
#define DUK_FORWDECL_H_INCLUDED
/*
@@ -253,13 +703,18 @@ struct duk_jmpbuf;
/* duk_tval intentionally skipped */
struct duk_heaphdr;
struct duk_heaphdr_string;
+struct duk_harray;
struct duk_hstring;
struct duk_hstring_external;
struct duk_hobject;
-struct duk_hcompiledfunction;
-struct duk_hnativefunction;
+struct duk_hcompfunc;
+struct duk_hnatfunc;
+struct duk_hboundfunc;
struct duk_hthread;
-struct duk_hbufferobject;
+struct duk_hbufobj;
+struct duk_hdecenv;
+struct duk_hobjenv;
+struct duk_hproxy;
struct duk_hbuffer;
struct duk_hbuffer_fixed;
struct duk_hbuffer_dynamic;
@@ -278,7 +733,7 @@ struct duk_strcache;
struct duk_ljstate;
struct duk_strtab_entry;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer;
#endif
@@ -308,13 +763,18 @@ typedef struct duk_jmpbuf duk_jmpbuf;
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
typedef struct duk_heaphdr_string duk_heaphdr_string;
+typedef struct duk_harray duk_harray;
typedef struct duk_hstring duk_hstring;
typedef struct duk_hstring_external duk_hstring_external;
typedef struct duk_hobject duk_hobject;
-typedef struct duk_hcompiledfunction duk_hcompiledfunction;
-typedef struct duk_hnativefunction duk_hnativefunction;
-typedef struct duk_hbufferobject duk_hbufferobject;
+typedef struct duk_hcompfunc duk_hcompfunc;
+typedef struct duk_hnatfunc duk_hnatfunc;
+typedef struct duk_hboundfunc duk_hboundfunc;
typedef struct duk_hthread duk_hthread;
+typedef struct duk_hbufobj duk_hbufobj;
+typedef struct duk_hdecenv duk_hdecenv;
+typedef struct duk_hobjenv duk_hobjenv;
+typedef struct duk_hproxy duk_hproxy;
typedef struct duk_hbuffer duk_hbuffer;
typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
@@ -333,7 +793,7 @@ typedef struct duk_strcache duk_strcache;
typedef struct duk_ljstate duk_ljstate;
typedef struct duk_strtab_entry duk_strtab_entry;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
typedef struct duk_fixedbuffer duk_fixedbuffer;
#endif
@@ -355,7 +815,7 @@ typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
#endif /* DUK_FORWDECL_H_INCLUDED */
-#line 1 "duk_tval.h"
+/* #include duk_tval.h */
/*
* Tagged type definition (duk_tval) and accessor macros.
*
@@ -368,15 +828,13 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
* 64-bit environments (it usually pads to 16 bytes per value).
*
* Selecting the tagged type format involves many trade-offs (memory
- * use, size and performance of generated code, portability, etc),
- * see doc/types.rst for a detailed discussion (especially of how the
- * IEEE double format is used to pack tagged values).
+ * use, size and performance of generated code, portability, etc).
*
* NB: because macro arguments are often expressions, macros should
* avoid evaluating their argument more than once.
*/
-#ifndef DUK_TVAL_H_INCLUDED
+#if !defined(DUK_TVAL_H_INCLUDED)
#define DUK_TVAL_H_INCLUDED
/* sanity */
@@ -393,10 +851,17 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
/* use duk_double_union as duk_tval directly */
typedef union duk_double_union duk_tval;
+typedef struct {
+ duk_uint16_t a;
+ duk_uint16_t b;
+ duk_uint16_t c;
+ duk_uint16_t d;
+} duk_tval_unused;
/* tags */
#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
/* avoid tag 0xfff0, no risk of confusion with negative infinity */
+#define DUK_TAG_MIN 0xfff1UL
#if defined(DUK_USE_FASTINT)
#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
#endif
@@ -410,195 +875,226 @@ typedef union duk_double_union duk_tval;
#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
+#define DUK_TAG_MAX 0xfffaUL
/* for convenience */
#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
+#define DUK_TVAL_IS_VALID_TAG(tv) \
+ (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
+
+/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */
+#define DUK_TVAL_UNUSED_INITIALIZER() \
+ { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED }
+
/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
} while (0)
#else
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
} while (0)
#endif
#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
} while (0)
#endif /* DUK_USE_64BIT_OPS */
#if defined(DUK_USE_64BIT_OPS)
/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
- ((duk_uint64_t) (flags)) | \
- (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
+ ((duk_uint64_t) (flags)) | \
+ (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
} while (0)
#else
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
- (((duk_uint64_t) (flags)) << 32) | \
- ((duk_uint64_t) (duk_uint32_t) (fp)); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
+ (((duk_uint64_t) (flags)) << 32) | \
+ ((duk_uint64_t) (duk_uint32_t) (fp)); \
} while (0)
#endif
#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
} while (0)
#endif /* DUK_USE_64BIT_OPS */
#if defined(DUK_USE_FASTINT)
/* Note: masking is done for 'i' to deal with negative numbers correctly */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
+#define DUK__TVAL_SET_I48(tv,i) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
} while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
+#define DUK__TVAL_SET_U32(tv,i) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
} while (0)
#else
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
+#define DUK__TVAL_SET_I48(tv,i) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \
} while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
+#define DUK__TVAL_SET_U32(tv,i) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
} while (0)
#endif
-#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
+/* This needs to go through a cast because sign extension is needed. */
+#define DUK__TVAL_SET_I32(tv,i) do { \
duk_int64_t duk__tmp = (duk_int64_t) (i); \
- DUK_TVAL_SET_FASTINT((v), duk__tmp); \
+ DUK_TVAL_SET_I48((tv), duk__tmp); \
} while (0)
-/* XXX: clumsy sign extend and masking of 16 topmost bits */
+/* XXX: Clumsy sign extend and masking of 16 topmost bits. */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
+#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
#else
-#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
+#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
#endif
-#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
-#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
+#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1])
+#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1])
#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_SET_UNDEFINED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
+#define DUK_TVAL_SET_UNDEFINED(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
} while (0)
-#define DUK_TVAL_SET_UNUSED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
+#define DUK_TVAL_SET_UNUSED(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
} while (0)
-#define DUK_TVAL_SET_NULL(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
+#define DUK_TVAL_SET_NULL(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
} while (0)
-#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
+#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
-#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
+#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv))
/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
+#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
duk_double_t duk__dblval; \
duk__dblval = (d); \
DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
+ DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
} while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
+#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i))
+#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i))
+#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d))
+#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
duk_tval *duk__tv; \
duk_double_t duk__d; \
- duk__tv = (v); \
+ duk__tv = (tv); \
if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
} \
} while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
+ duk_tval *duk__tv; \
+ duk_double_t duk__d; \
+ duk__tv = (tv); \
+ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
+ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
+ } \
+ } while (0)
+#else /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
duk_double_t duk__dblval; \
duk__dblval = (d); \
DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
+ DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
} while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
-#endif
+#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */
+#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
+#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
+#endif /* DUK_USE_FASTINT */
+
+#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */
-#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
-#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
-#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
-#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
-#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
+#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags))
+#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING)
+#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT)
+#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER)
+#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER)
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
+#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1])
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
-#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
-#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
-#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
-#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
+#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
+#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv))
+#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv))
+#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv))
+#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv))
#else
-#define DUK_TVAL_GET_NUMBER(v) ((v)->d)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
+#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d)
+#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
#endif
-#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
- (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
- (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
+#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
+ (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
+ (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
} while (0)
-#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
-#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
+#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1])
/* decoding */
-#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
-
-#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
-#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
-#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
-#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
-#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
-#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
-#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
-#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
-#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
-#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
-#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
+#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0])
+
+#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED)
+#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED)
+#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL)
+#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN)
+#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
+#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
+#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC)
+#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING)
+#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT)
+#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER)
+#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER)
#if defined(DUK_USE_FASTINT)
/* 0xfff0 is -Infinity */
-#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
+#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
+#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT)
+#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL)
#else
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
+#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
+#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
#endif
/* This is performance critical because it appears in every DECREF. */
-#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
+#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING)
#if defined(DUK_USE_FASTINT)
DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
@@ -633,8 +1129,8 @@ struct duk_tval_struct {
void *voidptr;
duk_hstring *hstring;
duk_hobject *hobject;
- duk_hcompiledfunction *hcompiledfunction;
- duk_hnativefunction *hnativefunction;
+ duk_hcompfunc *hcompfunc;
+ duk_hnatfunc *hnatfunc;
duk_hthread *hthread;
duk_hbuffer *hbuffer;
duk_heaphdr *heaphdr;
@@ -642,7 +1138,22 @@ struct duk_tval_struct {
} v;
};
-#define DUK__TAG_NUMBER 0 /* not exposed */
+typedef struct {
+ duk_small_uint_t t;
+ duk_small_uint_t v_extra;
+ /* The rest of the fields don't matter except for debug dumps and such
+ * for which a partial initializer may trigger out-ot-bounds memory
+ * reads. Include a double field which is usually as large or larger
+ * than pointers (not always however).
+ */
+ duk_double_t d;
+} duk_tval_unused;
+
+#define DUK_TVAL_UNUSED_INITIALIZER() \
+ { DUK_TAG_UNUSED, 0, 0.0 }
+
+#define DUK_TAG_MIN 0
+#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */
#if defined(DUK_USE_FASTINT)
#define DUK_TAG_FASTINT 1
#endif
@@ -655,8 +1166,12 @@ struct duk_tval_struct {
#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
#define DUK_TAG_OBJECT 9
#define DUK_TAG_BUFFER 10
+#define DUK_TAG_MAX 10
+
+#define DUK_TVAL_IS_VALID_TAG(tv) \
+ (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
-/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
+/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code
* to support the 8-byte representation. Further, it is a non-heap-allocated
* type so it should come before DUK_TAG_STRING. Finally, it should not break
* the tag value ranges covered by case-clauses in a switch-case.
@@ -664,106 +1179,159 @@ struct duk_tval_struct {
/* setters */
#define DUK_TVAL_SET_UNDEFINED(tv) do { \
- (tv)->t = DUK_TAG_UNDEFINED; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_UNDEFINED; \
} while (0)
#define DUK_TVAL_SET_UNUSED(tv) do { \
- (tv)->t = DUK_TAG_UNUSED; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_UNUSED; \
} while (0)
#define DUK_TVAL_SET_NULL(tv) do { \
- (tv)->t = DUK_TAG_NULL; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NULL; \
} while (0)
#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
- (tv)->t = DUK_TAG_BOOLEAN; \
- (tv)->v.i = (val); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_BOOLEAN; \
+ duk__tv->v.i = (duk_small_int_t) (val); \
} while (0)
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
+ duk_tval *duk__tv; \
+ duk_double_t duk__dblval; \
+ duk__dblval = (val); \
+ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = duk__dblval; \
} while (0)
-#define DUK_TVAL_SET_FASTINT(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (val); \
+#define DUK_TVAL_SET_I48(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (val); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
+#define DUK_TVAL_SET_U32(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (duk_int64_t) (val); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
+#define DUK_TVAL_SET_I32(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (duk_int64_t) (val); \
} while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
- duk_tval_set_number_chkfast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
+ duk_tval_set_number_chkfast_fast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
+ duk_tval_set_number_chkfast_slow((tv), (d))
#define DUK_TVAL_SET_NUMBER(tv,val) \
DUK_TVAL_SET_DOUBLE((tv), (val))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
duk_tval *duk__tv; \
duk_double_t duk__d; \
- duk__tv = (v); \
+ duk__tv = (tv); \
if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
} \
} while (0)
-#else
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
+ duk_tval *duk__tv; \
+ duk_double_t duk__d; \
+ duk__tv = (tv); \
+ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
+ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
+ } \
+ } while (0)
+#else /* DUK_USE_FASTINT */
#define DUK_TVAL_SET_DOUBLE(tv,d) \
DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_SET_FASTINT(tv,val) \
+#define DUK_TVAL_SET_I48(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) \
+#define DUK_TVAL_SET_U32(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) \
+#define DUK_TVAL_SET_I32(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
#define DUK_TVAL_SET_NUMBER(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
+ duk_tval *duk__tv; \
+ duk_double_t duk__dblval; \
+ duk__dblval = (val); \
+ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = duk__dblval; \
} while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
+ DUK_TVAL_SET_NUMBER((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT(tv,i) \
+ DUK_TVAL_SET_I48((tv), (i)) /* alias */
+
#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
- (tv)->t = DUK_TAG_POINTER; \
- (tv)->v.voidptr = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_POINTER; \
+ duk__tv->v.voidptr = (hptr); \
} while (0)
#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
- (tv)->t = DUK_TAG_LIGHTFUNC; \
- (tv)->v_extra = (flags); \
- (tv)->v.lightfunc = (duk_c_function) (fp); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_LIGHTFUNC; \
+ duk__tv->v_extra = (flags); \
+ duk__tv->v.lightfunc = (duk_c_function) (fp); \
} while (0)
#define DUK_TVAL_SET_STRING(tv,hptr) do { \
- (tv)->t = DUK_TAG_STRING; \
- (tv)->v.hstring = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_STRING; \
+ duk__tv->v.hstring = (hptr); \
} while (0)
#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
- (tv)->t = DUK_TAG_OBJECT; \
- (tv)->v.hobject = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_OBJECT; \
+ duk__tv->v.hobject = (hptr); \
} while (0)
#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
- (tv)->t = DUK_TAG_BUFFER; \
- (tv)->v.hbuffer = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_BUFFER; \
+ duk__tv->v.hbuffer = (hptr); \
} while (0)
#define DUK_TVAL_SET_NAN(tv) do { \
/* in non-packed representation we don't care about which NaN is used */ \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = DUK_DOUBLE_NAN; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = DUK_DOUBLE_NAN; \
} while (0)
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
+#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i)
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
@@ -790,7 +1358,7 @@ struct duk_tval_struct {
(out_fp) = (tv)->v.lightfunc; \
} while (0)
#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra))
#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
@@ -805,13 +1373,13 @@ struct duk_tval_struct {
#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
+#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER)
#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
+#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \
(tv)->t == DUK_TAG_FASTINT)
#else
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
+#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER)
+#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
#endif /* DUK_USE_FASTINT */
#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
@@ -833,7 +1401,7 @@ struct duk_tval_struct {
#if 0
DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
#endif
-DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
+DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
#endif
#endif /* DUK_USE_PACKED_TVAL */
@@ -842,19 +1410,24 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv
* Convenience (independent of representation)
*/
-#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
-#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
+#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1)
+#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0)
+
+#define DUK_TVAL_STRING_IS_SYMBOL(tv) \
+ DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv)))
/* Lightfunc flags packing and unpacking. */
-/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
+/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##.
+ * Avoid signed shifts due to portability limitations.
+ */
#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
- ((((duk_int32_t) (lf_flags)) << 16) >> 24)
+ ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
- (((lf_flags) >> 4) & 0x0f)
+ (((lf_flags) >> 4) & 0x0fU)
#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
- ((lf_flags) & 0x0f)
+ ((lf_flags) & 0x0fU)
#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
- (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
+ ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs)
#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
#define DUK_LFUNC_NARGS_MIN 0x00
@@ -866,24 +1439,25 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv
/* fastint constants etc */
#if defined(DUK_USE_FASTINT)
-#define DUK_FASTINT_MIN (-0x800000000000LL)
-#define DUK_FASTINT_MAX 0x7fffffffffffLL
+#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000))
+#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff))
#define DUK_FASTINT_BITS 48
-DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x);
+DUK_INTERNAL_DECL DUK_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
+DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
#endif
#endif /* DUK_TVAL_H_INCLUDED */
-#line 1 "duk_builtins.h"
+/* #include duk_builtins.h */
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
-#ifndef DUK_BUILTINS_H_INCLUDED
+#if !defined(DUK_BUILTINS_H_INCLUDED)
#define DUK_BUILTINS_H_INCLUDED
#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
@@ -891,102 +1465,102 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
-#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */
+#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */
+#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
+#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
+#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
-#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */
+#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */
#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
-#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */
+#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */
#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
-#define DUK_STRIDX_ARRAY 5 /* 'Array' */
+#define DUK_STRIDX_ARRAY 6 /* 'Array' */
#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
-#define DUK_STRIDX_UC_STRING 6 /* 'String' */
+#define DUK_STRIDX_UC_STRING 7 /* 'String' */
#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
-#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */
+#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */
#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
-#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */
+#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */
#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
-#define DUK_STRIDX_DATE 9 /* 'Date' */
+#define DUK_STRIDX_DATE 10 /* 'Date' */
#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
-#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */
+#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */
#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
-#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */
+#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */
#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
-#define DUK_STRIDX_MATH 12 /* 'Math' */
+#define DUK_STRIDX_MATH 13 /* 'Math' */
#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
-#define DUK_STRIDX_JSON 13 /* 'JSON' */
+#define DUK_STRIDX_JSON 14 /* 'JSON' */
#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
-#define DUK_STRIDX_EMPTY_STRING 14 /* '' */
+#define DUK_STRIDX_EMPTY_STRING 15 /* '' */
#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
-#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */
+#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */
#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
-#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */
+#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */
#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
-#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */
+#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */
#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
-#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */
+#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */
#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
-#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */
+#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */
#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
-#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */
+#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */
#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
-#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */
+#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */
#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
-#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */
+#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */
#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
-#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */
+#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */
#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
-#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */
+#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */
#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
-#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */
+#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */
#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
-#define DUK_STRIDX_GLOBAL 26 /* 'global' */
+#define DUK_STRIDX_GLOBAL 27 /* 'global' */
#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
-#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */
+#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */
#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
-#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */
+#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */
#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
-#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */
+#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */
#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
-#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */
+#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */
#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
-#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */
+#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */
#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
-#define DUK_STRIDX_EVAL 32 /* 'eval' */
+#define DUK_STRIDX_EVAL 33 /* 'eval' */
#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
-#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */
-#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
-#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
#define DUK_STRIDX_VALUE 34 /* 'value' */
#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
@@ -1029,9 +1603,9 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
-#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */
-#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
-#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
+#define DUK_STRIDX_FLAGS 48 /* 'flags' */
+#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
+#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
#define DUK_STRIDX_INDEX 49 /* 'index' */
#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
@@ -1053,30 +1627,30 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_LC_STRING 55 /* 'string' */
#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
-#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */
+#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */
+#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
+#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
+#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */
#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
-#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */
+#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */
#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
-#define DUK_STRIDX_NAN 58 /* 'NaN' */
+#define DUK_STRIDX_NAN 59 /* 'NaN' */
#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
-#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */
+#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */
#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
-#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */
+#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */
#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
-#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */
+#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */
#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
-#define DUK_STRIDX_COMMA 62 /* ',' */
+#define DUK_STRIDX_COMMA 63 /* ',' */
#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
-#define DUK_STRIDX_SPACE 63 /* ' ' */
-#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
-#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
@@ -1095,388 +1669,301 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_CALLER 69 /* 'caller' */
#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
-#define DUK_STRIDX_HAS 70 /* 'has' */
-#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
-#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
-#define DUK_STRIDX_GET 71 /* 'get' */
-#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
-#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
+#define DUK_STRIDX_APPLY 70 /* 'apply' */
+#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
+#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
+#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */
+#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
+#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
-#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */
-#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE)
-#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE)
-#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */
+#define DUK_STRIDX_GET 73 /* 'get' */
+#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
+#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
+#define DUK_STRIDX_HAS 74 /* 'has' */
+#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
+#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
+#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
-#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */
+#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */
#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */
+#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */
#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
-#define DUK_STRIDX_REQUIRE 77 /* 'require' */
-#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE)
-#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE)
-#define DUK_STRIDX_ID 78 /* 'id' */
-#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID)
-#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID)
-#define DUK_STRIDX_EXPORTS 79 /* 'exports' */
-#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS)
-#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS)
-#define DUK_STRIDX_FILENAME 80 /* 'filename' */
-#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME)
-#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME)
-#define DUK_STRIDX_TO_STRING 81 /* 'toString' */
+#define DUK_STRIDX_TO_STRING 78 /* 'toString' */
#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
-#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */
+#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */
#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
-#define DUK_STRIDX_TYPE 83 /* 'type' */
+#define DUK_STRIDX_TYPE 80 /* 'type' */
#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
-#define DUK_STRIDX_DATA 84 /* 'data' */
+#define DUK_STRIDX_DATA 81 /* 'data' */
#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
-#define DUK_STRIDX_LENGTH 85 /* 'length' */
+#define DUK_STRIDX_LENGTH 82 /* 'length' */
#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
-#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */
-#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */
-#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */
-#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_STRIDX_SET 89 /* 'set' */
+#define DUK_STRIDX_SET 83 /* 'set' */
#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
-#define DUK_STRIDX_STACK 90 /* 'stack' */
+#define DUK_STRIDX_STACK 84 /* 'stack' */
#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
-#define DUK_STRIDX_PC 91 /* 'pc' */
+#define DUK_STRIDX_PC 85 /* 'pc' */
#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
-#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */
+#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */
#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
-#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */
+#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */
#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_STRIDX_NAME 94 /* 'name' */
+#define DUK_STRIDX_NAME 88 /* 'name' */
#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
-#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */
+#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */
#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
-#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */
-#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
-#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
-#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */
+#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */
#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
-#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */
-#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
-#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
-#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */
+#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */
+#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
+#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
+#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */
#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
-#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */
+#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */
#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
-#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */
+#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */
#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
-#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */
+#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */
#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
-#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */
-#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
-#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
-#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */
-#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
-#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
-#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */
+#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */
#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
-#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */
+#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */
#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
-#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */
-#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
-#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
-#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */
+#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */
#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
-#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */
+#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */
+#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
+#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
+#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */
#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
-#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */
-#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
-#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
-#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */
-#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
-#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
-#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */
-#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
-#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
-#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */
-#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
-#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
-#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */
-#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
-#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
-#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */
-#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
-#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
-#define DUK_STRIDX_COMPILE 116 /* 'compile' */
+#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */
+#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
+#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
+#define DUK_STRIDX_COMPILE 102 /* 'compile' */
#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
-#define DUK_STRIDX_INPUT 117 /* 'input' */
+#define DUK_STRIDX_INPUT 103 /* 'input' */
#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
-#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */
+#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */
#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
-#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */
+#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */
#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
-#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */
-#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH)
-#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH)
-#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */
-#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED)
-#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED)
-#define DUK_STRIDX_ENV 122 /* 'env' */
+#define DUK_STRIDX_ENV 106 /* 'env' */
#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
-#define DUK_STRIDX_HEX 123 /* 'hex' */
+#define DUK_STRIDX_HEX 107 /* 'hex' */
#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
-#define DUK_STRIDX_BASE64 124 /* 'base64' */
+#define DUK_STRIDX_BASE64 108 /* 'base64' */
#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
-#define DUK_STRIDX_JX 125 /* 'jx' */
+#define DUK_STRIDX_JX 109 /* 'jx' */
#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
-#define DUK_STRIDX_JC 126 /* 'jc' */
+#define DUK_STRIDX_JC 110 /* 'jc' */
#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
-#define DUK_STRIDX_RESUME 127 /* 'resume' */
-#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
-#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
-#define DUK_STRIDX_FMT 128 /* 'fmt' */
-#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
-#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
-#define DUK_STRIDX_RAW 129 /* 'raw' */
-#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
-#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
-#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */
-#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
-#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
-#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */
-#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
-#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
-#define DUK_STRIDX_LC_INFO 132 /* 'info' */
-#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
-#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
-#define DUK_STRIDX_LC_WARN 133 /* 'warn' */
-#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
-#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
-#define DUK_STRIDX_LC_ERROR 134 /* 'error' */
-#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
-#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
-#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */
-#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
-#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
-#define DUK_STRIDX_LC_N 136 /* 'n' */
-#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
-#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
-#define DUK_STRIDX_LC_L 137 /* 'l' */
-#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
-#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
-#define DUK_STRIDX_CLOG 138 /* 'clog' */
-#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
-#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
-#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */
-#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */
+#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */
+#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */
+#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */
+#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_STRIDX_BREAK 146 /* 'break' */
+#define DUK_STRIDX_BREAK 117 /* 'break' */
#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
-#define DUK_STRIDX_CASE 147 /* 'case' */
+#define DUK_STRIDX_CASE 118 /* 'case' */
#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
-#define DUK_STRIDX_CATCH 148 /* 'catch' */
+#define DUK_STRIDX_CATCH 119 /* 'catch' */
#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
-#define DUK_STRIDX_CONTINUE 149 /* 'continue' */
+#define DUK_STRIDX_CONTINUE 120 /* 'continue' */
#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
-#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */
+#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */
#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
-#define DUK_STRIDX_DEFAULT 151 /* 'default' */
+#define DUK_STRIDX_DEFAULT 122 /* 'default' */
#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
-#define DUK_STRIDX_DELETE 152 /* 'delete' */
+#define DUK_STRIDX_DELETE 123 /* 'delete' */
#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
-#define DUK_STRIDX_DO 153 /* 'do' */
+#define DUK_STRIDX_DO 124 /* 'do' */
#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
-#define DUK_STRIDX_ELSE 154 /* 'else' */
+#define DUK_STRIDX_ELSE 125 /* 'else' */
#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
-#define DUK_STRIDX_FINALLY 155 /* 'finally' */
+#define DUK_STRIDX_FINALLY 126 /* 'finally' */
#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
-#define DUK_STRIDX_FOR 156 /* 'for' */
+#define DUK_STRIDX_FOR 127 /* 'for' */
#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
-#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */
+#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */
#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
-#define DUK_STRIDX_IF 158 /* 'if' */
+#define DUK_STRIDX_IF 129 /* 'if' */
#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
-#define DUK_STRIDX_IN 159 /* 'in' */
+#define DUK_STRIDX_IN 130 /* 'in' */
#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
-#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */
+#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */
#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
-#define DUK_STRIDX_NEW 161 /* 'new' */
+#define DUK_STRIDX_NEW 132 /* 'new' */
#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
-#define DUK_STRIDX_RETURN 162 /* 'return' */
+#define DUK_STRIDX_RETURN 133 /* 'return' */
#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
-#define DUK_STRIDX_SWITCH 163 /* 'switch' */
+#define DUK_STRIDX_SWITCH 134 /* 'switch' */
#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
-#define DUK_STRIDX_THIS 164 /* 'this' */
+#define DUK_STRIDX_THIS 135 /* 'this' */
#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
-#define DUK_STRIDX_THROW 165 /* 'throw' */
+#define DUK_STRIDX_THROW 136 /* 'throw' */
#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
-#define DUK_STRIDX_TRY 166 /* 'try' */
+#define DUK_STRIDX_TRY 137 /* 'try' */
#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
-#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */
+#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */
#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
-#define DUK_STRIDX_VAR 168 /* 'var' */
+#define DUK_STRIDX_VAR 139 /* 'var' */
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
-#define DUK_STRIDX_CONST 169 /* 'const' */
+#define DUK_STRIDX_CONST 140 /* 'const' */
#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
-#define DUK_STRIDX_VOID 170 /* 'void' */
+#define DUK_STRIDX_VOID 141 /* 'void' */
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
-#define DUK_STRIDX_WHILE 171 /* 'while' */
+#define DUK_STRIDX_WHILE 142 /* 'while' */
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
-#define DUK_STRIDX_WITH 172 /* 'with' */
+#define DUK_STRIDX_WITH 143 /* 'with' */
#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
-#define DUK_STRIDX_CLASS 173 /* 'class' */
+#define DUK_STRIDX_CLASS 144 /* 'class' */
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_STRIDX_ENUM 174 /* 'enum' */
+#define DUK_STRIDX_ENUM 145 /* 'enum' */
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
-#define DUK_STRIDX_EXPORT 175 /* 'export' */
+#define DUK_STRIDX_EXPORT 146 /* 'export' */
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
-#define DUK_STRIDX_EXTENDS 176 /* 'extends' */
+#define DUK_STRIDX_EXTENDS 147 /* 'extends' */
#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
-#define DUK_STRIDX_IMPORT 177 /* 'import' */
+#define DUK_STRIDX_IMPORT 148 /* 'import' */
#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
-#define DUK_STRIDX_SUPER 178 /* 'super' */
+#define DUK_STRIDX_SUPER 149 /* 'super' */
#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
-#define DUK_STRIDX_LC_NULL 179 /* 'null' */
+#define DUK_STRIDX_LC_NULL 150 /* 'null' */
#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
-#define DUK_STRIDX_TRUE 180 /* 'true' */
+#define DUK_STRIDX_TRUE 151 /* 'true' */
#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
-#define DUK_STRIDX_FALSE 181 /* 'false' */
+#define DUK_STRIDX_FALSE 152 /* 'false' */
#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
-#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */
+#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */
#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
-#define DUK_STRIDX_INTERFACE 183 /* 'interface' */
+#define DUK_STRIDX_INTERFACE 154 /* 'interface' */
#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
-#define DUK_STRIDX_LET 184 /* 'let' */
+#define DUK_STRIDX_LET 155 /* 'let' */
#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
-#define DUK_STRIDX_PACKAGE 185 /* 'package' */
+#define DUK_STRIDX_PACKAGE 156 /* 'package' */
#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
-#define DUK_STRIDX_PRIVATE 186 /* 'private' */
+#define DUK_STRIDX_PRIVATE 157 /* 'private' */
#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
-#define DUK_STRIDX_PROTECTED 187 /* 'protected' */
+#define DUK_STRIDX_PROTECTED 158 /* 'protected' */
#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
-#define DUK_STRIDX_PUBLIC 188 /* 'public' */
+#define DUK_STRIDX_PUBLIC 159 /* 'public' */
#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
-#define DUK_STRIDX_STATIC 189 /* 'static' */
+#define DUK_STRIDX_STATIC 160 /* 'static' */
#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
-#define DUK_STRIDX_YIELD 190 /* 'yield' */
+#define DUK_STRIDX_YIELD 161 /* 'yield' */
#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
-#define DUK_HEAP_NUM_STRINGS 191
-#define DUK_STRIDX_START_RESERVED 146
-#define DUK_STRIDX_START_STRICT_RESERVED 182
-#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */
+#define DUK_HEAP_NUM_STRINGS 162
+#define DUK_STRIDX_START_RESERVED 117
+#define DUK_STRIDX_START_STRICT_RESERVED 153
+#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */
/* To convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049];
+DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892];
#endif /* !DUK_SINGLE_FILE */
#define DUK_STRDATA_MAX_STRLEN 17
-#define DUK_STRDATA_DATA_LENGTH 1049
+#define DUK_STRDATA_DATA_LENGTH 892
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else
+#error RAM support not enabled, rerun configure.py with --ram-support
+#else /* DUK_USE_ROM_OBJECTS */
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
@@ -1488,15 +1975,15 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
@@ -1508,12 +1995,11 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
@@ -1521,16 +2007,21 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_con
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
@@ -1547,6 +2038,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *c
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
@@ -1561,6 +2053,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
@@ -1581,7 +2076,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
@@ -1591,9 +2088,13 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
@@ -1606,16 +2107,23 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
@@ -1626,122 +2134,111 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-#endif /* !DUK_SINGLE_FILE */
-#if defined(DUK_USE_BUILTIN_INITJS)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 204
-#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
#define DUK_BIDX_OBJECT_PROTOTYPE 3
#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
#define DUK_BIDX_FUNCTION_PROTOTYPE 5
-#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
-#define DUK_BIDX_ARRAY_PROTOTYPE 7
-#define DUK_BIDX_STRING_CONSTRUCTOR 8
-#define DUK_BIDX_STRING_PROTOTYPE 9
-#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
-#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
-#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
-#define DUK_BIDX_NUMBER_PROTOTYPE 13
-#define DUK_BIDX_DATE_CONSTRUCTOR 14
-#define DUK_BIDX_DATE_PROTOTYPE 15
-#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
-#define DUK_BIDX_REGEXP_PROTOTYPE 17
-#define DUK_BIDX_ERROR_CONSTRUCTOR 18
-#define DUK_BIDX_ERROR_PROTOTYPE 19
-#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
-#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
-#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
-#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
-#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
-#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
-#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
-#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
-#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
-#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
-#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
-#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
-#define DUK_BIDX_MATH 32
-#define DUK_BIDX_JSON 33
-#define DUK_BIDX_TYPE_ERROR_THROWER 34
-#define DUK_BIDX_PROXY_CONSTRUCTOR 35
-#define DUK_BIDX_DUKTAPE 36
-#define DUK_BIDX_THREAD_CONSTRUCTOR 37
-#define DUK_BIDX_THREAD_PROTOTYPE 38
-#define DUK_BIDX_BUFFER_CONSTRUCTOR 39
-#define DUK_BIDX_BUFFER_PROTOTYPE 40
-#define DUK_BIDX_POINTER_CONSTRUCTOR 41
-#define DUK_BIDX_POINTER_PROTOTYPE 42
-#define DUK_BIDX_LOGGER_CONSTRUCTOR 43
-#define DUK_BIDX_LOGGER_PROTOTYPE 44
-#define DUK_BIDX_DOUBLE_ERROR 45
-#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46
-#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47
-#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48
-#define DUK_BIDX_DATAVIEW_PROTOTYPE 49
-#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50
-#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51
-#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52
-#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53
-#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54
-#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55
-#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56
-#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57
-#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58
-#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59
-#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60
-#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61
-#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62
-#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63
-#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64
-#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65
-#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66
-#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67
-#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68
-#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69
-#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70
-#define DUK_NUM_BUILTINS 71
-#define DUK_NUM_BIDX_BUILTINS 71
-#define DUK_NUM_ALL_BUILTINS 71
+#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6
+#define DUK_BIDX_ARRAY_CONSTRUCTOR 7
+#define DUK_BIDX_ARRAY_PROTOTYPE 8
+#define DUK_BIDX_STRING_CONSTRUCTOR 9
+#define DUK_BIDX_STRING_PROTOTYPE 10
+#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11
+#define DUK_BIDX_BOOLEAN_PROTOTYPE 12
+#define DUK_BIDX_NUMBER_CONSTRUCTOR 13
+#define DUK_BIDX_NUMBER_PROTOTYPE 14
+#define DUK_BIDX_DATE_CONSTRUCTOR 15
+#define DUK_BIDX_DATE_PROTOTYPE 16
+#define DUK_BIDX_REGEXP_CONSTRUCTOR 17
+#define DUK_BIDX_REGEXP_PROTOTYPE 18
+#define DUK_BIDX_ERROR_CONSTRUCTOR 19
+#define DUK_BIDX_ERROR_PROTOTYPE 20
+#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21
+#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22
+#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23
+#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24
+#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25
+#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26
+#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27
+#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28
+#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29
+#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30
+#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31
+#define DUK_BIDX_URI_ERROR_PROTOTYPE 32
+#define DUK_BIDX_TYPE_ERROR_THROWER 33
+#define DUK_BIDX_DUKTAPE 34
+#define DUK_BIDX_THREAD_PROTOTYPE 35
+#define DUK_BIDX_POINTER_PROTOTYPE 36
+#define DUK_BIDX_DOUBLE_ERROR 37
+#define DUK_BIDX_SYMBOL_PROTOTYPE 38
+#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39
+#define DUK_BIDX_DATAVIEW_PROTOTYPE 40
+#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41
+#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42
+#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43
+#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44
+#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45
+#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46
+#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47
+#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48
+#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49
+#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
+#define DUK_NUM_BUILTINS 51
+#define DUK_NUM_BIDX_BUILTINS 51
+#define DUK_NUM_ALL_BUILTINS 76
#if defined(DUK_USE_DOUBLE_LE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_BE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_ME)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */
#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 52 "duk_internal.h"
-#line 1 "duk_util.h"
+/* #include duk_util.h */
/*
* Utilities
*/
-#ifndef DUK_UTIL_H_INCLUDED
+#if !defined(DUK_UTIL_H_INCLUDED)
#define DUK_UTIL_H_INCLUDED
-#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
+#if defined(DUK_USE_GET_RANDOM_DOUBLE)
+#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata)
+#else
+#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr)
+#endif
-#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
+/*
+ * Some useful constants
+ */
+
+#define DUK_DOUBLE_2TO32 4294967296.0
+#define DUK_DOUBLE_2TO31 2147483648.0
+#define DUK_DOUBLE_LOG2E 1.4426950408889634
+#define DUK_DOUBLE_LOG10E 0.4342944819032518
/*
* Endian conversion
@@ -1773,6 +2270,8 @@ struct duk_bitdecoder_ctx {
duk_small_int_t currbits;
};
+#define DUK_BD_BITPACKED_STRING_MAXLEN 256
+
/*
* Bitstream encoder
*/
@@ -1826,10 +2325,10 @@ struct duk_bitencoder_ctx {
/*
* Buffer writer (dynamic buffer only)
*
- * Helper for writing to a dynamic buffer with a concept of a "spare" area
+ * Helper for writing to a dynamic buffer with a concept of a "slack" area
* to reduce resizes. You can ensure there is enough space beforehand and
* then write for a while without further checks, relying on a stable data
- * pointer. Spare handling is automatic so call sites only indicate how
+ * pointer. Slack handling is automatic so call sites only indicate how
* much data they need right now.
*
* There are several ways to write using bufwriter. The best approach
@@ -1855,8 +2354,13 @@ struct duk_bufwriter_ctx {
duk_hbuffer_dynamic *buf;
};
-#define DUK_BW_SPARE_ADD 64
-#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
+#if defined(DUK_USE_PREFER_SIZE)
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */
+#else
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */
+#endif
/* Initialization and finalization (compaction), converting to other types. */
@@ -1871,7 +2375,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
- duk_push_lstring((duk_context *) (thr), \
+ duk_push_lstring((thr), \
(const char *) (bw_ctx)->p_base, \
(duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
} while (0)
@@ -1954,7 +2458,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
-/* Fast write calls which assume you control the spare beforehand.
+/* Fast write calls which assume you control the slack beforehand.
* Multibyte write variants exist and use a temporary write pointer
* because byte writes alias with anything: with a stored pointer
* explicit pointer load/stores get generated (e.g. gcc -Os).
@@ -2017,7 +2521,7 @@ struct duk_bufwriter_ctx {
#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
duk_ucodepoint_t duk__cp; \
duk_small_int_t duk__enc_len; \
- duk__cp = (cp); \
+ duk__cp = (duk_ucodepoint_t) (cp); \
DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
(bw_ctx)->p += duk__enc_len; \
@@ -2211,7 +2715,7 @@ DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
#endif /* !DUK_SINGLE_FILE */
/* Note: assumes that duk_util_probe_steps size is 32 */
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
+#if defined(DUK_USE_HOBJECT_HASH_PART)
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
#endif /* !DUK_SINGLE_FILE */
@@ -2221,19 +2725,20 @@ DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
#endif
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
-DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
-#endif
-
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
-DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
+DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value);
+DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx);
+DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out);
DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
-DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr);
+#endif
DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
@@ -2258,475 +2763,682 @@ DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint
DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
-DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
-#endif
+DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
+#endif
+
+DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
+DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x);
+DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x);
+DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#endif /* DUK_UTIL_H_INCLUDED */
-#line 1 "duk_strings.h"
+/* #include duk_strings.h */
/*
- * Shared error messages: declarations and macros
+ * Shared string macros.
*
- * Error messages are accessed through macros with fine-grained, explicit
- * error message distinctions. Concrete error messages are selected by the
- * macros and multiple macros can map to the same concrete string to save
- * on code footprint. This allows flexible footprint/verbosity tuning with
- * minimal code impact. There are a few limitations to this approach:
- * (1) switching between plain messages and format strings doesn't work
- * conveniently, and (2) conditional strings are a bit awkward to handle.
+ * Using shared macros helps minimize strings data size because it's easy
+ * to check if an existing string could be used. String constants don't
+ * need to be all defined here; defining a string here makes sense if there's
+ * a high chance the string could be reused. Also, using macros allows
+ * a call site express the exact string needed, but the macro may map to an
+ * approximate string to reduce unique string count. Macros can also be
+ * more easily tuned for low memory targets than #if defined()s throughout
+ * the code base.
*
* Because format strings behave differently in the call site (they need to
- * be followed by format arguments), they have a special prefix (DUK_STR_FMT_
- * and duk_str_fmt_).
+ * be followed by format arguments), they use a special prefix DUK_STR_FMT_.
*
* On some compilers using explicit shared strings is preferable; on others
* it may be better to use straight literals because the compiler will combine
* them anyway, and such strings won't end up unnecessarily in a symbol table.
*/
-#ifndef DUK_ERRMSG_H_INCLUDED
+#if !defined(DUK_ERRMSG_H_INCLUDED)
#define DUK_ERRMSG_H_INCLUDED
-#define DUK_STR_INTERNAL_ERROR duk_str_internal_error
-#define DUK_STR_INVALID_COUNT duk_str_invalid_count
-#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args
-#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable
-#define DUK_STR_NOT_CALLABLE duk_str_not_callable
-#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible
-#define DUK_STR_NOT_WRITABLE duk_str_not_writable
-#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_internal_error;
-DUK_INTERNAL_DECL const char *duk_str_invalid_count;
-DUK_INTERNAL_DECL const char *duk_str_invalid_call_args;
-DUK_INTERNAL_DECL const char *duk_str_not_constructable;
-DUK_INTERNAL_DECL const char *duk_str_not_callable;
-DUK_INTERNAL_DECL const char *duk_str_not_extensible;
-DUK_INTERNAL_DECL const char *duk_str_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_not_configurable;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
-#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
-#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
-#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
-#define DUK_STR_NOT_NULL duk_str_unexpected_type
-#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
-#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
-#define DUK_STR_NOT_STRING duk_str_unexpected_type
-#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
-#define DUK_STR_NOT_POINTER duk_str_unexpected_type
-#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
-#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
-#define DUK_STR_NOT_THREAD duk_str_unexpected_type
-#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
-#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
-#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
-#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
-#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long
-#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long
-#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long
-#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed
-#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many
-#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type
-#define DUK_STR_ENCODE_FAILED duk_str_encode_failed
-#define DUK_STR_DECODE_FAILED duk_str_decode_failed
-#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode
-#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long
-#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented
-#define DUK_STR_UNSUPPORTED duk_str_unsupported
-#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_context;
-DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
-DUK_INTERNAL_DECL const char *duk_str_not_buffer;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
-DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
-DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
-DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
-DUK_INTERNAL_DECL const char *duk_str_string_too_long;
-DUK_INTERNAL_DECL const char *duk_str_buffer_too_long;
-DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long;
-DUK_INTERNAL_DECL const char *duk_str_alloc_failed;
-DUK_INTERNAL_DECL const char *duk_str_pop_too_many;
-DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type;
-DUK_INTERNAL_DECL const char *duk_str_encode_failed;
-DUK_INTERNAL_DECL const char *duk_str_decode_failed;
-DUK_INTERNAL_DECL const char *duk_str_no_sourcecode;
-DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long;
-DUK_INTERNAL_DECL const char *duk_str_unimplemented;
-DUK_INTERNAL_DECL const char *duk_str_unsupported;
-DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_FMT_PTR duk_str_fmt_ptr
-#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json
-#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit
-#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit
-#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_fmt_ptr;
-DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json;
-DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_cyclic_input;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked
-#define DUK_STR_INVALID_BASE duk_str_invalid_base
-#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read
-#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected
-#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length
-#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed
-#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable
-#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined
-#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop
-#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor
-#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_proxy_revoked;
-DUK_INTERNAL_DECL const char *duk_str_invalid_base;
-DUK_INTERNAL_DECL const char *duk_str_strict_caller_read;
-DUK_INTERNAL_DECL const char *duk_str_proxy_rejected;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_length;
-DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed;
-DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_setter_undefined;
-DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop;
-DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor;
-DUK_INTERNAL_DECL const char *duk_str_property_is_virtual;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_PARSE_ERROR duk_str_parse_error
-#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label
-#define DUK_STR_INVALID_LABEL duk_str_invalid_label
-#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal
-#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal
-#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration
-#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier
-#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression
-#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue
-#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier
-#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed
-#define DUK_STR_INVALID_FOR duk_str_invalid_for
-#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch
-#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label
-#define DUK_STR_INVALID_RETURN duk_str_invalid_return
-#define DUK_STR_INVALID_TRY duk_str_invalid_try
-#define DUK_STR_INVALID_THROW duk_str_invalid_throw
-#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode
-#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed
-#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt
-#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name
-#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name
-#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name
-#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_parse_error;
-DUK_INTERNAL_DECL const char *duk_str_duplicate_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration;
-DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier;
-DUK_INTERNAL_DECL const char *duk_str_invalid_expression;
-DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue;
-DUK_INTERNAL_DECL const char *duk_str_expected_identifier;
-DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_invalid_for;
-DUK_INTERNAL_DECL const char *duk_str_invalid_switch;
-DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_return;
-DUK_INTERNAL_DECL const char *duk_str_invalid_try;
-DUK_INTERNAL_DECL const char *duk_str_invalid_throw;
-DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode;
-DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt;
-DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_func_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name;
-DUK_INTERNAL_DECL const char *duk_str_func_name_required;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom
-#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values
-#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies
-#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren
-#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern
-#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token
-#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags
-#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs
+/* Mostly API and built-in method related */
+#define DUK_STR_INTERNAL_ERROR "internal error"
+#define DUK_STR_UNSUPPORTED "unsupported"
+#define DUK_STR_INVALID_COUNT "invalid count"
+#define DUK_STR_INVALID_ARGS "invalid args"
+#define DUK_STR_INVALID_STATE "invalid state"
+#define DUK_STR_INVALID_INPUT "invalid input"
+#define DUK_STR_INVALID_LENGTH "invalid length"
+#define DUK_STR_NOT_CONSTRUCTABLE "not constructable"
+#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'"
+#define DUK_STR_NOT_CALLABLE "not callable"
+#define DUK_STR_NOT_EXTENSIBLE "not extensible"
+#define DUK_STR_NOT_WRITABLE "not writable"
+#define DUK_STR_NOT_CONFIGURABLE "not configurable"
+#define DUK_STR_INVALID_CONTEXT "invalid context"
+#define DUK_STR_INVALID_INDEX "invalid args"
+#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack"
+#define DUK_STR_NOT_UNDEFINED "unexpected type"
+#define DUK_STR_NOT_NULL "unexpected type"
+#define DUK_STR_NOT_BOOLEAN "unexpected type"
+#define DUK_STR_NOT_NUMBER "unexpected type"
+#define DUK_STR_NOT_STRING "unexpected type"
+#define DUK_STR_NOT_OBJECT "unexpected type"
+#define DUK_STR_NOT_POINTER "unexpected type"
+#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */
+#define DUK_STR_UNEXPECTED_TYPE "unexpected type"
+#define DUK_STR_NOT_THREAD "unexpected type"
+#define DUK_STR_NOT_COMPFUNC "unexpected type"
+#define DUK_STR_NOT_NATFUNC "unexpected type"
+#define DUK_STR_NOT_C_FUNCTION "unexpected type"
+#define DUK_STR_NOT_FUNCTION "unexpected type"
+#define DUK_STR_NOT_REGEXP "unexpected type"
+#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed"
+#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range"
+#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible"
+#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol"
+#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol"
+#define DUK_STR_STRING_TOO_LONG "string too long"
+#define DUK_STR_BUFFER_TOO_LONG "buffer too long"
+#define DUK_STR_ALLOC_FAILED "alloc failed"
+#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type"
+#define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed"
+#define DUK_STR_SOURCE_DECODE_FAILED "source decode failed"
+#define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed"
+#define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed"
+#define DUK_STR_HEX_DECODE_FAILED "hex decode failed"
+#define DUK_STR_INVALID_BYTECODE "invalid bytecode"
+#define DUK_STR_NO_SOURCECODE "no sourcecode"
+#define DUK_STR_RESULT_TOO_LONG "result too long"
+#define DUK_STR_INVALID_CFUNC_RC "invalid C function rc"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom;
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values;
-DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token;
-DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags;
-DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs;
-#endif /* !DUK_SINGLE_FILE */
+/* JSON */
+#define DUK_STR_FMT_PTR "%p"
+#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)"
+#define DUK_STR_JSONDEC_RECLIMIT "json decode recursion limit"
+#define DUK_STR_JSONENC_RECLIMIT "json encode recursion limit"
+#define DUK_STR_CYCLIC_INPUT "cyclic input"
-#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit
-#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit
-#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit
-#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit
-#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit
-#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit
-#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit
-#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit
-#define DUK_STR_REG_LIMIT duk_str_reg_limit
-#define DUK_STR_TEMP_LIMIT duk_str_temp_limit
-#define DUK_STR_CONST_LIMIT duk_str_const_limit
-#define DUK_STR_FUNC_LIMIT duk_str_func_limit
-#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit
+/* Object property access */
+#define DUK_STR_INVALID_BASE "invalid base value"
+#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'"
+#define DUK_STR_PROXY_REJECTED "proxy rejected"
+#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length"
+#define DUK_STR_SETTER_UNDEFINED "setter undefined"
+#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor"
+
+/* Proxy */
+#define DUK_STR_PROXY_REVOKED "proxy revoked"
+#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result"
+
+/* Variables */
+
+/* Lexer */
+#define DUK_STR_INVALID_ESCAPE "invalid escape"
+#define DUK_STR_UNTERMINATED_STRING "unterminated string"
+#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment"
+#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp"
+#define DUK_STR_TOKEN_LIMIT "token limit"
+#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled"
+#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal"
+#define DUK_STR_INVALID_TOKEN "invalid token"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_valstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_catchstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_bytecode_limit;
-DUK_INTERNAL_DECL const char *duk_str_reg_limit;
-DUK_INTERNAL_DECL const char *duk_str_temp_limit;
-DUK_INTERNAL_DECL const char *duk_str_const_limit;
-DUK_INTERNAL_DECL const char *duk_str_func_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit;
-#endif /* !DUK_SINGLE_FILE */
+/* Compiler */
+#define DUK_STR_PARSE_ERROR "parse error"
+#define DUK_STR_DUPLICATE_LABEL "duplicate label"
+#define DUK_STR_INVALID_LABEL "invalid label"
+#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal"
+#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal"
+#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration"
+#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier"
+#define DUK_STR_INVALID_EXPRESSION "invalid expression"
+#define DUK_STR_INVALID_LVALUE "invalid lvalue"
+#define DUK_STR_INVALID_NEWTARGET "invalid new.target"
+#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier"
+#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed"
+#define DUK_STR_INVALID_FOR "invalid for statement"
+#define DUK_STR_INVALID_SWITCH "invalid switch statement"
+#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label"
+#define DUK_STR_INVALID_RETURN "invalid return"
+#define DUK_STR_INVALID_TRY "invalid try"
+#define DUK_STR_INVALID_THROW "invalid throw"
+#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode"
+#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed"
+#define DUK_STR_UNTERMINATED_STMT "unterminated statement"
+#define DUK_STR_INVALID_ARG_NAME "invalid argument name"
+#define DUK_STR_INVALID_FUNC_NAME "invalid function name"
+#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name"
+#define DUK_STR_FUNC_NAME_REQUIRED "function name required"
+
+/* RegExp */
+#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier"
+#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom"
+#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)"
+#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies"
+#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis"
+#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern"
+#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp"
+#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags"
+#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape"
+#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)"
+#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character"
+#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group"
+#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class"
+#define DUK_STR_INVALID_RANGE "invalid range"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_anon;
-#endif /* !DUK_SINGLE_FILE */
+/* Limits */
+#define DUK_STR_VALSTACK_LIMIT "valstack limit"
+#define DUK_STR_CALLSTACK_LIMIT "callstack limit"
+#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit"
+#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit"
+#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit"
+#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit"
+#define DUK_STR_BYTECODE_LIMIT "bytecode limit"
+#define DUK_STR_REG_LIMIT "register limit"
+#define DUK_STR_TEMP_LIMIT "temp limit"
+#define DUK_STR_CONST_LIMIT "const limit"
+#define DUK_STR_FUNC_LIMIT "function limit"
+#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit"
+#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit"
+#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit"
#endif /* DUK_ERRMSG_H_INCLUDED */
-#line 1 "duk_js_bytecode.h"
+/* #include duk_js_bytecode.h */
/*
* Ecmascript bytecode
*/
-#ifndef DUK_JS_BYTECODE_H_INCLUDED
+#if !defined(DUK_JS_BYTECODE_H_INCLUDED)
#define DUK_JS_BYTECODE_H_INCLUDED
/*
- * Logical instruction layout
- * ==========================
+ * Bytecode instruction layout
+ * ===========================
+ *
+ * Instructions are unsigned 32-bit integers divided as follows:
*
* !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
* !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
- * +---------------------------------------------------+-----------+
- * ! C ! B ! A ! OP !
- * +---------------------------------------------------+-----------+
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !
+ * +-----------------------------------------------+---------------+
*
- * OP (6 bits): opcode (DUK_OP_*), access should be fastest
- * A (8 bits): typically a target register number
- * B (9 bits): typically first source register/constant number
- * C (9 bits): typically second source register/constant number
+ * OP (8 bits): opcode (DUK_OP_*), access should be fastest
+ * consecutive opcodes allocated when opcode needs flags
+ * A (8 bits): typically a target register number
+ * B (8 bits): typically first source register/constant number
+ * C (8 bits): typically second source register/constant number
*
* Some instructions combine BC or ABC together for larger parameter values.
- * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
- * specific bias. B and C may denote a register or a constant, see
- * DUK_BC_ISREG() and DUK_BC_ISCONST().
+ * Signed integers (e.g. jump offsets) are encoded as unsigned, with an
+ * opcode specific bias.
*
- * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
- * the field layout is logically "CBA".
+ * Some opcodes have flags which are handled by allocating consecutive
+ * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A'
+ * field when there's room for the specific opcode.
+ *
+ * For example, if three flags were needed, they could be allocated from
+ * the opcode field as follows:
+ *
+ * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
+ * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !Z!Y!X!
+ * +-----------------------------------------------+---------------+
+ *
+ * Some opcodes accept a reg/const argument which is handled by allocating
+ * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The
+ * following convention is shared by most opcodes, so that the compiler
+ * can handle reg/const flagging without opcode specific code paths:
+ *
+ * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
+ * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !Y!X!
+ * +-----------------------------------------------+---------------+
+ *
+ * X 1=B is const, 0=B is reg
+ * Y 1=C is const, 0=C is reg
+ *
+ * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the
+ * 8-bit opcode space for a single logical opcode. The base opcode
+ * number should be divisible by 4. If the opcode is called 'FOO'
+ * the following opcode constants would be defined:
+ *
+ * DUK_OP_FOO 100 // base opcode number
+ * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg
+ * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg
+ * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const
+ * DUK_OP_FOO_CC 103 // FOO, B=const, C=const
+ *
+ * If only B or C is a reg/const, the unused opcode combinations can be
+ * used for other opcodes (which take no reg/const argument). However,
+ * such opcode values are initially reserved, at least while opcode space
+ * is available. For example, if 'BAR' uses B for a register field and
+ * C is a reg/const:
+ *
+ * DUK_OP_BAR 116 // base opcode number
+ * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg
+ * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed
+ * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const
+ * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed
+ *
+ * Macro naming is a bit misleading, e.g. "ABC" in macro name but the
+ * field layout is concretely "CBA" in the register.
*/
typedef duk_uint32_t duk_instr_t;
-#define DUK_DEC_OP(x) ((x) & 0x3fUL)
-#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL)
-#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL)
-#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL)
-#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL)
-#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL)
+#define DUK_BC_SHIFT_OP 0
+#define DUK_BC_SHIFT_A 8
+#define DUK_BC_SHIFT_B 16
+#define DUK_BC_SHIFT_C 24
+#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B
+#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A
+
+#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_A 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_B 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_C 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL
+#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL
+
+#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP)
+#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A)
+#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B)
+#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C)
+#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC)
+#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC)
+
+#define DUK_DEC_OP(x) ((x) & 0xffUL)
+#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL)
+#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL)
+#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL)
+#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL)
+#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL)
#define DUK_ENC_OP(op) ((duk_instr_t) (op))
#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
- (((duk_instr_t) (abc)) << 6) | \
+ (((duk_instr_t) (abc)) << 8) | \
((duk_instr_t) (op)) \
))
#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
- (((duk_instr_t) (bc)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
+ (((duk_instr_t) (bc)) << 16) | \
+ (((duk_instr_t) (a)) << 8) | \
((duk_instr_t) (op)) \
))
#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
- (((duk_instr_t) (c)) << 23) | \
- (((duk_instr_t) (b)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
+ (((duk_instr_t) (c)) << 24) | \
+ (((duk_instr_t) (b)) << 16) | \
+ (((duk_instr_t) (a)) << 8) | \
((duk_instr_t) (op)) \
))
-#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0)
-#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0)
+#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0)
+#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0)
+#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc))
+
+/* Get opcode base value with B/C reg/const flags cleared. */
+#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc)
/* Constants should be signed so that signed arithmetic involving them
* won't cause values to be coerced accidentally to unsigned.
*/
#define DUK_BC_OP_MIN 0
-#define DUK_BC_OP_MAX 0x3fL
+#define DUK_BC_OP_MAX 0xffL
#define DUK_BC_A_MIN 0
#define DUK_BC_A_MAX 0xffL
#define DUK_BC_B_MIN 0
-#define DUK_BC_B_MAX 0x1ffL
+#define DUK_BC_B_MAX 0xffL
#define DUK_BC_C_MIN 0
-#define DUK_BC_C_MAX 0x1ffL
+#define DUK_BC_C_MAX 0xffL
#define DUK_BC_BC_MIN 0
-#define DUK_BC_BC_MAX 0x3ffffL
+#define DUK_BC_BC_MAX 0xffffL
#define DUK_BC_ABC_MIN 0
-#define DUK_BC_ABC_MAX 0x3ffffffL
-#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN
-#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX
+#define DUK_BC_ABC_MAX 0xffffffL
+/* Masks for B/C reg/const indicator in opcode field. */
+#define DUK_BC_REGCONST_B (0x01UL)
+#define DUK_BC_REGCONST_C (0x02UL)
+
+/* Misc. masks for opcode field. */
+#define DUK_BC_INCDECP_FLAG_DEC (0x04UL)
+#define DUK_BC_INCDECP_FLAG_POST (0x08UL)
+
+/* Opcodes. */
#define DUK_OP_LDREG 0
#define DUK_OP_STREG 1
-#define DUK_OP_LDCONST 2
-#define DUK_OP_LDINT 3
-#define DUK_OP_LDINTX 4
-#define DUK_OP_MPUTOBJ 5
-#define DUK_OP_MPUTOBJI 6
-#define DUK_OP_MPUTARR 7
-#define DUK_OP_MPUTARRI 8
-#define DUK_OP_NEW 9
-#define DUK_OP_NEWI 10
-#define DUK_OP_REGEXP 11
-#define DUK_OP_CSREG 12
-#define DUK_OP_CSREGI 13
-#define DUK_OP_GETVAR 14
-#define DUK_OP_PUTVAR 15
-#define DUK_OP_DECLVAR 16
-#define DUK_OP_DELVAR 17
-#define DUK_OP_CSVAR 18
-#define DUK_OP_CSVARI 19
-#define DUK_OP_CLOSURE 20
-#define DUK_OP_GETPROP 21
-#define DUK_OP_PUTPROP 22
-#define DUK_OP_DELPROP 23
-#define DUK_OP_CSPROP 24
-#define DUK_OP_CSPROPI 25
-#define DUK_OP_ADD 26
-#define DUK_OP_SUB 27
-#define DUK_OP_MUL 28
-#define DUK_OP_DIV 29
-#define DUK_OP_MOD 30
-#define DUK_OP_BAND 31
-#define DUK_OP_BOR 32
-#define DUK_OP_BXOR 33
-#define DUK_OP_BASL 34
-#define DUK_OP_BLSR 35
-#define DUK_OP_BASR 36
-#define DUK_OP_EQ 37
-#define DUK_OP_NEQ 38
-#define DUK_OP_SEQ 39
-#define DUK_OP_SNEQ 40
-#define DUK_OP_GT 41
-#define DUK_OP_GE 42
-#define DUK_OP_LT 43
+#define DUK_OP_JUMP 2
+#define DUK_OP_LDCONST 3
+#define DUK_OP_LDINT 4
+#define DUK_OP_LDINTX 5
+#define DUK_OP_LDTHIS 6
+#define DUK_OP_LDUNDEF 7
+#define DUK_OP_LDNULL 8
+#define DUK_OP_LDTRUE 9
+#define DUK_OP_LDFALSE 10
+#define DUK_OP_GETVAR 11
+#define DUK_OP_BNOT 12
+#define DUK_OP_LNOT 13
+#define DUK_OP_UNM 14
+#define DUK_OP_UNP 15
+#define DUK_OP_EQ 16
+#define DUK_OP_EQ_RR 16
+#define DUK_OP_EQ_CR 17
+#define DUK_OP_EQ_RC 18
+#define DUK_OP_EQ_CC 19
+#define DUK_OP_NEQ 20
+#define DUK_OP_NEQ_RR 20
+#define DUK_OP_NEQ_CR 21
+#define DUK_OP_NEQ_RC 22
+#define DUK_OP_NEQ_CC 23
+#define DUK_OP_SEQ 24
+#define DUK_OP_SEQ_RR 24
+#define DUK_OP_SEQ_CR 25
+#define DUK_OP_SEQ_RC 26
+#define DUK_OP_SEQ_CC 27
+#define DUK_OP_SNEQ 28
+#define DUK_OP_SNEQ_RR 28
+#define DUK_OP_SNEQ_CR 29
+#define DUK_OP_SNEQ_RC 30
+#define DUK_OP_SNEQ_CC 31
+#define DUK_OP_GT 32
+#define DUK_OP_GT_RR 32
+#define DUK_OP_GT_CR 33
+#define DUK_OP_GT_RC 34
+#define DUK_OP_GT_CC 35
+#define DUK_OP_GE 36
+#define DUK_OP_GE_RR 36
+#define DUK_OP_GE_CR 37
+#define DUK_OP_GE_RC 38
+#define DUK_OP_GE_CC 39
+#define DUK_OP_LT 40
+#define DUK_OP_LT_RR 40
+#define DUK_OP_LT_CR 41
+#define DUK_OP_LT_RC 42
+#define DUK_OP_LT_CC 43
#define DUK_OP_LE 44
-#define DUK_OP_IF 45
-#define DUK_OP_JUMP 46
-#define DUK_OP_RETURN 47
-#define DUK_OP_CALL 48
-#define DUK_OP_CALLI 49
-#define DUK_OP_TRYCATCH 50
-#define DUK_OP_EXTRA 51
-#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */
-#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */
-#define DUK_OP_POSTINCR 54
-#define DUK_OP_POSTDECR 55
-#define DUK_OP_PREINCV 56
-#define DUK_OP_PREDECV 57
-#define DUK_OP_POSTINCV 58
-#define DUK_OP_POSTDECV 59
-#define DUK_OP_PREINCP 60
-#define DUK_OP_PREDECP 61
-#define DUK_OP_POSTINCP 62
-#define DUK_OP_POSTDECP 63
-#define DUK_OP_NONE 64 /* dummy value used as marker */
-
-/* DUK_OP_EXTRA, sub-operation in A */
-#define DUK_EXTRAOP_NOP 0
-#define DUK_EXTRAOP_INVALID 1
-#define DUK_EXTRAOP_LDTHIS 2
-#define DUK_EXTRAOP_LDUNDEF 3
-#define DUK_EXTRAOP_LDNULL 4
-#define DUK_EXTRAOP_LDTRUE 5
-#define DUK_EXTRAOP_LDFALSE 6
-#define DUK_EXTRAOP_NEWOBJ 7
-#define DUK_EXTRAOP_NEWARR 8
-#define DUK_EXTRAOP_SETALEN 9
-#define DUK_EXTRAOP_TYPEOF 10
-#define DUK_EXTRAOP_TYPEOFID 11
-#define DUK_EXTRAOP_INITENUM 12
-#define DUK_EXTRAOP_NEXTENUM 13
-#define DUK_EXTRAOP_INITSET 14
-#define DUK_EXTRAOP_INITSETI 15
-#define DUK_EXTRAOP_INITGET 16
-#define DUK_EXTRAOP_INITGETI 17
-#define DUK_EXTRAOP_ENDTRY 18
-#define DUK_EXTRAOP_ENDCATCH 19
-#define DUK_EXTRAOP_ENDFIN 20
-#define DUK_EXTRAOP_THROW 21
-#define DUK_EXTRAOP_INVLHS 22
-#define DUK_EXTRAOP_UNM 23
-#define DUK_EXTRAOP_UNP 24
-#define DUK_EXTRAOP_DEBUGGER 25
-#define DUK_EXTRAOP_BREAK 26
-#define DUK_EXTRAOP_CONTINUE 27
-#define DUK_EXTRAOP_BNOT 28
-#define DUK_EXTRAOP_LNOT 29
-#define DUK_EXTRAOP_INSTOF 30
-#define DUK_EXTRAOP_IN 31
-#define DUK_EXTRAOP_LABEL 32
-#define DUK_EXTRAOP_ENDLABEL 33
-
-/* DUK_OP_CALL flags in A */
-#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0)
-#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1)
-
-/* DUK_OP_TRYCATCH flags in A */
-#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
-#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
-#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
-#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
-
-/* DUK_OP_RETURN flags in A */
-#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0)
-
-/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
-#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
-#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
-
-/* misc constants and helper macros */
-#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */
-#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT)
-#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT)
-#define DUK_BC_LDINT_BIAS (1L << 17)
-#define DUK_BC_LDINTX_SHIFT 18
-#define DUK_BC_JUMP_BIAS (1L << 25)
+#define DUK_OP_LE_RR 44
+#define DUK_OP_LE_CR 45
+#define DUK_OP_LE_RC 46
+#define DUK_OP_LE_CC 47
+#define DUK_OP_IFTRUE 48
+#define DUK_OP_IFTRUE_R 48
+#define DUK_OP_IFTRUE_C 49
+#define DUK_OP_IFFALSE 50
+#define DUK_OP_IFFALSE_R 50
+#define DUK_OP_IFFALSE_C 51
+#define DUK_OP_ADD 52
+#define DUK_OP_ADD_RR 52
+#define DUK_OP_ADD_CR 53
+#define DUK_OP_ADD_RC 54
+#define DUK_OP_ADD_CC 55
+#define DUK_OP_SUB 56
+#define DUK_OP_SUB_RR 56
+#define DUK_OP_SUB_CR 57
+#define DUK_OP_SUB_RC 58
+#define DUK_OP_SUB_CC 59
+#define DUK_OP_MUL 60
+#define DUK_OP_MUL_RR 60
+#define DUK_OP_MUL_CR 61
+#define DUK_OP_MUL_RC 62
+#define DUK_OP_MUL_CC 63
+#define DUK_OP_DIV 64
+#define DUK_OP_DIV_RR 64
+#define DUK_OP_DIV_CR 65
+#define DUK_OP_DIV_RC 66
+#define DUK_OP_DIV_CC 67
+#define DUK_OP_MOD 68
+#define DUK_OP_MOD_RR 68
+#define DUK_OP_MOD_CR 69
+#define DUK_OP_MOD_RC 70
+#define DUK_OP_MOD_CC 71
+#define DUK_OP_EXP 72
+#define DUK_OP_EXP_RR 72
+#define DUK_OP_EXP_CR 73
+#define DUK_OP_EXP_RC 74
+#define DUK_OP_EXP_CC 75
+#define DUK_OP_BAND 76
+#define DUK_OP_BAND_RR 76
+#define DUK_OP_BAND_CR 77
+#define DUK_OP_BAND_RC 78
+#define DUK_OP_BAND_CC 79
+#define DUK_OP_BOR 80
+#define DUK_OP_BOR_RR 80
+#define DUK_OP_BOR_CR 81
+#define DUK_OP_BOR_RC 82
+#define DUK_OP_BOR_CC 83
+#define DUK_OP_BXOR 84
+#define DUK_OP_BXOR_RR 84
+#define DUK_OP_BXOR_CR 85
+#define DUK_OP_BXOR_RC 86
+#define DUK_OP_BXOR_CC 87
+#define DUK_OP_BASL 88
+#define DUK_OP_BASL_RR 88
+#define DUK_OP_BASL_CR 89
+#define DUK_OP_BASL_RC 90
+#define DUK_OP_BASL_CC 91
+#define DUK_OP_BLSR 92
+#define DUK_OP_BLSR_RR 92
+#define DUK_OP_BLSR_CR 93
+#define DUK_OP_BLSR_RC 94
+#define DUK_OP_BLSR_CC 95
+#define DUK_OP_BASR 96
+#define DUK_OP_BASR_RR 96
+#define DUK_OP_BASR_CR 97
+#define DUK_OP_BASR_RC 98
+#define DUK_OP_BASR_CC 99
+#define DUK_OP_INSTOF 100
+#define DUK_OP_INSTOF_RR 100
+#define DUK_OP_INSTOF_CR 101
+#define DUK_OP_INSTOF_RC 102
+#define DUK_OP_INSTOF_CC 103
+#define DUK_OP_IN 104
+#define DUK_OP_IN_RR 104
+#define DUK_OP_IN_CR 105
+#define DUK_OP_IN_RC 106
+#define DUK_OP_IN_CC 107
+#define DUK_OP_GETPROP 108
+#define DUK_OP_GETPROP_RR 108
+#define DUK_OP_GETPROP_CR 109
+#define DUK_OP_GETPROP_RC 110
+#define DUK_OP_GETPROP_CC 111
+#define DUK_OP_PUTPROP 112
+#define DUK_OP_PUTPROP_RR 112
+#define DUK_OP_PUTPROP_CR 113
+#define DUK_OP_PUTPROP_RC 114
+#define DUK_OP_PUTPROP_CC 115
+#define DUK_OP_DELPROP 116
+#define DUK_OP_DELPROP_RR 116
+#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */
+#define DUK_OP_DELPROP_RC 118
+#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */
+#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */
+#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */
+#define DUK_OP_POSTINCR 122
+#define DUK_OP_POSTDECR 123
+#define DUK_OP_PREINCV 124
+#define DUK_OP_PREDECV 125
+#define DUK_OP_POSTINCV 126
+#define DUK_OP_POSTDECV 127
+#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */
+#define DUK_OP_PREINCP_RR 128
+#define DUK_OP_PREINCP_CR 129
+#define DUK_OP_PREINCP_RC 130
+#define DUK_OP_PREINCP_CC 131
+#define DUK_OP_PREDECP 132
+#define DUK_OP_PREDECP_RR 132
+#define DUK_OP_PREDECP_CR 133
+#define DUK_OP_PREDECP_RC 134
+#define DUK_OP_PREDECP_CC 135
+#define DUK_OP_POSTINCP 136
+#define DUK_OP_POSTINCP_RR 136
+#define DUK_OP_POSTINCP_CR 137
+#define DUK_OP_POSTINCP_RC 138
+#define DUK_OP_POSTINCP_CC 139
+#define DUK_OP_POSTDECP 140
+#define DUK_OP_POSTDECP_RR 140
+#define DUK_OP_POSTDECP_CR 141
+#define DUK_OP_POSTDECP_RC 142
+#define DUK_OP_POSTDECP_CC 143
+#define DUK_OP_DECLVAR 144
+#define DUK_OP_DECLVAR_RR 144
+#define DUK_OP_DECLVAR_CR 145
+#define DUK_OP_DECLVAR_RC 146
+#define DUK_OP_DECLVAR_CC 147
+#define DUK_OP_REGEXP 148
+#define DUK_OP_REGEXP_RR 148
+#define DUK_OP_REGEXP_CR 149
+#define DUK_OP_REGEXP_RC 150
+#define DUK_OP_REGEXP_CC 151
+#define DUK_OP_CLOSURE 152
+#define DUK_OP_TYPEOF 153
+#define DUK_OP_TYPEOFID 154
+#define DUK_OP_PUTVAR 155
+#define DUK_OP_DELVAR 156
+#define DUK_OP_RETREG 157
+#define DUK_OP_RETUNDEF 158
+#define DUK_OP_RETCONST 159
+#define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */
+#define DUK_OP_LABEL 161
+#define DUK_OP_ENDLABEL 162
+#define DUK_OP_BREAK 163
+#define DUK_OP_CONTINUE 164
+#define DUK_OP_TRYCATCH 165
+#define DUK_OP_ENDTRY 166
+#define DUK_OP_ENDCATCH 167
+#define DUK_OP_ENDFIN 168
+#define DUK_OP_THROW 169
+#define DUK_OP_INVLHS 170
+#define DUK_OP_CSREG 171
+#define DUK_OP_CSVAR 172
+#define DUK_OP_CSVAR_RR 172
+#define DUK_OP_CSVAR_CR 173
+#define DUK_OP_CSVAR_RC 174
+#define DUK_OP_CSVAR_CC 175
+#define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */
+#define DUK_OP_CALL1 177
+#define DUK_OP_CALL2 178
+#define DUK_OP_CALL3 179
+#define DUK_OP_CALL4 180
+#define DUK_OP_CALL5 181
+#define DUK_OP_CALL6 182
+#define DUK_OP_CALL7 183
+#define DUK_OP_CALL8 184
+#define DUK_OP_CALL9 185
+#define DUK_OP_CALL10 186
+#define DUK_OP_CALL11 187
+#define DUK_OP_CALL12 188
+#define DUK_OP_CALL13 189
+#define DUK_OP_CALL14 190
+#define DUK_OP_CALL15 191
+#define DUK_OP_NEWOBJ 192
+#define DUK_OP_NEWARR 193
+#define DUK_OP_MPUTOBJ 194
+#define DUK_OP_MPUTOBJI 195
+#define DUK_OP_INITSET 196
+#define DUK_OP_INITGET 197
+#define DUK_OP_MPUTARR 198
+#define DUK_OP_MPUTARRI 199
+#define DUK_OP_SETALEN 200
+#define DUK_OP_INITENUM 201
+#define DUK_OP_NEXTENUM 202
+#define DUK_OP_NEWTARGET 203
+#define DUK_OP_DEBUGGER 204
+#define DUK_OP_NOP 205
+#define DUK_OP_INVALID 206
+#define DUK_OP_UNUSED207 207
+#define DUK_OP_GETPROPC 208
+#define DUK_OP_GETPROPC_RR 208
+#define DUK_OP_GETPROPC_CR 209
+#define DUK_OP_GETPROPC_RC 210
+#define DUK_OP_GETPROPC_CC 211
+#define DUK_OP_UNUSED212 212
+#define DUK_OP_UNUSED213 213
+#define DUK_OP_UNUSED214 214
+#define DUK_OP_UNUSED215 215
+#define DUK_OP_UNUSED216 216
+#define DUK_OP_UNUSED217 217
+#define DUK_OP_UNUSED218 218
+#define DUK_OP_UNUSED219 219
+#define DUK_OP_UNUSED220 220
+#define DUK_OP_UNUSED221 221
+#define DUK_OP_UNUSED222 222
+#define DUK_OP_UNUSED223 223
+#define DUK_OP_UNUSED224 224
+#define DUK_OP_UNUSED225 225
+#define DUK_OP_UNUSED226 226
+#define DUK_OP_UNUSED227 227
+#define DUK_OP_UNUSED228 228
+#define DUK_OP_UNUSED229 229
+#define DUK_OP_UNUSED230 230
+#define DUK_OP_UNUSED231 231
+#define DUK_OP_UNUSED232 232
+#define DUK_OP_UNUSED233 233
+#define DUK_OP_UNUSED234 234
+#define DUK_OP_UNUSED235 235
+#define DUK_OP_UNUSED236 236
+#define DUK_OP_UNUSED237 237
+#define DUK_OP_UNUSED238 238
+#define DUK_OP_UNUSED239 239
+#define DUK_OP_UNUSED240 240
+#define DUK_OP_UNUSED241 241
+#define DUK_OP_UNUSED242 242
+#define DUK_OP_UNUSED243 243
+#define DUK_OP_UNUSED244 244
+#define DUK_OP_UNUSED245 245
+#define DUK_OP_UNUSED246 246
+#define DUK_OP_UNUSED247 247
+#define DUK_OP_UNUSED248 248
+#define DUK_OP_UNUSED249 249
+#define DUK_OP_UNUSED250 250
+#define DUK_OP_UNUSED251 251
+#define DUK_OP_UNUSED252 252
+#define DUK_OP_UNUSED253 253
+#define DUK_OP_UNUSED254 254
+#define DUK_OP_UNUSED255 255
+#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */
+
+/* XXX: Allocate flags from opcode field? Would take 16 opcode slots
+ * but avoids shuffling in more cases. Maybe not worth it.
+ */
+/* DUK_OP_TRYCATCH flags in A. */
+#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0)
+#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1)
+#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2)
+#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3)
+
+/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags
+ * (DUK_PROPDESC_FLAG_XXX).
+ */
+#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */
+
+/* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match
+ * DUK_CALL_FLAG_xxx directly.
+ */
+#define DUK_BC_CALL_FLAG_TAILCALL (1U << 0)
+#define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1)
+#define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2)
+#define DUK_BC_CALL_FLAG_INDIRECT (1U << 3)
+
+/* Misc constants and helper macros. */
+#define DUK_BC_LDINT_BIAS (1L << 15)
+#define DUK_BC_LDINTX_SHIFT 16
+#define DUK_BC_JUMP_BIAS (1L << 23)
#endif /* DUK_JS_BYTECODE_H_INCLUDED */
-#line 1 "duk_lexer.h"
+/* #include duk_lexer.h */
/*
* Lexer defines.
*/
-#ifndef DUK_LEXER_H_INCLUDED
+#if !defined(DUK_LEXER_H_INCLUDED)
#define DUK_LEXER_H_INCLUDED
typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
@@ -2754,10 +3466,9 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
-#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \
- (pt)->line = (ctx)->window[0].line; } while (0)
+#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt))
-/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
+/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */
#define DUK_LEXER_WINDOW_SIZE 6
#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
#define DUK_LEXER_BUFFER_SIZE 64
@@ -2859,41 +3570,45 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_TOK_MUL 68
#define DUK_TOK_DIV 69
#define DUK_TOK_MOD 70
-#define DUK_TOK_INCREMENT 71
-#define DUK_TOK_DECREMENT 72
-#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */
-#define DUK_TOK_ARSHIFT 74
-#define DUK_TOK_RSHIFT 75
-#define DUK_TOK_BAND 76
-#define DUK_TOK_BOR 77
-#define DUK_TOK_BXOR 78
-#define DUK_TOK_LNOT 79
-#define DUK_TOK_BNOT 80
-#define DUK_TOK_LAND 81
-#define DUK_TOK_LOR 82
-#define DUK_TOK_QUESTION 83
-#define DUK_TOK_COLON 84
-#define DUK_TOK_EQUALSIGN 85
-#define DUK_TOK_ADD_EQ 86
-#define DUK_TOK_SUB_EQ 87
-#define DUK_TOK_MUL_EQ 88
-#define DUK_TOK_DIV_EQ 89
-#define DUK_TOK_MOD_EQ 90
-#define DUK_TOK_ALSHIFT_EQ 91
-#define DUK_TOK_ARSHIFT_EQ 92
-#define DUK_TOK_RSHIFT_EQ 93
-#define DUK_TOK_BAND_EQ 94
-#define DUK_TOK_BOR_EQ 95
-#define DUK_TOK_BXOR_EQ 96
+#define DUK_TOK_EXP 71
+#define DUK_TOK_INCREMENT 72
+#define DUK_TOK_DECREMENT 73
+#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */
+#define DUK_TOK_ARSHIFT 75
+#define DUK_TOK_RSHIFT 76
+#define DUK_TOK_BAND 77
+#define DUK_TOK_BOR 78
+#define DUK_TOK_BXOR 79
+#define DUK_TOK_LNOT 80
+#define DUK_TOK_BNOT 81
+#define DUK_TOK_LAND 82
+#define DUK_TOK_LOR 83
+#define DUK_TOK_QUESTION 84
+#define DUK_TOK_COLON 85
+#define DUK_TOK_EQUALSIGN 86
+#define DUK_TOK_ADD_EQ 87
+#define DUK_TOK_SUB_EQ 88
+#define DUK_TOK_MUL_EQ 89
+#define DUK_TOK_DIV_EQ 90
+#define DUK_TOK_MOD_EQ 91
+#define DUK_TOK_EXP_EQ 92
+#define DUK_TOK_ALSHIFT_EQ 93
+#define DUK_TOK_ARSHIFT_EQ 94
+#define DUK_TOK_RSHIFT_EQ 95
+#define DUK_TOK_BAND_EQ 96
+#define DUK_TOK_BOR_EQ 97
+#define DUK_TOK_BXOR_EQ 98
/* literals (E5 Section 7.8), except null, true, false, which are treated
* like reserved words (above).
*/
-#define DUK_TOK_NUMBER 97
-#define DUK_TOK_STRING 98
-#define DUK_TOK_REGEXP 99
+#define DUK_TOK_NUMBER 99
+#define DUK_TOK_STRING 100
+#define DUK_TOK_REGEXP 101
-#define DUK_TOK_MAXVAL 99 /* inclusive */
+#define DUK_TOK_MAXVAL 101 /* inclusive */
+
+#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX
/* Convert heap string index to a token (reserved words) */
#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
@@ -3052,12 +3767,12 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
#define DUK_RETOK_ATOM_PERIOD 9
#define DUK_RETOK_ATOM_CHAR 10
-#define DUK_RETOK_ATOM_DIGIT 11
-#define DUK_RETOK_ATOM_NOT_DIGIT 12
-#define DUK_RETOK_ATOM_WHITE 13
-#define DUK_RETOK_ATOM_NOT_WHITE 14
-#define DUK_RETOK_ATOM_WORD_CHAR 15
-#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16
+#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */
+#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */
+#define DUK_RETOK_ATOM_WHITE 13 /* -""- */
+#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */
+#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */
+#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */
#define DUK_RETOK_ATOM_BACKREFERENCE 17
#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
@@ -3073,8 +3788,8 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
* stale values otherwise.
*/
struct duk_token {
- duk_small_int_t t; /* token type (with reserved word identification) */
- duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
+ duk_small_uint_t t; /* token type (with reserved word identification) */
+ duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
duk_double_t num; /* numeric value of token */
duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
@@ -3089,11 +3804,11 @@ struct duk_token {
/* A regexp token value. */
struct duk_re_token {
- duk_small_int_t t; /* token type */
- duk_small_int_t greedy;
- duk_uint_fast32_t num; /* numeric value (character, count) */
- duk_uint_fast32_t qmin;
- duk_uint_fast32_t qmax;
+ duk_small_uint_t t; /* token type */
+ duk_small_uint_t greedy;
+ duk_uint32_t num; /* numeric value (character, count) */
+ duk_uint32_t qmin;
+ duk_uint32_t qmax;
};
/* A structure for 'snapshotting' a point for rewinding */
@@ -3133,6 +3848,8 @@ struct duk_lexer_ctx {
duk_int_t token_count; /* number of tokens parsed */
duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
+
+ duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */
};
/*
@@ -3141,6 +3858,7 @@ struct duk_lexer_ctx {
DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
+DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
DUK_INTERNAL_DECL
@@ -3148,18 +3866,18 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
duk_token *out_token,
duk_bool_t strict_mode,
duk_bool_t regexp_mode);
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
#endif /* DUK_USE_REGEXP_SUPPORT */
#endif /* DUK_LEXER_H_INCLUDED */
-#line 1 "duk_js_compiler.h"
+/* #include duk_js_compiler.h */
/*
* Ecmascript compiler.
*/
-#ifndef DUK_JS_COMPILER_H_INCLUDED
+#if !defined(DUK_JS_COMPILER_H_INCLUDED)
#define DUK_JS_COMPILER_H_INCLUDED
/* ecmascript compiler limits */
@@ -3182,22 +3900,23 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_
#define DUK_IVAL_NONE 0 /* no value */
#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
-#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */
-#define DUK_IVAL_PROP 4 /* property access */
-#define DUK_IVAL_VAR 5 /* variable access */
+#define DUK_IVAL_PROP 3 /* property access */
+#define DUK_IVAL_VAR 4 /* variable access */
#define DUK_ISPEC_NONE 0 /* no value */
#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
-/* bit mask which indicates that a regconst is a constant instead of a register */
-#define DUK_JS_CONST_MARKER 0x80000000UL
-
-/* type to represent a reg/const reference during compilation */
-typedef duk_uint32_t duk_regconst_t;
+/* Bit mask which indicates that a regconst is a constant instead of a register.
+ * Chosen so that when a regconst is cast to duk_int32_t, all consts are
+ * negative values.
+ */
+#define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */
-/* type to represent a straight register reference, with <0 indicating none */
-typedef duk_int32_t duk_reg_t;
+/* Type to represent a reg/const reference during compilation, with <0
+ * indicating a constant. Some call sites also use -1 to indicate 'none'.
+ */
+typedef duk_int32_t duk_regconst_t;
typedef struct {
duk_small_uint_t t; /* DUK_ISPEC_XXX */
@@ -3215,7 +3934,7 @@ typedef struct {
/* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
duk_small_uint_t t; /* DUK_IVAL_XXX */
- duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */
+ duk_small_uint_t op; /* bytecode opcode for binary ops */
duk_ispec x1;
duk_ispec x2;
} duk_ivalue;
@@ -3237,8 +3956,8 @@ struct duk_compiler_instr {
* Compiler state
*/
-#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
-#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
+#define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0)
+#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1)
#define DUK_DECL_TYPE_VAR 0
#define DUK_DECL_TYPE_FUNC 1
@@ -3261,7 +3980,7 @@ typedef struct {
*/
} duk_labelinfo;
-/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
+/* Compiling state of one function, eventually converted to duk_hcompfunc */
struct duk_compiler_func {
/* These pointers are at the start of the struct so that they pack
* nicely. Mixing pointers and integer values is bad on some
@@ -3285,7 +4004,7 @@ struct duk_compiler_func {
duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
- /* value stack indices for tracking objects */
+ /* Value stack indices for tracking objects. */
/* code_idx: not needed */
duk_idx_t consts_idx;
duk_idx_t funcs_idx;
@@ -3295,52 +4014,54 @@ struct duk_compiler_func {
duk_idx_t argnames_idx;
duk_idx_t varmap_idx;
- /* temp reg handling */
- duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
- duk_reg_t temp_next; /* next temporary register to allocate */
- duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
+ /* Temp reg handling. */
+ duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */
+ duk_regconst_t temp_next; /* next temporary register to allocate */
+ duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
- /* shuffle registers if large number of regs/consts */
- duk_reg_t shuffle1;
- duk_reg_t shuffle2;
- duk_reg_t shuffle3;
+ /* Shuffle registers if large number of regs/consts. */
+ duk_regconst_t shuffle1;
+ duk_regconst_t shuffle2;
+ duk_regconst_t shuffle3;
- /* stats for current expression being parsed */
+ /* Stats for current expression being parsed. */
duk_int_t nud_count;
duk_int_t led_count;
duk_int_t paren_level; /* parenthesis count, 0 = top level */
duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
duk_bool_t allow_in; /* current paren level allows 'in' token */
- /* misc */
+ /* Misc. */
duk_int_t stmt_next; /* statement id allocation (running counter) */
duk_int_t label_next; /* label id allocation (running counter) */
duk_int_t catch_depth; /* catch stack depth */
duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
duk_int_t fnum_next; /* inner function numbering */
duk_int_t num_formals; /* number of formal arguments */
- duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
+ duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */
+ duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
duk_int_t max_line;
#endif
- /* status booleans */
- duk_bool_t is_function; /* is an actual function (not global/eval code) */
- duk_bool_t is_eval; /* is eval code */
- duk_bool_t is_global; /* is global code */
- duk_bool_t is_setget; /* is a setter/getter */
- duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */
- duk_bool_t is_strict; /* function is strict */
- duk_bool_t is_notail; /* function must not be tail called */
- duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
- duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */
- duk_bool_t may_direct_eval; /* function may call direct eval */
- duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */
- duk_bool_t id_access_slow; /* function makes one or more slow path accesses */
- duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
- duk_bool_t needs_shuffle; /* function needs shuffle registers */
- duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
+ /* Status booleans. */
+ duk_uint8_t is_function; /* is an actual function (not global/eval code) */
+ duk_uint8_t is_eval; /* is eval code */
+ duk_uint8_t is_global; /* is global code */
+ duk_uint8_t is_namebinding; /* needs a name binding */
+ duk_uint8_t is_constructable; /* result is constructable */
+ duk_uint8_t is_setget; /* is a setter/getter */
+ duk_uint8_t is_strict; /* function is strict */
+ duk_uint8_t is_notail; /* function must not be tail called */
+ duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
+ duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */
+ duk_uint8_t may_direct_eval; /* function may call direct eval */
+ duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */
+ duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */
+ duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */
+ duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
+ duk_uint8_t needs_shuffle; /* function needs shuffle registers */
+ duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
};
struct duk_compiler_ctx {
@@ -3375,19 +4096,15 @@ struct duk_compiler_ctx {
* Prototypes
*/
-#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
-#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
-#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
-
DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags);
#endif /* DUK_JS_COMPILER_H_INCLUDED */
-#line 1 "duk_regexp.h"
+/* #include duk_regexp.h */
/*
* Regular expression structs, constants, and bytecode defines.
*/
-#ifndef DUK_REGEXP_H_INCLUDED
+#if !defined(DUK_REGEXP_H_INCLUDED)
#define DUK_REGEXP_H_INCLUDED
/* maximum bytecode copies for {n,m} quantifiers */
@@ -3421,9 +4138,9 @@ DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_b
#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
/* flags */
-#define DUK_RE_FLAG_GLOBAL (1 << 0)
-#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
-#define DUK_RE_FLAG_MULTILINE (1 << 2)
+#define DUK_RE_FLAG_GLOBAL (1U << 0)
+#define DUK_RE_FLAG_IGNORE_CASE (1U << 1)
+#define DUK_RE_FLAG_MULTILINE (1U << 2)
struct duk_re_matcher_ctx {
duk_hthread *thr;
@@ -3459,19 +4176,21 @@ struct duk_re_compiler_ctx {
* Prototypes
*/
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
+#endif
#endif /* DUK_REGEXP_H_INCLUDED */
-#line 1 "duk_heaphdr.h"
+/* #include duk_heaphdr.h */
/*
* Heap header definition and assorted macros, including ref counting.
* Access all fields through the accessor macros.
*/
-#ifndef DUK_HEAPHDR_H_INCLUDED
+#if !defined(DUK_HEAPHDR_H_INCLUDED)
#define DUK_HEAPHDR_H_INCLUDED
/*
@@ -3479,30 +4198,48 @@ DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hack
*
* All heap objects share the same flags and refcount fields. Objects other
* than strings also need to have a single or double linked list pointers
- * for insertion into the "heap allocated" list. Strings are held in the
- * heap-wide string table so they don't need link pointers.
+ * for insertion into the "heap allocated" list. Strings have single linked
+ * list pointers for string table chaining.
*
* Technically, 'h_refcount' must be wide enough to guarantee that it cannot
- * wrap (otherwise objects might be freed incorrectly after wrapping). This
- * means essentially that the refcount field must be as wide as data pointers.
- * On 64-bit platforms this means that the refcount needs to be 64 bits even
- * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
- * this might be reasonable in the future.
+ * wrap; otherwise objects might be freed incorrectly after wrapping. The
+ * default refcount field is 32 bits even on 64-bit systems: while that's in
+ * theory incorrect, the Duktape heap needs to be larger than 64GB for the
+ * count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely
+ * to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes
+ * Duktape to use size_t for refcounts which should always be safe.
*
* Heap header size on 32-bit platforms: 8 bytes without reference counting,
* 16 bytes with reference counting.
+ *
+ * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
+ * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
+ * around them.
*/
+/* XXX: macro for shared header fields (avoids some padding issues) */
+
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
+#pragma pack(push, 8)
+#endif
struct duk_heaphdr {
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_ASSERTIONS)
+ /* When assertions enabled, used by mark-and-sweep for refcount
+ * validation. Largest reasonable type; also detects overflows.
+ */
+ duk_size_t h_assert_refcount;
+#endif
#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
+ duk_uint16_t h_refcount;
+#elif defined(DUK_USE_REFCOUNT32)
+ duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
-#endif
+#endif /* DUK_USE_REFERENCE_COUNTING */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_next16;
@@ -3530,7 +4267,16 @@ struct duk_heaphdr {
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_extra16;
#endif
-};
+}
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
+__attribute__ ((aligned (8)))
+#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
+__attribute__ ((aligned (8)))
+#endif
+;
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
+#pragma pack(pop)
+#endif
struct duk_heaphdr_string {
/* 16 bits would be enough for shared heaphdr flags and duk_hstring
@@ -3542,13 +4288,26 @@ struct duk_heaphdr_string {
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_ASSERTIONS)
+ /* When assertions enabled, used by mark-and-sweep for refcount
+ * validation. Largest reasonable type; also detects overflows.
+ */
+ duk_size_t h_assert_refcount;
+#endif
#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
+ duk_uint16_t h_refcount;
duk_uint16_t h_strextra16; /* round out to 8 bytes */
+#elif defined(DUK_USE_REFCOUNT32)
+ duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
-#endif
+#else
+ duk_uint16_t h_strextra16;
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+ duk_hstring *h_next;
+ /* No 'h_prev' pointer for strings. */
};
#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
@@ -3569,11 +4328,11 @@ struct duk_heaphdr_string {
#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
-#define DUK_HTYPE_MIN 1
-#define DUK_HTYPE_STRING 1
-#define DUK_HTYPE_OBJECT 2
-#define DUK_HTYPE_BUFFER 3
-#define DUK_HTYPE_MAX 3
+#define DUK_HTYPE_MIN 0
+#define DUK_HTYPE_STRING 0
+#define DUK_HTYPE_OBJECT 1
+#define DUK_HTYPE_BUFFER 2
+#define DUK_HTYPE_MAX 2
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HEAPHDR_GET_NEXT(heap,h) \
@@ -3604,23 +4363,15 @@ struct duk_heaphdr_string {
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
-#if defined(DUK_USE_REFCOUNT16)
-#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
-#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
- (h)->h_refcount16 = (val); \
- } while (0)
-#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
-#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
-#else
#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
(h)->h_refcount = (val); \
+ DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \
} while (0)
#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
-#endif
#else
-/* refcount macros not defined without refcounting, caller must #ifdef now */
+/* refcount macros not defined without refcounting, caller must #if defined() now */
#endif /* DUK_USE_REFERENCE_COUNTING */
/*
@@ -3629,19 +4380,22 @@ struct duk_heaphdr_string {
*/
#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
-
+#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \
+ (h)->h_flags = (val); } \
+ }
#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
} while (0)
-
#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
} while (0)
+/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
+ * and the comparison is unsigned, it's always true and generates warnings.
+ */
#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
- DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
)
@@ -3687,7 +4441,7 @@ struct duk_heaphdr_string {
#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
(h)->h_flags = \
- ((h)->h_flags & (~(((1 << (n)) - 1) << (m)))) \
+ ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
| ((v) << (m)); \
} while (0)
@@ -3703,7 +4457,23 @@ struct duk_heaphdr_string {
} while (0)
#endif
-#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
+#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \
+ (h)->h_next = NULL; \
+ } while (0)
+
+/*
+ * Type tests
+ */
+
+/* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit
+ * is only set for DUK_HTYPE_OBJECT (= 1).
+ */
+#if 0
+#define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
+#endif
+#define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL)
+#define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
+#define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
/*
* Assert helpers
@@ -3726,17 +4496,23 @@ struct duk_heaphdr_string {
#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
#endif
+#define DUK_ASSERT_HEAPHDR_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \
+ } while (0)
+
+#endif /* DUK_HEAPHDR_H_INCLUDED */
+/* #include duk_refcount.h */
/*
* Reference counting helper macros. The macros take a thread argument
* and must thus always be executed in a specific thread context. The
- * thread argument is needed for features like finalization. Currently
- * it is not required for INCREF, but it is included just in case.
- *
- * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
- * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
- * around them.
+ * thread argument is not really needed anymore: DECREF can operate with
+ * a heap pointer only, and INCREF needs neither.
*/
+#if !defined(DUK_REFCOUNT_H_INCLUDED)
+#define DUK_REFCOUNT_H_INCLUDED
+
#if defined(DUK_USE_REFERENCE_COUNTING)
#if defined(DUK_USE_ROM_OBJECTS)
@@ -3766,6 +4542,7 @@ struct duk_heaphdr_string {
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
} \
} while (0)
#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
@@ -3781,87 +4558,208 @@ struct duk_heaphdr_string {
} \
} \
} while (0)
+#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \
+ duk_tval *duk__tv = (tv); \
+ DUK_ASSERT(duk__tv != NULL); \
+ if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
+ duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
+ DUK_ASSERT(duk__h != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
+ duk_heaphdr_refzero_norz((thr), duk__h); \
+ } \
+ } \
+ } while (0)
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
} \
} while (0)
-#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
+#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
- duk_heaphdr_refzero((thr), duk__h); \
+ (rzcall)((thr), (rzcast) duk__h); \
} \
} \
} while (0)
+#define DUK_HEAPHDR_DECREF_FAST(thr,h) \
+ DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
+#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \
+ DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
/* Slow variants, call to a helper to reduce code size.
* Can be used explicitly when size is always more important than speed.
*/
-#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
- duk_tval_incref((tv)); \
- } while (0)
-#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
- duk_tval_decref((thr), (tv)); \
- } while (0)
-#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
- duk_heaphdr_incref((duk_heaphdr *) (h)); \
- } while (0)
-#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
- duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
- } while (0)
+#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0)
+#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0)
+#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0)
+#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
/* Default variants. Selection depends on speed/size preference.
* Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
* is about +1kB for _FAST variants.
*/
#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+/* XXX: It would be nice to specialize for specific duk_hobject subtypes
+ * but current refzero queue handling prevents that.
+ */
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
+#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
-#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
+#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
+#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)
+#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */
+#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */
+#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
#else
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
+#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
-#endif
-
-/* Casting convenience. */
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h))
#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
+#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h))
+#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h))
#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
+#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h))
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h))
#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h))
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h))
+#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#endif
/* Convenience for some situations; the above macros don't allow NULLs
- * for performance reasons.
+ * for performance reasons. Macros cover only actually needed cases.
*/
-#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
+#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
-#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
+#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
+#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+
+/* Called after one or more DECREF NORZ calls to handle pending side effects.
+ * At present DECREF NORZ does freeing inline but doesn't execute finalizers,
+ * so these macros check for pending finalizers and execute them. The FAST
+ * variant is performance critical.
+ */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+#define DUK_REFZERO_CHECK_FAST(thr) do { \
+ duk_refzero_check_fast((thr)); \
+ } while (0)
+#define DUK_REFZERO_CHECK_SLOW(thr) do { \
+ duk_refzero_check_slow((thr)); \
+ } while (0)
+#else /* DUK_USE_FINALIZER_SUPPORT */
+#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0)
+#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0)
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Macros to set a duk_tval and update refcount of the target (decref the
@@ -3876,6 +4774,13 @@ struct duk_heaphdr_string {
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \
+ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
+ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
+ DUK_TVAL_SET_UNDEFINED(tv__dst); \
+ DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \
+ } while (0)
+
#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
@@ -3906,7 +4811,7 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
@@ -3922,22 +4827,22 @@ struct duk_heaphdr_string {
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
+ DUK_TVAL_SET_I48(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
+ DUK_TVAL_SET_I32(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
+ DUK_TVAL_SET_U32(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#else
@@ -4019,6 +4924,7 @@ struct duk_heaphdr_string {
/* XXX: no optimized variants yet */
#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0
#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
@@ -4027,14 +4933,15 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
@@ -4055,34 +4962,76 @@ struct duk_heaphdr_string {
#else /* DUK_USE_REFERENCE_COUNTING */
+#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0
+#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0
+
#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+
+#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
+
+#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */
+#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */
#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
@@ -4115,7 +5064,7 @@ struct duk_heaphdr_string {
} while (0)
#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
@@ -4129,19 +5078,19 @@ struct duk_heaphdr_string {
DUK_UNREF((thr)); \
} while (0)
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
+ DUK_TVAL_SET_I48(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
+ DUK_TVAL_SET_I32(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
+ DUK_TVAL_SET_U32(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
#else
@@ -4187,6 +5136,7 @@ struct duk_heaphdr_string {
} while (0)
#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
@@ -4195,14 +5145,15 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
@@ -4215,16 +5166,79 @@ struct duk_heaphdr_string {
#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_HEAPHDR_H_INCLUDED */
-#line 1 "duk_api_internal.h"
+/*
+ * Some convenience macros that don't have optimized implementations now.
+ */
+
+#define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_tval *duk__src = (tv_src); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_TVAL(duk__dst, duk__src); \
+ DUK_TVAL_INCREF(thr, duk__dst); \
+ } while (0)
+
+#define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_uint32_t duk__val = (duk_uint32_t) (val); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_U32(duk__dst, duk__val); \
+ } while (0)
+
+/*
+ * Prototypes
+ */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr);
+DUK_INTERNAL_DECL DUK_INLINE void duk_refzero_check_fast(duk_hthread *thr);
+#endif
+DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr);
+DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h);
+#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */
+DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h);
+#endif
+DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h);
+#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */
+DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */
+DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h);
+#else
+DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
+DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h);
+#endif
+#else /* DUK_USE_REFERENCE_COUNTING */
+/* no refcounting */
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+#endif /* DUK_REFCOUNT_H_INCLUDED */
+/* #include duk_api_internal.h */
/*
* Internal API calls which have (stack and other) semantics similar
* to the public API.
*/
-#ifndef DUK_API_INTERNAL_H_INCLUDED
+#if !defined(DUK_API_INTERNAL_H_INCLUDED)
#define DUK_API_INTERNAL_H_INCLUDED
+#define DUK_INTERNAL_SYMBOL(x) ("\x82" x)
+
/* duk_push_sprintf constants */
#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
@@ -4234,184 +5248,336 @@ struct duk_heaphdr_string {
*/
#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
-/* Valstack resize flags */
-#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
-#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
-#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
-
/* Current convention is to use duk_size_t for value stack sizes and global indices,
* and duk_idx_t for local frame indices.
*/
-DUK_INTERNAL_DECL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags);
+DUK_INTERNAL_DECL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
+
+DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
+
+DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
+
+DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
+
+DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
+/* duk_dup_m1() would be same as duk_dup_top() */
+DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+
+DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
+DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
#endif
+DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
/* Push the current 'this' binding; throw TypeError if binding is not object
* coercible (CheckObjectCoercible).
*/
-DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
-DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
-DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
* make sure there's an active callstack entry. Note that the returned pointer
* is unstable with regards to side effects.
*/
-DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
+DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
/* XXX: add fastint support? */
-#define duk_push_u64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
-#define duk_push_i64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
+#define duk_push_u64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
+#define duk_push_i64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
-#define duk_push_u32(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_i32(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
+#define duk_push_u32(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_i32(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
/* sometimes stack and array indices need to go on the stack */
-#define duk_push_idx(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
-#define duk_push_uarridx(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_size_t(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
+#define duk_push_idx(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
+#define duk_push_uarridx(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_size_t(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
+
+DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
+
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+#define duk_require_hobject_promote_lfunc(thr,idx) \
+ duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
+#define duk_get_hobject_promote_lfunc(thr,idx) \
+ duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
-DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
+#endif
+
+DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
+
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
+DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
-#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
+DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
+#endif
+DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
+DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
+
+DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
+DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
+#define duk_push_hthread(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+#define duk_push_hnatfunc(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
+
+/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
+ * duk_push_hobject() etc which don't create a new value.
+ */
+DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
+DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
+
+DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
+#if 0 /* not used yet */
+DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
#endif
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+#endif
+
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
+
+DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
+
+/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
+ * enough to be packed into a single 32-bit integer argument. Argument limits
+ * vary per call; typically 16 bits are assigned to the signed value stack index
+ * and the stridx. In practice these work well for footprint with constant
+ * arguments and such call sites are also easiest to verify to be correct.
+ */
+
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
+
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+#if 0 /* Too few call sites to be useful. */
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
+ duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+#endif
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_del_prop_stridx((thr), (obj_idx), (stridx))
+
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+#if 0 /* Too few call sites to be useful. */
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
+ duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+#endif
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_has_prop_stridx((thr), (obj_idx), (stridx))
+
+DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
+
+DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
+
+/* XXX: Because stridx and desc_flags have a limited range, this call could
+ * always pack stridx and desc_flags into a single argument.
+ */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
+ duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
+
+#define duk_xdef_prop_wec(thr,obj_idx) \
+ duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
+ duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index);
-#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
#endif
-DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
+
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+
+DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
+#if 0
+DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
#endif
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index);
-#endif
-
-DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
-
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
-
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
-
-DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx);
-DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
-#define duk_push_hthread(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hcompiledfunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hnativefunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-
-DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
-DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
-#endif
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
-DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
-
-DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */
-
-/* These are macros for now, but could be separate functions to reduce code
- * footprint (check call site count before refactoring).
- */
-#define duk_xdef_prop_wec(ctx,obj_index) \
- duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \
- duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \
- duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC)
-
-/* Set object 'length'. */
-DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
+DUK_INTERNAL_DECL void duk_require_constructor_call(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
+
+DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
+
+DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+
+DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
* Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
*/
-#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
-#define DUK_GET_TVAL_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
-#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
-#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
+#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_ASSERT_VALID_POSIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_GET_TVAL_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
+#define DUK_GET_TVAL_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
+#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
+#define DUK_GET_HOBJECT_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
+
+#define DUK_GET_THIS_TVAL_PTR(thr) \
+ (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
+ (thr)->valstack_bottom - 1)
+
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#endif /* DUK_API_INTERNAL_H_INCLUDED */
-#line 1 "duk_hstring.h"
+/* #include duk_hstring.h */
/*
* Heap string representation.
*
@@ -4428,7 +5594,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
* really a practical issue.
*/
-#ifndef DUK_HSTRING_H_INCLUDED
+#if !defined(DUK_HSTRING_H_INCLUDED)
#define DUK_HSTRING_H_INCLUDED
/* Impose a maximum string length for now. Restricted artificially to
@@ -4454,15 +5620,17 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
-#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */
-#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */
-#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */
-#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */
-#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */
+#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */
+#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */
+#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */
+#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */
+#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */
+#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */
#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4470,7 +5638,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4478,7 +5647,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4489,7 +5659,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
*/
#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
#endif
-#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
+#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */
#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
#if defined(DUK_USE_STRHASH16)
@@ -4510,7 +5680,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
(x)->hdr.h_strextra16 = (v); \
} while (0)
#if defined(DUK_USE_HSTRING_CLEN)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
+#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
(x)->clen16 = (v); \
} while (0)
@@ -4525,7 +5695,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
(x)->blen = (v); \
} while (0)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
+#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
(x)->clen = (v); \
} while (0)
@@ -4545,23 +5715,39 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_GET_DATA_END(x) \
(DUK_HSTRING_GET_DATA((x)) + (x)->blen)
-/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
+/* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest
+ * valid).
+ */
#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
-/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
+#if defined(DUK_USE_HSTRING_ARRIDX)
+#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx)
+#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx)
+#else
+/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
* avoids helper call if string has no array index value.
*/
#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
- (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
+ (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
-/* slower but more compact variant */
+/* Slower but more compact variant. */
#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
- (duk_js_to_arrayindex_string_helper((h)))
+ (duk_js_to_arrayindex_hstring_fast((h)))
+#endif
+
+/* XXX: these actually fit into duk_hstring */
+#define DUK_SYMBOL_TYPE_HIDDEN 0
+#define DUK_SYMBOL_TYPE_GLOBAL 1
+#define DUK_SYMBOL_TYPE_LOCAL 2
+#define DUK_SYMBOL_TYPE_WELLKNOWN 3
/*
* Misc
*/
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
+#pragma pack(push, 8)
+#endif
struct duk_hstring {
/* Smaller heaphdr than for other objects, because strings are held
* in string intern table which requires no link pointers. Much of
@@ -4570,25 +5756,26 @@ struct duk_hstring {
*/
duk_heaphdr_string hdr;
- /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
- * shared heap header. Good hashing needs more hash bits though.
- */
-
- /* string hash */
+ /* String hash. */
#if defined(DUK_USE_STRHASH16)
/* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
#else
duk_uint32_t hash;
#endif
- /* length in bytes (not counting NUL term) */
+ /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */
+#if defined(DUK_USE_HSTRING_ARRIDX)
+ duk_uarridx_t arridx;
+#endif
+
+ /* Length in bytes (not counting NUL term). */
#if defined(DUK_USE_STRLEN16)
/* placed in duk_heaphdr_string */
#else
duk_uint32_t blen;
#endif
- /* length in codepoints (must be E5 compatible) */
+ /* Length in codepoints (must be E5 compatible). */
#if defined(DUK_USE_STRLEN16)
#if defined(DUK_USE_HSTRING_CLEN)
duk_uint16_t clen16;
@@ -4600,12 +5787,21 @@ struct duk_hstring {
#endif
/*
- * String value of 'blen+1' bytes follows (+1 for NUL termination
+ * String data of 'blen+1' bytes follows (+1 for NUL termination
* convenience for C API). No alignment needs to be guaranteed
* for strings, but fields above should guarantee alignment-by-4
* (but not alignment-by-8).
*/
-};
+}
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
+__attribute__ ((aligned (8)))
+#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
+__attribute__ ((aligned (8)))
+#endif
+;
+#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
+#pragma pack(pop)
+#endif
/* The external string struct is defined even when the feature is inactive. */
struct duk_hstring_external {
@@ -4624,14 +5820,15 @@ struct duk_hstring_external {
* Prototypes
*/
-DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos);
-
-#if !defined(DUK_USE_HSTRING_CLEN)
+DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware);
+DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr);
DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
+#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
+DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
#endif
#endif /* DUK_HSTRING_H_INCLUDED */
-#line 1 "duk_hobject.h"
+/* #include duk_hobject.h */
/*
* Heap object representation.
*
@@ -4663,31 +5860,36 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
* parts are resized together, and makes property access a bit complicated.
*/
-#ifndef DUK_HOBJECT_H_INCLUDED
+#if !defined(DUK_HOBJECT_H_INCLUDED)
#define DUK_HOBJECT_H_INCLUDED
-/* Object flag. There are currently 26 flag bits available. Make sure
- * this stays in sync with debugger object inspection code.
+/* Object flags. Make sure this stays in sync with debugger object
+ * inspection code.
+ */
+
+/* XXX: some flags are object subtype specific (e.g. common to all function
+ * subtypes, duk_harray, etc) and could be reused for different subtypes.
*/
#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
-#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
-#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */
-#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */
-#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */
-#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
+#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */
+#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */
+#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
+#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
+#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
+#define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */
#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
-#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */
+#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
-#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
+#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
-#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
-#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */
#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
#define DUK_HOBJECT_FLAG_CLASS_BITS 5
@@ -4708,26 +5910,27 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
/* E5 Section 8.6.2 + custom classes */
-#define DUK_HOBJECT_CLASS_UNUSED 0
-#define DUK_HOBJECT_CLASS_ARGUMENTS 1
+#define DUK_HOBJECT_CLASS_NONE 0
+#define DUK_HOBJECT_CLASS_OBJECT 1
#define DUK_HOBJECT_CLASS_ARRAY 2
-#define DUK_HOBJECT_CLASS_BOOLEAN 3
-#define DUK_HOBJECT_CLASS_DATE 4
-#define DUK_HOBJECT_CLASS_ERROR 5
-#define DUK_HOBJECT_CLASS_FUNCTION 6
-#define DUK_HOBJECT_CLASS_JSON 7
-#define DUK_HOBJECT_CLASS_MATH 8
-#define DUK_HOBJECT_CLASS_NUMBER 9
-#define DUK_HOBJECT_CLASS_OBJECT 10
+#define DUK_HOBJECT_CLASS_FUNCTION 3
+#define DUK_HOBJECT_CLASS_ARGUMENTS 4
+#define DUK_HOBJECT_CLASS_BOOLEAN 5
+#define DUK_HOBJECT_CLASS_DATE 6
+#define DUK_HOBJECT_CLASS_ERROR 7
+#define DUK_HOBJECT_CLASS_JSON 8
+#define DUK_HOBJECT_CLASS_MATH 9
+#define DUK_HOBJECT_CLASS_NUMBER 10
#define DUK_HOBJECT_CLASS_REGEXP 11
#define DUK_HOBJECT_CLASS_STRING 12
#define DUK_HOBJECT_CLASS_GLOBAL 13
-#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */
-#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */
-#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */
+#define DUK_HOBJECT_CLASS_SYMBOL 14
+#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */
+#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */
#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
-#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */
+#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19
+#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */
#define DUK_HOBJECT_CLASS_DATAVIEW 20
#define DUK_HOBJECT_CLASS_INT8ARRAY 21
#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
@@ -4738,11 +5941,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
+#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29
#define DUK_HOBJECT_CLASS_MAX 29
-/* class masks */
+/* Class masks. */
#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
-#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED)
+#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE)
#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
@@ -4756,11 +5960,10 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
+#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL)
#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
-#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER)
#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
-#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
@@ -4773,9 +5976,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
-#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \
- (DUK_HOBJECT_CMASK_BUFFER | \
- DUK_HOBJECT_CMASK_ARRAYBUFFER | \
+#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
+ (DUK_HOBJECT_CMASK_ARRAYBUFFER | \
DUK_HOBJECT_CMASK_DATAVIEW | \
DUK_HOBJECT_CMASK_INT8ARRAY | \
DUK_HOBJECT_CMASK_UINT8ARRAY | \
@@ -4790,102 +5992,144 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
-#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
-#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */
+#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_IS_BUFOBJ(h) 0
+#endif
+#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
+#if defined(DUK_USE_ES6_PROXY)
+#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
+#else
+#define DUK_HOBJECT_IS_PROXY(h) 0
+#endif
#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+ DUK_HOBJECT_FLAG_COMPFUNC | \
+ DUK_HOBJECT_FLAG_NATFUNC)
#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+ DUK_HOBJECT_FLAG_BOUNDFUNC | \
+ DUK_HOBJECT_FLAG_COMPFUNC | \
+ DUK_HOBJECT_FLAG_NATFUNC)
-#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h))
-/* object has any exotic behavior(s) */
+/* Object has any exotic behavior(s). */
#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
- DUK_HOBJECT_FLAG_BUFFEROBJECT | \
+ DUK_HOBJECT_FLAG_BUFOBJ | \
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
+/* Object has any virtual properties (not counting Proxy behavior). */
+#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
+ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
+ DUK_HOBJECT_FLAG_BUFOBJ)
+#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
+
#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_HAS_BUFOBJ(h) 0
+#endif
+#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#else
+#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0
+#endif
+#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
+#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
+#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
-/* flags used for property attributes in duk_propdesc and packed flags */
-#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
-#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
+/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
+ * duk_hobject base header. This is used just for asserts so doesn't need to
+ * be optimized.
+ */
+#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
+ (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
+ DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
+ DUK_HOBJECT_IS_BOUNDFUNC((h)))
+#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
+
+/* Flags used for property attributes in duk_propdesc and packed flags.
+ * Must fit into 8 bits.
+ */
+#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */
+#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored
* (used by e.g. buffer virtual properties)
*/
#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
@@ -4893,12 +6137,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_PROPDESC_FLAG_CONFIGURABLE | \
DUK_PROPDESC_FLAG_ACCESSOR)
-/* additional flags which are passed in the same flags argument as property
+/* Additional flags which are passed in the same flags argument as property
* flags but are not stored in object properties.
*/
-#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
+#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */
-/* convenience */
+/* Convenience defines for property attributes. */
#define DUK_PROPDESC_FLAGS_NONE 0
#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
@@ -4910,9 +6154,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_PROPDESC_FLAG_ENUMERABLE | \
DUK_PROPDESC_FLAG_CONFIGURABLE)
-/* flags for duk_hobject_get_own_propdesc() and variants */
-#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
-#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
+/* Flags for duk_hobject_get_own_propdesc() and variants. */
+#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */
+#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */
/*
* Macro for object validity check
@@ -4924,9 +6168,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_ASSERT((h) != NULL); \
DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
- DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \
- (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
+ DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \
+ (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
@@ -4937,6 +6180,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
+ /* Object is an Array <=> object has exotic array behavior */ \
+ DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \
+ (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \
} while (0)
/*
@@ -5219,9 +6465,6 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
*/
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
-/* Maximum traversal depth for "bound function" chains. */
-#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
-
/*
* Ecmascript [[Class]]
*/
@@ -5253,9 +6496,32 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
} while (0)
#endif
-/* note: this updates refcounts */
+/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
+/* Set initial prototype, assume NULL previous prototype, INCREF new value,
+ * tolerate NULL.
+ */
+#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_hobject *duk__obj = (h); \
+ duk_hobject *duk__proto = (proto); \
+ DUK_UNREF(duk__thr); \
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
+ DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
+ DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
+ } while (0)
+
+/*
+ * Finalizer check
+ */
+
+#if defined(DUK_USE_HEAPPTR16)
+#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h))
+#else
+#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h))
+#endif
+
/*
* Resizing and hash behavior
*/
@@ -5269,22 +6535,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#if defined(DUK_USE_OBJSIZES16)
#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
#else
-#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
+#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */
#endif
-/* higher value conserves memory; also note that linear scan is cache friendly */
-#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
-
-/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
-#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
-
-/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
-#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
-
-/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
-/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
-#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
-
/* internal align target for props allocation, must be 2*n for some n */
#if (DUK_USE_ALIGN_BY == 4)
#define DUK_HOBJECT_ALIGN_TARGET 4
@@ -5296,18 +6549,6 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#error invalid DUK_USE_ALIGN_BY
#endif
-/* controls for minimum entry part growth */
-#define DUK_HOBJECT_E_MIN_GROW_ADD 16
-#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* controls for minimum array part growth */
-#define DUK_HOBJECT_A_MIN_GROW_ADD 16
-#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* probe sequence */
-#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
/*
* PC-to-line constants
*/
@@ -5337,7 +6578,7 @@ union duk_propvalue {
struct duk_propdesc {
/* read-only values 'lifted' for ease of use */
- duk_small_int_t flags;
+ duk_small_uint_t flags;
duk_hobject *get;
duk_hobject *set;
@@ -5418,7 +6659,7 @@ struct duk_hobject {
#if defined(DUK_USE_HEAPPTR16)
/* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
- * duk_hcompiledfunction) are not free to use h_extra16 for this reason.
+ * duk_hcompfunc) are not free to use h_extra16 for this reason.
*/
#else
duk_uint8_t *props;
@@ -5461,19 +6702,41 @@ DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
*/
/* alloc and init */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-#if 0 /* unused */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+#endif
+DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+
+/* resize */
+DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size,
+ duk_uint32_t new_a_size,
+ duk_uint32_t new_h_size,
+ duk_bool_t abandon_array);
+DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size);
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_a_size);
#endif
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
/* low-level property functions */
-DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
+DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
@@ -5490,39 +6753,40 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
/* internal property functions */
-#define DUK_DELPROP_FLAG_THROW (1 << 0)
-#define DUK_DELPROP_FLAG_FORCE (1 << 1)
+#define DUK_DELPROP_FLAG_THROW (1U << 0)
+#define DUK_DELPROP_FLAG_FORCE (1U << 1)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags);
-DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
-DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
-DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
+DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
+#if defined(DUK_USE_HEAPPTR16)
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj);
+#else
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj);
+#endif
/* helpers for defineProperty() and defineProperties() */
-DUK_INTERNAL_DECL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
- duk_idx_t idx_in,
- duk_uint_t *out_defprop_flags,
- duk_idx_t *out_idx_value,
- duk_hobject **out_getter,
- duk_hobject **out_setter);
-DUK_INTERNAL_DECL
-void duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set);
+DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
+ duk_idx_t idx_in,
+ duk_uint_t *out_defprop_flags,
+ duk_idx_t *out_idx_value,
+ duk_hobject **out_getter,
+ duk_hobject **out_setter);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
+ duk_uint_t defprop_flags,
+ duk_hobject *obj,
+ duk_hstring *key,
+ duk_idx_t idx_value,
+ duk_hobject *get,
+ duk_hobject *set,
+ duk_bool_t throw_flag);
/* Object built-in methods */
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
/* internal properties */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
@@ -5531,34 +6795,39 @@ DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *h
/* hobject management functions */
DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
-/* ES6 proxy */
+/* ES2015 proxy */
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
#endif
/* enumeration */
-DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
+DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
/* macros */
DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
-/* finalization */
-DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
-
/* pc2line */
#if defined(DUK_USE_PC2LINE)
DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
+DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
#endif
/* misc */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
+#if !defined(DUK_USE_OBJECT_BUILTIN)
+/* These declarations are needed when related built-in is disabled and
+ * genbuiltins.py won't automatically emit the declerations.
+ */
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
+#endif
+
#endif /* DUK_HOBJECT_H_INCLUDED */
-#line 1 "duk_hcompiledfunction.h"
+/* #include duk_hcompfunc.h */
/*
* Heap compiled function (Ecmascript function) representation.
*
@@ -5566,8 +6835,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
* bytecode, constants, and inner functions.
*/
-#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
-#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
+#if !defined(DUK_HCOMPFUNC_H_INCLUDED)
+#define DUK_HCOMPFUNC_H_INCLUDED
/*
* Field accessor macros
@@ -5576,37 +6845,52 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
/* XXX: casts could be improved, especially for GET/SET DATA */
#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
+#define DUK_HCOMPFUNC_GET_DATA(heap,h) \
((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
+#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \
((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
+#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \
((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
+#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \
+ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
+#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
+ (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
+ } while (0)
+#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \
+ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
+#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
+ (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
+ } while (0)
#else
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
- ((duk_hbuffer_fixed *) (void *) (h)->data)
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data)
+#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data = (duk_hbuffer *) (v); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
- ((h)->funcs)
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs)
+#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs = (v); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
- ((h)->bytecode)
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode)
+#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode = (v); \
} while (0)
+#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env)
+#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
+ (h)->lex_env = (v); \
+ } while (0)
+#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env)
+#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
+ (h)->var_env = (v); \
+ } while (0)
#endif
/*
@@ -5614,71 +6898,78 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
*/
/* Note: assumes 'data' is always a fixed buffer */
-#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
+#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \
+ DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
+#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \
+ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
+#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \
+ DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
+#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \
+ DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
+#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \
+ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \
- ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
+#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \
+ ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
-/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \
- ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
- DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
+/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
+#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \
+ ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
+ DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
+#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
+#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
+#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
+/*
+ * Validity assert
+ */
+
+#define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ } while (0)
/*
* Main struct
*/
-struct duk_hcompiledfunction {
+struct duk_hcompfunc {
/* shared object part */
duk_hobject obj;
@@ -5725,6 +7016,17 @@ struct duk_hcompiledfunction {
duk_instr_t *bytecode;
#endif
+ /* Lexenv: lexical environment of closure, NULL for templates.
+ * Varenv: variable environment of closure, NULL for templates.
+ */
+#if defined(DUK_USE_HEAPPTR16)
+ duk_uint16_t lex_env16;
+ duk_uint16_t var_env16;
+#else
+ duk_hobject *lex_env;
+ duk_hobject *var_env;
+#endif
+
/*
* 'nregs' registers are allocated on function entry, at most 'nargs'
* are initialized to arguments, and the rest to undefined. Arguments
@@ -5780,8 +7082,6 @@ struct duk_hcompiledfunction {
* _Formals: [ "arg1", "arg2" ],
* _Source: "function func(arg1, arg2) { ... }",
* _Pc2line: <debug info for pc-to-line mapping>,
- * _Varenv: <variable environment of closure>,
- * _Lexenv: <lexical environment of closure (if differs from _Varenv)>
* }
*
* More detailed description of these properties can be found
@@ -5797,19 +7097,19 @@ struct duk_hcompiledfunction {
#endif
};
-#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
-#line 1 "duk_hnativefunction.h"
+#endif /* DUK_HCOMPFUNC_H_INCLUDED */
+/* #include duk_hnatfunc.h */
/*
* Heap native function representation.
*/
-#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
-#define DUK_HNATIVEFUNCTION_H_INCLUDED
+#if !defined(DUK_HNATFUNC_H_INCLUDED)
+#define DUK_HNATFUNC_H_INCLUDED
-#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1)
-#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff)
+#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1)
+#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff)
-struct duk_hnativefunction {
+struct duk_hnatfunc {
/* shared object part */
duk_hobject obj;
@@ -5826,46 +7126,89 @@ struct duk_hnativefunction {
* versa.
*
* Note: cannot place nargs/magic into the heaphdr flags, because
- * duk_hobject takes almost all flags already (and needs the spare).
+ * duk_hobject takes almost all flags already.
+ */
+};
+
+#endif /* DUK_HNATFUNC_H_INCLUDED */
+/* #include duk_hboundfunc.h */
+/*
+ * Bound function representation.
+ */
+
+#if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
+#define DUK_HBOUNDFUNC_H_INCLUDED
+
+/* Artificial limit for args length. Ensures arithmetic won't overflow
+ * 32 bits when combining bound functions.
+ */
+#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
+
+#define DUK_ASSERT_HBOUNDFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) (h))); \
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&(h)->target) || \
+ (DUK_TVAL_IS_OBJECT(&(h)->target) && \
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&(h)->target)))); \
+ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&(h)->this_binding)); \
+ DUK_ASSERT((h)->nargs == 0 || (h)->args != NULL); \
+ } while (0)
+
+struct duk_hboundfunc {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Final target function, stored as duk_tval so that lightfunc can be
+ * represented too.
*/
+ duk_tval target;
+
+ /* This binding. */
+ duk_tval this_binding;
+
+ /* Arguments to prepend. */
+ duk_tval *args; /* Separate allocation. */
+ duk_idx_t nargs;
};
-#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */
-#line 1 "duk_hbufferobject.h"
+#endif /* DUK_HBOUNDFUNC_H_INCLUDED */
+/* #include duk_hbufobj.h */
/*
* Heap Buffer object representation. Used for all Buffer variants.
*/
-#ifndef DUK_HBUFFEROBJECT_H_INCLUDED
-#define DUK_HBUFFEROBJECT_H_INCLUDED
+#if !defined(DUK_HBUFOBJ_H_INCLUDED)
+#define DUK_HBUFOBJ_H_INCLUDED
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* All element accessors are host endian now (driven by TypedArray spec). */
-#define DUK_HBUFFEROBJECT_ELEM_UINT8 0
-#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
-#define DUK_HBUFFEROBJECT_ELEM_INT8 2
-#define DUK_HBUFFEROBJECT_ELEM_UINT16 3
-#define DUK_HBUFFEROBJECT_ELEM_INT16 4
-#define DUK_HBUFFEROBJECT_ELEM_UINT32 5
-#define DUK_HBUFFEROBJECT_ELEM_INT32 6
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
-#define DUK_HBUFFEROBJECT_ELEM_MAX 8
-
-#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
+#define DUK_HBUFOBJ_ELEM_UINT8 0
+#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1
+#define DUK_HBUFOBJ_ELEM_INT8 2
+#define DUK_HBUFOBJ_ELEM_UINT16 3
+#define DUK_HBUFOBJ_ELEM_INT16 4
+#define DUK_HBUFOBJ_ELEM_UINT32 5
+#define DUK_HBUFOBJ_ELEM_INT32 6
+#define DUK_HBUFOBJ_ELEM_FLOAT32 7
+#define DUK_HBUFOBJ_ELEM_FLOAT64 8
+#define DUK_HBUFOBJ_ELEM_MAX 8
+
+#define DUK_ASSERT_HBUFOBJ_VALID(h) do { \
DUK_ASSERT((h) != NULL); \
DUK_ASSERT((h)->shift <= 3); \
- DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
- DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
- ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
- DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \
+ DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \
+ ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \
+ ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \
+ ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \
+ ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \
+ ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \
+ DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \
+ DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \
if ((h)->buf == NULL) { \
DUK_ASSERT((h)->offset == 0); \
DUK_ASSERT((h)->length == 0); \
@@ -5881,58 +7224,64 @@ struct duk_hnativefunction {
/* Get the current data pointer (caller must ensure buf != NULL) as a
* duk_uint8_t ptr.
*/
-#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
+#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
(((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
/* True if slice is full, i.e. offset is zero and length covers the entire
- * buffer. This status may change independently of the duk_hbufferobject if
- * the underlying buffer is dynamic and changes without the hbufferobject
+ * buffer. This status may change independently of the duk_hbufobj if
+ * the underlying buffer is dynamic and changes without the hbufobj
* being changed.
*/
-#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
+#define DUK_HBUFOBJ_FULL_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate that the whole slice [0,length[ is contained in the underlying
* buffer. Caller must ensure 'buf' != NULL.
*/
-#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
+#define DUK_HBUFOBJ_VALID_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate byte read/write for virtual 'offset', i.e. check that the
* offset, taking into account h->offset, is within the underlying
* buffer size. This is a safety check which is needed to ensure
- * that even a misconfigured duk_hbufferobject never causes memory
- * unsafe behavior (e.g. if an underlying dynamic buffer changes
- * after being setup). Caller must ensure 'buf' != NULL.
+ * that even a misconfigured duk_hbufobj never causes memory unsafe
+ * behavior (e.g. if an underlying dynamic buffer changes after being
+ * setup). Caller must ensure 'buf' != NULL.
*/
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
+#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
+#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Clamp an input byte length (already assumed to be within the nominal
- * duk_hbufferobject 'length') to the current dynamic buffer limits to
- * yield a byte length limit that's safe for memory accesses. This value
- * can be invalidated by any side effect because it may trigger a user
+ * duk_hbufobj 'length') to the current dynamic buffer limits to yield
+ * a byte length limit that's safe for memory accesses. This value can
+ * be invalidated by any side effect because it may trigger a user
* callback that resizes the underlying buffer.
*/
-#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
+#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
(DUK_ASSERT_EXPR((h) != NULL), \
- duk_hbufferobject_clamp_bytelength((h), (len)))
+ duk_hbufobj_clamp_bytelength((h), (len)))
+
+/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
+#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray)
-struct duk_hbufferobject {
+struct duk_hbufobj {
/* Shared object part. */
duk_hobject obj;
/* Underlying buffer (refcounted), may be NULL. */
duk_hbuffer *buf;
+ /* .buffer reference to an ArrayBuffer, may be NULL. */
+ duk_hobject *buf_prop;
+
/* Slice and accessor information.
*
* Because the underlying buffer may be dynamic, these may be
@@ -5955,86 +7304,73 @@ struct duk_hbufferobject {
* 3 = double
*/
duk_uint8_t elem_type; /* element type */
- duk_uint8_t is_view;
+ duk_uint8_t is_typedarray;
};
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len);
-#endif
-DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
+DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
+DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
-#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */
-#line 1 "duk_hthread.h"
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+#endif /* DUK_HBUFOBJ_H_INCLUDED */
+/* #include duk_hthread.h */
/*
* Heap thread object representation.
*
- * duk_hthread is also the 'context' (duk_context) for exposed APIs
- * which mostly operate on the topmost frame of the value stack.
+ * duk_hthread is also the 'context' for public API functions via a
+ * different typedef. Most API calls operate on the topmost frame
+ * of the value stack only.
*/
-#ifndef DUK_HTHREAD_H_INCLUDED
+#if !defined(DUK_HTHREAD_H_INCLUDED)
#define DUK_HTHREAD_H_INCLUDED
/*
* Stack constants
*/
-#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
-#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
-#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
-#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
-#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
- * always added to user-defined 'extra' for e.g. the
- * duk_check_stack() call.
- */
-#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
- /* number of elements guaranteed to be user accessible
- * (in addition to call arguments) on Duktape/C function entry.
- */
+/* Initial valstack size, roughly 0.7kiB. */
+#define DUK_VALSTACK_INITIAL_SIZE 96U
-/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
- * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
- * requirements.
+/* Internal extra elements assumed on function entry, always added to
+ * user-defined 'extra' for e.g. the duk_check_stack() call.
*/
+#define DUK_VALSTACK_INTERNAL_EXTRA 32U
-#define DUK_VALSTACK_DEFAULT_MAX 1000000L
-
-#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
-#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_INITIAL_SIZE 8
-#define DUK_CALLSTACK_DEFAULT_MAX 10000L
-
-#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
-#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_INITIAL_SIZE 4
-#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
+/* Number of elements guaranteed to be user accessible (in addition to call
+ * arguments) on Duktape/C function entry. This is the major public API
+ * commitment.
+ */
+#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
/*
* Activation defines
*/
-#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
-#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
-#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
-#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
-#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
-#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
+#define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */
+#define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */
+#define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */
+#define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */
+#define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */
+#define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */
+#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */
-#define DUK_ACT_GET_FUNC(act) ((act)->func)
+#define DUK_ACT_GET_FUNC(act) ((act)->func)
/*
* Flags for __FILE__ / __LINE__ registered into tracedata
*/
-#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
+#define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
/*
* Catcher defines
*/
+/* XXX: remove catcher type entirely */
+
/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
#define DUK_CAT_TYPE_MASK 0x0000000fUL
#define DUK_CAT_TYPE_BITS 4
@@ -6042,10 +7378,10 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
#define DUK_CAT_LABEL_BITS 24
#define DUK_CAT_LABEL_SHIFT 8
-#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
-#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
-#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
-#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
+#define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */
+#define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */
+#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */
+#define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */
#define DUK_CAT_TYPE_UNKNOWN 0
#define DUK_CAT_TYPE_TCF 1
@@ -6102,8 +7438,6 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
#endif
#endif /* DUK_USE_ROM_STRINGS */
-#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
-
/* values for the state field */
#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
@@ -6128,42 +7462,75 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
* diagnose behavior so it's worth checking even when the check is not 100%.
*/
-#if defined(DUK_USE_PREFER_SIZE)
-#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
-#else
-#define DUK_ASSERT_CTX_VSSIZE(ctx) \
- DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
- ((duk_hthread *) (ctx))->valstack_size)
-#endif
-#define DUK_ASSERT_CTX_VALID(ctx) do { \
- DUK_ASSERT((ctx) != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
- DUK_ASSERT_CTX_VSSIZE((ctx)); \
+/* Assertions for internals. */
+#define DUK_ASSERT_HTHREAD_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (thr)) == DUK_HTYPE_OBJECT); \
+ DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (thr))); \
+ DUK_ASSERT((thr)->unused1 == 0); \
+ DUK_ASSERT((thr)->unused2 == 0); \
+ } while (0)
+
+/* Assertions for public API calls; a bit stronger. */
+#define DUK_ASSERT_CTX_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT_HTHREAD_VALID((thr)); \
+ DUK_ASSERT((thr)->valstack != NULL); \
+ DUK_ASSERT((thr)->valstack_bottom != NULL); \
+ DUK_ASSERT((thr)->valstack_top != NULL); \
+ DUK_ASSERT((thr)->valstack_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack_bottom); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack_top); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack_end); \
+ } while (0)
+
+/* Assertions for API call entry specifically. Checks 'ctx' but also may
+ * check internal state (e.g. not in a debugger transport callback).
+ */
+#define DUK_ASSERT_API_ENTRY(thr) do { \
+ DUK_ASSERT_CTX_VALID((thr)); \
+ DUK_ASSERT((thr)->heap != NULL); \
+ DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \
} while (0)
/*
- * Struct defines
+ * Assertion helpers.
+ */
+
+#define DUK_ASSERT_STRIDX_VALID(val) \
+ DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS)
+
+#define DUK_ASSERT_BIDX_VALID(val) \
+ DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS)
+
+/*
+ * Misc
*/
-/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
- * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
+/* Fast access to 'this' binding. Assumes there's a call in progress. */
+#define DUK_HTHREAD_THIS_PTR(thr) \
+ (DUK_ASSERT_EXPR((thr) != NULL), \
+ DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
+ (thr)->valstack_bottom - 1)
+
+/*
+ * Struct defines
*/
-/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
+/* Fields are ordered for alignment/packing. */
struct duk_activation {
duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
+ duk_activation *parent; /* previous (parent) activation (or NULL if none) */
duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+ duk_catcher *cat; /* current catcher (or NULL) */
+
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
/* Previous value of 'func' caller, restored when unwound. Only in use
* when 'func' is non-strict.
*/
@@ -6171,52 +7538,61 @@ struct duk_activation {
#endif
duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_uint32_t prev_line; /* needed for stepping */
-#endif
- duk_small_uint_t flags;
- /* idx_bottom and idx_retval are only used for book-keeping of
- * Ecmascript-initiated calls, to allow returning to an Ecmascript
- * function properly. They are duk_size_t to match the convention
- * that value stack sizes are duk_size_t and local frame indices
- * are duk_idx_t.
+ /* bottom_byteoff and retval_byteoff are only used for book-keeping
+ * of Ecmascript-initiated calls, to allow returning to an Ecmascript
+ * function properly.
*/
/* Bottom of valstack for this activation, used to reset
- * valstack_bottom on return; index is absolute. Note:
- * idx_top not needed because top is set to 'nregs' always
- * when returning to an Ecmascript activation.
+ * valstack_bottom on return; offset is absolute. There's
+ * no need to track 'top' because native call handling deals
+ * with that using locals, and for Ecmascript returns 'nregs'
+ * indicates the necessary top.
*/
- duk_size_t idx_bottom;
+ duk_size_t bottom_byteoff;
/* Return value when returning to this activation (points to caller
- * reg, not callee reg); index is absolute (only set if activation is
+ * reg, not callee reg); offset is absolute (only set if activation is
* not topmost).
*
- * Note: idx_bottom is always set, while idx_retval is only applicable
- * for activations below the topmost one. Currently idx_retval for
- * the topmost activation is considered garbage (and it not initialized
- * on entry or cleared on return; may contain previous or garbage
- * values).
+ * Note: bottom_byteoff is always set, while retval_byteoff is only
+ * applicable for activations below the topmost one. Currently
+ * retval_byteoff for the topmost activation is considered garbage
+ * (and it not initialized on entry or cleared on return; may contain
+ * previous or garbage values).
*/
- duk_size_t idx_retval;
+ duk_size_t retval_byteoff;
- /* Current 'this' binding is the value just below idx_bottom.
+ /* Current 'this' binding is the value just below bottom.
* Previously, 'this' binding was handled with an index to the
* (calling) valstack. This works for everything except tail
- * calls, which must not "cumulate" valstack temps.
+ * calls, which must not "accumulate" valstack temps.
+ */
+
+ /* Value stack reserve (valstack_end) byte offset to be restored
+ * when returning to this activation. Only used by the bytecode
+ * executor.
*/
+ duk_size_t reserve_byteoff;
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_uint32_t prev_line; /* needed for stepping */
+#endif
+
+ duk_small_uint_t flags;
};
-/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
struct duk_catcher {
+ duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */
duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
/* (reference is valid as long activation exists) */
duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
- duk_size_t callstack_index; /* callstack index of related activation */
duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
duk_uint32_t flags; /* type and control flags, label number */
+ /* XXX: could pack 'flags' and 'idx_base' to same value in practice,
+ * on 32-bit targets this would make duk_catcher 16 bytes.
+ */
};
struct duk_hthread {
@@ -6241,39 +7617,49 @@ struct duk_hthread {
duk_uint8_t unused1;
duk_uint8_t unused2;
- /* Sanity limits for stack sizes. */
- duk_size_t valstack_max;
- duk_size_t callstack_max;
- duk_size_t catchstack_max;
-
- /* XXX: Valstack, callstack, and catchstack are currently assumed
- * to have non-NULL pointers. Relaxing this would not lead to big
- * benefits (except perhaps for terminated threads).
+ /* XXX: Valstack and callstack are currently assumed to have non-NULL
+ * pointers. Relaxing this would not lead to big benefits (except
+ * perhaps for terminated threads).
*/
- /* Value stack: these are expressed as pointers for faster stack manipulation.
- * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
- * not GC-reachable but kept initialized as 'undefined'.
+ /* Value stack: these are expressed as pointers for faster stack
+ * manipulation. [valstack,valstack_top[ is GC-reachable,
+ * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept
+ * initialized as 'undefined'. [valstack,valstack_end[ is the
+ * guaranteed/reserved space and the valstack cannot be resized to
+ * a smaller size. [valstack_end,valstack_alloc_end[ is currently
+ * allocated slack that can be used to grow the current guaranteed
+ * space but may be shrunk away without notice.
+ *
+ *
+ * <----------------------- guaranteed --->
+ * <---- slack --->
+ * <--- frame --->
+ * .-------------+=============+----------+--------------.
+ * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu|
+ * `-------------+=============+----------+--------------'
+ *
+ * ^ ^ ^ ^ ^
+ * | | | | |
+ * valstack bottom top end alloc_end
+ *
+ * xxx = arbitrary values, below current frame
+ * yyy = arbitrary values, inside current frame
+ * uuu = outside active value stack, initialized to 'undefined'
*/
duk_tval *valstack; /* start of valstack allocation */
- duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
+ duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */
+ duk_tval *valstack_alloc_end; /* end of valstack allocation */
duk_tval *valstack_bottom; /* bottom of current frame */
duk_tval *valstack_top; /* top of current frame (exclusive) */
-#if !defined(DUK_USE_PREFER_SIZE)
- duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
-#endif
- /* Call stack. [0,callstack_top[ is GC reachable. */
- duk_activation *callstack;
- duk_size_t callstack_size; /* allocation size */
- duk_size_t callstack_top; /* next to use, highest used is top - 1 */
+ /* Call stack, represented as a linked list starting from the current
+ * activation (or NULL if nothing is active).
+ */
+ duk_activation *callstack_curr; /* current activation (or NULL if none) */
+ duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */
duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
- /* Catch stack. [0,catchstack_top[ is GC reachable. */
- duk_catcher *catchstack;
- duk_size_t catchstack_size; /* allocation size */
- duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
-
/* Yield/resume book-keeping. */
duk_hthread *resumer; /* who resumed us (if any) */
@@ -6326,17 +7712,22 @@ DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
+DUK_INTERNAL_DECL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level);
+
+DUK_INTERNAL_DECL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act);
+
+#if defined(DUK_USE_FINALIZER_TORTURE)
+DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr);
+#endif
-DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
@@ -6346,7 +7737,104 @@ DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
#endif /* DUK_HTHREAD_H_INCLUDED */
-#line 1 "duk_hbuffer.h"
+/* #include duk_harray.h */
+/*
+ * Array object representation, used for actual Array instances.
+ *
+ * All objects with the exotic array behavior (which must coincide with having
+ * internal class array) MUST be duk_harrays. No other object can be a
+ * duk_harray. However, duk_harrays may not always have an array part.
+ */
+
+#if !defined(DUK_HARRAY_H_INCLUDED)
+#define DUK_HARRAY_H_INCLUDED
+
+#define DUK_ASSERT_HARRAY_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \
+ } while (0)
+
+#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable)
+#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable)
+#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0)
+#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0)
+
+struct duk_harray {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Array .length.
+ *
+ * At present Array .length may be smaller, equal, or even larger
+ * than the allocated underlying array part. Fast path code must
+ * always take this into account carefully.
+ */
+ duk_uint32_t length;
+
+ /* Array .length property attributes. The property is always
+ * non-enumerable and non-configurable. It's initially writable
+ * but per Object.defineProperty() rules it can be made non-writable
+ * even if it is non-configurable. Thus we need to track the
+ * writability explicitly.
+ *
+ * XXX: this field to be eliminated and moved into duk_hobject
+ * flags field to save space.
+ */
+ duk_bool_t length_nonwritable;
+};
+
+#endif /* DUK_HARRAY_H_INCLUDED */
+/* #include duk_henv.h */
+/*
+ * Environment object representation.
+ */
+
+#if !defined(DUK_HENV_H_INCLUDED)
+#define DUK_HENV_H_INCLUDED
+
+#define DUK_ASSERT_HDECENV_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \
+ } while (0)
+
+#define DUK_ASSERT_HOBJENV_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->target != NULL); \
+ DUK_ASSERT((h)->has_this == 0 || (h)->has_this == 1); \
+ } while (0)
+
+struct duk_hdecenv {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* These control variables provide enough information to access live
+ * variables for a closure that is still open. If thread == NULL,
+ * the record is closed and the identifiers are in the property table.
+ */
+ duk_hthread *thread;
+ duk_hobject *varmap;
+ duk_size_t regbase_byteoff;
+};
+
+struct duk_hobjenv {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Target object and 'this' binding for object binding. */
+ duk_hobject *target;
+
+ /* The 'target' object is used as a this binding in only some object
+ * environments. For example, the global environment does not provide
+ * a this binding, but a with statement does.
+ */
+ duk_bool_t has_this;
+};
+
+#endif /* DUK_HENV_H_INCLUDED */
+/* #include duk_hbuffer.h */
/*
* Heap buffer representation.
*
@@ -6358,7 +7846,7 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
* The data pointer for a variable size buffer of zero size may be NULL.
*/
-#ifndef DUK_HBUFFER_H_INCLUDED
+#if !defined(DUK_HBUFFER_H_INCLUDED)
#define DUK_HBUFFER_H_INCLUDED
/*
@@ -6404,9 +7892,6 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
* Field access
*/
-/* Get/set the current user visible size, without accounting for a dynamic
- * buffer's "spare" (= usable size).
- */
#if defined(DUK_USE_BUFLEN16)
/* size stored in duk_heaphdr unused flag bits */
#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
@@ -6526,7 +8011,7 @@ struct duk_hbuffer {
* it is useful for writing robust native code.
*/
- /* Current size (not counting a dynamic buffer's "spare"). */
+ /* Current size. */
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
@@ -6675,7 +8160,34 @@ DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic
DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
#endif /* DUK_HBUFFER_H_INCLUDED */
-#line 1 "duk_heap.h"
+/* #include duk_hproxy.h */
+/*
+ * Proxy object representation.
+ */
+
+#if !defined(DUK_HPROXY_H_INCLUDED)
+#define DUK_HPROXY_H_INCLUDED
+
+#define DUK_ASSERT_HPROXY_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT((h)->target != NULL); \
+ DUK_ASSERT((h)->handler != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) (h))); \
+ } while (0)
+
+struct duk_hproxy {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Proxy target object. */
+ duk_hobject *target;
+
+ /* Proxy handlers (traps). */
+ duk_hobject *handler;
+};
+
+#endif /* DUK_HPROXY_H_INCLUDED */
+/* #include duk_heap.h */
/*
* Heap structure.
*
@@ -6683,7 +8195,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* strings for one or more threads.
*/
-#ifndef DUK_HEAP_H_INCLUDED
+#if !defined(DUK_HEAP_H_INCLUDED)
#define DUK_HEAP_H_INCLUDED
/* alloc function typedefs in duktape.h */
@@ -6692,12 +8204,10 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* Heap flags
*/
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
-#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
-#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
-#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
-#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
+#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
+#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */
+#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */
+#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */
#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
@@ -6707,26 +8217,20 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
(heap)->flags &= ~(bits); \
} while (0)
-#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
-#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
-#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
/*
* Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
@@ -6749,11 +8253,25 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* field and the GC caller can impose further flags.
*/
-#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
-#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
-#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
-#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
-#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
+/* Emergency mark-and-sweep: try extra hard, even at the cost of
+ * performance.
+ */
+#define DUK_MS_FLAG_EMERGENCY (1U << 0)
+
+/* Voluntary mark-and-sweep: triggered periodically. */
+#define DUK_MS_FLAG_VOLUNTARY (1U << 1)
+
+/* Postpone rescue decisions for reachable objects with FINALIZED set.
+ * Used during finalize_list processing to avoid incorrect rescue
+ * decisions due to finalize_list being a reachability root.
+ */
+#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 2)
+
+/* Don't compact objects; needed during object property table resize
+ * to prevent a recursive resize. It would suffice to protect only the
+ * current object being resized, but this is not yet implemented.
+ */
+#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 3)
/*
* Thread switching
@@ -6772,6 +8290,18 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#endif
/*
+ * Stats
+ */
+
+#if defined(DUK_USE_DEBUG)
+#define DUK_STATS_INC(heap,fieldname) do { \
+ (heap)->fieldname += 1; \
+ } while (0)
+#else
+#define DUK_STATS_INC(heap,fieldname) do {} while (0)
+#endif
+
+/*
* Other heap related defines
*/
@@ -6785,7 +8315,6 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* GC is skipped because there is no thread do it with yet (happens
* only during init phases).
*/
-#if defined(DUK_USE_MARK_AND_SWEEP)
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
@@ -6795,6 +8324,12 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
#endif
+
+/* GC torture. */
+#if defined(DUK_USE_GC_TORTURE)
+#define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0)
+#else
+#define DUK_GC_TORTURE(heap) do { } while (0)
#endif
/* Stringcache is used for speeding up char-offset-to-byte-offset
@@ -6803,33 +8338,15 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_STRCACHE_SIZE 4
#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
-/* helper to insert a (non-string) heap object into heap allocated list */
-#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
-
-/*
- * Stringtable
- */
-
-/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
-#define DUK_STRTAB_INITIAL_SIZE 17
-
-/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
-#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
-
-/* resizing parameters */
-#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
-#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
-#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
-
-#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
-#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
-
-/* probe sequence (open addressing) */
-#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
-/* fixed top level hashtable size (separate chaining) */
-#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
+/* Some list management macros. */
+#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr))
+#if defined(DUK_USE_REFERENCE_COUNTING)
+#define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr))
+#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+#define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr))
+#define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr))
+#endif
/*
* Built-in strings
@@ -6900,10 +8417,21 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
/*
+ * Checked allocation, relative to a thread
+ *
+ * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
+ * for convenience.
+ */
+
+#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size))
+#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size))
+#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr))
+
+/*
* Memory constants
*/
-#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
+#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this
* many times. A single mark-and-sweep round is
* not guaranteed to free all unreferenced memory
* because of finalization (in fact, ANY number of
@@ -6933,38 +8461,20 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
/* Milliseconds between status notify and transport peeks. */
#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
-/* Step types */
-#define DUK_STEP_TYPE_NONE 0
-#define DUK_STEP_TYPE_INTO 1
-#define DUK_STEP_TYPE_OVER 2
-#define DUK_STEP_TYPE_OUT 3
+/* Debugger pause flags. */
+#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */
+#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */
+#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */
+#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */
+#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */
+#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */
+#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */
struct duk_breakpoint {
duk_hstring *filename;
duk_uint32_t line;
};
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
-#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
- (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
- (heap)->dbg_step_thread = NULL; \
- (heap)->dbg_step_csindex = 0; \
- (heap)->dbg_step_startline = 0; \
- } while (0)
-#define DUK_HEAP_SET_PAUSED(heap) do { \
- (heap)->dbg_paused = 1; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
- (heap)->dbg_paused = 0; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused)
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
/*
* String cache should ideally be at duk_hthread level, but that would
* cause string finalization to slow down relative to the number of
@@ -6993,28 +8503,17 @@ struct duk_ljstate {
duk_tval value2; /* 2nd related value (type specific) */
};
-/*
- * Stringtable entry for fixed size stringtable
- */
-
-struct duk_strtab_entry {
-#if defined(DUK_USE_HEAPPTR16)
- /* A 16-bit listlen makes sense with 16-bit heap pointers: there
- * won't be space for 64k strings anyway.
- */
- duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
- union {
- duk_uint16_t strlist16;
- duk_uint16_t str16;
- } u;
-#else
- duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
- union {
- duk_hstring **strlist;
- duk_hstring *str;
- } u;
-#endif
-};
+#define DUK_ASSERT_LJSTATE_UNSET(heap) do { \
+ DUK_ASSERT(heap != NULL); \
+ DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \
+ DUK_ASSERT(heap->lj.iserror == 0); \
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \
+ } while (0)
+#define DUK_ASSERT_LJSTATE_SET(heap) do { \
+ DUK_ASSERT(heap != NULL); \
+ DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \
+ } while (0)
/*
* Main heap structure
@@ -7029,16 +8528,10 @@ struct duk_heap {
duk_free_function free_func;
/* Heap udata, used for allocator functions but also for other heap
- * level callbacks like pointer compression, etc.
+ * level callbacks like fatal function, pointer compression, etc.
*/
void *heap_udata;
- /* Precomputed pointers when using 16-bit heap pointer packing. */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t heapptr_null16;
- duk_uint16_t heapptr_deleted16;
-#endif
-
/* Fatal error handling, called e.g. when a longjmp() is needed but
* lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
* declared as "noreturn" because doing that for typedefs is a bit
@@ -7046,56 +8539,144 @@ struct duk_heap {
*/
duk_fatal_function fatal_func;
- /* allocated heap objects */
+ /* Main list of allocated heap objects. Objects are either here,
+ * in finalize_list waiting for processing, or in refzero_list
+ * temporarily while a DECREF refzero cascade finishes.
+ */
duk_heaphdr *heap_allocated;
- /* work list for objects whose refcounts are zero but which have not been
- * "finalized"; avoids recursive C calls when refcounts go to zero in a
- * chain of objects.
+ /* Temporary work list for freeing a cascade of objects when a DECREF
+ * (or DECREF_NORZ) encounters a zero refcount. Using a work list
+ * allows fixed C stack size when refcounts go to zero for a chain of
+ * objects. Outside of DECREF this is always a NULL because DECREF is
+ * processed without side effects (only memory free calls).
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_heaphdr *refzero_list;
- duk_heaphdr *refzero_list_tail;
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* mark-and-sweep control */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ /* Work list for objects to be finalized. */
+ duk_heaphdr *finalize_list;
+#if defined(DUK_USE_ASSERTIONS)
+ /* Object whose finalizer is executing right now (no nesting). */
+ duk_heaphdr *currently_finalizing;
+#endif
+#endif
+
+ /* Freelist for duk_activations and duk_catchers. */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ duk_activation *activation_free;
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ duk_catcher *catcher_free;
+#endif
+
+ /* Voluntary mark-and-sweep trigger counter. Intentionally signed
+ * because we continue decreasing the value when voluntary GC cannot
+ * run.
+ */
#if defined(DUK_USE_VOLUNTARY_GC)
- duk_int_t mark_and_sweep_trigger_counter;
+ duk_int_t ms_trigger_counter;
#endif
- duk_int_t mark_and_sweep_recursion_depth;
- /* mark-and-sweep flags automatically active (used for critical sections) */
- duk_small_uint_t mark_and_sweep_base_flags;
+ /* Mark-and-sweep recursion control: too deep recursion causes
+ * multi-pass processing to avoid growing C stack without bound.
+ */
+ duk_uint_t ms_recursion_depth;
- /* work list for objects to be finalized (by mark-and-sweep) */
- duk_heaphdr *finalize_list;
+ /* Mark-and-sweep flags automatically active (used for critical sections). */
+ duk_small_uint_t ms_base_flags;
+
+ /* Mark-and-sweep running flag. Prevents re-entry, and also causes
+ * refzero events to be ignored (= objects won't be queued to refzero_list).
+ */
+ duk_uint_t ms_running;
+
+ /* Mark-and-sweep prevent count, stacking. Used to avoid M&S side
+ * effects (besides finalizers which are controlled separately) such
+ * as compacting the string table or object property tables. This
+ * is also bumped when ms_running is set to prevent recursive re-entry.
+ * Can also be bumped when mark-and-sweep is not running.
+ */
+ duk_uint_t ms_prevent_count;
+
+ /* Finalizer processing prevent count, stacking. Bumped when finalizers
+ * are processed to prevent recursive finalizer processing (first call site
+ * processing finalizers handles all finalizers until the list is empty).
+ * Can also be bumped explicitly to prevent finalizer execution.
+ */
+ duk_uint_t pf_prevent_count;
+
+ /* When processing finalize_list, don't actually run finalizers but
+ * queue finalizable objects back to heap_allocated as is. This is
+ * used during heap destruction to deal with finalizers that keep
+ * on creating more finalizable garbage.
+ */
+ duk_uint_t pf_skip_finalizers;
+
+#if defined(DUK_USE_ASSERTIONS)
+ /* Set when we're in a critical path where an error throw would cause
+ * e.g. sandboxing/protected call violations or state corruption. This
+ * is just used for asserts.
+ */
+ duk_bool_t error_not_allowed;
#endif
- /* longjmp state */
- duk_ljstate lj;
+#if defined(DUK_USE_ASSERTIONS)
+ /* Set when heap is still being initialized, helps with writing
+ * some assertions.
+ */
+ duk_bool_t heap_initializing;
+#endif
- /* marker for detecting internal "double faults", see duk_error_throw.c */
- duk_bool_t handling_error;
+ /* Marker for detecting internal "double faults", errors thrown when
+ * we're trying to create an error object, see duk_error_throw.c.
+ */
+ duk_bool_t creating_error;
- /* heap thread, used internally and for finalization */
+ /* Marker for indicating we're calling a user error augmentation
+ * (errCreate/errThrow) function. Errors created/thrown during
+ * such a call are not augmented.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ duk_bool_t augmenting_error;
+#endif
+
+ /* Longjmp state. */
+ duk_ljstate lj;
+
+ /* Heap thread, used internally and for finalization. */
duk_hthread *heap_thread;
- /* current thread */
- duk_hthread *curr_thread; /* currently running thread */
+ /* Current running thread. */
+ duk_hthread *curr_thread;
- /* heap level "stash" object (e.g., various reachability roots) */
+ /* Heap level "stash" object (e.g., various reachability roots). */
duk_hobject *heap_object;
/* duk_handle_call / duk_handle_safe_call recursion depth limiting */
duk_int_t call_recursion_depth;
duk_int_t call_recursion_limit;
- /* mix-in value for computing string hashes; should be reasonably unpredictable */
+ /* Mix-in value for computing string hashes; should be reasonably unpredictable. */
duk_uint32_t hash_seed;
- /* rnd_state for duk_util_tinyrandom.c */
- duk_uint32_t rnd_state;
+ /* Random number state for duk_util_tinyrandom.c. */
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
+#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
+ duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */
+#else
+ duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */
+#endif
+#endif
+
+ /* Counter for unique local symbol creation. */
+ /* XXX: When 64-bit types are available, it would be more efficient to
+ * use a duk_uint64_t at least for incrementing but maybe also for
+ * string formatting in the Symbol constructor.
+ */
+ duk_uint32_t sym_counter[2];
/* For manual debugging: instruction count based on executor and
* interrupt counter book-keeping. Inspect debug logs to see how
@@ -7106,10 +8687,9 @@ struct duk_heap {
duk_int_t inst_count_interrupt;
#endif
- /* debugger */
-
+ /* Debugger state. */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
+ /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */
duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
duk_debug_write_function dbg_write_cb; /* required */
duk_debug_peek_function dbg_peek_cb;
@@ -7119,55 +8699,51 @@ struct duk_heap {
duk_debug_detached_function dbg_detached_cb;
void *dbg_udata;
- /* debugger state, only relevant when attached */
+ /* The following are only relevant when debugger is attached. */
duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
- duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
- duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
- duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
- duk_size_t dbg_step_csindex; /* callstack index */
- duk_uint32_t dbg_step_startline; /* starting line number */
+ duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */
+ duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */
+ duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */
duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
duk_small_uint_t dbg_breakpoint_count;
duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
/* XXX: make active breakpoints actual copies instead of pointers? */
/* These are for rate limiting Status notifications and transport peeking. */
- duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
- duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
+ duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
+ duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
/* Used to support single-byte stream lookahead. */
duk_bool_t dbg_have_next_byte;
duk_uint8_t dbg_next_byte;
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */
#endif
- /* string intern table (weak refs) */
-#if defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
+ /* String intern table (weak refs). */
+#if defined(DUK_USE_STRTAB_PTRCOMP)
duk_uint16_t *strtable16;
#else
duk_hstring **strtable;
#endif
- duk_uint32_t st_size; /* alloc size in elements */
- duk_uint32_t st_used; /* used elements (includes DELETED) */
+ duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */
+ duk_uint32_t st_size; /* stringtable size */
+#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
+ duk_uint32_t st_count; /* string count for resize load factor checks */
#endif
+ duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */
- /* XXX: static alloc is OK until separate chaining stringtable
- * resizing is implemented.
- */
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
-#endif
-
- /* string access cache (codepoint offset -> byte offset) for fast string
+ /* String access cache (codepoint offset -> byte offset) for fast string
* character looping; 'weak' reference which needs special handling in GC.
*/
duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
- /* built-in strings */
+ /* Built-in strings. */
#if defined(DUK_USE_ROM_STRINGS)
/* No field needed when strings are in ROM. */
#else
@@ -7177,6 +8753,51 @@ struct duk_heap {
duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
#endif
#endif
+
+ /* Stats. */
+#if defined(DUK_USE_DEBUG)
+ duk_int_t stats_exec_opcodes;
+ duk_int_t stats_exec_interrupt;
+ duk_int_t stats_exec_throw;
+ duk_int_t stats_call_all;
+ duk_int_t stats_call_tailcall;
+ duk_int_t stats_call_ecmatoecma;
+ duk_int_t stats_safecall_all;
+ duk_int_t stats_safecall_nothrow;
+ duk_int_t stats_safecall_throw;
+ duk_int_t stats_ms_try_count;
+ duk_int_t stats_ms_skip_count;
+ duk_int_t stats_ms_emergency_count;
+ duk_int_t stats_strtab_intern_hit;
+ duk_int_t stats_strtab_intern_miss;
+ duk_int_t stats_strtab_resize_check;
+ duk_int_t stats_strtab_resize_grow;
+ duk_int_t stats_strtab_resize_shrink;
+ duk_int_t stats_object_realloc_props;
+ duk_int_t stats_object_abandon_array;
+ duk_int_t stats_getownpropdesc_count;
+ duk_int_t stats_getownpropdesc_hit;
+ duk_int_t stats_getownpropdesc_miss;
+ duk_int_t stats_getpropdesc_count;
+ duk_int_t stats_getpropdesc_hit;
+ duk_int_t stats_getpropdesc_miss;
+ duk_int_t stats_getprop_all;
+ duk_int_t stats_getprop_arrayidx;
+ duk_int_t stats_getprop_bufobjidx;
+ duk_int_t stats_getprop_bufferidx;
+ duk_int_t stats_getprop_bufferlen;
+ duk_int_t stats_getprop_stringidx;
+ duk_int_t stats_getprop_stringlen;
+ duk_int_t stats_getprop_proxy;
+ duk_int_t stats_getprop_arguments;
+ duk_int_t stats_putprop_all;
+ duk_int_t stats_putprop_arrayidx;
+ duk_int_t stats_putprop_bufobjidx;
+ duk_int_t stats_putprop_bufferidx;
+ duk_int_t stats_putprop_proxy;
+ duk_int_t stats_getvar_all;
+ duk_int_t stats_putvar_all;
+#endif
};
/*
@@ -7190,41 +8811,40 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
void *heap_udata,
duk_fatal_function fatal_func);
DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
-DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h);
-DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
+#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
+DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
+#endif
+#if defined(DUK_USE_ASSERTIONS)
+DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr);
#endif
#if defined(DUK_USE_INTERRUPT_COUNTER)
DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
#endif
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
-#endif
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
-DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h);
#endif
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev);
+DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap);
+DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap);
#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
+DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap);
#endif
-
DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
@@ -7236,44 +8856,26 @@ DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
+DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size);
+DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
-#ifdef DUK_USE_REFERENCE_COUNTING
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
-#endif
-DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
-#endif
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
-#endif
-DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
-#else
-/* no refcounting */
-#endif
+DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
-#if defined(DUK_USE_MARK_AND_SWEEP)
-DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
-#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
+DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
#endif /* DUK_HEAP_H_INCLUDED */
-#line 1 "duk_debugger.h"
-#ifndef DUK_DEBUGGER_H_INCLUDED
+/* #include duk_debugger.h */
+#if !defined(DUK_DEBUGGER_H_INCLUDED)
#define DUK_DEBUGGER_H_INCLUDED
/* Debugger protocol version is defined in the public API header. */
@@ -7314,9 +8916,9 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
/* Commands and notifys initiated by Duktape. */
#define DUK_DBG_CMD_STATUS 0x01
-#define DUK_DBG_CMD_PRINT 0x02
-#define DUK_DBG_CMD_ALERT 0x03
-#define DUK_DBG_CMD_LOG 0x04
+#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */
+#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */
+#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */
#define DUK_DBG_CMD_THROW 0x05
#define DUK_DBG_CMD_DETACHING 0x06
#define DUK_DBG_CMD_APPNOTIFY 0x07
@@ -7348,7 +8950,8 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
* The remaining flags are specific to the debugger.
*/
-#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8)
+#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8)
+#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9)
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
@@ -7414,10 +9017,16 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bo
DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
-#endif
+
+DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
+DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
#endif /* DUK_DEBUGGER_H_INCLUDED */
-#line 1 "duk_debug.h"
+/* #include duk_debug.h */
/*
* Debugging macros, DUK_DPRINT() and its variants in particular.
*
@@ -7440,24 +9049,24 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* works poorly with threading.
*/
-#ifndef DUK_DEBUG_H_INCLUDED
+#if !defined(DUK_DEBUG_H_INCLUDED)
#define DUK_DEBUG_H_INCLUDED
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
-#if defined(DUK_USE_DPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_D(x) x
#else
#define DUK_D(x) do { } while (0) /* omit */
#endif
-#if defined(DUK_USE_DDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DD(x) x
#else
#define DUK_DD(x) do { } while (0) /* omit */
#endif
-#if defined(DUK_USE_DDDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDD(x) x
#else
#define DUK_DDD(x) do { } while (0) /* omit */
@@ -7467,26 +9076,26 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* Exposed debug macros: debugging enabled
*/
-#define DUK_LEVEL_DEBUG 1
-#define DUK_LEVEL_DDEBUG 2
-#define DUK_LEVEL_DDDEBUG 3
-
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
* possible compile time, but waste some space with shared function names.
*/
-#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
+#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
+#else
+#define DUK_DPRINT(...)
+#endif
-#ifdef DUK_USE_DDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
#else
#define DUK_DDPRINT(...)
#endif
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
#else
#define DUK_DDDPRINT(...)
@@ -7496,11 +9105,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
#define DUK__DEBUG_STASH(lev) \
(void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
- duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
- (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \
- duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
+ (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
+ (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
(void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
- duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
+ (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
(void) (duk_debug_level_stash = (lev))
/* Without variadic macros resort to comma expression trickery to handle debug
@@ -7509,19 +9117,19 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* statement from the compiler.
*/
-#ifdef DUK_USE_DPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
#endif
-#ifdef DUK_USE_DDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDPRINT 0 && /* args */
#endif
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDDPRINT 0 && /* args */
@@ -7539,7 +9147,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
#define DUK_DD(x) do { } while (0) /* omit */
#define DUK_DDD(x) do { } while (0) /* omit */
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
#define DUK_DPRINT(...)
#define DUK_DDPRINT(...)
@@ -7559,7 +9167,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* Structs
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer {
duk_uint8_t *buffer;
duk_size_t length;
@@ -7572,23 +9180,23 @@ struct duk_fixedbuffer {
* Prototypes
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
#if 0 /*unused*/
DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
#endif
DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
-#ifdef DUK_USE_VARIADIC_MACROS
-DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
+#if defined(DUK_USE_VARIADIC_MACROS)
+DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
#else /* DUK_USE_VARIADIC_MACROS */
/* parameter passing, not thread safe */
#define DUK_DEBUG_STASH_SIZE 128
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
+DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
+DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
#endif
DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
#endif /* DUK_USE_VARIADIC_MACROS */
@@ -7603,22 +9211,23 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif /* DUK_USE_DEBUG */
#endif /* DUK_DEBUG_H_INCLUDED */
-#line 1 "duk_error.h"
+/* #include duk_error.h */
/*
* Error handling macros, assertion macro, error codes.
*
- * There are three level of 'errors':
+ * There are three types of 'errors':
*
- * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
- * 2. Fatal errors, relative to a heap, cause fatal handler to be called.
- * 3. Panic errors, unrelated to a heap and cause a process exit.
+ * 1. Ordinary errors relative to a thread, cause a longjmp, catchable.
+ * 2. Fatal errors relative to a heap, cause fatal handler to be called.
+ * 3. Fatal errors without context, cause the default (not heap specific)
+ * fatal handler to be called.
*
- * Panics are used by the default fatal error handler and by debug code
- * such as assertions. By providing a proper fatal error handler, user
- * code can avoid panics in non-debug builds.
+ * Fatal errors without context are used by debug code such as assertions.
+ * By providing a fatal error handler for a Duktape heap, user code can
+ * avoid fatal errors without context in non-debug builds.
*/
-#ifndef DUK_ERROR_H_INCLUDED
+#if !defined(DUK_ERROR_H_INCLUDED)
#define DUK_ERROR_H_INCLUDED
/*
@@ -7733,66 +9342,247 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
- * Fatal error
+ * Fatal error without context
*
- * There are no fatal error macros at the moment. There are so few call
- * sites that the fatal error handler is called directly.
+ * The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
*/
+#define DUK_FATAL_WITHOUT_CONTEXT(msg) \
+ duk_default_fatal_handler(NULL, (msg))
+
/*
- * Panic error
+ * Error throwing helpers
*
- * Panic errors are not relative to either a heap or a thread, and cause
- * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER,
- * DUK_PANIC() calls a helper which prints out the error and causes a process
- * exit.
+ * The goal is to provide verbose and configurable error messages. Call
+ * sites should be clean in source code and compile to a small footprint.
+ * Small footprint is also useful for performance because small cold paths
+ * reduce code cache pressure. Adding macros here only makes sense if there
+ * are enough call sites to get concrete benefits.
*
- * The user can override the macro to provide custom handling. A macro is
- * used to allow the user to have inline panic handling if desired (without
- * causing a potentially risky function call).
+ * DUK_ERROR_xxx() macros are generic and can be used anywhere.
*
- * Panics are only used in debug code such as assertions, and by the default
- * fatal error handler.
+ * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
+ * the "return DUK_RET_xxx;" shorthand is available for low memory targets.
+ * The DUK_DCERROR_xxx() macros always either throw or perform a
+ * 'return DUK_RET_xxx' from the calling function.
*/
-#if defined(DUK_USE_PANIC_HANDLER)
-/* already defined, good */
-#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg))
-#else
-#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg))
-#endif /* DUK_USE_PANIC_HANDLER */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+/* Verbose errors with key/value summaries (non-paranoid) or without key/value
+ * summaries (paranoid, for some security sensitive environments), the paranoid
+ * vs. non-paranoid distinction affects only a few specific errors.
+ */
+#if defined(DUK_USE_PARANOID_ERRORS)
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
+ } while (0)
+#else /* DUK_USE_PARANOID_ERRORS */
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
+ } while (0)
+#endif /* DUK_USE_PARANOID_ERRORS */
+
+#define DUK_ERROR_INTERNAL(thr) do { \
+ duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_ERROR_INTERNAL((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_ALLOC_FAILED(thr) do { \
+ duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_ERROR_UNSUPPORTED(thr) do { \
+ DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
+ } while (0)
+#define DUK_ERROR_ERROR(thr,msg) do { \
+ duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
+ duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
+ } while (0)
+#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
+ duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE(thr,msg) do { \
+ duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
+ } while (0)
+#define DUK_ERROR_EVAL(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_REFERENCE(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_SYNTAX(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
+ duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
+ DUK_ERROR_TYPE_INVALID_STATE((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
+ } while (0)
+#define DUK_ERROR_TYPE(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_URI(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
+ } while (0)
+#else /* DUK_USE_VERBOSE_ERRORS */
+/* Non-verbose errors for low memory targets: no file, line, or message. */
+
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+
+#define DUK_ERROR_INTERNAL(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_ERROR; \
+ } while (0)
+#define DUK_ERROR_ALLOC_FAILED(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_UNSUPPORTED(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_ERROR(thr,msg) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE(thr,msg) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_EVAL(thr,msg) do { \
+ duk_err_eval((thr)); \
+ } while (0)
+#define DUK_ERROR_REFERENCE(thr,msg) do { \
+ duk_err_reference((thr)); \
+ } while (0)
+#define DUK_ERROR_SYNTAX(thr,msg) do { \
+ duk_err_syntax((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_TYPE_ERROR; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_TYPE_ERROR; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE(thr,msg) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_URI(thr,msg) do { \
+ duk_err_uri((thr)); \
+ } while (0)
+#endif /* DUK_USE_VERBOSE_ERRORS */
/*
- * Assert macro: failure causes panic.
+ * Assert macro: failure causes a fatal error.
+ *
+ * NOTE: since the assert macro doesn't take a heap/context argument, there's
+ * no way to look up a heap/context specific fatal error handler which may have
+ * been given by the application. Instead, assertion failures always use the
+ * internal default fatal error handler; it can be replaced via duk_config.h
+ * and then applies to all Duktape heaps.
*/
#if defined(DUK_USE_ASSERTIONS)
-/* the message should be a compile time constant without formatting (less risk);
+/* The message should be a compile time constant without formatting (less risk);
* we don't care about assertion text size because they're not used in production
* builds.
*/
#define DUK_ASSERT(x) do { \
if (!(x)) { \
- DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
+ DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
} \
} while (0)
-/* Assertion compatible inside a comma expression, evaluates to void.
- * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have
- * a statement block.
- */
-#if defined(DUK_USE_PANIC_HANDLER)
-/* XXX: resolve macro definition issue or call through a helper function? */
-#define DUK_ASSERT_EXPR(x) ((void) 0)
-#else
+/* Assertion compatible inside a comma expression, evaluates to void. */
#define DUK_ASSERT_EXPR(x) \
- ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
+ ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
-#endif
#else /* DUK_USE_ASSERTIONS */
@@ -7837,6 +9627,22 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
#endif
+#define DUK_ASSERT_VS_SPACE(thr) \
+ DUK_ASSERT(thr->valstack_top < thr->valstack_end)
+
+/*
+ * Helper to initialize a memory area (e.g. struct) with garbage when
+ * assertions enabled.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
+ DUK_MEMSET((void *) (ptr), 0x5a, size); \
+ } while (0)
+#else
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
+#endif
+
/*
* Helper for valstack space
*
@@ -7858,126 +9664,6 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif
/*
- * Error throwing helpers
- *
- * The goal is to provide verbose and configurable error messages. Call
- * sites should be clean in source code and compile to a small footprint.
- * Small footprint is also useful for performance because small cold paths
- * reduce code cache pressure. Adding macros here only makes sense if there
- * are enough call sites to get concrete benefits.
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-/* Verbose errors with key/value summaries (non-paranoid) or without key/value
- * summaries (paranoid, for some security sensitive environments), the paranoid
- * vs. non-paranoid distinction affects only a few specific errors.
- */
-#if defined(DUK_USE_PARANOID_ERRORS)
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#else /* DUK_USE_PARANOID_ERRORS */
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#endif /* DUK_USE_PARANOID_ERRORS */
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \
- } while (0)
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#endif
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \
- } while (0)
-/* DUK_ERR_ASSERTION_ERROR: no macros needed */
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */
-/* DUK_ERR_ERROR: no macros needed */
-/* DUK_ERR_EVAL: no macros needed */
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_REFERENCE_ERROR: no macros needed */
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
- } while (0)
-/* DUK_ERR_URI_ERROR: no macros needed */
-#else /* DUK_USE_VERBOSE_ERRORS */
-/* Non-verbose errors for low memory targets: no file, line, or message. */
-
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_type((thr)); \
- } while (0)
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr)); \
- } while (0)
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- duk_err_syntax((thr)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- duk_err_type((thr)); \
- } while (0)
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
-/*
* Prototypes
*/
@@ -7996,8 +9682,11 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, d
DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
+#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */
+#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */
+
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline);
+DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags);
#endif
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
@@ -8005,50 +9694,47 @@ DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
#else
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
#else /* DUK_VERBOSE_ERRORS */
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
#endif /* DUK_VERBOSE_ERRORS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg));
+DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr);
#endif
-DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
-
DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
#endif /* DUK_ERROR_H_INCLUDED */
-#line 1 "duk_unicode.h"
+/* #include duk_unicode.h */
/*
* Unicode helpers
*/
-#ifndef DUK_UNICODE_H_INCLUDED
+#if !defined(DUK_UNICODE_H_INCLUDED)
#define DUK_UNICODE_H_INCLUDED
/*
@@ -8212,24 +9898,33 @@ DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, d
#define DUK_ASC_DEL 0x7f
/*
+ * Miscellaneous
+ */
+
+/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase
+ * to lowercase.
+ */
+#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20)
+
+/*
* Unicode tables
*/
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noa[791];
+extern const duk_uint8_t duk_unicode_ids_noa[1036];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noabmp[611];
+extern const duk_uint8_t duk_unicode_ids_noabmp[625];
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
@@ -8243,26 +9938,26 @@ extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357];
#endif
/*
* Automatically generated by extract_caseconv.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
-extern const duk_uint8_t duk_unicode_caseconv_lc[616];
+extern const duk_uint8_t duk_unicode_caseconv_uc[1386];
+extern const duk_uint8_t duk_unicode_caseconv_lc[680];
#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
/*
@@ -8272,6 +9967,17 @@ extern const duk_uint8_t duk_unicode_caseconv_lc[616];
extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
#endif
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/*
+ * Automatically generated by extract_caseconv.py, do not edit!
+ */
+
+#define DUK_CANON_BITMAP_BLKSIZE 32
+#define DUK_CANON_BITMAP_BLKSHIFT 5
+#define DUK_CANON_BITMAP_BLKMASK 31
+extern const duk_uint8_t duk_unicode_re_canon_bitmap[256];
+#endif
+
/*
* Extern
*/
@@ -8307,23 +10013,25 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
+#endif
#endif /* DUK_UNICODE_H_INCLUDED */
-#line 1 "duk_json.h"
+/* #include duk_json.h */
/*
* Defines for JSON, especially duk_bi_json.c.
*/
-#ifndef DUK_JSON_H_INCLUDED
+#if !defined(DUK_JSON_H_INCLUDED)
#define DUK_JSON_H_INCLUDED
/* Encoding/decoding flags */
-#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
-#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
-#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
-#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
+#define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */
+#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */
+#define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */
+#define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */
/* How much stack to require on entry to object/array encode */
#define DUK_JSON_ENC_REQSTACK 32
@@ -8350,8 +10058,8 @@ typedef struct {
duk_small_uint_t flag_ext_compatible;
duk_small_uint_t flag_ext_custom_or_compatible;
#endif
- duk_int_t recursion_depth;
- duk_int_t recursion_limit;
+ duk_uint_t recursion_depth;
+ duk_uint_t recursion_limit;
duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
duk_small_uint_t stridx_custom_undefined;
@@ -8380,28 +10088,30 @@ typedef struct {
} duk_json_dec_ctx;
#endif /* DUK_JSON_H_INCLUDED */
-#line 1 "duk_js.h"
+/* #include duk_js.h */
/*
* Ecmascript execution, support primitives.
*/
-#ifndef DUK_JS_H_INCLUDED
+#if !defined(DUK_JS_H_INCLUDED)
#define DUK_JS_H_INCLUDED
-/* Flags for call handling. */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
+/* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */
+#define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */
+#define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */
+#define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */
+#define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */
+#define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */
+#define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */
+#define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */
/* Flags for duk_js_equals_helper(). */
-#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
-#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
+#define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */
+#define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */
/* Flags for duk_js_compare_helper(). */
-#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */
-#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */
+#define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */
+#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */
/* conversions, coercions, comparison, etc */
DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
@@ -8411,18 +10121,25 @@ DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx);
-DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
-DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen);
+#if !defined(DUK_USE_HSTRING_ARRIDX)
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h);
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h);
+#endif
+DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2);
DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
#if 0 /* unused */
DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
-DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
+DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
+
+/* arithmetic */
+DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y);
+DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y);
#define duk_js_equals(thr,tv_x,tv_y) \
duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
@@ -8459,56 +10176,58 @@ DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
#endif
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
-DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl);
+DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl);
DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
-DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
-DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
-DUK_INTERNAL_DECL
-void duk_js_push_closure(duk_hthread *thr,
- duk_hcompiledfunction *fun_temp,
- duk_hobject *outer_var_env,
- duk_hobject *outer_lex_env,
- duk_bool_t add_auto_proto);
+DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env);
+DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff);
+DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr,
+ duk_hcompfunc *fun_temp,
+ duk_hobject *outer_var_env,
+ duk_hobject *outer_lex_env,
+ duk_bool_t add_auto_proto);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
-DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
-DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
-DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
+DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant);
+#if defined(DUK_USE_VERBOSE_ERRORS)
+DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key);
+#endif
/* bytecode execution */
DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
#endif /* DUK_JS_H_INCLUDED */
-#line 1 "duk_numconv.h"
-#ifndef DUK_NUMCONV_H_INCLUDED
-#define DUK_NUMCONV_H_INCLUDED
-
+/* #include duk_numconv.h */
/*
* Number-to-string conversion. The semantics of these is very tightly
* bound with the Ecmascript semantics required for call sites.
*/
+#if !defined(DUK_NUMCONV_H_INCLUDED)
+#define DUK_NUMCONV_H_INCLUDED
+
/* Output a specified number of digits instead of using the shortest
* form. Used for toPrecision() and toFixed().
*/
-#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
+#define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0)
/* Force exponential format. Used for toExponential(). */
-#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
+#define DUK_N2S_FLAG_FORCE_EXP (1U << 1)
/* If number would need zero padding (for whole number part), use
* exponential format instead. E.g. if input number is 12300, 3
* digits are generated ("123"), output "1.23e+4" instead of "12300".
* Used for toPrecision().
*/
-#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
+#define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2)
/* Digit count indicates number of fractions (i.e. an absolute
* digit index instead of a relative one). Used together with
* DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
*/
-#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
+#define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3)
/*
* String-to-number conversion
@@ -8521,152 +10240,166 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
#define DUK_S2N_MAX_EXPONENT 1000000000
/* Trim white space (= allow leading and trailing whitespace) */
-#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
+#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0)
/* Allow exponent */
-#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
+#define DUK_S2N_FLAG_ALLOW_EXP (1U << 1)
/* Allow trailing garbage (e.g. treat "123foo" as "123) */
-#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
+#define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2)
/* Allow leading plus sign */
-#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
+#define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3)
/* Allow leading minus sign */
-#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
+#define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4)
/* Allow 'Infinity' */
-#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
+#define DUK_S2N_FLAG_ALLOW_INF (1U << 5)
/* Allow fraction part */
-#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
+#define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6)
/* Allow naked fraction (e.g. ".123") */
-#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
+#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7)
/* Allow empty fraction (e.g. "123.") */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8)
/* Allow empty string to be interpreted as 0 */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9)
/* Allow leading zeroes (e.g. "0123" -> "123") */
-#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
+#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10)
/* Allow automatic detection of hex base ("0x" or "0X" prefix),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
+#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11)
+
+/* Allow automatic detection of legacy octal base ("0n"),
+ * overrides radix argument and forces integer mode.
+ */
+#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12)
+
+/* Allow automatic detection of ES2015 octal base ("0o123"),
+ * overrides radix argument and forces integer mode.
+ */
+#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13)
-/* Allow automatic detection of octal base, overrides radix
- * argument and forces integer mode.
+/* Allow automatic detection of ES2015 binary base ("0b10001"),
+ * overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12)
+#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14)
/*
* Prototypes
*/
-DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags);
#endif /* DUK_NUMCONV_H_INCLUDED */
-#line 1 "duk_bi_protos.h"
+/* #include duk_bi_protos.h */
/*
* Prototypes for built-in functions not automatically covered by the
* header declarations emitted by genbuiltins.py.
*/
-#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
+#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
#define DUK_BUILTIN_PROTOS_H_INCLUDED
-/* Buffer size needed for duk_bi_date_format_timeval().
+/* Buffer size needed for ISO 8601 formatting.
* Accurate value is 32 + 1 for NUL termination:
* >>> len('+123456-01-23T12:34:56.123+12:34')
* 32
* Include additional space to be safe.
*/
-#define DUK_BI_DATE_ISO8601_BUFSIZE 48
-
-/* Maximum length of CommonJS module identifier to resolve. Length includes
- * both current module ID, requested (possibly relative) module ID, and a
- * slash in between.
- */
-#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256
+#define DUK_BI_DATE_ISO8601_BUFSIZE 40
/* Helpers exposed for internal use */
DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
/* Built-in providers */
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
#endif
#if defined(DUK_USE_DATE_NOW_TIME)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
#endif
#if defined(DUK_USE_DATE_NOW_WINDOWS)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
+#endif
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
#endif
-#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
+#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
#endif
#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
#endif
+#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d);
+#endif
#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+#endif
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
+#endif
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
#endif
DUK_INTERNAL_DECL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags);
DUK_INTERNAL_DECL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags);
+DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
+#endif
+
#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
-#line 1 "duk_selftest.h"
+/* #include duk_selftest.h */
/*
* Selftest code
*/
-#ifndef DUK_SELFTEST_H_INCLUDED
+#if !defined(DUK_SELFTEST_H_INCLUDED)
#define DUK_SELFTEST_H_INCLUDED
#if defined(DUK_USE_SELF_TESTS)
-DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
+DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *udata);
#endif
#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 78 "duk_internal.h"
#endif /* DUK_INTERNAL_H_INCLUDED */
-#line 1 "duk_replacements.c"
-/*
- * Replacements for missing platform functions.
- *
- * Unlike the originals, fpclassify() and signbit() replacements don't
- * work on any floating point types, only doubles. The C typing here
- * mimics the standard prototypes.
- */
-
-/* include removed: duk_internal.h */
#if defined(DUK_USE_COMPUTED_NAN)
DUK_INTERNAL double duk_computed_nan;
@@ -8740,130 +10473,13 @@ DUK_INTERNAL int duk_repl_isinf(double x) {
return (c == DUK_FP_INFINITE);
}
#endif
-#line 1 "duk_strings.c"
-/*
- * Shared error message strings
- *
- * To minimize code footprint, try to share error messages inside Duktape
- * code. Modern compilers will do this automatically anyway, this is mostly
- * for older compilers.
- */
-
-/* include removed: duk_internal.h */
-
-/* Mostly API and built-in method related */
-DUK_INTERNAL const char *duk_str_internal_error = "internal error";
-DUK_INTERNAL const char *duk_str_invalid_count = "invalid count";
-DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args";
-DUK_INTERNAL const char *duk_str_not_constructable = "not constructable";
-DUK_INTERNAL const char *duk_str_not_callable = "not callable";
-DUK_INTERNAL const char *duk_str_not_extensible = "not extensible";
-DUK_INTERNAL const char *duk_str_not_writable = "not writable";
-DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
-
-DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
-DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
-DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
-DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
-DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
-DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
-DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
-DUK_INTERNAL const char *duk_str_string_too_long = "string too long";
-DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long";
-DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long";
-DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed";
-DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries";
-DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type";
-DUK_INTERNAL const char *duk_str_encode_failed = "encode failed";
-DUK_INTERNAL const char *duk_str_decode_failed = "decode failed";
-DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode";
-DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long";
-DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented";
-DUK_INTERNAL const char *duk_str_unsupported = "unsupported";
-DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G";
-
-/* JSON */
-DUK_INTERNAL const char *duk_str_fmt_ptr = "%p";
-DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)";
-DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit";
-DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit";
-DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input";
-
-/* Object property access */
-DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked";
-DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value";
-DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'";
-DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected";
-DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length";
-DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed";
-DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable";
-DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined";
-DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property";
-DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor";
-DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual";
-
-/* Compiler */
-DUK_INTERNAL const char *duk_str_parse_error = "parse error";
-DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label";
-DUK_INTERNAL const char *duk_str_invalid_label = "invalid label";
-DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal";
-DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal";
-DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration";
-DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier";
-DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression";
-DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue";
-DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier";
-DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed";
-DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement";
-DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement";
-DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label";
-DUK_INTERNAL const char *duk_str_invalid_return = "invalid return";
-DUK_INTERNAL const char *duk_str_invalid_try = "invalid try";
-DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw";
-DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode";
-DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed";
-DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement";
-DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name";
-DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name";
-DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name";
-DUK_INTERNAL const char *duk_str_func_name_required = "function name required";
-
-/* Regexp */
-DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom";
-DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)";
-DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies";
-DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis";
-DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern";
-DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp";
-DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags";
-DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)";
-
-/* Limits */
-DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit";
-DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit";
-DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit";
-DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit";
-DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit";
-DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit";
-DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit";
-DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit";
-DUK_INTERNAL const char *duk_str_reg_limit = "register limit";
-DUK_INTERNAL const char *duk_str_temp_limit = "temp limit";
-DUK_INTERNAL const char *duk_str_const_limit = "const limit";
-DUK_INTERNAL const char *duk_str_func_limit = "function limit";
-DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit";
-
-/* Misc */
-#line 1 "duk_debug_macros.c"
/*
* Debugging macro calls.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
/*
* Debugging enabled
@@ -8873,91 +10489,34 @@ DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit
#include <stdlib.h>
#include <stdarg.h>
-#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
-DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE];
-
-DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return "D";
- case DUK_LEVEL_DDEBUG:
- return "DD";
- case DUK_LEVEL_DDDEBUG:
- return "DDD";
- }
- return "???";
-}
-
-#ifdef DUK_USE_DPRINT_COLORS
-
-/* http://en.wikipedia.org/wiki/ANSI_escape_code */
-#define DUK__TERM_REVERSE "\x1b[7m"
-#define DUK__TERM_BRIGHT "\x1b[1m"
-#define DUK__TERM_RESET "\x1b[0m"
-#define DUK__TERM_BLUE "\x1b[34m"
-#define DUK__TERM_RED "\x1b[31m"
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RED;
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
- case DUK_LEVEL_DDEBUG:
- return (const char *) (DUK__TERM_RESET);
- case DUK_LEVEL_DDDEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
- }
- return (const char *) DUK__TERM_RESET;
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RESET;
-}
-
-#else
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
+#if !defined(DUK_USE_DEBUG_WRITE)
+#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
+#endif
-#endif /* DUK_USE_DPRINT_COLORS */
+#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
-DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
+DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
va_list ap;
+ long arg_level;
+ const char *arg_file;
+ long arg_line;
+ const char *arg_func;
+ const char *arg_msg;
+ char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
+ DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(level),
- (const char *) file,
- (long) line,
- (const char *) func,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
+ arg_level = (long) level;
+ arg_file = (const char *) file;
+ arg_line = (long) line;
+ arg_func = (const char *) func;
+ arg_msg = (const char *) buf;
+ DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
@@ -8965,29 +10524,30 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int
#else /* DUK_USE_VARIADIC_MACROS */
DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
+DUK_INTERNAL duk_int_t duk_debug_line_stash;
DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL duk_small_int_t duk_debug_level_stash;
+DUK_INTERNAL duk_int_t duk_debug_level_stash;
DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
va_list ap;
- duk_small_int_t level = duk_debug_level_stash;
+ long arg_level;
+ const char *arg_file;
+ long arg_line;
+ const char *arg_func;
+ const char *arg_msg;
+ char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
+ DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(duk_debug_level_stash),
- (const char *) duk_debug_file_stash,
- (const char *) duk_debug_line_stash,
- (const char *) duk_debug_func_stash,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
+ arg_level = (long) duk_debug_level_stash;
+ arg_file = (const char *) duk_debug_file_stash;
+ arg_line = (long) duk_debug_line_stash;
+ arg_func = (const char *) duk_debug_func_stash;
+ arg_msg = (const char *) buf;
+ DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
@@ -9001,75 +10561,77 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
*/
#endif /* DUK_USE_DEBUG */
-#line 1 "duk_builtins.c"
+
+/* automatic undefs */
+#undef DUK__DEBUG_BUFSIZE
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/
+#else
+#define DUK__REFCINIT(refc) (refc) /*actual*/
+#endif
#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
-DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = {
-79,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73,
-5,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150,
-64,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117,
-128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118,
-168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196,
-123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219,
-160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217,
-116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236,
-254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4,
-11,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13,
-153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64,
-186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132,
-75,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119,
-169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156,
-189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66,
-208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233,
-124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46,
-114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72,
-49,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245,
-191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223,
-93,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107,
-33,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194,
-72,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58,
-226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84,
-44,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6,
-89,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14,
-38,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73,
-214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24,
-52,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56,
-153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109,
-79,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208,
-68,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239,
-162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153,
-119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9,
-24,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218,
-140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136,
-44,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133,
-161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11,
-244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253,
-111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75,
-244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127,
-235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64,
-156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226,
-17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213,
-33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72,
-179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182,
-58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104,
-228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24,
-245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20,
-84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96,
+DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = {
+79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
+35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
+129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
+140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
+193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
+196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
+196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
+229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
+183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
+184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
+178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
+32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
+113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
+119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
+101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
+226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
+52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
+67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
+249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
+186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
+32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
+231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166,
+233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76,
+105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166,
+1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194,
+32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227,
+73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176,
+15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4,
+72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133,
+67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204,
+16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132,
+251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52,
+187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159,
+125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162,
+249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132,
+64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57,
+80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20,
+109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6,
+158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9,
+72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71,
+146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204,
+145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83,
+32,204,250,5,104,17,165,48,77,2,46,16,69,140,
};
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_OBJECTS */
-/* native functions: 149 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
+/* native functions: 176 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
+ NULL,
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
@@ -9091,8 +10653,6 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_boolean_constructor,
duk_bi_boolean_prototype_tostring_shared,
duk_bi_buffer_compare_shared,
- duk_bi_buffer_constructor,
- duk_bi_buffer_prototype_tostring_shared,
duk_bi_buffer_readfield,
duk_bi_buffer_slice_shared,
duk_bi_buffer_writefield,
@@ -9139,20 +10699,20 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_global_object_is_nan,
duk_bi_global_object_parse_float,
duk_bi_global_object_parse_int,
- duk_bi_global_object_print_helper,
- duk_bi_global_object_require,
duk_bi_global_object_unescape,
duk_bi_json_object_parse,
duk_bi_json_object_stringify,
- duk_bi_logger_constructor,
- duk_bi_logger_prototype_fmt,
- duk_bi_logger_prototype_log_shared,
- duk_bi_logger_prototype_raw,
+ duk_bi_math_object_clz32,
+ duk_bi_math_object_hypot,
+ duk_bi_math_object_imul,
duk_bi_math_object_max,
duk_bi_math_object_min,
duk_bi_math_object_onearg_shared,
duk_bi_math_object_random,
+ duk_bi_math_object_sign,
duk_bi_math_object_twoarg_shared,
+ duk_bi_native_function_length,
+ duk_bi_native_function_name,
duk_bi_nodejs_buffer_byte_length,
duk_bi_nodejs_buffer_concat,
duk_bi_nodejs_buffer_constructor,
@@ -9171,625 +10731,653 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_number_prototype_to_string,
duk_bi_number_prototype_value_of,
duk_bi_object_constructor,
+ duk_bi_object_constructor_assign,
duk_bi_object_constructor_create,
duk_bi_object_constructor_define_properties,
duk_bi_object_constructor_define_property,
duk_bi_object_constructor_get_own_property_descriptor,
+ duk_bi_object_constructor_is,
duk_bi_object_constructor_is_extensible,
duk_bi_object_constructor_is_sealed_frozen_shared,
duk_bi_object_constructor_keys_shared,
duk_bi_object_constructor_prevent_extensions,
duk_bi_object_constructor_seal_freeze_shared,
duk_bi_object_getprototype_shared,
+ duk_bi_object_prototype_defineaccessor,
duk_bi_object_prototype_has_own_property,
duk_bi_object_prototype_is_prototype_of,
+ duk_bi_object_prototype_lookupaccessor,
duk_bi_object_prototype_property_is_enumerable,
duk_bi_object_prototype_to_locale_string,
duk_bi_object_prototype_to_string,
duk_bi_object_prototype_value_of,
duk_bi_object_setprototype_shared,
+ duk_bi_performance_now,
duk_bi_pointer_constructor,
duk_bi_pointer_prototype_tostring_shared,
duk_bi_proxy_constructor,
+ duk_bi_reflect_apply,
+ duk_bi_reflect_construct,
+ duk_bi_reflect_object_delete_property,
+ duk_bi_reflect_object_get,
+ duk_bi_reflect_object_has,
+ duk_bi_reflect_object_set,
duk_bi_regexp_constructor,
duk_bi_regexp_prototype_exec,
+ duk_bi_regexp_prototype_flags,
+ duk_bi_regexp_prototype_shared_getter,
duk_bi_regexp_prototype_test,
- duk_bi_regexp_prototype_to_string,
+ duk_bi_regexp_prototype_tostring,
duk_bi_string_constructor,
duk_bi_string_constructor_from_char_code,
+ duk_bi_string_constructor_from_code_point,
duk_bi_string_prototype_caseconv_shared,
duk_bi_string_prototype_char_at,
duk_bi_string_prototype_char_code_at,
duk_bi_string_prototype_concat,
+ duk_bi_string_prototype_includes,
duk_bi_string_prototype_indexof_shared,
duk_bi_string_prototype_locale_compare,
duk_bi_string_prototype_match,
+ duk_bi_string_prototype_repeat,
duk_bi_string_prototype_replace,
duk_bi_string_prototype_search,
duk_bi_string_prototype_slice,
duk_bi_string_prototype_split,
+ duk_bi_string_prototype_startswith_endswith,
duk_bi_string_prototype_substr,
duk_bi_string_prototype_substring,
duk_bi_string_prototype_to_string,
duk_bi_string_prototype_trim,
+ duk_bi_textdecoder_constructor,
+ duk_bi_textdecoder_prototype_decode,
+ duk_bi_textdecoder_prototype_shared_getter,
+ duk_bi_textencoder_constructor,
+ duk_bi_textencoder_prototype_encode,
+ duk_bi_textencoder_prototype_encoding_getter,
duk_bi_thread_constructor,
duk_bi_thread_current,
duk_bi_thread_resume,
duk_bi_thread_yield,
duk_bi_type_error_thrower,
+ duk_bi_typedarray_buffer_getter,
+ duk_bi_typedarray_bytelength_getter,
+ duk_bi_typedarray_byteoffset_getter,
duk_bi_typedarray_constructor,
duk_bi_typedarray_set,
+ duk_bi_uint8array_allocplain,
+ duk_bi_uint8array_plainof,
};
-#if defined(DUK_USE_BUILTIN_INITJS)
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = {
-40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
-105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
-102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
-108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
-109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
-108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
-108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
-41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106,
-101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116,
-104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
-};
-#endif /* DUK_USE_BUILTIN_INITJS */
#if defined(DUK_USE_DOUBLE_LE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0,
-0,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0,
-0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5,
-64,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156,
-253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248,
-52,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69,
-79,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22,
-157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,90,98,
-32,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
-60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0,
-0,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1,
-151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8,
-177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0,
-203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88,
-128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0,
+0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136,
+113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2,
+185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130,
+249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138,
+9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15,
+38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64,
+243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124,
+35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116,
+88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70,
+68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132,
+9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27,
+60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204,
+123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112,
+152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199,
+89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205,
+227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18,
+2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23,
+60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141,
+159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197,
+217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130,
+166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0,
+100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111,
+31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62,
+46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52,
+156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255,
+239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31,
+15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20,
+0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,
+13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,32,93,105,160,
+91,60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,
+168,110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,
+115,36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,
+145,139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,
+166,28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,
+145,92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,
+41,100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,
+177,69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,
+99,68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,
+9,49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,
+52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0,
+31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138,
+217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159,
+130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219,
+251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121,
+35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16,
+113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,
+104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,
+165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,
+154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,
+147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_BE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15,
-253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-0,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0,
-0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87,
-105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243,
-23,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232,
-52,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31,
-181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22,
-157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,90,0,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1,
-255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255,
+224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0,
+0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90,
+67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0,
+0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13,
+155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222,
+17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112,
+164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224,
+65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78,
+12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67,
+77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47,
+128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190,
+96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206,
+185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76,
+150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39,
+195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39,
+198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163,
+18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40,
+15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90,
+36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160,
+3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166,
+74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205,
+28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13,
+164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79,
+135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62,
+12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54,
+103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225,
+104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223,
+224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38,
+193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89,
+252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131,
+64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231,
+197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228,
+74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1,
+64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64,
+174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168,
+167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19,
+177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,32,0,0,0,0,91,
+60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
+110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
+36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
+139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
+28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
+92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
+100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
+69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
+68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
+49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,
+32,2,223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,
+31,86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,
+81,217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,
+2,235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,
+243,51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,
+35,180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,
+113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,
+104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,
+165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,
+154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,
+147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_ME)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-64,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228,
-206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0,
-0,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,
-248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,
-167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,
-64,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20,
-139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23,
-115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88,
-52,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16,
-148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52,
-22,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48,
-227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,
-195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,
-15,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,90,98,32,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0,
-0,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3,
+225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0,
+0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78,
+20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,
+68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,93,105,160,0,0,0,0,
+91,60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,
+168,110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,
+115,36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,
+145,139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,
+166,28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,
+145,92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,
+41,100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,
+177,69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,
+99,68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,
+9,49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5,
+95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236,
+31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125,
+207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10,
+130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49,
+254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,
+140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0,
+0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,
+18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,
+70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,
+7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,
+232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */
-#line 1 "duk_error_macros.c"
+
+/* automatic undefs */
+#undef DUK__REFCINIT
/*
- * Error, fatal, and panic handling.
+ * Error and fatal handling.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
#if defined(DUK_USE_VERBOSE_ERRORS)
-DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
va_list ap;
char msg[DUK__ERRFMT_BUFSIZE];
va_start(ap, fmt);
@@ -9799,13 +11387,13 @@ DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filenam
va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
}
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
}
#else /* DUK_USE_VERBOSE_ERRORS */
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
duk_err_create_and_throw(thr, code);
}
@@ -9817,69 +11405,72 @@ DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
+DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
+ expect_name, duk_get_type_name(thr, idx), (long) idx);
}
#else
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
+DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
+ expect_name, duk_push_string_readable(thr, idx), (long) idx);
}
#endif
-DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
}
-DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) {
- DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
+DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
}
-DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED);
+DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
}
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED);
+DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
+ DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
}
-#endif
-DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR);
+DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+}
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
}
#else
/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
* when non-verbose errors are used.
*/
-DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL);
+
+DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
+DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
+ DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_ERROR);
}
-DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
}
-DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
}
-DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
}
-DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_URI_ERROR);
}
#endif
@@ -9887,68 +11478,48 @@ DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
* Default fatal error handler
*/
-DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
- DUK_UNREF(ctx);
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
-#endif
- DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code));
- DUK_PANIC(code, msg);
- DUK_UNREACHABLE();
-}
-
-/*
- * Default panic handler
- */
-
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
-#if defined(DUK_USE_PANIC_ABORT)
- "calling abort"
-#elif defined(DUK_USE_PANIC_EXIT)
- "calling exit"
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- "segfaulting on purpose"
-#else
-#error no DUK_USE_PANIC_xxx macro defined
-#endif
- ")\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
- DUK_UNREF(code);
+DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) {
+ DUK_UNREF(udata);
DUK_UNREF(msg);
-#endif
-#if defined(DUK_USE_PANIC_ABORT)
- DUK_ABORT();
-#elif defined(DUK_USE_PANIC_EXIT)
- DUK_EXIT(-1);
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- /* exit() afterwards to satisfy "noreturn" */
- DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */
- DUK_EXIT(-1);
+#if defined(DUK_USE_FATAL_HANDLER)
+ /* duk_config.h provided a custom default fatal handler. */
+ DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_USE_FATAL_HANDLER(udata, msg);
#else
-#error no DUK_USE_PANIC_xxx macro defined
+ /* Default behavior is to abort() on error. There's no printout
+ * which makes this awkward, so it's always recommended to use an
+ * explicit fatal error handler.
+ *
+ * ====================================================================
+ * NOTE: If you are seeing this, you are most likely dealing with an
+ * uncaught error. You should provide a fatal error handler in Duktape
+ * heap creation, and should consider using a protected call as your
+ * first call into an empty Duktape context to properly handle errors.
+ * See:
+ * - http://duktape.org/guide.html#error-handling
+ * - http://wiki.duktape.org/HowtoFatalErrors.html
+ * - http://duktape.org/api.html#taglist-protected
+ * ====================================================================
+ */
+ DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_ABORT();
#endif
- DUK_UNREACHABLE();
+ DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
+ for (;;) {
+ /* Loop forever to ensure we don't return. */
+ }
}
-#endif /* !DUK_USE_PANIC_HANDLER */
+/* automatic undefs */
#undef DUK__ERRFMT_BUFSIZE
-#line 1 "duk_unicode_support.c"
/*
* Various Unicode help functions for character classification predicates,
* case conversion, decoding, etc.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Fast path tables
@@ -10195,8 +11766,17 @@ DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const du
while (n > 0) {
DUK_ASSERT(p >= ptr_start && p < ptr_end);
- res = res << 6;
- res += (duk_uint32_t) ((*p++) & 0x3f);
+ ch = (duk_uint_fast8_t) (*p++);
+#if 0
+ if (ch & 0xc0 != 0x80) {
+ /* not a continuation byte */
+ p--;
+ *ptr = p;
+ *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ return 1;
+ }
+#endif
+ res = (res << 6) + (duk_uint32_t) (ch & 0x3f);
n--;
}
@@ -10215,7 +11795,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
return cp;
}
- DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */
+ DUK_ERROR_INTERNAL(thr);
DUK_UNREACHABLE();
return 0;
}
@@ -10230,7 +11810,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
* chosen from several variants, based on x64 gcc -O2 testing. See:
* https://github.com/svaarala/duktape/pull/422
*
- * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length().
+ * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length().
*/
#if defined(DUK_USE_PREFER_SIZE)
@@ -10341,7 +11921,7 @@ DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *d
* Used for slow path Unicode matching.
*/
-/* Must match src/extract_chars.py, generate_match_table3(). */
+/* Must match tools/extract_chars.py, generate_match_table3(). */
DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
duk_uint32_t t;
@@ -10412,7 +11992,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
*
* It also specifies any Unicode category 'Zs' characters as white
- * space. These can be extracted with the "src/extract_chars.py" script.
+ * space. These can be extracted with the "tools/extract_chars.py" script.
* Current result:
*
* RAW OUTPUT:
@@ -10519,7 +12099,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp)
*
* The "UnicodeLetter" alternative of the production allows letters
* from various Unicode categories. These can be extracted with the
- * "src/extract_chars.py" script.
+ * "tools/extract_chars.py" script.
*
* Because the result has hundreds of Unicode codepoint ranges, matching
* for any values >= 0x80 are done using a very slow range-by-range scan
@@ -10550,7 +12130,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp)
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
(duk_size_t) sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp)) {
@@ -10616,7 +12196,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp)
* The matching code reuses the "identifier start" tables, and then
* consults a separate range set for characters in "identifier part"
* but not in "identifier start". These can be extracted with the
- * "src/extract_chars.py" script.
+ * "tools/extract_chars.py" script.
*
* UnicodeCombiningMark -> categories Mn, Mc
* UnicodeDigit -> categories Nd
@@ -10640,7 +12220,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp)
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp) ||
@@ -10699,7 +12279,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp) &&
@@ -10731,14 +12311,14 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
/*
* Complex case conversion helper which decodes a bit-packed conversion
- * control stream generated by unicode/extract_caseconv.py. The conversion
+ * control stream generated by tools/extract_caseconv.py. The conversion
* is very slow because it runs through the conversion data in a linear
* fashion to save space (which is why ASCII characters have a special
* fast path before arriving here).
*
* The particular bit counts etc have been determined experimentally to
* be small but still sufficient, and must match the Python script
- * (src/extract_caseconv.py).
+ * (tools/extract_caseconv.py).
*
* The return value is the case converted codepoint or -1 if the conversion
* results in multiple characters (this is useful for regexp Canonicalization
@@ -10762,8 +12342,8 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
duk_codepoint_t start_i;
duk_codepoint_t start_o;
- DUK_UNREF(thr);
DUK_ASSERT(bd_ctx != NULL);
+ DUK_UNREF(thr);
DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
@@ -10798,7 +12378,7 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
}
/* 1:1 conversion */
- n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
+ n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
while (n--) {
start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
@@ -10945,15 +12525,14 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
* Replace valstack top with case converted version.
*/
-DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t prev, curr, next;
- h_input = duk_require_hstring(ctx, -1);
+ h_input = duk_require_hstring(thr, -1); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
@@ -10973,7 +12552,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
curr = next;
next = -1;
if (p < p_end) {
- next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
} else {
/* end of input and last char has been processed */
if (curr < 0) {
@@ -11000,11 +12579,12 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
}
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1); /* invalidates h_buf pointer */
- duk_remove(ctx, -2);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */
+ /* invalidates h_buf pointer */
+ duk_remove_m2(thr);
}
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
/*
* Canonicalize() abstract operation needed for canonicalization of individual
@@ -11116,12 +12696,11 @@ DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
};
#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_util_misc.c"
/*
* Misc util stuff
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Lowercase digits for radix values 2 to 36. Also doubles as lowercase
@@ -11339,90 +12918,194 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
}
}
#endif
-#line 1 "duk_util_hashprime.c"
+
/*
- * Round a number upwards to a prime (not usually the nearest one).
- *
- * Uses a table of successive 32-bit primes whose ratio is roughly
- * constant. This keeps the relative upwards 'rounding error' bounded
- * and the data size small. A simple 'predict-correct' compression is
- * used to compress primes to one byte per prime. See genhashsizes.py
- * for details.
- *
- * The minimum prime returned here must be coordinated with the possible
- * probe sequence steps in duk_hobject and duk_heap stringtable.
+ * Miscellaneous coercion / clamping helpers.
*/
-/* include removed: duk_internal.h */
-
-/* Awkward inclusion condition: drop out of compilation if not needed by any
- * call site: object hash part or probing stringtable.
+/* Check whether a duk_double_t is a whole number in the 32-bit range (reject
+ * negative zero), and if so, return a duk_int32_t.
+ * For compiler use: don't allow negative zero as it will cause trouble with
+ * LDINT+LDINTX, positive zero is OK.
*/
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
+DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
+ duk_int32_t t;
-/* hash size ratio goal, must match genhashsizes.py */
-#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
+ t = (duk_int32_t) x;
+ if (!((duk_double_t) t == x)) {
+ return 0;
+ }
+ if (t == 0) {
+ duk_double_union du;
+ du.d = x;
+ if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
+ return 0;
+ }
+ }
+ *ival = t;
+ return 1;
+}
-/* prediction corrections for prime list (see genhashsizes.py) */
-DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
- 17, /* minimum prime */
- 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
- 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
- 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
- 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
- 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
- 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
- 10, 23, 16, 9, 2,
- -1
-};
+/* Check whether a duk_double_t is a whole number in the 32-bit range, and if
+ * so, return a duk_int32_t.
+ */
+DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
+ duk_int32_t t;
-/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
- * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
+ t = (duk_int32_t) x;
+ if (!((duk_double_t) t == x)) {
+ return 0;
+ }
+ *ival = t;
+ return 1;
+}
+
+/*
+ * IEEE double checks
*/
-DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
- 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
- 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
-};
-DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
- const duk_int8_t *p = duk__hash_size_corrections;
- duk_uint32_t curr;
+DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_ANYINF(&du);
+}
- curr = (duk_uint32_t) *p++;
- for (;;) {
- duk_small_int_t t = (duk_small_int_t) *p++;
- if (t < 0) {
- /* may happen if size is very close to 2^32-1 */
- break;
- }
+DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_POSINF(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_NEGINF(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* Assumes we're dealing with a Duktape internal NaN which is
+ * NaN normalized if duk_tval requires it.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ return DUK_DBLUNION_IS_NAN(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* Assumes we're dealing with a Duktape internal NaN which is
+ * NaN normalized if duk_tval requires it.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
+}
- /* prediction: portable variant using doubles if 64-bit values not available */
-#ifdef DUK_USE_64BIT_OPS
- curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
+DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* If exponent is 0x7FF the argument is either a NaN or an
+ * infinity. We don't need to check any other fields.
+ */
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
#else
- /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
- curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
#endif
+#else
+ return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
+#endif
+}
- /* correction */
- curr += t;
+DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
+ duk_double_union du;
+#if defined(DUK_USE_64BIT_OPS)
+ duk_uint64_t t;
+#else
+ duk_uint32_t t;
+#endif
+ du.d = x;
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
+ return t == 0;
+ }
+ if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
+ return 1;
+ }
+#else
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
+ return t == 0;
+ }
+ if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
+ return 1;
+ }
+#endif
+#else
+ t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
+ if (t == 0x00000000UL) {
+ return DUK_DBLUNION_IS_ANYZERO(&du);
+ }
+ if (t == 0x7ff00000UL) {
+ return 1;
+ }
+#endif
+ return 0;
+}
- DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
+DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
+}
- if (curr >= size) {
- return curr;
- }
+DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
+ /* XXX: optimize */
+ duk_small_uint_t s = duk_double_signbit(x);
+ x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
+ if (s) {
+ x = -x;
}
- return 0;
+ return x;
}
-#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
-#line 1 "duk_hobject_class.c"
+DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
+ duk_double_union du1;
+ duk_double_union du2;
+ du1.d = x;
+ du2.d = y;
+
+ return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
+}
+
+DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
+ /* Doesn't replicate fmin() behavior exactly: for fmin() if one
+ * argument is a NaN, the other argument should be returned.
+ * Duktape doesn't rely on this behavior so the replacement can
+ * be simplified.
+ */
+ return (x < y ? x : y);
+}
+
+DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
+ /* Doesn't replicate fmax() behavior exactly: for fmax() if one
+ * argument is a NaN, the other argument should be returned.
+ * Duktape doesn't rely on this behavior so the replacement can
+ * be simplified.
+ */
+ return (x > y ? x : y);
+}
/*
* Hobject Ecmascript [[Class]].
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if (DUK_STRIDX_UC_ARGUMENTS > 255)
#error constant too large
@@ -11469,9 +13152,6 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
#if (DUK_STRIDX_DEC_ENV > 255)
#error constant too large
#endif
-#if (DUK_STRIDX_UC_BUFFER > 255)
-#error constant too large
-#endif
#if (DUK_STRIDX_UC_POINTER > 255)
#error constant too large
#endif
@@ -11517,23 +13197,23 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
- DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
- DUK_STRIDX_UC_ARGUMENTS,
+ DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */
+ DUK_STRIDX_UC_OBJECT,
DUK_STRIDX_ARRAY,
+ DUK_STRIDX_UC_FUNCTION,
+ DUK_STRIDX_UC_ARGUMENTS,
DUK_STRIDX_UC_BOOLEAN,
DUK_STRIDX_DATE,
DUK_STRIDX_UC_ERROR,
- DUK_STRIDX_UC_FUNCTION,
DUK_STRIDX_JSON,
DUK_STRIDX_MATH,
DUK_STRIDX_UC_NUMBER,
- DUK_STRIDX_UC_OBJECT,
DUK_STRIDX_REG_EXP,
DUK_STRIDX_UC_STRING,
DUK_STRIDX_GLOBAL,
+ DUK_STRIDX_UC_SYMBOL,
DUK_STRIDX_OBJ_ENV,
DUK_STRIDX_DEC_ENV,
- DUK_STRIDX_UC_BUFFER,
DUK_STRIDX_UC_POINTER,
DUK_STRIDX_UC_THREAD,
DUK_STRIDX_ARRAY_BUFFER,
@@ -11550,7 +13230,6 @@ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
};
-#line 1 "duk_alloc_default.c"
/*
* Default allocation functions.
*
@@ -11558,7 +13237,7 @@ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
* a NULL or a unique pointer which is a no-op for free.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
@@ -11585,20 +13264,18 @@ DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
DUK_ANSI_FREE(ptr);
}
#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
-#line 1 "duk_api_buffer.c"
/*
* Buffer
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
duk_hbuffer_dynamic *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -11611,15 +13288,14 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size
return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
}
-DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
duk_hbuffer_dynamic *h;
void *ptr;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -11642,13 +13318,12 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_
return ptr;
}
-DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
duk_hbuffer_external *h;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
@@ -11659,7 +13334,6 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr
DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
}
-#line 1 "duk_api_bytecode.c"
/*
* Bytecode dump/load
*
@@ -11672,35 +13346,35 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr
* validated which is not easy to do with indirect register references etc.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-#define DUK__SER_MARKER 0xff
-#define DUK__SER_VERSION 0x00
+#define DUK__SER_MARKER 0xbf
#define DUK__SER_STRING 0x00
#define DUK__SER_NUMBER 0x01
#define DUK__BYTECODE_INITIAL_ALLOC 256
+#define DUK__NO_FORMALS 0xffffffffUL
/*
* Dump/load helpers, xxx_raw() helpers do no buffer checks
*/
-DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
len = DUK_RAW_READ_U32_BE(p);
- duk_push_lstring(ctx, (const char *) p, len);
+ duk_push_lstring(thr, (const char *) p, len);
p += len;
return p;
}
-DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
duk_uint8_t *buf;
len = DUK_RAW_READ_U32_BE(p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
p += len;
@@ -11756,7 +13430,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, d
DUK_ASSERT(h_str != NULL);
}
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
p = duk__dump_hstring_raw(p, h_str);
return p;
}
@@ -11770,10 +13444,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, d
h_buf = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h_buf != NULL);
DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
p = duk__dump_hbuffer_raw(thr, p, h_buf);
} else {
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0);
}
return p;
@@ -11789,7 +13463,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, d
} else {
val = def_value;
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, val);
return p;
}
@@ -11830,12 +13504,12 @@ DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bu
#endif
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
p = duk__dump_hstring_raw(p, key);
DUK_RAW_WRITE_U32_BE(p, val);
}
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
return p;
}
@@ -11845,42 +13519,48 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_uint_fast32_t i;
+ duk_harray *h;
+ duk_uint32_t i;
- h = DUK_TVAL_GET_OBJECT(tv);
+ /* Here we rely on _Formals being a dense array containing
+ * strings. This should be the case unless _Formals has been
+ * tweaked by the application (which we don't support right
+ * now).
+ */
+ h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
+ DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
- /* We know _Formals is dense and all entries will be in the
- * array part. GC and finalizers shouldn't affect _Formals
- * so side effects should be fine.
- */
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
+ DUK_RAW_WRITE_U32_BE(p, h->length);
+
+ for (i = 0; i < h->length; i++) {
duk_tval *tv_val;
duk_hstring *varname;
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
+ tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
DUK_ASSERT(tv_val != NULL);
- if (DUK_TVAL_IS_STRING(tv_val)) {
- /* Array is dense and contains only strings, but ASIZE may
- * be larger than used part and there are UNUSED entries.
- */
- varname = DUK_TVAL_GET_STRING(tv_val);
- DUK_ASSERT(varname != NULL);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
- p = duk__dump_hstring_raw(p, varname);
- }
+ varname = DUK_TVAL_GET_STRING(tv_val);
+ DUK_ASSERT(varname != NULL);
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
+
+ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
+ p = duk__dump_hstring_raw(p, varname);
}
+ } else {
+ DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
return p;
}
-static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
- duk_hthread *thr;
+static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
duk_tval *tv, *tv_end;
duk_instr_t *ins, *ins_end;
duk_hobject **fn, **fn_end;
@@ -11890,39 +13570,35 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
duk_uint16_t tmp16;
duk_double_t d;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
- DUK_UNREF(thr);
-
DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
"consts=[%p,%p[ (%ld bytes, %ld items), "
"funcs=[%p,%p[ (%ld bytes, %ld items), "
"code=[%p,%p[ (%ld bytes, %ld items)",
(void *) func,
(void *) p,
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func)));
+ (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
- count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func);
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
+ count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
/* Fixed header info. */
tmp32 = count_instr;
DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func);
+ tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func);
+ tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
DUK_RAW_WRITE_U32_BE(p, tmp32);
tmp16 = func->nregs;
DUK_RAW_WRITE_U16_BE(p, tmp16);
@@ -11937,14 +13613,15 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
DUK_RAW_WRITE_U32_BE(p, 0);
DUK_RAW_WRITE_U32_BE(p, 0);
#endif
- tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK;
+ tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */
+ tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */
DUK_RAW_WRITE_U32_BE(p, tmp32);
/* Bytecode instructions: endian conversion needed unless
* platform is big endian.
*/
- ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func);
- ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func);
+ ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
+ ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
#if defined(DUK_USE_INTEGER_BE)
DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
@@ -11958,8 +13635,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
#endif
/* Constants: variable size encoding. */
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func);
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
+ tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
while (tv != tv_end) {
/* constants are strings or numbers now */
DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
@@ -11969,12 +13646,12 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p),
*p++ = DUK__SER_STRING;
p = duk__dump_hstring_raw(p, h_str);
} else {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
*p++ = DUK__SER_NUMBER;
d = DUK_TVAL_GET_NUMBER(tv);
DUK_RAW_WRITE_DOUBLE_BE(p, d);
@@ -11983,8 +13660,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
}
/* Inner functions recursively. */
- fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func);
- fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func);
+ fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
+ fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
while (fn != fn_end) {
/* XXX: This causes recursion up to inner function depth
* which is normally not an issue, e.g. mark-and-sweep uses
@@ -11992,11 +13669,13 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
* this would mean some sort of a work list or just refusing
* to serialize deep functions.
*/
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn));
- p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
+ p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
fn++;
}
+ /* Lexenv and varenv are not dumped. */
+
/* Object extra properties.
*
* There are some difference between function templates and functions.
@@ -12005,9 +13684,15 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
*/
p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
+#endif
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
+#endif
+#if defined(DUK_USE_PC2LINE)
p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
+#endif
p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
@@ -12030,9 +13715,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
} while (0)
-static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
- duk_hthread *thr;
- duk_hcompiledfunction *h_fun;
+static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t *p_end) {
+ duk_hcompfunc *h_fun;
duk_hbuffer *h_data;
duk_size_t data_size;
duk_uint32_t count_instr, count_const, count_funcs;
@@ -12044,14 +13728,16 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_idx_t idx_base;
duk_tval *tv1;
duk_uarridx_t arr_idx;
+ duk_uarridx_t arr_limit;
+ duk_hobject *func_env;
+ duk_bool_t need_pop;
/* XXX: There's some overlap with duk_js_closure() here, but
* seems difficult to share code. Ensure that the final function
* looks the same as created by duk_js_closure().
*/
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
@@ -12072,19 +13758,19 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* inner functions being loaded. Require enough space to handle
* large functions correctly.
*/
- duk_require_stack(ctx, 2 + count_const + count_funcs);
- idx_base = duk_get_top(ctx);
+ duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
+ idx_base = duk_get_top(thr);
/* Push function object, init flags etc. This must match
* duk_js_push_closure() quite carefully.
*/
- duk_push_compiledfunction(ctx);
- h_fun = duk_get_hcompiledfunction(ctx, -1);
+ h_fun = duk_push_hcompfunc(thr);
DUK_ASSERT(h_fun != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun));
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
h_fun->nregs = DUK_RAW_READ_U16_BE(p);
h_fun->nargs = DUK_RAW_READ_U16_BE(p);
@@ -12095,25 +13781,28 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
p += 8; /* skip line info */
#endif
- /* duk_hcompiledfunction flags; quite version specific */
+ /* duk_hcompfunc flags; quite version specific */
tmp32 = DUK_RAW_READ_U32_BE(p);
- DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);
+ DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
- /* standard prototype */
+ /* standard prototype (no need to set here, already set) */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#endif
/* assert just a few critical flags */
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
/* Create function 'data' buffer but don't attach it yet. */
- fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size);
+ fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
DUK_ASSERT(fun_data != NULL);
/* Load bytecode instructions. */
@@ -12139,7 +13828,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
const_type = DUK_RAW_READ_U8(p);
switch (const_type) {
case DUK__SER_STRING: {
- p = duk__load_string_raw(ctx, p);
+ p = duk__load_string_raw(thr, p);
break;
}
case DUK__SER_NUMBER: {
@@ -12150,8 +13839,8 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_double_t val;
DUK__ASSERT_LEFT(8);
val = DUK_RAW_READ_DOUBLE_BE(p);
- DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val);
- duk_push_tval(ctx, &tv_tmp);
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
+ duk_push_tval(thr, &tv_tmp);
break;
}
default: {
@@ -12162,7 +13851,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
/* Load inner functions to value stack, but don't yet copy to buffer. */
for (n = count_funcs; n > 0; n--) {
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
@@ -12177,13 +13866,12 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* them afterwards.
*/
- h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1);
- DUK_ASSERT(h_data != NULL);
+ h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data);
+ DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
DUK_HBUFFER_INCREF(thr, h_data);
- tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
+ tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */
DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
q = fun_data;
@@ -12197,7 +13885,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
tv1 += count_const;
}
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
+ DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
for (n = count_funcs; n > 0; n--) {
duk_hobject *h_obj;
@@ -12211,108 +13899,140 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
q += sizeof(duk_hobject *);
}
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
+ DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
/* The function object is now reachable and refcounts are fine,
* so we can pop off all the temporaries.
*/
- DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
- duk_set_top(ctx, idx_base + 1);
+ DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
+ duk_set_top(thr, idx_base + 1);
/* Setup function properties. */
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
-
- p = duk__load_string_raw(ctx, p);
+ duk_push_u32(thr, tmp32);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
+
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */
+ func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
+ DUK_ASSERT(func_env != NULL);
+ need_pop = 0;
if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
/* Original function instance/template had NAMEBINDING.
* Must create a lexical environment on loading to allow
* recursive functions like 'function foo() { foo(); }'.
*/
- duk_hobject *proto;
+ duk_hdecenv *new_env;
- proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- proto);
- duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */
- duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
- duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
+ DUK_ASSERT(new_env != NULL);
+ DUK_ASSERT(new_env->thread == NULL); /* Closed. */
+ DUK_ASSERT(new_env->varmap == NULL);
+ DUK_ASSERT(new_env->regbase_byteoff == 0);
+ DUK_ASSERT_HDECENV_VALID(new_env);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+
+ func_env = (duk_hobject *) new_env;
+
+ duk_push_hobject(thr, (duk_hobject *) new_env);
+
+ duk_dup_m2(thr); /* -> [ func funcname env funcname ] */
+ duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
+
+ need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
+ }
+ DUK_ASSERT(func_env != NULL);
+ DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
+ DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+ if (need_pop) {
+ duk_pop(thr);
+ }
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#endif /* DUK_USE_FUNC_NAME_PROPERTY */
+
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
+ p = duk__load_string_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
+
+ if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
+ /* Restore empty external .prototype only for constructable
+ * functions.
*/
+ duk_push_object(thr);
+ duk_dup_m2(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
}
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- p = duk__load_string_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
-
- duk_push_object(ctx);
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
- p = duk__load_buffer_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
+#if defined(DUK_USE_PC2LINE)
+ p = duk__load_buffer_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
+#endif /* DUK_USE_PC2LINE */
- duk_push_object(ctx); /* _Varmap */
+ duk_push_object(thr); /* _Varmap */
for (;;) {
/* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
+ p = duk__load_string_raw(thr, p);
+ if (duk_get_length(thr, -1) == 0) {
+ duk_pop(thr);
break;
}
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_put_prop(ctx, -3);
+ duk_push_u32(thr, tmp32);
+ duk_put_prop(thr, -3);
}
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
- duk_push_array(ctx); /* _Formals */
- for (arr_idx = 0; ; arr_idx++) {
- /* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
- break;
+ /* _Formals may have been missing in the original function, which is
+ * handled using a marker length.
+ */
+ arr_limit = DUK_RAW_READ_U32_BE(p);
+ if (arr_limit != DUK__NO_FORMALS) {
+ duk_push_array(thr); /* _Formals */
+ for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
+ p = duk__load_string_raw(thr, p);
+ duk_put_prop_index(thr, -2, arr_idx);
}
- duk_put_prop_index(ctx, -2, arr_idx);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
+ } else {
+ DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
}
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
/* Return with final function pushed on stack top. */
- DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
- DUK_ASSERT_TOP(ctx, idx_base + 1);
+ DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
+ DUK_ASSERT_TOP(thr, idx_base + 1);
return p;
format_error:
return NULL;
}
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- duk_hthread *thr;
- duk_hcompiledfunction *func;
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
+ duk_hcompfunc *func;
duk_bufwriter_ctx bw_ctx_alloc;
duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
duk_uint8_t *p;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
/* Bound functions don't have all properties so we'd either need to
* lookup the non-bound target function or reject bound functions.
- * For now, bound functions are rejected.
+ * For now, bound functions are rejected with TypeError.
*/
- func = duk_require_hcompiledfunction(ctx, -1);
+ func = duk_require_hcompfunc(thr, -1);
DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
/* Estimating the result size beforehand would be costly, so
* start with a reasonable size and extend as needed.
@@ -12320,26 +14040,22 @@ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
p = DUK_BW_GET_PTR(thr, bw_ctx);
*p++ = DUK__SER_MARKER;
- *p++ = DUK__SER_VERSION;
- p = duk__dump_func(ctx, func, bw_ctx, p);
+ p = duk__dump_func(thr, func, bw_ctx, p);
DUK_BW_SET_PTR(thr, bw_ctx, p);
DUK_BW_COMPACT(thr, bw_ctx);
- DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
+ DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
- duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */
+ duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
duk_uint8_t *p_buf, *p, *p_end;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
+ p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
DUK_ASSERT(p_buf != NULL);
/* The caller is responsible for being sure that bytecode being loaded
@@ -12348,511 +14064,443 @@ DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
* (instruction validation would be quite complex to implement).
*
* This signature check is the only sanity check for detecting
- * accidental invalid inputs. The initial 0xFF byte ensures no
- * ordinary string will be accepted by accident.
+ * accidental invalid inputs. The initial byte ensures no ordinary
+ * string or Symbol will be accepted by accident.
*/
p = p_buf;
p_end = p_buf + sz;
- if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
+ if (sz < 1 || p[0] != DUK__SER_MARKER) {
goto format_error;
}
- p += 2;
+ p++;
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
- duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */
+ duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */
return;
format_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
}
-#undef DUK__SER_MARKER
-#undef DUK__SER_VERSION
-#undef DUK__SER_STRING
-#undef DUK__SER_NUMBER
-#undef DUK__BYTECODE_INITIAL_ALLOC
-
#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-#line 1 "duk_api_call.c"
+
+/* automatic undefs */
+#undef DUK__ASSERT_LEFT
+#undef DUK__BYTECODE_INITIAL_ALLOC
+#undef DUK__NO_FORMALS
+#undef DUK__SER_MARKER
+#undef DUK__SER_NUMBER
+#undef DUK__SER_STRING
/*
* Calls.
*
- * Protected variants should avoid ever throwing an error.
+ * Protected variants should avoid ever throwing an error. Must be careful
+ * to catch errors related to value stack manipulation and property lookup,
+ * not just the call itself.
+ *
+ * The only exception is when arguments are insane, e.g. nargs/nrets are out
+ * of bounds; in such cases an error is thrown for two reasons. First, we
+ * can't always respect the value stack input/output guarantees in such cases
+ * so the caller would end up with the value stack in an unexpected state.
+ * Second, an attempt to create an error might itself fail (although this
+ * could be avoided by pushing a preallocated object/string or a primitive
+ * value).
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/*
+ * Helpers
+ */
+
+struct duk__pcall_prop_args {
+ duk_idx_t obj_idx;
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_prop_args duk__pcall_prop_args;
+
+struct duk__pcall_method_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_method_args duk__pcall_method_args;
+
+struct duk__pcall_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_args duk__pcall_args;
+
+/* Compute and validate idx_func for a certain 'nargs' and 'other'
+ * parameter count (1 or 2, depending on whether 'this' binding is
+ * present).
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ /* unreachable */
+ }
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
+
+/* Compute idx_func, assume index will be valid. This is a valid assumption
+ * for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
+ * validates the argument count.
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(nargs >= 0);
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ DUK_ASSERT(idx_func >= 0);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
/* Prepare value stack for a method call through an object property.
* May currently throw an error e.g. when getting the property.
*/
-DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(nargs >= 0);
- DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld",
- (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
+ (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
/* [... key arg1 ... argN] */
/* duplicate key */
- duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
- duk_get_prop(ctx, normalized_obj_index);
+ duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
+ (void) duk_get_prop(thr, normalized_obj_idx);
- DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
+ duk_tval *tv_targ;
+ duk_tval *tv_base;
+ duk_tval *tv_key;
+
+ tv_targ = DUK_GET_TVAL_NEGIDX(thr, -1);
+ tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
+ DUK_ASSERT(tv_targ >= thr->valstack_bottom && tv_targ < thr->valstack_top);
+ DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
+ DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
+
+ duk_call_setup_propcall_error(thr, tv_targ, tv_base, tv_key);
+ }
+#endif
/* [... key arg1 ... argN func] */
- duk_replace(ctx, -nargs - 2);
+ duk_replace(thr, -nargs - 2);
/* [... func arg1 ... argN] */
- duk_dup(ctx, normalized_obj_index);
- duk_insert(ctx, -nargs - 1);
+ duk_dup(thr, normalized_obj_idx);
+ duk_insert(thr, -nargs - 1);
/* [... func this arg1 ... argN] */
}
-DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 1;
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- /* XXX: awkward; we assume there is space for this, overwrite
- * directly instead?
- */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ duk_insert_undefined(thr, idx_func + 1);
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
+DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
/*
* XXX: if duk_handle_call() took values through indices, this could be
* made much more sensible. However, duk_handle_call() needs to fudge
- * the 'this' and 'func' values to handle bound function chains, which
- * is now done "in-place", so this is not a trivial change.
+ * the 'this' and 'func' values to handle bound functions, which is now
+ * done "in-place", so this is not a trivial change.
*/
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
+ obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
+ duk__call_prop_prep_stack(thr, obj_idx, nargs);
- duk_call_method(ctx, nargs);
+ duk_call_method(thr, nargs);
}
-DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
+DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_args *args;
duk_idx_t idx_func;
- duk_int_t rc;
+ duk_int_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
- idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* We can't reliably pop anything here because the stack input
- * shape is incorrect. So we throw an error; if the caller has
- * no catch point for this, a fatal error will occur. Another
- * alternative would be to just return an error. But then the
- * stack would be in an unknown state which might cause some
- * very hard to diagnose problems later on. Also note that even
- * if we did not throw an error here, the underlying call handler
- * might STILL throw an out-of-memory error or some other internal
- * fatal error.
- */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
+ args = (duk__pcall_args *) udata;
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- /* awkward; we assume there is space for this */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ duk_insert_undefined(thr, idx_func + 1);
- call_flags = 0; /* respect reclimit, not constructor */
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
+ return 1;
}
-DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
- duk_idx_t idx_func;
- duk_int_t rc;
+DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
+ duk__pcall_args args;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
+ args.call_flags = 0;
- call_flags = 0; /* respect reclimit, not constructor */
-
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
+ return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
}
-DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) {
- duk_idx_t obj_index;
- duk_idx_t nargs;
-
- /* Get the original arguments. Note that obj_index may be a relative
- * index so the stack must have the same top when we use it.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = (duk_idx_t) duk_get_int(ctx, -2);
- nargs = (duk_idx_t) duk_get_int(ctx, -1);
- duk_pop_2(ctx);
+DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_method_args *args;
+ duk_idx_t idx_func;
+ duk_int_t ret;
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
- duk_call_method(ctx, nargs);
- return 1;
-}
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
-DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
- /*
- * Must be careful to catch errors related to value stack manipulation
- * and property lookup, not just the call itself.
- */
+ args = (duk__pcall_method_args *) udata;
- DUK_ASSERT_CTX_VALID(ctx);
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- duk_push_idx(ctx, obj_index);
- duk_push_idx(ctx, nargs);
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
- /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
- * If the value stack does not contain enough args, an error is thrown; this matches
- * behavior of the other protected call API functions.
- */
- return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
+ return 1;
}
-DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t rc;
+DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
+ duk__pcall_method_args args;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_get_top(ctx) < nargs || nrets < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
+ args.call_flags = call_flags;
- rc = duk_handle_safe_call(thr, /* thread */
- func, /* func */
- nargs, /* num_stack_args */
- nrets); /* num_stack_res */
-
- return rc;
+ return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
}
-DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
- /*
- * There are two [[Construct]] operations in the specification:
- *
- * - E5 Section 13.2.2: for Function objects
- * - E5 Section 15.3.4.5.2: for "bound" Function objects
- *
- * The chain of bound functions is resolved in Section 15.3.4.5.2,
- * with arguments "piling up" until the [[Construct]] internal
- * method is called on the final, actual Function object. Note
- * that the "prototype" property is looked up *only* from the
- * final object, *before* calling the constructor.
- *
- * Currently we follow the bound function chain here to get the
- * "prototype" property value from the final, non-bound function.
- * However, we let duk_handle_call() handle the argument "piling"
- * when the constructor is called. The bound function chain is
- * thus now processed twice.
- *
- * When constructing new Array instances, an unnecessary object is
- * created and discarded now: the standard [[Construct]] creates an
- * object, and calls the Array constructor. The Array constructor
- * returns an Array instance, which is used as the result value for
- * the "new" operation; the object created before the Array constructor
- * call is discarded.
- *
- * This would be easy to fix, e.g. by knowing that the Array constructor
- * will always create a replacement object and skip creating the fallback
- * object in that case.
- *
- * Note: functions called via "new" need to know they are called as a
- * constructor. For instance, built-in constructors behave differently
- * depending on how they are called.
- */
+DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
+ DUK_ASSERT_API_ENTRY(thr);
- /* XXX: merge this with duk_js_call.c, as this function implements
- * core semantics (or perhaps merge the two files altogether).
- */
-
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *proto;
- duk_hobject *cons;
- duk_hobject *fallback;
- duk_idx_t idx_cons;
- duk_small_uint_t call_flags;
+ return duk_pcall_method_flags(thr, nargs, 0);
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_prop_args *args;
+ duk_idx_t obj_idx;
+ duk_int_t ret;
- /* [... constructor arg1 ... argN] */
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
- idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
+ args = (duk__pcall_prop_args *) udata;
- DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
- (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
+ obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */
+ duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
- /* XXX: code duplication */
+ ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
+ return 1;
+}
- /*
- * Figure out the final, non-bound constructor, to get "prototype"
- * property.
- */
+DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
+ duk__pcall_prop_args args;
- duk_dup(ctx, idx_cons);
- for (;;) {
- duk_tval *tv;
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- cons = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(cons != NULL);
- if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
- /* Checking callability of the immediate target
- * is important, same for constructability.
- * Checking it for functions down the bound
- * function chain is not strictly necessary
- * because .bind() should normally reject them.
- * But it's good to check anyway because it's
- * technically possible to edit the bound function
- * chain via internal keys.
- */
- goto not_constructable;
- }
- if (!DUK_HOBJECT_HAS_BOUND(cons)) {
- break;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- /* Lightfuncs cannot be bound. */
- break;
- } else {
- /* Anything else is not constructable. */
- goto not_constructable;
- }
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
- duk_remove(ctx, -2); /* -> [... target] */
+ args.obj_idx = obj_idx;
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
}
- DUK_ASSERT(duk_is_callable(ctx, -1));
- DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
- (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1))));
-
- /* [... constructor arg1 ... argN final_cons] */
+ args.call_flags = 0;
- /*
- * Create "fallback" object to be used as the object instance,
- * unless the constructor returns a replacement value.
- * Its internal prototype needs to be set based on "prototype"
- * property of the constructor.
- */
-
- duk_push_object(ctx); /* class Object, extensible */
+ return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
+}
- /* [... constructor arg1 ... argN final_cons fallback] */
+DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
+ duk_int_t rc;
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
- proto = duk_get_hobject(ctx, -1);
- if (!proto) {
- DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
- "-> leave standard Object prototype as fallback prototype"));
- } else {
- DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
- "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
- fallback = duk_get_hobject(ctx, -2);
- DUK_ASSERT(fallback != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* nargs condition; fail if: top - bottom < nargs
+ * <=> top < bottom + nargs
+ * nrets condition; fail if: end - (top - nargs) < nrets
+ * <=> end - top + nargs < nrets
+ * <=> end + nargs < top + nrets
+ */
+ /* XXX: check for any reserve? */
+
+ if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */
+ thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */
+ thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */
+ DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
+ "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
+ "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
+ (long) nargs,
+ (long) nrets,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) (thr->valstack_bottom - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_end - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) nrets));
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
}
- duk_pop(ctx);
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- /*
- * Manipulate callstack for the call.
- */
-
- duk_dup_top(ctx);
- duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
- duk_insert(ctx, idx_cons); /* also stash it before constructor,
- * in case we need it (as the fallback value)
- */
- duk_pop(ctx); /* pop final_cons */
-
-
- /* [... fallback constructor fallback(this) arg1 ... argN];
- * Note: idx_cons points to first 'fallback', not 'constructor'.
- */
-
- DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
- "nargs=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
- (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
- (long) nargs,
- (long) duk_get_top(ctx)));
- /*
- * Call the constructor function (called in "constructor mode").
- */
-
- call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- /* [... fallback retval] */
-
- DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Determine whether to use the constructor return value as the created
- * object instance or not.
- */
+ rc = duk_handle_safe_call(thr, /* thread */
+ func, /* func */
+ udata, /* udata */
+ nargs, /* num_stack_args */
+ nrets); /* num_stack_res */
- if (duk_is_object(ctx, -1)) {
- duk_remove(ctx, -2);
- } else {
- duk_pop(ctx);
- }
+ return rc;
+}
- /*
- * Augment created errors upon creation (not when they are thrown or
- * rethrown). __FILE__ and __LINE__ are not desirable here; the call
- * stack reflects the caller which is correct.
- */
+DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
+ duk_idx_t idx_func;
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_hthread_sync_currpc(thr);
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
-#endif
+ DUK_ASSERT_API_ENTRY(thr);
- /* [... retval] */
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- return;
+ duk_push_object(thr); /* default instance; internal proto updated by call handling */
+ duk_insert(thr, idx_func + 1);
- not_constructable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
+ duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
}
-DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) {
- duk_uint_t nargs;
+DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
+ duk_idx_t nargs;
- nargs = duk_to_uint(ctx, -1);
- duk_pop(ctx);
+ DUK_ASSERT(udata != NULL);
+ nargs = *((duk_idx_t *) udata);
- duk_new(ctx, nargs);
+ duk_new(thr, nargs);
return 1;
}
-DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
+DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* For now, just use duk_safe_call() to wrap duk_new(). We can't
- * simply use a protected duk_handle_call() because there's post
- * processing which might throw. It should be possible to ensure
- * the post processing never throws (except in internal errors and
- * out of memory etc which are always allowed) and then remove this
- * wrapper.
+ * simply use a protected duk_handle_call() because pushing the
+ * default instance might throw.
*/
- duk_push_uint(ctx, nargs);
- rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/);
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
+ }
+
+ rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
- DUK_ASSERT(act != NULL); /* because callstack_top > 0 */
- return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
+ }
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* XXX: Make this obsolete by adding a function flag for rejecting a
+ * non-constructor call automatically?
+ */
+DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (!duk_is_constructor_call(thr)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
+ }
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
duk_activation *act;
/* For user code this could just return 1 (strict) always
@@ -12864,32 +14512,28 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
* the internal call sites.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
- if (act == NULL) {
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
+ } else {
/* Strict by default. */
return 1;
}
- return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
}
/*
* Duktape/C function magic
*/
-DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
duk_activation *act;
duk_hobject *func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
+ act = thr->callstack_curr;
if (act) {
func = DUK_ACT_GET_FUNC(act);
if (!func) {
@@ -12900,29 +14544,28 @@ DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
}
DUK_ASSERT(func != NULL);
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- duk_hnativefunction *nf = (duk_hnativefunction *) func;
+ if (DUK_HOBJECT_IS_NATFUNC(func)) {
+ duk_hnatfunc *nf = (duk_hnatfunc *) func;
return (duk_int_t) nf->magic;
}
}
return 0;
}
-DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
+ if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
goto type_error;
}
- return (duk_int_t) ((duk_hnativefunction *) h)->magic;
+ return (duk_int_t) ((duk_hnatfunc *) h)->magic;
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
@@ -12934,16 +14577,55 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
return 0;
}
-DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) {
- duk_hnativefunction *nf;
+DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
+ duk_hnatfunc *nf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- nf = duk_require_hnativefunction(ctx, index);
+ nf = duk_require_hnatfunc(thr, idx);
DUK_ASSERT(nf != NULL);
nf->magic = (duk_int16_t) magic;
}
-#line 1 "duk_api_codec.c"
+
+/*
+ * Misc helpers
+ */
+
+/* Resolve a bound function on value stack top to a non-bound target
+ * (leave other values as is).
+ */
+DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_HTHREAD_VALID(thr);
+
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
+ duk_push_tval(thr, &((duk_hboundfunc *) h)->target);
+ duk_replace(thr, -2);
+#if 0
+ DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
+ DUK_TVAL_INCREF(thr, tv);
+ DUK_HOBJECT_DECREF_NORZ(thr, h);
+#endif
+ /* Rely on Function.prototype.bind() on never creating a bound
+ * function whose target is not proper. This is now safe
+ * because the target is not even an internal property but a
+ * struct member.
+ */
+ DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
+ }
+ }
+
+ /* Lightfuncs cannot be bound but are always callable and
+ * constructable.
+ */
+}
/*
* Encoding and decoding basic formats: hex, base64.
*
@@ -12952,19 +14634,27 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t mag
* Base-64: https://tools.ietf.org/html/rfc4648#section-4
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Shared handling for encode/decode argument. Fast path handling for
* buffer and string values because they're the most common. In particular,
* avoid creating a temporary string or buffer when possible.
*/
-DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
- if (duk_is_buffer(ctx, index)) {
- return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
- } else {
- return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
+DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ void *ptr;
+ duk_bool_t isbuffer;
+
+ DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */
+
+ /* XXX: with def_ptr set to a stack related pointer, isbuffer could
+ * be removed from the helper?
+ */
+ ptr = duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
+ if (isbuffer) {
+ DUK_ASSERT(*out_len == 0 || ptr != NULL);
+ return (const duk_uint8_t *) ptr;
}
+ return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len);
}
#if defined(DUK_USE_BASE64_FASTPATH)
@@ -13151,13 +14841,13 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
t <<= 6;
} else {
DUK_ASSERT(x == -1);
- goto error;
+ goto decode_error;
}
} else {
DUK_ASSERT(x >= 0 && x <= 63);
if (n_equal > 0) {
/* Don't allow actual chars after equal sign. */
- goto error;
+ goto decode_error;
}
t = (t << 6) + x;
}
@@ -13183,7 +14873,7 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
/* XX== */
dst -= 2;
} else {
- goto error; /* invalid padding */
+ goto decode_error; /* invalid padding */
}
/* Continue parsing after padding, allows concatenated,
@@ -13207,13 +14897,13 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
* (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
* accepted.
*/
- goto error;
+ goto decode_error;
}
*out_dst_final = dst;
return 1;
- error:
+ decode_error:
return 0;
}
#else /* DUK_USE_BASE64_FASTPATH */
@@ -13255,12 +14945,12 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
/* allow basic ASCII whitespace */
continue;
} else {
- goto error;
+ goto decode_error;
}
if (n_equal > 0) {
/* Don't allow mixed padding and actual chars. */
- goto error;
+ goto decode_error;
}
t = (t << 6) + y;
skip_add:
@@ -13279,7 +14969,7 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
} else if (n_equal == 2) {
dst -= 2;
} else {
- goto error; /* invalid padding */
+ goto decode_error; /* invalid padding */
}
/* Here we can choose either to end parsing and ignore
@@ -13302,33 +14992,32 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
* (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
* accepted.
*/
- goto error;
+ goto decode_error;
}
*out_dst_final = dst;
return 1;
- error:
+ decode_error:
return 0;
}
#endif /* DUK_USE_BASE64_FASTPATH */
-DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for string inputs: no need to coerce to a buffer
* which makes a copy of the input.
*/
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Note: for srclen=0, src may be NULL */
/* Computation must not wrap; this limit works for 32-bit size_t:
@@ -13340,21 +15029,20 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
goto type_error;
}
dstlen = (srclen + 2) / 3 * 4;
- dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
return NULL; /* never here */
}
-DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
@@ -13362,14 +15050,14 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
duk_uint8_t *dst_final;
duk_bool_t retval;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for buffer inputs: no need to coerce to a string
* which causes an unnecessary interning.
*/
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Computation must not wrap, only srclen + 3 is at risk of
* wrapping because after that the number gets smaller.
@@ -13380,7 +15068,7 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
goto type_error;
}
dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
- dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
/* Note: for dstlen=0, dst may be NULL */
retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
@@ -13389,15 +15077,15 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
}
/* XXX: convert to fixed buffer? */
- (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
- duk_replace(ctx, index);
+ (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
}
-DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -13408,14 +15096,14 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
duk_uint16_t *p16;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -13448,13 +15136,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
* caller coerce to string if necessary?
*/
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
}
-DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -13466,10 +15153,10 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
duk_size_t len_safe;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
if (len & 0x01) {
@@ -13477,7 +15164,7 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
}
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -13530,64 +15217,77 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
}
#endif /* DUK_USE_HEX_FASTPATH */
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
}
-DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_JSON_SUPPORT)
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
+#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ top_at_entry = duk_get_top(thr);
#endif
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_stringify_helper(ctx,
- index /*idx_value*/,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_stringify_helper(thr,
+ idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_replacer*/,
DUK_INVALID_INDEX /*idx_space*/,
0 /*flags*/);
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_replace(ctx, index);
- ret = duk_get_string(ctx, index);
+ DUK_ASSERT(duk_is_string(thr, -1));
+ duk_replace(thr, idx);
+ ret = duk_get_string(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
return ret;
}
-DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
+#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ top_at_entry = duk_get_top(thr);
#endif
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_parse_helper(ctx,
- index /*idx_value*/,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_parse_helper(thr,
+ idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_reviver*/,
0 /*flags*/);
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
+}
+#else /* DUK_USE_JSON_SUPPORT */
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-#line 1 "duk_api_compile.c"
+
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_JSON_SUPPORT */
/*
* Compilation and evaluation
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
typedef struct duk__compile_raw_args duk__compile_raw_args;
struct duk__compile_raw_args {
@@ -13597,11 +15297,10 @@ struct duk__compile_raw_args {
};
/* Eval is just a wrapper now. */
-DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
- duk_uint_t comp_flags;
+DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: strictness is *not* inherited from the current Duktape/C.
* This would be confusing because the current strictness state
@@ -13612,9 +15311,7 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
/* [ ... source? filename? ] (depends on flags) */
- comp_flags = flags;
- comp_flags |= DUK_COMPILE_EVAL;
- rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
+ rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
/* [ ... closure/error ] */
@@ -13623,12 +15320,12 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
goto got_rc;
}
- duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
+ duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
if (flags & DUK_COMPILE_SAFE) {
- rc = duk_pcall_method(ctx, 0);
+ rc = duk_pcall_method(thr, 0);
} else {
- duk_call_method(ctx, 0);
+ duk_call_method(thr, 0);
rc = DUK_EXEC_SUCCESS;
}
@@ -13636,21 +15333,20 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
got_rc:
if (flags & DUK_COMPILE_NORESULT) {
- duk_pop(ctx);
+ duk_pop(thr);
}
return rc;
}
/* Helper which can be called both directly and with duk_safe_call(). */
-DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
duk__compile_raw_args *comp_args;
duk_uint_t flags;
- duk_small_uint_t comp_flags;
- duk_hcompiledfunction *h_templ;
+ duk_hcompfunc *h_templ;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
/* Note: strictness is not inherited from the current Duktape/C
* context. Otherwise it would not be possible to compile
@@ -13659,17 +15355,14 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
* for discussion.
*/
- /* [ ... source? filename? &comp_args ] (depends on flags) */
+ /* [ ... source? filename? ] (depends on flags) */
- comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
+ comp_args = (duk__compile_raw_args *) udata;
flags = comp_args->flags;
- duk_pop(ctx);
-
- /* [ ... source? filename? ] */
if (flags & DUK_COMPILE_NOFILENAME) {
/* Automatic filename: 'eval' or 'input'. */
- duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
+ duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
}
/* [ ... source? filename ] */
@@ -13677,14 +15370,10 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
if (!comp_args->src_buffer) {
duk_hstring *h_sourcecode;
- h_sourcecode = duk_get_hstring(ctx, -2);
+ h_sourcecode = duk_get_hstring(thr, -2);
if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
(h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
- /* XXX: when this error is caused by a nonexistent
- * file given to duk_peval_file() or similar, the
- * error message is not the best possible.
- */
- DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
+ DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
}
DUK_ASSERT(h_sourcecode != NULL);
comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
@@ -13692,52 +15381,42 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
}
DUK_ASSERT(comp_args->src_buffer != NULL);
- /* XXX: unnecessary translation of flags */
- comp_flags = 0;
- if (flags & DUK_COMPILE_EVAL) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
- }
if (flags & DUK_COMPILE_FUNCTION) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
- DUK_JS_COMPILE_FLAG_FUNCEXPR;
- }
- if (flags & DUK_COMPILE_STRICT) {
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
+ flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
}
/* [ ... source? filename ] */
- duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
+ duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
/* [ ... source? func_template ] */
if (flags & DUK_COMPILE_NOSOURCE) {
;
} else {
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
/* [ ... func_template ] */
- h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_templ != NULL);
+ h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
duk_js_push_closure(thr,
h_templ,
thr->builtins[DUK_BIDX_GLOBAL_ENV],
thr->builtins[DUK_BIDX_GLOBAL_ENV],
1 /*add_auto_proto*/);
- duk_remove(ctx, -2); /* -> [ ... closure ] */
+ duk_remove_m2(thr); /* -> [ ... closure ] */
/* [ ... closure ] */
return 1;
}
-DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
+DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk__compile_raw_args comp_args_alloc;
duk__compile_raw_args *comp_args = &comp_args_alloc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
/* String length is computed here to avoid multiple evaluation
@@ -13749,9 +15428,8 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
comp_args->src_length = src_length;
comp_args->flags = flags;
- duk_push_pointer(ctx, (void *) comp_args);
- /* [ ... source? filename? &comp_args ] (depends on flags) */
+ /* [ ... source? filename? ] (depends on flags) */
if (flags & DUK_COMPILE_SAFE) {
duk_int_t rc;
@@ -13763,73 +15441,77 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
* directly into flags.
*/
nargs = flags & 0x07;
- DUK_ASSERT(nargs == (1 +
- ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
- ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)));
- rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets);
+ DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
+ ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
+ rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
/* [ ... closure ] */
return rc;
}
- (void) duk__do_compile(ctx);
+ (void) duk__do_compile(thr, (void *) comp_args);
/* [ ... closure ] */
return DUK_EXEC_SUCCESS;
}
-#line 1 "duk_api_debug.c"
/*
* Debugging related API calls
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
+#if defined(DUK_USE_JSON_SUPPORT)
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
duk_idx_t idx;
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* We don't duk_require_stack() here now, but rely on the caller having
* enough space.
*/
- top = duk_get_top(ctx);
- duk_push_array(ctx);
+ top = duk_get_top(thr);
+ duk_push_array(thr);
for (idx = 0; idx < top; idx++) {
- duk_dup(ctx, idx);
- duk_put_prop_index(ctx, -2, idx);
+ duk_dup(thr, idx);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
}
/* XXX: conversion errors should not propagate outwards.
* Perhaps values need to be coerced individually?
*/
- duk_bi_json_stringify_helper(ctx,
- duk_get_top_index(ctx), /*idx_value*/
+ duk_bi_json_stringify_helper(thr,
+ duk_get_top_index(thr), /*idx_value*/
DUK_INVALID_INDEX, /*idx_replacer*/
DUK_INVALID_INDEX, /*idx_space*/
DUK_JSON_FLAG_EXT_CUSTOM |
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
- duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
- duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
- duk_pop(ctx);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
+ duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
+ duk_pop(thr);
+ DUK_ASSERT(duk_is_string(thr, -1));
+}
+#else /* DUK_USE_JSON_SUPPORT */
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
+#endif /* DUK_USE_JSON_SUPPORT */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
+ duk_debug_read_function read_cb,
+ duk_debug_write_function write_cb,
+ duk_debug_peek_function peek_cb,
+ duk_debug_read_flush_function read_flush_cb,
+ duk_debug_write_flush_function write_flush_cb,
+ duk_debug_request_function request_cb,
+ duk_debug_detached_function detached_cb,
+ void *udata) {
duk_heap *heap;
const char *str;
duk_size_t len;
@@ -13840,7 +15522,7 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(read_cb != NULL);
DUK_ASSERT(write_cb != NULL);
/* Other callbacks are optional. */
@@ -13858,59 +15540,51 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
/* Start in paused state. */
heap->dbg_processing = 0;
- heap->dbg_paused = 1;
- heap->dbg_state_dirty = 1;
+ heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
heap->dbg_exec_counter = 0;
heap->dbg_last_counter = 0;
heap->dbg_last_time = 0.0;
+ duk_debug_set_paused(heap); /* XXX: overlap with fields above */
/* Send version identification and flush right afterwards. Note that
* we must write raw, unframed bytes here.
*/
- duk_push_sprintf(ctx, "%ld %ld %s %s\n",
+ duk_push_sprintf(thr, "%ld %ld %s %s\n",
(long) DUK_DEBUG_PROTOCOL_VERSION,
(long) DUK_VERSION,
(const char *) DUK_GIT_DESCRIBE,
(const char *) DUK_USE_TARGET_INFO);
- str = duk_get_lstring(ctx, -1, &len);
+ str = duk_get_lstring(thr, -1, &len);
DUK_ASSERT(str != NULL);
duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
duk_debug_write_flush(thr);
- duk_pop(ctx);
+ duk_pop(thr);
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- duk_hthread *thr;
-
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
/* Can be called multiple times with no harm. */
duk_debug_do_detach(thr->heap);
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
duk_bool_t processed_messages;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
- if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (!duk_debug_is_attached(thr->heap)) {
return;
}
- if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
+ if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
/* Calling duk_debugger_cooperate() while Duktape is being
* called into is not supported. This is not a 100% check
* but prevents any damage in most cases.
@@ -13922,28 +15596,25 @@ DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
DUK_UNREF(processed_messages);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
- duk_hthread *thr;
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
duk_idx_t idx;
duk_bool_t ret = 0;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
- DUK_ERROR_API(thr, "not enough stack values for notify");
+ DUK_ERROR_RANGE(thr, "not enough stack values for notify");
return ret; /* unreachable */
}
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (duk_debug_is_attached(thr->heap)) {
duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
for (idx = top - nvalues; idx < top; idx++) {
- duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
duk_debug_write_tval(thr, tv);
}
duk_debug_write_eom(thr);
@@ -13953,49 +15624,49 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues)
* a transport error was not indicated by the transport write
* callback. This is not a 100% guarantee of course.
*/
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (duk_debug_is_attached(thr->heap)) {
ret = 1;
}
}
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return ret;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
/* Treat like a debugger statement: ignore when not attached. */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_HEAP_SET_PAUSED(thr->heap);
+ if (duk_debug_is_attached(thr->heap)) {
+ if (duk_debug_is_paused(thr->heap)) {
+ DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring"));
+ } else {
+ duk_debug_set_paused(thr->heap);
- /* Pause on the next opcode executed. This is always safe to do even
- * inside the debugger message loop: the interrupt counter will be reset
- * to its proper value when the message loop exits.
- */
- thr->interrupt_init = 1;
- thr->interrupt_counter = 0;
+ /* Pause on the next opcode executed. This is always safe to do even
+ * inside the debugger message loop: the interrupt counter will be reset
+ * to its proper value when the message loop exits.
+ */
+ thr->interrupt_init = 1;
+ thr->interrupt_counter = 0;
+ }
}
}
#else /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
+ duk_debug_read_function read_cb,
+ duk_debug_write_function write_cb,
+ duk_debug_peek_function peek_cb,
+ duk_debug_read_flush_function read_flush_cb,
+ duk_debug_write_flush_function write_flush_cb,
+ duk_debug_request_function request_cb,
+ duk_debug_detached_function detached_cb,
+ void *udata) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(read_cb);
DUK_UNREF(write_cb);
DUK_UNREF(peek_cb);
@@ -14004,67 +15675,65 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
DUK_UNREF(request_cb);
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
/* nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
- DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify");
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
return 0; /* unreachable */
}
/* No debugger support, just pop values. */
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return 0;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
/* Treat like debugger statement: nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
-#line 1 "duk_api_heap.c"
/*
* Heap creation and destruction
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
typedef struct duk_internal_thread_state duk_internal_thread_state;
struct duk_internal_thread_state {
duk_ljstate lj;
- duk_bool_t handling_error;
+ duk_bool_t creating_error;
duk_hthread *curr_thread;
duk_int_t call_recursion_depth;
};
-DUK_EXTERNAL
-duk_context *duk_create_heap(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_handler) {
+DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *heap_udata,
+ duk_fatal_function fatal_handler) {
duk_heap *heap = NULL;
- duk_context *ctx;
+ duk_hthread *thr;
/* Assume that either all memory funcs are NULL or non-NULL, mixed
* cases will now be unsafe.
@@ -14103,44 +15772,55 @@ duk_context *duk_create_heap(duk_alloc_function alloc_func,
if (!heap) {
return NULL;
}
- ctx = (duk_context *) heap->heap_thread;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
- return ctx;
+ thr = heap->heap_thread;
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ return thr;
}
-DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
duk_heap *heap;
- if (!ctx) {
+ if (!thr) {
return;
}
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
duk_heap_free(heap);
}
-DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
duk_heap *heap;
duk_ljstate *lj;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
+ /* Currently not supported when called from within a finalizer.
+ * If that is done, the finalizer will remain running indefinitely,
+ * preventing other finalizers from executing. The assert is a bit
+ * wider, checking that it would be OK to run pending finalizers.
+ */
+ DUK_ASSERT(thr->heap->pf_prevent_count == 0);
+
+ /* Currently not supported to duk_suspend() from an errCreate()
+ * call.
+ */
+ DUK_ASSERT(thr->heap->creating_error == 0);
+
heap = thr->heap;
lj = &heap->lj;
- duk_push_tval(ctx, &lj->value1);
- duk_push_tval(ctx, &lj->value2);
+ duk_push_tval(thr, &lj->value1);
+ duk_push_tval(thr, &lj->value2);
+ /* XXX: creating_error == 0 is asserted above, so no need to store. */
DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
- snapshot->handling_error = heap->handling_error;
+ snapshot->creating_error = heap->creating_error;
snapshot->curr_thread = heap->curr_thread;
snapshot->call_recursion_depth = heap->call_recursion_depth;
@@ -14148,42 +15828,47 @@ DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
lj->type = DUK_LJ_TYPE_UNKNOWN;
DUK_TVAL_SET_UNDEFINED(&lj->value1);
DUK_TVAL_SET_UNDEFINED(&lj->value2);
- heap->handling_error = 0;
+ heap->creating_error = 0;
heap->curr_thread = NULL;
heap->call_recursion_depth = 0;
}
-DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
+ /* Shouldn't be necessary if duk_suspend() is called before
+ * duk_resume(), but assert in case API sequence is incorrect.
+ */
+ DUK_ASSERT(thr->heap->pf_prevent_count == 0);
+ DUK_ASSERT(thr->heap->creating_error == 0);
+
heap = thr->heap;
DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
- heap->handling_error = snapshot->handling_error;
+ heap->creating_error = snapshot->creating_error;
heap->curr_thread = snapshot->curr_thread;
heap->call_recursion_depth = snapshot->call_recursion_depth;
- duk_pop_2(ctx);
+ duk_pop_2(thr);
}
/* XXX: better place for this */
-DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
duk_hobject *h_glob;
duk_hobject *h_prev_glob;
- duk_hobject *h_env;
+ duk_hobjenv *h_env;
duk_hobject *h_prev_env;
- DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
- h_glob = duk_require_hobject(ctx, -1);
+ h_glob = duk_require_hobject(thr, -1);
DUK_ASSERT(h_glob != NULL);
/*
@@ -14205,141 +15890,316 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
* same (initial) built-ins.
*/
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype, updated below */
-
- duk_dup(ctx, -2);
- duk_dup(ctx, -3);
-
- /* [ ... new_glob new_env new_glob new_glob ] */
-
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
+ h_env = duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
+ DUK_ASSERT(h_env != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL);
- /* [ ... new_glob new_env ] */
+ DUK_ASSERT(h_env->target == NULL);
+ DUK_ASSERT(h_glob != NULL);
+ h_env->target = h_glob;
+ DUK_HOBJECT_INCREF(thr, h_glob);
+ DUK_ASSERT(h_env->has_this == 0);
- h_env = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_env != NULL);
+ /* [ ... new_glob ] */
h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
- DUK_HOBJECT_INCREF(thr, h_env);
+ thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env;
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
DUK_UNREF(h_env); /* without refcounts */
DUK_UNREF(h_prev_env);
- /* [ ... new_glob new_env ] */
+ /* [ ... new_glob ] */
- duk_pop_2(ctx);
+ duk_pop(thr);
/* [ ... ] */
}
-#line 1 "duk_api_logging.c"
/*
- * Logging
- *
- * Current logging primitive is a sprintf-style log which is convenient
- * for most C code. Another useful primitive would be to log N arguments
- * from value stack (like the Ecmascript binding does).
+ * Inspection
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
- /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */
- static const duk_uint16_t stridx_logfunc[6] = {
- DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
- DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
- };
+/* For footprint efficient multiple value setting: arrays are much better than
+ * varargs, format string with parsing is often better than string pointer arrays.
+ */
+DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
+ duk_int_t val;
+ const char *p;
+ const char *p_curr;
+ duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ for (p = fmt;;) {
+ len = DUK_STRLEN(p);
+ p_curr = p;
+ p += len + 1;
+ if (len == 0) {
+ /* Double NUL (= empty key) terminates. */
+ break;
+ }
+ val = *vals++;
+ if (val >= 0) {
+ /* Negative values are markers to skip key. */
+ duk_push_string(thr, p_curr);
+ duk_push_int(thr, val);
+ duk_put_prop(thr, -3);
+ }
+ }
+}
- if (level < 0) {
- level = 0;
- } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
- level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
+/* Raw helper to extract internal information / statistics about a value.
+ * The return value is an object with properties that are version specific.
+ * The properties must not expose anything that would lead to security
+ * issues (e.g. exposing compiled function 'data' buffer might be an issue).
+ * Currently only counts and sizes and such are given so there shouldn't
+ * be security implications.
+ */
+
+#define DUK__IDX_TYPE 0
+#define DUK__IDX_ITAG 1
+#define DUK__IDX_REFC 2
+#define DUK__IDX_HBYTES 3
+#define DUK__IDX_CLASS 4
+#define DUK__IDX_PBYTES 5
+#define DUK__IDX_ESIZE 6
+#define DUK__IDX_ENEXT 7
+#define DUK__IDX_ASIZE 8
+#define DUK__IDX_HSIZE 9
+#define DUK__IDX_BCBYTES 10
+#define DUK__IDX_DBYTES 11
+#define DUK__IDX_TSTATE 12
+#define DUK__IDX_VARIANT 13
+
+DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_heaphdr *h;
+ /* The temporary values should be in an array rather than individual
+ * variables which (in practice) ensures that the compiler won't map
+ * them to registers and emit a lot of unnecessary shuffling code.
+ */
+ duk_int_t vals[14];
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* Assume two's complement and set everything to -1. */
+ DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals));
+ DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
+
+ vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
+ vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
+
+ duk_push_bare_object(thr); /* Invalidates 'tv'. */
+ tv = NULL;
+
+ if (h == NULL) {
+ goto finish;
}
+ duk_push_pointer(thr, (void *) h);
+ duk_put_prop_string(thr, -2, "hptr");
- duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
- duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
- duk_dup(ctx, -2);
+#if 0
+ /* Covers a lot of information, e.g. buffer and string variants. */
+ duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
+ duk_put_prop_string(thr, -2, "hflags");
+#endif
- /* [ ... Logger clog logfunc clog ] */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
+#endif
+ vals[DUK__IDX_VARIANT] = 0;
+
+ /* Heaphdr size and additional allocation size, followed by
+ * type specific stuff (with varying value count).
+ */
+ switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
+ case DUK_HTYPE_STRING: {
+ duk_hstring *h_str = (duk_hstring *) h;
+ vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
+#if defined(DUK_USE_HSTRING_EXTDATA)
+ if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
+ vals[DUK__IDX_VARIANT] = 1;
+ }
+#endif
+ break;
+ }
+ case DUK_HTYPE_OBJECT: {
+ duk_hobject *h_obj = (duk_hobject *) h;
+
+ /* XXX: variants here are maybe pointless; class is enough? */
+ if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
+ } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
+ } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
+ } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
+ vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
+ /* XXX: some size information */
+#endif
+ } else {
+ vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
+ }
- duk_push_vsprintf(ctx, fmt, ap);
+ vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
+ vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj),
+ vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
+ vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
+ vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
+ vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
- /* [ ... Logger clog logfunc clog(=this) msg ] */
+ /* Note: e_next indicates the number of gc-reachable entries
+ * in the entry part, and also indicates the index where the
+ * next new property would be inserted. It does *not* indicate
+ * the number of non-NULL keys present in the object. That
+ * value could be counted separately but requires a pass through
+ * the key list.
+ */
- duk_call_method(ctx, 1 /*nargs*/);
+ if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
+ duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
+ vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
+ }
+ break;
+ }
+ case DUK_HTYPE_BUFFER: {
+ duk_hbuffer *h_buf = (duk_hbuffer *) h;
- /* [ ... Logger clog res ] */
+ if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
+ if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
+ vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */
+ vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
+ } else {
+ /* When alloc_size == 0 the second allocation may not
+ * actually exist.
+ */
+ vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
+ vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
+ }
+ vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
+ } else {
+ DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
+ vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
+ }
+ break;
+ }
+ }
- duk_pop_3(ctx);
+ finish:
+ duk__inspect_multiple_uint(thr,
+ "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
+ "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
+ "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
+ (duk_int_t *) &vals);
}
-DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
- va_list ap;
+DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
+ duk_activation *act;
+ duk_uint_fast32_t pc;
+ duk_uint_fast32_t line;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- va_start(ap, fmt);
- duk_log_va(ctx, level, fmt, ap);
- va_end(ap);
+ /* -1 = top callstack entry
+ * -2 = caller of level -1
+ * etc
+ */
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ duk_push_undefined(thr);
+ return;
+ }
+ duk_push_bare_object(thr);
+
+ /* Relevant PC is just before current one because PC is
+ * post-incremented. This should match what error augment
+ * code does.
+ */
+ pc = duk_hthread_get_act_prev_pc(thr, act);
+
+ duk_push_tval(thr, &act->tv_func);
+
+ duk_push_uint(thr, (duk_uint_t) pc);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
+
+#if defined(DUK_USE_PC2LINE)
+ line = duk_hobject_pc2line_query(thr, -1, pc);
+#else
+ line = 0;
+#endif
+ duk_push_uint(thr, (duk_uint_t) line);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
+
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
+ /* Providing access to e.g. act->lex_env would be dangerous: these
+ * internal structures must never be accessible to the application.
+ * Duktape relies on them having consistent data, and this consistency
+ * is only asserted for, not checked for.
+ */
}
-#line 1 "duk_api_memory.c"
+
+/* automatic undefs */
+#undef DUK__IDX_ASIZE
+#undef DUK__IDX_BCBYTES
+#undef DUK__IDX_CLASS
+#undef DUK__IDX_DBYTES
+#undef DUK__IDX_ENEXT
+#undef DUK__IDX_ESIZE
+#undef DUK__IDX_HBYTES
+#undef DUK__IDX_HSIZE
+#undef DUK__IDX_ITAG
+#undef DUK__IDX_PBYTES
+#undef DUK__IDX_REFC
+#undef DUK__IDX_TSTATE
+#undef DUK__IDX_TYPE
+#undef DUK__IDX_VARIANT
/*
* Memory calls.
*/
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* #include duk_internal.h -> already included */
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC_RAW(thr->heap, size);
}
-DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_FREE_RAW(thr->heap, ptr);
}
-DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_REALLOC_RAW(thr->heap, ptr, size);
}
-DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC(thr->heap, size);
}
-DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_FREE(thr->heap, ptr);
+ DUK_FREE_CHECKED(thr, ptr);
}
-DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Note: since this is an exposed API call, there should be
@@ -14354,11 +16214,10 @@ DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
return DUK_REALLOC(thr->heap, ptr, size);
}
-DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(out_funcs != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -14370,35 +16229,24 @@ DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_function
out_funcs->udata = heap->heap_udata;
}
-DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
duk_heap *heap;
+ duk_small_uint_t ms_flags;
- DUK_UNREF(flags);
-
- /* NULL accepted */
- if (!ctx) {
- return;
- }
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
- duk_heap_mark_and_sweep(heap, 0);
-#else
- DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring"));
- DUK_UNREF(ctx);
- DUK_UNREF(flags);
-#endif
+ DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */
+ ms_flags = (duk_small_uint_t) flags;
+ duk_heap_mark_and_sweep(heap, ms_flags);
}
-#line 1 "duk_api_object.c"
/*
* Object handling: property access and other support functions.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Property handling
@@ -14408,82 +16256,98 @@ DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
* defineProperty, getOwnPropertyDescriptor).
*/
-DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property get right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_getprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
/* a value is left on stack regardless of rc */
- duk_remove(ctx, -2); /* remove key */
+ duk_remove_m2(thr); /* remove key */
+ DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1);
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_get_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_get_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_get_prop(thr, obj_idx);
+}
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_get_prop(ctx, obj_index);
+DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) {
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_get_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
- rc = duk_get_prop_stridx(ctx, obj_index, stridx);
+ rc = duk_get_prop_stridx(thr, obj_idx, stridx);
if (out_has_prop) {
*out_has_prop = rc;
}
- rc = duk_to_boolean(ctx, -1);
+ rc = duk_to_boolean(thr, -1);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx);
+ duk_pop(thr);
return rc;
}
-DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
@@ -14496,254 +16360,323 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d
*/
DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
(idx_key == -1 && (idx_key ^ 1) == -2));
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, idx_key);
- tv_val = duk_require_tval(ctx, idx_key ^ 1);
- throw_flag = duk_is_strict_call(ctx);
+ /* XXX: Direct access; faster validation. */
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, idx_key);
+ tv_val = duk_require_tval(thr, idx_key ^ 1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop_2(ctx); /* remove key and value */
+ duk_pop_2(thr); /* remove key and value */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__put_prop_shared(ctx, obj_idx, -2);
+DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__put_prop_shared(thr, obj_idx, -2);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
/* Careful here and with other duk_put_prop_xxx() helpers: the
* target object and the property value may be in the same value
* stack slot (unusual, but still conceptually clear).
*/
- obj_idx = duk_normalize_index(ctx, obj_idx);
- (void) duk_push_string(ctx, key);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_string(thr, key);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk__put_prop_shared(ctx, obj_idx, -1);
+DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
+
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+
+DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property delete right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
- throw_flag = duk_is_strict_call(ctx);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_del_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_del_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_del_prop(thr, obj_idx);
+}
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_del_prop(ctx, obj_index);
+DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_del_prop(thr, obj_idx);
+}
+
+#if 0
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+#endif
+
+DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property existence check right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_has_prop(thr, obj_idx);
+}
+
+DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_has_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_has_prop(thr, obj_idx);
}
-/* Define own property without inheritance looks and such. This differs from
+#if 0
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+#endif
+
+/* Define own property without inheritance lookups and such. This differs from
* [[DefineOwnProperty]] because special behaviors (like Array 'length') are
* not invoked by this method. The caller must be careful to invoke any such
* behaviors if necessary.
*/
-DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
- key = duk_to_hstring(ctx, -2);
+ key = duk_to_property_key_hstring(thr, -2);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
- duk_pop(ctx); /* pop key */
+ duk_pop(thr); /* pop key */
}
-DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
- duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
+ duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
+ (duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
+ (duk_small_uint_t) (packed_args & 0xffL));
+}
+
+#if 0 /*unused*/
+DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_ASSERT_DISABLE(builtin_idx >= 0);
- DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ DUK_ASSERT_BIDX_VALID(builtin_idx);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
+#endif
/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
* setter/getter into an object property. This is needed by the 'arguments'
* object creation code, function instance creation code, and Function.prototype.bind().
*/
-DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj = duk_require_hobject(ctx, obj_index);
- duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
- duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
+DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring_stridx(thr, stridx);
+ duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER);
+ duk_dup_top(thr);
+ duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
+}
+
+/* Object.getOwnPropertyDescriptor() equivalent C binding. */
+DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(flags); /* no flags defined yet */
+
+ duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */
}
/* Object.defineProperty() equivalent C binding. */
-DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
duk_idx_t idx_base;
duk_hobject *obj;
duk_hstring *key;
@@ -14753,9 +16686,9 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
duk_uint_t is_data_desc;
duk_uint_t is_acc_desc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
@@ -14767,12 +16700,12 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
goto fail_invalid_desc;
}
- idx_base = duk_get_top_index(ctx);
+ idx_base = duk_get_top_index(thr);
if (flags & DUK_DEFPROP_HAVE_SETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
+ set = duk_get_hobject_promote_lfunc(thr, idx_base);
if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
goto fail_not_callable;
}
@@ -14781,10 +16714,10 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
set = NULL;
}
if (flags & DUK_DEFPROP_HAVE_GETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
+ get = duk_get_hobject_promote_lfunc(thr, idx_base);
if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
goto fail_not_callable;
}
@@ -14798,21 +16731,23 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
} else {
idx_value = (duk_idx_t) -1;
}
- key = duk_require_hstring(ctx, idx_base);
+ key = duk_to_property_key_hstring(thr, idx_base);
+ DUK_ASSERT(key != NULL);
- duk_require_valid_index(ctx, idx_base);
+ duk_require_valid_index(thr, idx_base);
- duk_hobject_define_property_helper(ctx,
+ duk_hobject_define_property_helper(thr,
flags /*defprop_flags*/,
obj,
key,
idx_value,
get,
- set);
+ set,
+ 1 /*throw_flag*/);
/* Clean up stack */
- duk_set_top(ctx, idx_base);
+ duk_set_top(thr, idx_base);
/* [ ... obj ... ] */
@@ -14834,66 +16769,140 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
* and are not exposed through the API.
*/
-DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, obj_index);
+ obj = duk_get_hobject(thr, obj_idx);
if (obj) {
/* Note: this may fail, caller should protect the call if necessary */
duk_hobject_compact_props(thr, obj);
}
}
+DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_compact(thr, -1);
+}
+
/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
-DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_dup(thr, obj_idx);
+ duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */
+}
+
+DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_require_hobject(thr, enum_index);
+ duk_dup(thr, enum_index);
+ return duk_hobject_enumerator_next(thr, get_value);
+}
+
+DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) {
+ duk_tval *tv;
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, obj_idx);
+ DUK_ASSERT(tv != NULL);
+
+ /* Seal/freeze are quite rare in practice so it'd be nice to get the
+ * correct behavior simply via automatic promotion (at the cost of some
+ * memory churn). However, the promoted objects don't behave the same,
+ * e.g. promoted lightfuncs are extensible.
+ */
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_BUFFER:
+ /* Plain buffer: already sealed, but not frozen (and can't be frozen
+ * because index properties can't be made non-writable.
+ */
+ if (is_freeze) {
+ goto fail_cannot_freeze;
+ }
+ break;
+ case DUK_TAG_LIGHTFUNC:
+ /* Lightfunc: already sealed and frozen, success. */
+ break;
+ case DUK_TAG_OBJECT:
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
+ /* Buffer objects cannot be frozen because there's no internal
+ * support for making virtual array indices non-writable.
+ */
+ DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
+ goto fail_cannot_freeze;
+ }
+ duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
+
+ /* Sealed and frozen objects cannot gain any more properties,
+ * so this is a good time to compact them.
+ */
+ duk_hobject_compact_props(thr, h);
+ break;
+ default:
+ /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
+ break;
+ }
+ return;
+
+ fail_cannot_freeze:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
+}
+
+DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_dup(ctx, obj_index);
- duk_require_hobject_or_lfunc_coerce(ctx, -1);
- duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
+ duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/);
}
-DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_require_hobject(ctx, enum_index);
- duk_dup(ctx, enum_index);
- return duk_hobject_enumerator_next(ctx, get_value);
+ duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/);
}
/*
* Helpers for writing multiple properties
*/
-DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) {
+DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
const duk_function_list_entry *ent = funcs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- duk_push_c_function(ctx, ent->value, ent->nargs);
- duk_put_prop_string(ctx, obj_index, ent->key);
+ duk_push_c_function(thr, ent->value, ent->nargs);
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
}
-DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) {
+DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
const duk_number_list_entry *ent = numbers;
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- duk_push_number(ctx, ent->value);
- duk_put_prop_string(ctx, obj_index, ent->key);
+ tv = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
@@ -14903,34 +16912,61 @@ DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, con
* Shortcut for accessing global object properties
*/
-DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- ret = duk_get_prop_string(ctx, -1, key);
- duk_remove(ctx, -2);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_string(thr, -1, key);
+ duk_remove_m2(thr);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- duk_insert(ctx, -2);
- ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
- duk_pop(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_lstring(thr, -1, key, key_len);
+ duk_remove_m2(thr);
+ return ret;
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
+ return ret;
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
return ret;
}
@@ -14938,38 +16974,35 @@ DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key)
* Object prototype
*/
-DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, index);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
/* XXX: shared helper for duk_push_hobject_or_undefined()? */
proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
if (proto) {
- duk_push_hobject(ctx, proto);
+ duk_push_hobject(thr, proto);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, index);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT);
- proto = duk_get_hobject(ctx, -1);
+ proto = duk_get_hobject(thr, -1);
/* proto can also be NULL here (allowed explicitly) */
#if defined(DUK_USE_ROM_OBJECTS)
@@ -14981,30 +17014,65 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
- duk_pop(ctx);
+ duk_pop(thr);
}
/*
* Object finalizer
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
/* XXX: these could be implemented as macros calling an internal function
* directly.
* XXX: same issue as with Duktape.fin: there's no way to delete the property
* now (just set it to undefined).
*/
-DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
}
-DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+ duk_bool_t callable;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */
+ callable = duk_is_callable(thr, -1);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
+
+ /* In addition to setting the finalizer property, keep a "have
+ * finalizer" flag in duk_hobject in sync so that refzero can do
+ * a very quick finalizer check by walking the prototype chain
+ * and checking the flag alone. (Note that this means that just
+ * setting _Finalizer on an object won't affect finalizer checks.)
+ *
+ * NOTE: if the argument is a Proxy object, this flag will be set
+ * on the Proxy, not the target. As a result, the target won't get
+ * a finalizer flag and the Proxy also won't be finalized as there's
+ * an explicit Proxy check in finalization now.
+ */
+ if (callable) {
+ DUK_HOBJECT_SET_HAVE_FINALIZER(h);
+ } else {
+ DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h);
+ }
+}
+#else /* DUK_USE_FINALIZER_SUPPORT */
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
- duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-#line 1 "duk_api_stack.c"
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* API calls related to general value stack manipulation: resizing the value
* stack, pushing and popping values, type checking and reading values,
@@ -15017,19 +17085,19 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
/* XXX: repetition of stack pre-checks -> helper or macro or inline */
/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Forward declarations
*/
-DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags);
+DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx);
/*
* Global state for working around missing variadic macros
*/
-#ifndef DUK_USE_VARIADIC_MACROS
+#if !defined(DUK_USE_VARIADIC_MACROS)
DUK_EXTERNAL const char *duk_api_global_filename = NULL;
DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
#endif
@@ -15038,34 +17106,99 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
* Misc helpers
*/
+DUK_LOCAL const char * const duk__symbol_type_strings[4] = {
+ "hidden", "global", "local", "wellknown"
+};
+
+#if !defined(DUK_USE_PACKED_TVAL)
+DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
+ DUK_TYPE_NUMBER,
+ DUK_TYPE_NUMBER, /* fastint */
+ DUK_TYPE_UNDEFINED,
+ DUK_TYPE_NULL,
+ DUK_TYPE_BOOLEAN,
+ DUK_TYPE_POINTER,
+ DUK_TYPE_LIGHTFUNC,
+ DUK_TYPE_NONE,
+ DUK_TYPE_STRING,
+ DUK_TYPE_OBJECT,
+ DUK_TYPE_BUFFER,
+};
+DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
+ DUK_TYPE_MASK_NUMBER,
+ DUK_TYPE_MASK_NUMBER, /* fastint */
+ DUK_TYPE_MASK_UNDEFINED,
+ DUK_TYPE_MASK_NULL,
+ DUK_TYPE_MASK_BOOLEAN,
+ DUK_TYPE_MASK_POINTER,
+ DUK_TYPE_MASK_LIGHTFUNC,
+ DUK_TYPE_MASK_NONE,
+ DUK_TYPE_MASK_STRING,
+ DUK_TYPE_MASK_OBJECT,
+ DUK_TYPE_MASK_BUFFER,
+};
+#endif /* !DUK_USE_PACKED_TVAL */
+
+/* Assert that there's room for one value. */
+#define DUK__ASSERT_SPACE() do { \
+ DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
+ } while (0)
+
/* Check that there's room to push one value. */
#if defined(DUK_USE_VALSTACK_UNSAFE)
/* Faster but value stack overruns are memory unsafe. */
-#define DUK__CHECK_SPACE() do { \
- DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
- } while (0)
+#define DUK__CHECK_SPACE() DUK__ASSERT_SPACE()
#else
#define DUK__CHECK_SPACE() do { \
if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
+ DUK_ERROR_RANGE_PUSH_BEYOND(thr); \
} \
} while (0)
#endif
-DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
+DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) {
+ const duk_uint8_t *data;
+ duk_size_t len;
-DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h));
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */
+
+ data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ DUK_ASSERT(len >= 1);
+
+ /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */
+
+ if (data[0] == 0xffU) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x82U) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x80U) {
+ return DUK_SYMBOL_TYPE_GLOBAL;
+ } else if (data[len - 1] != 0xffU) {
+ return DUK_SYMBOL_TYPE_LOCAL;
+ } else {
+ return DUK_SYMBOL_TYPE_WELLKNOWN;
+ }
+}
+
+DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) {
+ duk_small_uint_t idx;
+ idx = duk__get_symbol_type(h);
+ DUK_ASSERT(idx < sizeof(duk__symbol_type_strings));
+ return duk__symbol_type_strings[idx];
+}
+
+DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag);
+
+DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
/*
* Special cases like NaN and +/- Infinity are handled explicitly
@@ -15112,29 +17245,23 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b
}
}
- error_notnumber:
-
if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
- return 0;
+
+ return def_value;
}
-DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
+DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
/* Same as above but for unsigned int range. */
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv)) {
@@ -15169,13 +17296,12 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk
}
}
- error_notnumber:
-
if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
- return 0;
+
+ return def_value;
}
/*
@@ -15187,12 +17313,11 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk
* There's some repetition because of this; keep the functions in sync.
*/
-DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
/* Care must be taken to avoid pointer wrapping in the index
@@ -15206,86 +17331,103 @@ DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
/* since index non-negative */
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return (duk_idx_t) uidx;
}
return DUK_INVALID_INDEX;
}
-DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return (duk_idx_t) uidx;
}
- DUK_ERROR_API_INDEX(thr, index);
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return 0; /* unreachable */
}
-DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return thr->valstack_bottom + uidx;
}
return NULL;
}
-DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval
+ * pointer. When duk_get_tval() would return NULL, this variant returns a
+ * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site
+ * to avoid an unnecessary NULL check which sometimes leads to better code.
+ * The return duk_tval is read only (at least for the UNUSED value).
+ */
+DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
+
+DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval(thr, idx);
+ if (tv != NULL) {
+ return tv;
+ }
+ return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
+}
+
+DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -15293,40 +17435,38 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
/* Use unsigned arithmetic to optimize comparison. */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return thr->valstack_bottom + uidx;
}
- DUK_ERROR_API_INDEX(thr, index);
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return NULL;
}
/* Non-critical. */
-DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- return (duk_normalize_index(ctx, index) >= 0);
+ return (duk_normalize_index(thr, idx) >= 0);
}
/* Non-critical. */
-DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- if (duk_normalize_index(ctx, index) < 0) {
- DUK_ERROR_API_INDEX(thr, index);
+ if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return; /* unreachable */
}
}
@@ -15335,26 +17475,38 @@ DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
* Value stack top handling
*/
-DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
}
+/* Internal helper to get current top but to require a minimum top value
+ * (TypeError if not met).
+ */
+DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) {
+ duk_idx_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ if (DUK_UNLIKELY(ret < min_top)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ return ret;
+}
+
/* Set stack top within currently allocated range, but don't reallocate.
* This is performance critical especially for call handling, so whenever
* changing, profile and look at generated code.
*/
-DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t vs_limit;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -15362,16 +17514,16 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
- if (index < 0) {
+ if (idx < 0) {
/* Negative indices are always within allocated stack but
* must not go below zero index.
*/
- uindex = vs_size + (duk_uidx_t) index;
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
/* Positive index can be higher than valstack top but must
* not go above allocated stack (equality is OK).
*/
- uindex = (duk_uidx_t) index;
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
@@ -15379,15 +17531,15 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
#if defined(DUK_USE_VALSTACK_UNSAFE)
- DUK_ASSERT(uindex <= vs_limit);
+ DUK_ASSERT(uidx <= vs_limit);
DUK_UNREF(vs_limit);
#else
- if (DUK_UNLIKELY(uindex > vs_limit)) {
- DUK_ERROR_API_INDEX(thr, index);
+ if (DUK_UNLIKELY(uidx > vs_limit)) {
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return; /* unreachable */
}
#endif
- DUK_ASSERT(uindex <= vs_limit);
+ DUK_ASSERT(uidx <= vs_limit);
/* Handle change in value stack top. Respect value stack
* initialization policy: 'undefined' above top. Note that
@@ -15395,37 +17547,113 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
* so must relookup after DECREF.
*/
- if (uindex >= vs_size) {
+ if (uidx >= vs_size) {
/* Stack size increases or stays the same. */
#if defined(DUK_USE_ASSERTIONS)
duk_uidx_t count;
- count = uindex - vs_size;
+ count = uidx - vs_size;
while (count != 0) {
count--;
tv = thr->valstack_top + count;
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
}
#endif
- thr->valstack_top = thr->valstack_bottom + uindex;
+ thr->valstack_top = thr->valstack_bottom + uidx;
} else {
/* Stack size decreases. */
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_uidx_t count;
+ duk_tval *tv_end;
- count = vs_size - uindex;
+ count = vs_size - uidx;
DUK_ASSERT(count > 0);
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end); /* Because count > 0. */
+ do {
+ tv--;
DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+ DUK_REFZERO_CHECK_FAST(thr);
+#else /* DUK_USE_REFERENCE_COUNTING */
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end);
+ do {
+ tv--;
+ DUK_TVAL_SET_UNDEFINED(tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+#endif /* DUK_USE_REFERENCE_COUNTING */
+ }
+}
+
+/* Internal variant with a non-negative index and no runtime size checks. */
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_set_top(thr, idx);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ duk_uidx_t uidx;
+ duk_uidx_t vs_size;
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
+ DUK_ASSERT(idx >= 0);
+ DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom));
+
+ /* XXX: byte arithmetic */
+ uidx = (duk_uidx_t) idx;
+ vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
+
+ if (uidx >= vs_size) {
+ /* Stack size increases or stays the same. */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_uidx_t count;
+
+ count = uidx - vs_size;
+ while (count != 0) {
+ count--;
+ tv = thr->valstack_top + count;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
}
+#endif
+ thr->valstack_top = thr->valstack_bottom + uidx;
+ } else {
+ /* Stack size decreases. */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ DUK_ASSERT(count > 0);
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end); /* Because count > 0. */
+ do {
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+ DUK_REFZERO_CHECK_FAST(thr);
#else /* DUK_USE_REFERENCE_COUNTING */
duk_uidx_t count;
duk_tval *tv_end;
- count = vs_size - uindex;
+ count = vs_size - uidx;
tv = thr->valstack_top;
tv_end = tv - count;
DUK_ASSERT(tv > tv_end);
@@ -15437,14 +17665,30 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
#endif /* DUK_USE_REFERENCE_COUNTING */
}
}
+#endif /* DUK_USE_PREFER_SIZE */
-DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to
+ * 'undefined' (doing nothing if idx_wipe_start == top). Indices are
+ * positive and within value stack reserve. This is used by call handling.
+ */
+DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(top >= 0);
+ DUK_ASSERT(idx_wipe_start >= 0);
+ DUK_ASSERT(idx_wipe_start <= top);
+ DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end);
+ DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end);
+
+ duk_set_top_unsafe(thr, idx_wipe_start);
+ duk_set_top_unsafe(thr, top);
+}
+
+DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
/* Return invalid index; if caller uses this without checking
* in another API call, the index won't map to a valid stack
@@ -15455,15 +17699,26 @@ DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
return ret;
}
-DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Internal variant: call assumes there is at least one element on the value
+ * stack frame; this is only asserted for.
+ */
+DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
+ return ret;
+}
+
+DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
+ duk_idx_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
- DUK_ERROR_API_INDEX(thr, -1);
+ DUK_ERROR_RANGE_INDEX(thr, -1);
return 0; /* unreachable */
}
return ret;
@@ -15474,64 +17729,74 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
*
* This resizing happens above the current "top": the value stack can be
* grown or shrunk, but the "top" is not affected. The value stack cannot
- * be resized to a size below the current "top".
+ * be resized to a size below the current reserve.
*
* The low level reallocation primitive must carefully recompute all value
* stack pointers, and must also work if ALL pointers are NULL. The resize
* is quite tricky because the valstack realloc may cause a mark-and-sweep,
* which may run finalizers. Running finalizers may resize the valstack
* recursively (the same value stack we're working on). So, after realloc
- * returns, we know that the valstack "top" should still be the same (there
- * should not be live values above the "top"), but its underlying size and
- * pointer may have changed.
+ * returns, we know that the valstack bottom, top, and reserve should still
+ * be the same (there should not be live values above the "top"), but its
+ * underlying size, alloc_end, and base pointer may have changed.
+ *
+ * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that
+ * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
*/
-/* XXX: perhaps refactor this to allow caller to specify some parameters, or
- * at least a 'compact' flag which skips any spare or round-up .. useful for
- * emergency gc.
+/* Low level valstack resize primitive, used for both grow and shrink. All
+ * adjustments for slack etc have already been done. Doesn't throw but does
+ * have allocation side effects.
*/
-
-DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_ptrdiff_t old_bottom_offset;
- duk_ptrdiff_t old_top_offset;
- duk_ptrdiff_t old_end_offset_post;
-#ifdef DUK_USE_DEBUG
- duk_ptrdiff_t old_end_offset_pre;
- duk_tval *old_valstack_pre;
- duk_tval *old_valstack_post;
-#endif
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) {
+ duk_tval *pre_valstack;
+ duk_tval *pre_bottom;
+ duk_tval *pre_top;
+ duk_tval *pre_end;
+ duk_tval *pre_alloc_end;
+ duk_ptrdiff_t ptr_diff;
duk_tval *new_valstack;
duk_size_t new_alloc_size;
+ duk_tval *tv_prev_alloc_end;
duk_tval *p;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_HTHREAD_VALID(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
- DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
+ DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */
DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
- /* get pointer offsets for tweaking below */
- old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
- old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
-#ifdef DUK_USE_DEBUG
- old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
- old_valstack_pre = thr->valstack;
-#endif
+ /* Pre-realloc pointer copies for asserts and debug logs. */
+ pre_valstack = thr->valstack;
+ pre_bottom = thr->valstack_bottom;
+ pre_top = thr->valstack_top;
+ pre_end = thr->valstack_end;
+ pre_alloc_end = thr->valstack_alloc_end;
- /* Allocate a new valstack.
- *
- * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
- * invalidate the original thr->valstack base pointer inside the realloc
- * process. See doc/memory-management.rst.
+ DUK_UNREF(pre_valstack);
+ DUK_UNREF(pre_bottom);
+ DUK_UNREF(pre_top);
+ DUK_UNREF(pre_end);
+ DUK_UNREF(pre_alloc_end);
+
+ /* If finalizer torture enabled, force base pointer change every time
+ * when it would be allowed.
*/
+#if defined(DUK_USE_FINALIZER_TORTURE)
+ if (thr->heap->pf_prevent_count == 0) {
+ duk_hthread_valstack_torture_realloc(thr);
+ }
+#endif
+ /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with
+ * a side effect changing the base pointer.
+ */
new_alloc_size = sizeof(duk_tval) * new_size;
new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
- if (!new_valstack) {
+ if (DUK_UNLIKELY(new_valstack == NULL)) {
/* Because new_size != 0, if condition doesn't need to be
* (new_valstack != NULL || new_size == 0).
*/
@@ -15541,69 +17806,78 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 0;
}
- /* Note: the realloc may have triggered a mark-and-sweep which may
- * have resized our valstack internally. However, the mark-and-sweep
- * MUST NOT leave the stack bottom/top in a different state. Particular
- * assumptions and facts:
- *
- * - The thr->valstack pointer may be different after realloc,
- * and the offset between thr->valstack_end <-> thr->valstack
- * may have changed.
- * - The offset between thr->valstack_bottom <-> thr->valstack
- * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
- * because mark-and-sweep must adhere to a strict stack policy.
- * In other words, logical bottom and top MUST NOT have changed.
- * - All values above the top are unreachable but are initialized
- * to UNDEFINED, up to the post-realloc valstack_end.
- * - 'old_end_offset' must be computed after realloc to be correct.
- */
-
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
-
- /* success, fixup pointers */
- old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
-#ifdef DUK_USE_DEBUG
- old_valstack_post = thr->valstack;
+ /* Debug log any changes in pointer(s) by side effects. These don't
+ * necessarily imply any incorrect behavior, but should be rare in
+ * practice.
+ */
+#if defined(DUK_USE_DEBUG)
+ if (thr->valstack != pre_valstack) {
+ DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p",
+ (void *) pre_valstack, (void *) thr->valstack));
+ }
+ if (thr->valstack_bottom != pre_bottom) {
+ DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p",
+ (void *) pre_bottom, (void *) thr->valstack_bottom));
+ }
+ if (thr->valstack_top != pre_top) {
+ DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p",
+ (void *) pre_top, (void *) thr->valstack_top));
+ }
+ if (thr->valstack_end != pre_end) {
+ DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_end, (void *) thr->valstack_end));
+ }
+ if (thr->valstack_alloc_end != pre_alloc_end) {
+ DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end));
+ }
#endif
+
+ /* Assertions: offsets for bottom, top, and end (reserve) must not
+ * have changed even with side effects because they are always
+ * restored in unwind. For alloc_end there's no guarantee: it may
+ * have grown or shrunk (but remain above 'end').
+ */
+ DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack);
+ DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack);
+ DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
+ /* Write new pointers. Most pointers can be handled as a pointer
+ * difference.
+ */
+ ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack);
+ tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff);
thr->valstack = new_valstack;
- thr->valstack_end = new_valstack + new_size;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = new_size;
-#endif
- thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
- thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff);
+ thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size);
+ /* Assertions: pointer sanity after pointer updates. */
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
- /* useful for debugging */
-#ifdef DUK_USE_DEBUG
- if (old_end_offset_pre != old_end_offset_post) {
- DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
- "end offset changed: %lu -> %lu",
- (unsigned long) old_end_offset_pre,
- (unsigned long) old_end_offset_post));
- }
- if (old_valstack_pre != old_valstack_post) {
- DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
- (void *) old_valstack_pre,
- (void *) old_valstack_post));
- }
-#endif
-
- DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
- "new pointers: start=%p end=%p bottom=%p top=%p",
- (unsigned long) new_size, (unsigned long) new_alloc_size,
- (long) (thr->valstack_bottom - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (void *) thr->valstack, (void *) thr->valstack_end,
- (void *) thr->valstack_bottom, (void *) thr->valstack_top));
-
- /* Init newly allocated slots (only). */
- p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
- while (p < thr->valstack_end) {
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
+ DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): "
+ "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), "
+ "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);"
+ " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)",
+ (unsigned long) (pre_alloc_end - pre_valstack),
+ (unsigned long) new_size,
+ (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack),
+ (unsigned long) new_alloc_size,
+ (void *) pre_valstack, (void *) thr->valstack,
+ (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack),
+ (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack),
+ (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack),
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack),
+ (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end)));
+
+ /* If allocation grew, init any new slots to 'undefined'. */
+ p = tv_prev_alloc_end;
+ while (p < thr->valstack_alloc_end) {
/* Never executed if new size is smaller. */
DUK_TVAL_SET_UNDEFINED(p);
p++;
@@ -15612,7 +17886,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
/* Assert for value stack initialization policy. */
#if defined(DUK_USE_ASSERTIONS)
p = thr->valstack_top;
- while (p < thr->valstack_end) {
+ while (p < thr->valstack_alloc_end) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
p++;
}
@@ -15621,204 +17895,257 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 1;
}
-DUK_INTERNAL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t old_size;
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) {
+ duk_size_t min_size;
duk_size_t new_size;
- duk_bool_t is_shrink = 0;
- duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
- duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
- duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
-
- DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
- "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
- (unsigned long) min_new_size,
- (long) (thr->valstack_end - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (long) (thr->valstack_bottom - thr->valstack),
- (int) shrink_flag, (int) compact_flag, (int) throw_flag));
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-#if defined(DUK_USE_PREFER_SIZE)
- old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
+ DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes);
+ min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */
+
+#if defined(DUK_USE_VALSTACK_GROW_SHIFT)
+ /* New size is minimum size plus a proportional slack, e.g. shift of
+ * 2 means a 25% slack.
+ */
+ new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT);
#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- old_size = thr->valstack_size;
+ /* New size is tight with no slack. This is sometimes preferred in
+ * low memory environments.
+ */
+ new_size = min_size;
#endif
- if (min_new_size <= old_size) {
- is_shrink = 1;
- if (!shrink_flag ||
- old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
- DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
- return 1;
+ if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) {
+ /* Note: may be triggered even if minimal new_size would not reach the limit,
+ * plan limit accordingly.
+ */
+ if (throw_on_error) {
+ DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
}
+ return 0;
}
- new_size = min_new_size;
- if (!compact_flag) {
- if (is_shrink) {
- /* shrink case; leave some spare */
- new_size += DUK_VALSTACK_SHRINK_SPARE;
+ if (duk__resize_valstack(thr, new_size) == 0) {
+ if (throw_on_error) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
-
- /* round up roughly to next 'grow step' */
- new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
+ return 0;
}
- DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
- (const char *) (new_size > old_size ? "grow" : "shrink"),
- (unsigned long) old_size, (unsigned long) new_size,
- (unsigned long) min_new_size));
+ thr->valstack_end = thr->valstack + min_size;
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
- if (new_size > thr->valstack_max) {
- /* Note: may be triggered even if minimal new_size would not reach the limit,
- * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
+ return 1;
+}
+
+/* Hot, inlined value stack grow check. Because value stack almost never
+ * grows, the actual resize call is in a NOINLINE helper.
+ */
+DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
+
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ /* Values in [valstack_top,valstack_alloc_end[ are initialized
+ * to 'undefined' so we can just move the end pointer.
*/
- if (throw_flag) {
- DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
- } else {
- return 0;
- }
+ thr->valstack_end = tv;
+ return;
}
+ (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/);
+}
- /*
- * When resizing the valstack, a mark-and-sweep may be triggered for
- * the allocation of the new valstack. If the mark-and-sweep needs
- * to use our thread for something, it may cause *the same valstack*
- * to be resized recursively. This happens e.g. when mark-and-sweep
- * finalizers are called. This is taken into account carefully in
- * duk__resize_valstack().
- *
- * 'new_size' is known to be <= valstack_max, which ensures that
- * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
- */
+/* Hot, inlined value stack grow check which doesn't throw. */
+DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
- if (!duk__resize_valstack(ctx, new_size)) {
- if (is_shrink) {
- DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
- return 1;
- }
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return 1;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ thr->valstack_end = tv;
+ return 1;
+ }
+ return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/);
+}
- DUK_DD(DUK_DDPRINT("valstack resize failed"));
+/* Value stack shrink check, called from mark-and-sweep. */
+DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) {
+ duk_size_t alloc_bytes;
+ duk_size_t reserve_bytes;
+ duk_size_t shrink_bytes;
- if (throw_flag) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- } else {
- return 0;
+ alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
+ reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ DUK_ASSERT(alloc_bytes >= reserve_bytes);
+
+ /* We're free to shrink the value stack allocation down to
+ * reserve_bytes but not more. If 'snug' (emergency GC)
+ * shrink whatever we can. Otherwise only shrink if the new
+ * size would be considerably smaller.
+ */
+
+#if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT)
+ if (snug) {
+ shrink_bytes = reserve_bytes;
+ } else {
+ duk_size_t proportion, slack;
+
+ /* Require that value stack shrinks by at least X% of its
+ * current size. For example, shift of 2 means at least
+ * 25%. The proportion is computed as bytes and may not
+ * be a multiple of sizeof(duk_tval); that's OK here.
+ */
+ proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT;
+ if (alloc_bytes - reserve_bytes < proportion) {
+ /* Too little would be freed, do nothing. */
+ return;
}
+
+ /* Keep a slack after shrinking. The slack is again a
+ * proportion of the current size (the proportion should
+ * of course be smaller than the check proportion above).
+ */
+#if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT)
+ DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT);
+ slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT;
+#else
+ slack = 0;
+#endif
+ shrink_bytes = reserve_bytes +
+ slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */
+ }
+#else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
+ /* Always snug, useful in some low memory environments. */
+ DUK_UNREF(snug);
+ shrink_bytes = reserve_bytes;
+#endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
+
+ DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)",
+ (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes));
+ DUK_ASSERT(shrink_bytes >= reserve_bytes);
+ if (shrink_bytes >= alloc_bytes) {
+ /* Skip if shrink target is same as current one (or higher,
+ * though that shouldn't happen in practice).
+ */
+ return;
}
+ DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes);
- DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
- return 1;
+ DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug));
+
+ duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval));
}
-DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
-DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
+DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
/*
* Basic stack manipulation: swap, dup, insert, replace, etc
*/
-DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, index1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
/* If tv1==tv2 this is a NOP, no check is needed */
@@ -15827,22 +18154,20 @@ DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2)
DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
}
-DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_swap(ctx, index, -1);
+ duk_swap(thr, idx, -1);
}
-DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) {
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
- tv_from = duk_require_tval(ctx, from_index);
+ tv_from = duk_require_tval(thr, from_idx);
tv_to = thr->valstack_top++;
DUK_ASSERT(tv_from != NULL);
DUK_ASSERT(tv_to != NULL);
@@ -15850,17 +18175,18 @@ DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
}
-DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_dup(thr, -1);
+#else
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
- if (thr->valstack_top - thr->valstack_bottom <= 0) {
- DUK_ERROR_API_INDEX(thr, -1);
+ if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
+ DUK_ERROR_RANGE_INDEX(thr, -1);
return; /* unreachable */
}
tv_from = thr->valstack_top - 1;
@@ -15869,19 +18195,45 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
DUK_ASSERT(tv_to != NULL);
DUK_TVAL_SET_TVAL(tv_to, tv_from);
DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
+#endif
}
-DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
+DUK_INTERNAL void duk_dup_0(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 0);
+}
+DUK_INTERNAL void duk_dup_1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 1);
+}
+DUK_INTERNAL void duk_dup_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 2);
+}
+DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -2);
+}
+DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -3);
+}
+DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -4);
+}
+
+DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *p;
duk_tval *q;
duk_tval tv_tmp;
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, to_index);
+ p = duk_require_tval(thr, to_idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -15894,8 +18246,8 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
- DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu",
- (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes));
+ DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
+ (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
/* No net refcount changes. */
@@ -15911,21 +18263,43 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
}
}
-DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */
+
+ duk_push_undefined(thr);
+ duk_insert(thr, idx);
+}
+
+DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ duk_tval *tv, *tv_end;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */
+ DUK_ASSERT(count >= 0);
+
+ tv = duk_reserve_gap(thr, idx, count);
+ tv_end = tv + count;
+ while (tv != tv_end) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ tv++;
+ }
+}
+
+DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, -1);
+ tv1 = duk_require_tval(thr, -1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, both pointing to stack top, the end result
- * is same as duk_pop(ctx).
+ * is same as duk_pop(thr).
*/
DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
DUK_TVAL_SET_TVAL(tv2, tv1);
@@ -15934,37 +18308,34 @@ DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
}
-DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr); /* w/o refcounting */
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, from_index);
+ tv1 = duk_require_tval(thr, from_idx);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, this is a no-op (no explicit check needed). */
DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
}
-DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
duk_tval *p;
duk_tval *q;
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
duk_tval tv_tmp;
#endif
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, index);
+ p = duk_require_tval(thr, idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -15975,7 +18346,7 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
* => [ ... | x | x | q ] [ ... ]
*/
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
/* use a temp: decref only when valstack reachable values are correct */
DUK_TVAL_SET_TVAL(&tv_tmp, p);
#endif
@@ -15986,18 +18357,79 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
DUK_TVAL_SET_UNDEFINED(q);
thr->valstack_top--;
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
#endif
}
+DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, idx); /* XXX: no optimization for now */
+}
+
+DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, -2);
+}
+
+DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+#if defined(DUK_USE_PREFER_SIZE)
+ /* XXX: maybe too slow even when preferring size? */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ while (count-- > 0) {
+ duk_remove(thr, idx);
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_tval *tv_newtop;
+ duk_tval *tv;
+ duk_size_t bytes;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ tv_dst = thr->valstack_bottom + idx;
+ DUK_ASSERT(tv_dst <= thr->valstack_top);
+ tv_src = tv_dst + count;
+ DUK_ASSERT(tv_src <= thr->valstack_top);
+ bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+
+ for (tv = tv_dst; tv < tv_src; tv++) {
+ DUK_TVAL_DECREF_NORZ(thr, tv);
+ }
+
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes);
+
+ tv_newtop = thr->valstack_top - count;
+ for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ }
+ thr->valstack_top = tv_newtop;
+
+ /* When not preferring size, only NORZ macros are used; caller
+ * is expected to DUK_REFZERO_CHECK().
+ */
+#endif /* DUK_USE_PREFER_SIZE */
+}
+
+DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove_n(thr, idx, count); /* XXX: no optimization for now */
+}
+
/*
* Stack slice primitives
*/
-DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
- duk_hthread *to_thr = (duk_hthread *) to_ctx;
- duk_hthread *from_thr = (duk_hthread *) from_ctx;
+DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) {
void *src;
duk_size_t nbytes;
duk_tval *p;
@@ -16005,36 +18437,38 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
/* XXX: several pointer comparison issues here */
- DUK_ASSERT_CTX_VALID(to_ctx);
- DUK_ASSERT_CTX_VALID(from_ctx);
- DUK_ASSERT(to_ctx != NULL);
- DUK_ASSERT(from_ctx != NULL);
+ DUK_ASSERT_API_ENTRY(to_thr);
+ DUK_ASSERT_CTX_VALID(to_thr);
+ DUK_ASSERT_CTX_VALID(from_thr);
+ DUK_ASSERT(to_thr->heap == from_thr->heap);
- if (to_ctx == from_ctx) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
+ if (DUK_UNLIKELY(to_thr == from_thr)) {
+ DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
return;
}
- if ((count < 0) ||
- (count > (duk_idx_t) to_thr->valstack_max)) {
- /* Maximum value check ensures 'nbytes' won't wrap below. */
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
+ /* Maximum value check ensures 'nbytes' won't wrap below.
+ * Also handles negative count.
+ */
+ DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
return;
}
+ DUK_ASSERT(count >= 0);
- nbytes = sizeof(duk_tval) * count;
- if (nbytes == 0) {
+ nbytes = sizeof(duk_tval) * (duk_size_t) count;
+ if (DUK_UNLIKELY(nbytes == 0)) {
return;
}
DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
- if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
- DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) {
+ DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
}
src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
- if (src < (void *) from_thr->valstack_bottom) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
+ if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
}
- /* copy values (no overlap even if to_ctx == from_ctx; that's not
+ /* copy values (no overlap even if to_thr == from_thr; that's not
* allowed now anyway)
*/
DUK_ASSERT(nbytes > 0);
@@ -16064,338 +18498,632 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
}
}
+/* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a
+ * pointer to the gap. Values in the gap are garbage and MUST be initialized by
+ * the caller before any side effects may occur. The caller must ensure there's
+ * enough stack reserve for 'count' values.
+ */
+DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) {
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_size_t gap_bytes;
+ duk_size_t copy_bytes;
+
+ /* Caller is responsible for ensuring there's enough preallocated
+ * value stack.
+ */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count);
+
+ tv_src = thr->valstack_bottom + idx_base;
+ gap_bytes = (duk_size_t) count * sizeof(duk_tval);
+ tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
+ copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes);
+
+ /* Values in the gap are left as garbage: caller must fill them in
+ * and INCREF them before any side effects.
+ */
+ return tv_src;
+}
+
/*
- * Get/require
+ * Get/opt/require
*/
-DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
- return;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
- return; /* not reachable */
}
-DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NULL(tv)) {
- return;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
- return; /* not reachable */
}
-DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) {
- duk_bool_t ret = 0; /* default: false */
+DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ duk_bool_t ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BOOLEAN(tv)) {
ret = DUK_TVAL_GET_BOOLEAN(tv);
+ DUK_ASSERT(ret == 0 || ret == 1);
+ } else {
+ ret = def_value;
+ /* Not guaranteed to be 0 or 1. */
}
- DUK_ASSERT(ret == 0 || ret == 1);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_boolean_raw(thr, idx, 0); /* default: false */
+}
+
+DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_boolean_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
- duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) {
+ ret = DUK_TVAL_GET_BOOLEAN(tv);
DUK_ASSERT(ret == 0 || ret == 1);
return ret;
+ } else {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
- return 0; /* not reachable */
}
-DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_boolean(thr, idx);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
duk_double_union ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- ret.d = DUK_DOUBLE_NAN; /* default: NaN */
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- ret.d = DUK_TVAL_GET_NUMBER(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+#if defined(DUK_USE_FASTINT)
+ if (DUK_TVAL_IS_FASTINT(tv)) {
+ ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */
+ }
+ else
+#endif
+ if (DUK_TVAL_IS_DOUBLE(tv)) {
+ /* When using packed duk_tval, number must be in NaN-normalized form
+ * for it to be a duk_tval, so no need to normalize. NOP for unpacked
+ * duk_tval.
+ */
+ ret.d = DUK_TVAL_GET_DOUBLE(tv);
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
+ } else {
+ ret.d = def_value;
+ /* Default value (including NaN) may not be normalized. */
}
- /*
- * Number should already be in NaN-normalized form, but let's
- * normalize anyway.
- */
-
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
return ret.d;
}
-DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */
+}
+
+DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ duk_double_union ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- duk_double_union ret;
- ret.d = DUK_TVAL_GET_NUMBER(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
+ }
- /*
- * Number should already be in NaN-normalized form,
- * but let's normalize anyway.
- */
+ ret.d = DUK_TVAL_GET_NUMBER(tv);
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
- return ret.d;
+ /* When using packed duk_tval, number must be in NaN-normalized form
+ * for it to be a duk_tval, so no need to normalize. NOP for unpacked
+ * duk_tval.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
+ return ret.d;
+}
+
+DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ /* User provided default is not NaN normalized. */
+ return def_value;
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
- return DUK_DOUBLE_NAN; /* not reachable */
+ return duk_require_number(thr, idx);
}
-DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
+DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
+}
+
+DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
+DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/);
+}
+
+DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/);
}
-DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/);
+DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/);
+}
+
+DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/);
+}
+
+DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_int(thr, idx);
}
-DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/);
+DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_uint(thr, idx);
}
-DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
+DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
const char *ret;
- duk_tval *tv;
+ duk_size_t len;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ ret = (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ len = 0;
+ ret = NULL;
+ }
- DUK_ASSERT_CTX_VALID(ctx);
+ if (out_len != NULL) {
+ *out_len = len;
+ }
+ return ret;
+}
+
+DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
- /* default: NULL, length 0 */
- ret = NULL;
+ h = duk_require_hstring(thr, idx);
+ DUK_ASSERT(h != NULL);
if (out_len) {
- *out_len = 0;
+ *out_len = DUK_HSTRING_GET_BYTELEN(h);
}
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_STRING(tv)) {
- /* Here we rely on duk_hstring instances always being zero
- * terminated even if the actual string is not.
- */
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
- ret = (const char *) DUK_HSTRING_GET_DATA(h);
- if (out_len) {
- *out_len = DUK_HSTRING_GET_BYTELEN(h);
+DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hstring_notsymbol(thr, idx);
+ DUK_ASSERT(h != NULL);
+ if (out_len) {
+ *out_len = DUK_HSTRING_GET_BYTELEN(h);
+ }
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+
+DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return NULL;
+ }
+}
+
+DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_len != NULL) {
+ *out_len = def_len;
}
+ return def_ptr;
}
+ return duk_require_lstring(thr, idx, out_len);
+}
- return ret;
+DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_ptr;
+ }
+ return duk_require_string(thr, idx);
}
-DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+ duk_hstring *h;
const char *ret;
+ duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* Note: this check relies on the fact that even a zero-size string
- * has a non-NULL pointer.
- */
- ret = duk_get_lstring(ctx, index, out_len);
- if (ret) {
- return ret;
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ ret = (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ len = def_len;
+ ret = def_ptr;
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
- return NULL; /* not reachable */
+
+ if (out_len != NULL) {
+ *out_len = len;
+ }
+ return ret;
}
-DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_get_lstring(ctx, index, NULL);
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return def_value;
+ }
}
-DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_require_lstring(ctx, index, NULL);
+ h = duk_get_hstring_notsymbol(thr, idx);
+ if (h) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return NULL;
+ }
}
-DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_require_lstring(thr, idx, NULL);
+}
+
+DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hstring_notsymbol(thr, idx);
+ DUK_ASSERT(h != NULL);
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+
+DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
}
+}
- return NULL;
+DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ duk_tval *tv;
+ void *p;
+
+ DUK_ASSERT_CTX_VALID(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (!DUK_TVAL_IS_POINTER(tv)) {
+ return def_value;
+ }
+
+ p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
+ return p;
}
-DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, NULL /*def_value*/);
+}
+
+DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_pointer(thr, idx);
+}
+
+DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ void *p;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: here we must be wary of the fact that a pointer may be
* valid and be a NULL.
*/
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
- return NULL; /* not reachable */
+ p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
+ return p;
}
#if 0 /*unused*/
-DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ duk_heaphdr *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- return (void *) h;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
+ return NULL;
}
- return NULL;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ return (void *) h;
}
#endif
-DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) {
+ duk_hbuffer *h;
+ void *ret;
+ duk_size_t len;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_CTX_VALID(thr);
if (out_size != NULL) {
*out_size = 0;
}
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) {
+ h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- if (out_size) {
- *out_size = DUK_HBUFFER_GET_SIZE(h);
+
+ len = DUK_HBUFFER_GET_SIZE(h);
+ ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
+ } else {
+ if (throw_flag) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
}
- return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
+ len = def_size;
+ ret = def_ptr;
}
- if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
+ if (out_size != NULL) {
+ *out_size = len;
}
- return NULL;
+ return ret;
+}
+
+DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
}
-DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/);
+DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_size != NULL) {
+ *out_size = def_size;
+ }
+ return def_ptr;
+ }
+ return duk_require_buffer(thr, idx, out_size);
}
-DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/);
+DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
}
-DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
+}
+
+/* Get the active buffer data area for a plain buffer or a buffer object.
+ * Return NULL if the the value is not a buffer. Note that a buffer may
+ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
+ * argument allows caller to detect this reliably.
+ */
+DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 0;
+ }
if (out_size != NULL) {
- *out_size = 0;
+ *out_size = def_size;
}
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto fail;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- if (out_size) {
+ if (out_size != NULL) {
*out_size = DUK_HBUFFER_GET_SIZE(h);
}
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 1;
+ }
return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
+ }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ else if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
+ if (DUK_HOBJECT_IS_BUFOBJ(h)) {
/* XXX: this is probably a useful shared helper: for a
- * duk_hbufferobject, get a validated buffer pointer/length.
+ * duk_hbufobj, get a validated buffer pointer/length.
*/
- duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ duk_hbufobj *h_bufobj = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
duk_uint8_t *p;
p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
if (out_size != NULL) {
*out_size = (duk_size_t) h_bufobj->length;
}
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 1;
+ }
return (void *) (p + h_bufobj->offset);
}
/* if slice not fully valid, treat as error */
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- fail:
if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
}
- return NULL;
+ return def_ptr;
+}
+
+DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
+}
+
+DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
}
-DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/);
+DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_size != NULL) {
+ *out_size = def_size;
+ }
+ return def_ptr;
+ }
+ return duk_require_buffer_data(thr, idx, out_size);
}
-DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
+DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
}
/* Raw helper for getting a value from the stack, checking its tag.
@@ -16403,318 +19131,435 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, du
* tag in the packed representation.
*/
-DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
+DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) {
duk_tval *tv;
+ duk_heaphdr *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
- duk_heaphdr *ret;
- ret = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
- return ret;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_GET_TAG(tv) != tag) {
+ return (duk_heaphdr *) NULL;
}
- return (duk_heaphdr *) NULL;
+ ret = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
+ return ret;
+
}
-DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
- return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
+DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
}
-DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
+DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) {
+ return NULL;
}
- return (duk_hstring *) h;
+ return h;
}
-DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
- return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
+ }
+ return h;
}
-DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
+DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
}
- return (duk_hobject *) h;
+ return h;
}
-DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
- return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
+DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
}
-DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
+DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
}
- return (duk_hbuffer *) h;
+ return h;
+}
+
+DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
+}
+
+DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ duk_hbuffer *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
+ }
+ return h;
}
-DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
+DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) {
h = NULL;
}
return (duk_hthread *) h;
}
-DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
+DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
}
return (duk_hthread *) h;
}
-DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
+DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) {
h = NULL;
}
- return (duk_hcompiledfunction *) h;
+ return (duk_hcompfunc *) h;
}
-DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
+DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
}
- return (duk_hcompiledfunction *) h;
+ return (duk_hcompfunc *) h;
}
-DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
+DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) {
h = NULL;
}
- return (duk_hnativefunction *) h;
+ return (duk_hnatfunc *) h;
}
-DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
+DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
}
- return (duk_hnativefunction *) h;
+ return (duk_hnatfunc *) h;
}
-DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
- duk_hnativefunction *f;
+ duk_hnatfunc *f;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return NULL;
- }
- if (!DUK_TVAL_IS_OBJECT(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
return NULL;
}
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) {
return NULL;
}
- DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
- f = (duk_hnativefunction *) h;
+ DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h));
+ f = (duk_hnatfunc *) h;
return f->func;
}
-DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_c_function(thr, idx);
+}
+
+DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
+ duk_c_function ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_c_function(thr, idx);
+ if (ret != NULL) {
+ return ret;
+ }
+
+ return def_value;
+}
+
+DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) {
duk_c_function ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_c_function(ctx, index);
- if (!ret) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
+ ret = duk_get_c_function(thr, idx);
+ if (DUK_UNLIKELY(!ret)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
}
return ret;
}
-DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
- if (!duk_is_function(ctx, index)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
+DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
}
}
-DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_context *) duk_get_hthread(ctx, index);
+ h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
+ }
+ /* Lightfuncs (h == NULL) are constructable. */
}
-DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_context *) duk_require_hthread(ctx, index);
+ return duk_get_hthread(thr, idx);
}
-DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- void *ret;
+DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_require_hthread(thr, idx);
+}
+
+DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_context(thr, idx);
+}
+
+DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ duk_hthread *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
+ ret = duk_get_context(thr, idx);
+ if (ret != NULL) {
return ret;
}
- return (void *) NULL;
+ return def_value;
}
-DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
- return ret;
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
+ return (void *) NULL;
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
- return (void *) NULL; /* not reachable */
+ ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL);
+ return ret;
}
-#if 0
-/* This would be pointless: we'd return NULL for both lightfuncs and
- * unexpected types.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_heapptr(thr, idx);
}
-#endif
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is NULL if value is neither an object nor a
- * lightfunc.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
+DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
+ ret = duk_get_heapptr(thr, idx);
+ if (ret != NULL) {
+ return ret;
}
- return NULL;
+ return def_value;
}
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Returns NULL for a lightfunc.
- */
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- return NULL;
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
+
+ ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL);
+ return ret;
}
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is never NULL.
- */
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
+/* Internal helper for getting/requiring a duk_hobject with possible promotion. */
+DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ duk_uint_t val_mask;
+ duk_hobject *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_require_tval(ctx, index);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
+ res = duk_get_hobject(thr, idx); /* common case, not promoted */
+ if (DUK_LIKELY(res != NULL)) {
+ DUK_ASSERT(res != NULL);
+ return res;
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
+
+ val_mask = duk_get_type_mask(thr, idx);
+ if (val_mask & type_mask) {
+ if (type_mask & DUK_TYPE_MASK_PROMOTE) {
+ res = duk_to_hobject(thr, idx);
+ DUK_ASSERT(res != NULL);
+ return res;
+ } else {
+ return NULL; /* accept without promoting */
+ }
+ }
+
+ if (type_mask & DUK_TYPE_MASK_THROW) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ }
+ return NULL;
+}
+
+/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the
+ * supplied 'type_mask', promote it to an object and return the duk_hobject *.
+ * This is useful for call sites which want an object but also accept a plain
+ * buffer and/or a lightfunc which gets automatically promoted to an object.
+ * Return value is NULL if value is neither an object nor a plain type allowed
+ * by the mask.
+ */
+DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
}
-DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
+/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
+ * returning a NULL.
+ */
+DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
+}
+
+/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
+ * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError.
+ */
+DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW);
+}
+
+DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) {
h = NULL;
}
return h;
}
-DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
- duk_hthread *thr;
+DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- thr = (duk_hthread *) ctx;
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) {
duk_hstring *h_class;
h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
DUK_UNREF(h_class);
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
}
return h;
}
-DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED:
@@ -16722,51 +19567,130 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
case DUK_TAG_BOOLEAN:
case DUK_TAG_POINTER:
return 0;
+#if defined(DUK_USE_PREFER_SIZE)
+ /* String and buffer have a virtual non-configurable .length property
+ * which is within size_t range so it can be looked up without specific
+ * type checks. Lightfuncs inherit from %NativeFunctionPrototype%
+ * which provides an inherited .length accessor; it could be overwritten
+ * to produce unexpected types or values, but just number convert and
+ * duk_size_t cast for now.
+ */
+ case DUK_TAG_STRING:
+ case DUK_TAG_BUFFER:
+ case DUK_TAG_LIGHTFUNC: {
+ duk_size_t ret;
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return ret;
+ }
+#else /* DUK_USE_PREFER_SIZE */
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 0;
+ }
return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
}
- case DUK_TAG_OBJECT: {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
- }
case DUK_TAG_BUFFER: {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
}
case DUK_TAG_LIGHTFUNC: {
- duk_small_uint_t lf_flags;
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ /* We could look up the length from the lightfunc duk_tval,
+ * but since Duktape 2.2 lightfunc .length comes from
+ * %NativeFunctionPrototype% which can be overridden, so
+ * look up the property explicitly.
+ */
+ duk_size_t ret;
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return ret;
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+ case DUK_TAG_OBJECT: {
+ duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return (duk_size_t) duk_hobject_get_length(thr, h);
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
#endif
default:
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ /* number or 'unused' */
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv));
return 0;
}
DUK_UNREACHABLE();
}
-DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
+/*
+ * duk_known_xxx() helpers
+ *
+ * Used internally when we're 100% sure that a certain index is valid and
+ * contains an object of a certain type. For example, if we duk_push_object()
+ * we can then safely duk_known_hobject(thr, -1). These helpers just assert
+ * for the index and type, and if the assumptions are not valid, memory unsafe
+ * behavior happens.
+ */
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_heaphdr *h;
- h = duk_get_hobject(ctx, index);
- if (!h) {
- return;
+ DUK_ASSERT_CTX_VALID(thr);
+ if (idx < 0) {
+ tv = thr->valstack_top + idx;
+ } else {
+ tv = thr->valstack_bottom + idx;
}
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_ASSERT(tv < thr->valstack_top);
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ return h;
+}
- duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
+DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return (duk_hstring *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hobject(thr, idx) != NULL);
+ return (duk_hobject *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL);
+ return (duk_hbuffer *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL);
+ return (duk_hcompfunc *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL);
+ return (duk_hnatfunc *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ idx = duk_normalize_index(thr, idx);
+ duk_push_uint(thr, (duk_uint_t) len);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
}
/*
@@ -16779,40 +19703,99 @@ DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t l
/* E5 Section 8.12.8 */
-DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) {
- if (duk_get_prop_stridx(ctx, index, func_stridx)) {
+DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) {
+ if (duk_get_prop_stridx(thr, idx, func_stridx)) {
/* [ ... func ] */
- if (duk_is_callable(ctx, -1)) {
- duk_dup(ctx, index); /* -> [ ... func this ] */
- duk_call_method(ctx, 0); /* -> [ ... retval ] */
- if (duk_is_primitive(ctx, -1)) {
- duk_replace(ctx, index);
+ if (duk_is_callable(thr, -1)) {
+ duk_dup(thr, idx); /* -> [ ... func this ] */
+ duk_call_method(thr, 0); /* -> [ ... retval ] */
+ if (duk_is_primitive(thr, -1)) {
+ duk_replace(thr, idx);
return 1;
}
/* [ ... retval ]; popped below */
}
}
- duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */
return 0;
}
-DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
+DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+}
+
+DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
+}
+
+/* E5 Section 9.1 */
+DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
/* inline initializer for coercers[] is not allowed by old compilers like BCC */
- duk_small_int_t coercers[2];
+ duk_small_uint_t coercers[2];
+ duk_small_uint_t class_number;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
+
+ idx = duk_require_normalize_index(thr, idx);
+
+ if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER)) {
+ /* Any other values stay as is. */
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
+ return;
+ }
+
+ class_number = duk_get_class_number(thr, idx);
+
+ /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive()
+ * algorithm which consults value[@@toPrimitive] and avoids calling
+ * .valueOf() and .toString(). Before that is implemented, special
+ * case Symbol objects to behave as if they had the default @@toPrimitive
+ * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value
+ * with no further side effects.
+ */
+
+ if (class_number == DUK_HOBJECT_CLASS_SYMBOL) {
+ duk_hobject *h_obj;
+ duk_hstring *h_str;
+
+ /* XXX: pretty awkward, index based API for internal value access? */
+ h_obj = duk_known_hobject(thr, idx);
+ h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj);
+ if (h_str) {
+ duk_push_hstring(thr, h_str);
+ duk_replace(thr, idx);
+ return;
+ }
+ }
+
+
+ /* Objects are coerced based on E5 specification.
+ * Lightfuncs are coerced because they behave like
+ * objects even if they're internally a primitive
+ * type. Same applies to plain buffers, which behave
+ * like ArrayBuffer objects since Duktape 2.x.
+ */
coercers[0] = DUK_STRIDX_VALUE_OF;
coercers[1] = DUK_STRIDX_TO_STRING;
- index = duk_require_normalize_index(ctx, index);
- obj = duk_require_hobject_or_lfunc(ctx, index);
-
if (hint == DUK_HINT_NONE) {
- if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
+ if (class_number == DUK_HOBJECT_CLASS_DATE) {
hint = DUK_HINT_STRING;
} else {
hint = DUK_HINT_NUMBER;
@@ -16824,204 +19807,214 @@ DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int
coercers[1] = DUK_STRIDX_VALUE_OF;
}
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED);
-}
-
-DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
-}
-
-DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
-}
-
-/* E5 Section 9.1 */
-DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
-
- index = duk_require_normalize_index(ctx, index);
-
- if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- /* everything except object stay as is */
- return;
- }
- duk_to_defaultvalue(ctx, index, hint);
+ DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
}
/* E5 Section 9.2 */
-DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_bool_t val;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- index = duk_require_normalize_index(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
val = duk_js_toboolean(tv);
DUK_ASSERT(val == 0 || val == 1);
- /* Note: no need to re-lookup tv, conversion is side effect free */
+ /* Note: no need to re-lookup tv, conversion is side effect free. */
DUK_ASSERT(tv != NULL);
DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
return val;
}
-DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ /* XXX: No need to normalize; the whole operation could be inlined here to
+ * avoid 'tv' re-lookup.
+ */
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
- /* XXX: fastint? */
- d = duk_js_tonumber(thr, tv);
+ d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */
- /* Note: need to re-lookup because ToNumber() may have side effects */
- tv = duk_require_tval(ctx, index);
+ /* ToNumber() may have side effects so must relookup 'tv'. */
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
+DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -1);
+}
+DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -2);
+}
+
+DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_double_t res;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_push_tval(thr, tv);
+ res = duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return res;
+#else
+ duk_double_t res;
+ duk_tval *tv_dst;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ASSERT_SPACE();
+
+ tv_dst = thr->valstack_top++;
+ DUK_TVAL_SET_TVAL(tv_dst, tv);
+ DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */
+ res = duk_to_number_m1(thr); /* invalidates tv_dst */
+
+ tv_dst = --thr->valstack_top;
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */
+ DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */
+
+ return res;
+#endif
+}
+
/* XXX: combine all the integer conversions: they share everything
* but the helper function for coercion.
*/
typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
-DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
+
+#if defined(DUK_USE_FASTINT)
+ /* If argument is a fastint, guarantee that it remains one.
+ * There's no downgrade check for other cases.
+ */
+ if (DUK_TVAL_IS_FASTINT(tv)) {
+ /* XXX: Unnecessary conversion back and forth. */
+ return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
+ }
+#endif
d = coerce_func(thr, tv);
/* XXX: fastint? */
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
-DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
+DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) {
+ /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
+ * API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
+DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) {
+ /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
+ * API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_int32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_toint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint16_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint16(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Special coercion for Uint8ClampedArray. */
-DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) {
duk_double_t d;
duk_double_t t;
duk_uint8_t ret;
+ DUK_ASSERT_API_ENTRY(thr);
+
/* XXX: Simplify this algorithm, should be possible to come up with
* a shorter and faster algorithm by inspecting IEEE representation
* directly.
*/
- d = duk_to_number(ctx, index);
+ d = duk_to_number(thr, idx);
if (d <= 0.0) {
return 0;
} else if (d >= 255) {
@@ -17046,119 +20039,176 @@ DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index)
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- (void) duk_to_string(ctx, index);
- return duk_require_lstring(ctx, index, out_len);
+ (void) duk_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_lstring(thr, idx, out_len);
}
-DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) {
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_UNREF(udata);
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
/* We intentionally ignore the duk_safe_call() return value and only
* check the output type. This way we don't also need to check that
* the returned value is indeed a string in the success case.
*/
- duk_dup(ctx, index);
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ duk_dup(thr, idx);
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Error: try coercing error to string once. */
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Double error */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
+ duk_pop_unsafe(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
} else {
;
}
} else {
+ /* String; may be a symbol, accepted. */
;
}
- DUK_ASSERT(duk_is_string(ctx, -1));
- DUK_ASSERT(duk_get_string(ctx, -1) != NULL);
+ DUK_ASSERT(duk_is_string(thr, -1));
- duk_replace(ctx, index);
- return duk_get_lstring(ctx, index, out_len);
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_get_string(thr, idx) != NULL);
+ return duk_get_lstring(thr, idx, out_len);
+}
+
+DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
+ h = duk_get_hstring(thr, idx);
+ if (h == NULL) {
+ /* The "is string?" check may seem unnecessary, but as things
+ * are duk_to_hstring() invokes ToString() which fails for
+ * symbols. But since symbols are already strings for Duktape
+ * C API, we check for that before doing the coercion.
+ */
+ h = duk_to_hstring(thr, idx);
+ }
+ DUK_ASSERT(h != NULL);
+ return h;
}
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) {
- (void) duk_safe_to_string(ctx, index);
- DUK_ASSERT(duk_is_string(ctx, index));
- DUK_ASSERT(duk_get_hstring(ctx, index) != NULL);
- return duk_get_hstring(ctx, index);
+DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_safe_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return duk_known_hstring(thr, idx);
}
#endif
-/* Coerce top into Object.prototype.toString() output. */
-DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
- duk_hthread *thr;
- duk_uint_t typemask;
+/* Push Object.prototype.toString() output for 'tv'. */
+DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) {
+ duk_small_uint_t stridx;
duk_hstring *h_strclass;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- typemask = duk_get_type_mask(ctx, -1);
- if (typemask & DUK_TYPE_MASK_UNDEFINED) {
- h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
- } else if (typemask & DUK_TYPE_MASK_NULL) {
- h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
- } else {
- duk_hobject *h_obj;
-
- duk_to_object(ctx, -1);
- h_obj = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_obj != NULL);
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
+ case DUK_TAG_UNDEFINED: {
+ stridx = DUK_STRIDX_UC_UNDEFINED;
+ break;
+ }
+ case DUK_TAG_NULL: {
+ stridx = DUK_STRIDX_UC_NULL;
+ break;
+ }
+ case DUK_TAG_BOOLEAN: {
+ stridx = DUK_STRIDX_UC_BOOLEAN;
+ break;
+ }
+ case DUK_TAG_POINTER: {
+ stridx = DUK_STRIDX_UC_POINTER;
+ break;
+ }
+ case DUK_TAG_LIGHTFUNC: {
+ stridx = DUK_STRIDX_UC_FUNCTION;
+ break;
+ }
+ case DUK_TAG_STRING: {
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ stridx = DUK_STRIDX_UC_SYMBOL;
+ } else {
+ stridx = DUK_STRIDX_UC_STRING;
+ }
+ break;
+ }
+ case DUK_TAG_OBJECT: {
+ duk_hobject *h;
+ duk_small_uint_t classnum;
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
+
+ /* XXX: This is not entirely correct anymore; in ES2015 the
+ * default lookup should use @@toStringTag to come up with
+ * e.g. [object Symbol], [object Uint8Array], etc. See
+ * ES2015 Section 19.1.3.6. The downside of implementing that
+ * directly is that the @@toStringTag lookup may have side
+ * effects, so all call sites must be checked for that.
+ * Some may need a side-effect free lookup, e.g. avoiding
+ * getters which are not typical.
+ */
+ break;
+ }
+ case DUK_TAG_BUFFER: {
+ stridx = DUK_STRIDX_UINT8_ARRAY;
+ break;
+ }
+#if defined(DUK_USE_FASTINT)
+ case DUK_TAG_FASTINT:
+ /* Fall through to generic number case. */
+#endif
+ default: {
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */
+ stridx = DUK_STRIDX_UC_NUMBER;
+ break;
+ }
}
+ h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(h_strclass != NULL);
- duk_pop(ctx);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
-}
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
- duk_hthread *thr;
- duk_hstring *h_strclass;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
- DUK_ASSERT(h_strclass != NULL);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+ duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
}
-#endif /* !DUK_USE_PARANOID_ERRORS */
/* XXX: other variants like uint, u32 etc */
-DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
duk_tval *tv;
duk_tval tv_tmp;
duk_double_t d, dmin, dmax;
duk_int_t res;
duk_bool_t clamped = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
@@ -17180,12 +20230,12 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index,
/* 'd' and 'res' agree here */
/* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
- tv = duk_get_tval(ctx, index);
+ tv = duk_get_tval(thr, idx);
DUK_ASSERT(tv != NULL); /* not popped by side effect */
DUK_TVAL_SET_TVAL(&tv_tmp, tv);
#if defined(DUK_USE_FASTINT)
#if (DUK_INT_MAX <= 0x7fffffffL)
- DUK_TVAL_SET_FASTINT_I32(tv, res);
+ DUK_TVAL_SET_I32(tv, res);
#else
/* Clamping needed if duk_int_t is 64 bits. */
if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
@@ -17211,79 +20261,93 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index,
return res;
}
-DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) {
+DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
duk_bool_t dummy;
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy);
}
-DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) {
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
+DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
}
-DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- index = duk_require_normalize_index(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED);
break;
}
case DUK_TAG_NULL: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
break;
}
case DUK_TAG_BOOLEAN: {
if (DUK_TVAL_GET_BOOLEAN(tv)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE);
} else {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE);
}
break;
}
case DUK_TAG_STRING: {
- /* nop */
+ /* Nop for actual strings, TypeError for Symbols.
+ * Because various internals rely on ToString() coercion of
+ * internal strings, -allow- (NOP) string coercion for hidden
+ * symbols.
+ */
+#if 1
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
+ } else {
+ goto skip_replace;
+ }
+#else
goto skip_replace;
+#endif
}
+ case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
case DUK_TAG_OBJECT: {
- duk_to_primitive(ctx, index, DUK_HINT_STRING);
- return duk_to_string(ctx, index); /* Note: recursive call */
- }
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
-
- /* Note: this allows creation of internal strings. */
-
- DUK_ASSERT(h != NULL);
- duk_push_lstring(ctx,
- (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
- break;
+ /* Plain buffers: go through ArrayBuffer.prototype.toString()
+ * for coercion.
+ *
+ * Symbol objects: duk_to_primitive() results in a plain symbol
+ * value, and duk_to_string() then causes a TypeError.
+ */
+ duk_to_primitive(thr, idx, DUK_HINT_STRING);
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */
+ DUK_ASSERT(!duk_is_object(thr, idx));
+ return duk_to_string(thr, idx); /* Note: recursive call */
}
case DUK_TAG_POINTER: {
void *ptr = DUK_TVAL_GET_POINTER(tv);
if (ptr != NULL) {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr);
} else {
/* Represent a null pointer as 'null' to be consistent with
* the JX format variant. Native '%p' format for a NULL
* pointer may be e.g. '(nil)'.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
}
break;
}
case DUK_TAG_LIGHTFUNC: {
/* Should match Function.prototype.toString() */
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
break;
}
#if defined(DUK_USE_FASTINT)
@@ -17293,8 +20357,8 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
/* number */
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_push_tval(ctx, tv);
- duk_numconv_stringify(ctx,
+ duk_push_tval(thr, tv);
+ duk_numconv_stringify(thr,
10 /*radix*/,
0 /*precision:shortest*/,
0 /*force_exponential*/);
@@ -17302,34 +20366,76 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
}
}
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
skip_replace:
- return duk_require_string(ctx, index);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_string(thr, idx);
}
-DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- duk_to_string(ctx, index);
- ret = duk_get_hstring(ctx, index);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_string(thr, idx);
+ ret = duk_get_hstring(thr, idx);
DUK_ASSERT(ret != NULL);
return ret;
}
-DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_hstring(thr, -1);
+}
+
+DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_hstring(thr, idx);
+ if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) {
+ return ret;
+ }
+ return duk_to_hstring(thr, idx);
+}
+
+/* Convert a plain buffer or any buffer object into a string, using the buffer
+ * bytes 1:1 in the internal string representation. For views the active byte
+ * slice (not element slice interpreted as an initializer) is used. This is
+ * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a
+ * string with the same bytes as in the buffer but rather (usually)
+ * '[object ArrayBuffer]'.
+ */
+DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) {
+ void *ptr_src;
+ duk_size_t len;
+ const char *res;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ idx = duk_require_normalize_index(thr, idx);
+
+ ptr_src = duk_require_buffer_data(thr, idx, &len);
+ DUK_ASSERT(ptr_src != NULL || len == 0);
+
+ res = duk_push_lstring(thr, (const char *) ptr_src, len);
+ duk_replace(thr, idx);
+ return res;
+}
+
+DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
duk_hbuffer *h_buf;
const duk_uint8_t *src_data;
duk_size_t src_size;
duk_uint8_t *dst_data;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
- h_buf = duk_get_hbuffer(ctx, index);
+ h_buf = duk_get_hbuffer(thr, idx);
if (h_buf != NULL) {
/* Buffer is kept as is, with the fixed/dynamic nature of the
* buffer only changed if requested. An external buffer
@@ -17355,13 +20461,13 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
} else {
/* Non-buffer value is first ToString() coerced, then converted
* to a buffer (fixed buffer is used unless a dynamic buffer is
- * explicitly requested).
+ * explicitly requested). Symbols are rejected with a TypeError.
+ * XXX: C API could maybe allow symbol-to-buffer coercion?
*/
-
- src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size);
+ src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size);
}
- dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
+ dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
if (DUK_LIKELY(src_size > 0)) {
/* When src_size == 0, src_data may be NULL (if source
* buffer is dynamic), and dst_data may be NULL (if
@@ -17370,7 +20476,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
*/
DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
}
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
skip_copy:
if (out_size) {
@@ -17379,15 +20485,14 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
return dst_data;
}
-DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *res;
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -17425,25 +20530,64 @@ DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
break;
}
- duk_push_pointer(ctx, res);
- duk_replace(ctx, index);
+ duk_push_pointer(thr, res);
+ duk_replace(thr, idx);
return res;
}
-DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
+ duk_idx_t nargs;
+ duk_uint_t flags = 0; /* shared flags for a subset of types */
+ duk_small_uint_t lf_len;
+ duk_hnatfunc *nf;
+
+ nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (nargs == DUK_LFUNC_NARGS_VARARGS) {
+ nargs = (duk_idx_t) DUK_VARARGS;
+ }
+
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
+ DUK_HOBJECT_FLAG_NEWENV |
+ DUK_HOBJECT_FLAG_STRICT |
+ DUK_HOBJECT_FLAG_NOTAIL |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
+
+ lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ if ((duk_idx_t) lf_len != nargs) {
+ /* Explicit length is only needed if it differs from 'nargs'. */
+ duk_push_int(thr, (duk_int_t) lf_len);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ }
+
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#endif
+
+ nf = duk_known_hnatfunc(thr, -1);
+ nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
+}
+
+DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint_t flags = 0; /* shared flags for a subset of types */
duk_small_int_t proto = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
+#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */
+#endif
case DUK_TAG_UNDEFINED:
case DUK_TAG_NULL: {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
@@ -17451,54 +20595,53 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
}
case DUK_TAG_BOOLEAN: {
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
goto create_object;
}
case DUK_TAG_STRING: {
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
- proto = DUK_BIDX_STRING_PROTOTYPE;
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL);
+ proto = DUK_BIDX_SYMBOL_PROTOTYPE;
+ } else {
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
+ proto = DUK_BIDX_STRING_PROTOTYPE;
+ }
goto create_object;
}
case DUK_TAG_OBJECT: {
/* nop */
break;
}
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
case DUK_TAG_BUFFER: {
- /* A plain buffer coerces to a Duktape.Buffer because it's the
- * object counterpart of the plain buffer value. But it might
- * still make more sense to produce an ArrayBuffer here?
+ /* A plain buffer object coerces to a full ArrayBuffer which
+ * is not fully transparent behavior (ToObject() should be a
+ * nop for an object). This behavior matches lightfuncs which
+ * also coerce to an equivalent Function object. There are
+ * also downsides to defining ToObject(plainBuffer) as a no-op;
+ * for example duk_to_hobject() could result in a NULL pointer.
*/
+ duk_hbuffer *h_buf;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj));
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj));
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
- DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_buf = DUK_TVAL_GET_BUFFER(tv);
+ DUK_ASSERT(h_buf != NULL);
+ duk_hbufobj_push_uint8array_from_plain(thr, h_buf);
goto replace_value;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
case DUK_TAG_POINTER: {
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
proto = DUK_BIDX_POINTER_PROTOTYPE;
goto create_object;
@@ -17506,50 +20649,18 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
case DUK_TAG_LIGHTFUNC: {
/* Lightfunc coerces to a Function instance with concrete
* properties. Since 'length' is virtual for Duktape/C
- * functions, don't need to define that.
+ * functions, don't need to define that. The result is made
+ * extensible to mimic what happens to strings in object
+ * coercion:
*
- * The result is made extensible to mimic what happens to
- * strings:
* > Object.isExtensible(Object('foo'))
* true
*/
duk_small_uint_t lf_flags;
- duk_idx_t nargs;
- duk_small_uint_t lf_len;
duk_c_function func;
- duk_hnativefunction *nf;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
-
- nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = (duk_idx_t) DUK_VARARGS;
- }
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- DUK_HOBJECT_FLAG_NOTAIL |
- /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
-
- lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- if ((duk_idx_t) lf_len != nargs) {
- /* Explicit length is only needed if it differs from 'nargs'. */
- duk_push_int(ctx, (duk_int_t) lf_len);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
- }
- duk_push_lightfunc_name(ctx, tv);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- nf = duk_get_hnativefunction(ctx, -1);
- DUK_ASSERT(nf != NULL);
- nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
-
- /* Enable DUKFUNC exotic behavior once properties are set up. */
- DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
+ duk__push_func_from_lightfunc(thr, func, lf_flags);
goto replace_value;
}
#if defined(DUK_USE_FASTINT)
@@ -17559,15 +20670,17 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
proto = DUK_BIDX_NUMBER_PROTOTYPE;
goto create_object;
}
}
+ DUK_ASSERT(duk_is_object(thr, idx));
return;
create_object:
- (void) duk_push_object_helper(ctx, flags, proto);
+ (void) duk_push_object_helper(thr, flags, proto);
/* Note: Boolean prototype's internal value property is not writable,
* but duk_xdef_prop_stridx() disregards the write protection. Boolean
@@ -17576,49 +20689,55 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
* String and buffer special behaviors are already enabled which is not
* ideal, but a write to the internal value is not affected by them.
*/
- duk_dup(ctx, index);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, idx);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
replace_value:
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_is_object(thr, idx));
+}
+
+DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_object(thr, idx);
+ ret = duk_known_hobject(thr, idx);
+ return ret;
}
/*
* Type checking
*/
-DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) {
+DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) {
duk_tval *tv;
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
return (DUK_TVAL_GET_TAG(tv) == tag);
}
-DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) {
+DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, index);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
+ DUK_ASSERT(tv != NULL);
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_NONE;
- }
+#if defined(DUK_USE_PACKED_TVAL)
switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED:
+ return DUK_TYPE_NONE;
case DUK_TAG_UNDEFINED:
return DUK_TYPE_UNDEFINED;
case DUK_TAG_NULL:
@@ -17644,11 +20763,26 @@ DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
return DUK_TYPE_NUMBER;
}
- DUK_UNREACHABLE();
+#else /* DUK_USE_PACKED_TVAL */
+ DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
+ DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
+ return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
+#endif /* DUK_USE_PACKED_TVAL */
+}
+
+DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ return duk_get_type_tval(tv);
}
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_LOCAL const char *duk__type_names[] = {
+DUK_LOCAL const char * const duk__type_names[] = {
"none",
"undefined",
"null",
@@ -17661,33 +20795,58 @@ DUK_LOCAL const char *duk__type_names[] = {
"lightfunc"
};
-DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) {
duk_int_t type_tag;
- type_tag = duk_get_type(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ type_tag = duk_get_type(thr, idx);
DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
return duk__type_names[type_tag];
}
-#endif
+#endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */
-DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_hobject *obj;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
- return (duk_get_type(ctx, index) == type) ? 1 : 0;
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_OBJECT:
+ obj = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(obj != NULL);
+ return DUK_HOBJECT_GET_CLASS_NUMBER(obj);
+ case DUK_TAG_BUFFER:
+ /* Buffers behave like Uint8Array objects. */
+ return DUK_HOBJECT_CLASS_UINT8ARRAY;
+ case DUK_TAG_LIGHTFUNC:
+ /* Lightfuncs behave like Function objects. */
+ return DUK_HOBJECT_CLASS_FUNCTION;
+ default:
+ /* Primitive or UNUSED, no class number. */
+ return DUK_HOBJECT_CLASS_NONE;
+ }
}
-DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
+DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_get_type(thr, idx) == type) ? 1 : 0;
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
+ DUK_ASSERT(tv != NULL);
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_MASK_NONE;
- }
+#if defined(DUK_USE_PACKED_TVAL)
switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED:
+ return DUK_TYPE_MASK_NONE;
case DUK_TAG_UNDEFINED:
return DUK_TYPE_MASK_UNDEFINED;
case DUK_TAG_NULL:
@@ -17713,15 +20872,28 @@ DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
return DUK_TYPE_MASK_NUMBER;
}
- DUK_UNREACHABLE();
+#else /* DUK_USE_PACKED_TVAL */
+ DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
+ DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
+ return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
+#endif /* DUK_USE_PACKED_TVAL */
}
-DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ return duk_get_type_mask_tval(tv);
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_get_type_mask(ctx, index) & mask) {
+ if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) {
return 1;
}
if (mask & DUK_TYPE_MASK_THROW) {
@@ -17731,55 +20903,39 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, d
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
+DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED);
}
-DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_NULL);
+DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_NULL);
}
-DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- duk_small_uint_t tag;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
- tag = DUK_TVAL_GET_TAG(tv);
- return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
+DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN);
}
-DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Number is special because it doesn't have a specific
* tag in the 8-byte representation.
*/
- /* XXX: shorter version for 12-byte representation? */
+ /* XXX: shorter version for unpacked representation? */
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
return DUK_TVAL_IS_NUMBER(tv);
}
-DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) {
/* XXX: This will now return false for non-numbers, even though they would
* coerce to NaN (as a general rule). In particular, duk_get_number()
* returns a NaN for non-numbers, so should this function also return
@@ -17788,103 +20944,196 @@ DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
+ if (!DUK_TVAL_IS_NUMBER(tv)) {
return 0;
}
- return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
+ return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_STRING);
+}
+
+DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_hstring_notsymbol(thr, idx) != NULL;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_OBJECT);
}
-DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_STRING);
+DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BUFFER);
}
-DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
+ return 1;
+ } else if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ return 1;
+ }
+ }
+ return 0;
}
+#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
-DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
+ return duk_is_buffer(thr, idx);
}
-DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_POINTER);
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_POINTER);
}
-DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC);
+DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ h = duk_get_hstring(thr, idx);
+ /* Use DUK_LIKELY() here because caller may be more likely to type
+ * check an expected symbol than not.
+ */
+ if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, index);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
return 1;
}
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_BOUND);
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_NATIVEFUNCTION);
+DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_UNREF(thr);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
+DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_NATFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_BOUND);
+DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_COMPFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_THREAD);
+DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_BOUNDFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *obj;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj = duk_get_hobject(thr, idx);
+ if (obj) {
+ return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0);
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
@@ -17892,13 +21141,14 @@ DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
@@ -17906,13 +21156,14 @@ DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index)
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
@@ -17920,20 +21171,22 @@ DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index
return 0;
}
-DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
duk_uint_t sanity;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hobject(ctx, index);
+ h = duk_get_hobject(thr, idx);
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
if (!h) {
return DUK_ERR_NONE;
}
+
+ /* XXX: something more convenient? */
+
if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
return DUK_ERR_EVAL_ERROR;
}
@@ -17966,24 +21219,21 @@ DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index)
* Pushers
*/
-DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
+DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(tv != NULL);
- thr = (duk_hthread *) ctx;
+
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_TVAL(tv_slot, tv);
DUK_TVAL_INCREF(thr, tv); /* no side effects */
}
-DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
DUK__CHECK_SPACE();
/* Because value stack init policy is 'undefined above top',
@@ -17993,60 +21243,50 @@ DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
}
-DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_null(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_NULL(tv_slot);
}
-DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) {
duk_tval *tv_slot;
duk_small_int_t b;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN(tv_slot, b);
}
-DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_true(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
}
-DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_false(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
}
/* normalize NaN which may not match our canonical internal NaN */
-DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
du.d = val;
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
@@ -18054,17 +21294,15 @@ DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
+DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_INT_MAX <= 0x7fffffffL
- DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val);
+ DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val);
#else
if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
@@ -18074,12 +21312,10 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -18087,17 +21323,15 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
+DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_UINT_MAX <= 0xffffffffUL
- DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val);
+ DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val);
#else
if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
/* XXX: take advantage of val being unsigned, no need to mask */
@@ -18108,12 +21342,10 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -18121,13 +21353,11 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
DUK_DBLUNION_SET_NAN(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
@@ -18135,17 +21365,14 @@ DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) {
duk_hstring *h;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* check stack before interning (avoid hanging temp) */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* NULL with zero length represents an empty string; NULL with higher
* length is also now trated like an empty string although it is
@@ -18157,11 +21384,11 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
}
/* Check for maximum string length */
- if (len > DUK_HSTRING_MAX_BYTELEN) {
+ if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
}
- h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
+ h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
DUK_ASSERT(h != NULL);
tv_slot = thr->valstack_top++;
@@ -18171,112 +21398,47 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
+ DUK_ASSERT_API_ENTRY(thr);
if (str) {
- return duk_push_lstring(ctx, str, DUK_STRLEN(str));
+ return duk_push_lstring(thr, str, DUK_STRLEN(str));
} else {
- duk_push_null(ctx);
+ duk_push_null(thr);
return NULL;
}
}
-#ifdef DUK_USE_FILE_IO
-/* This is a bit clunky because it is ANSI C portable. Should perhaps
- * relocate to another file because this is potentially platform
- * dependent.
- */
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_file *f = NULL;
- char *buf;
- long sz; /* ANSI C typing */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (!path) {
- goto fail;
- }
- f = DUK_FOPEN(path, "rb");
- if (!f) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
- goto fail;
- }
- sz = DUK_FTELL(f);
- if (sz < 0) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
- goto fail;
- }
- buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz);
- DUK_ASSERT(buf != NULL);
- if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) {
- goto fail;
- }
- (void) DUK_FCLOSE(f); /* ignore fclose() error */
- f = NULL;
- return duk_to_string(ctx, -1);
-
- fail:
- if (f) {
- DUK_FCLOSE(f);
- }
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_TYPE(thr, "read file error");
- }
- return NULL;
-}
-#else
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(path);
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled");
- }
- return NULL;
-}
-#endif /* DUK_USE_FILE_IO */
-
-DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_POINTER(tv_slot, val);
}
-DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
- duk_hthread *thr;
+DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) {
+ duk_hstring *h_tmp;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
+ duk_push_uint(thr, (duk_uint_t) i);
+ h_tmp = duk_to_hstring_m1(thr);
+ DUK_ASSERT(h_tmp != NULL);
+ return h_tmp;
+}
+
+DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
DUK__CHECK_SPACE();
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
tv_slot = thr->valstack_top++;
- if (DUK_UNLIKELY(thr->callstack_top == 0)) {
+ if (DUK_UNLIKELY(thr->callstack_curr == NULL)) {
if (check_object_coercible) {
goto type_error;
}
@@ -18302,137 +21464,119 @@ DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_ob
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
}
-DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 0 /*check_object_coercible*/);
}
-DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
}
-DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
+DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_object(ctx, -1);
- h = duk_get_hobject(ctx, -1);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ h = duk_to_hobject(thr, -1);
DUK_ASSERT(h != NULL);
return h;
}
-DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
- duk_hstring *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_string(ctx, -1);
- h = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h != NULL);
- return h;
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */
}
-DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
+ DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */
DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
return thr->valstack_bottom - 1;
}
-DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_push_tval(ctx, &act->tv_func);
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ duk_push_tval(thr, &act->tv_func);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
if (thr->heap->curr_thread) {
- duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
+ duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
}
/* XXX: size optimize */
-DUK_LOCAL void duk__push_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
+DUK_LOCAL void duk__push_stash(duk_hthread *thr) {
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) {
DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
- duk_pop(ctx);
- duk_push_object_internal(ctx);
- duk_dup_top(ctx);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
+ duk_pop_unsafe(thr);
+ duk_push_bare_object(thr);
+ duk_dup_top(thr);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
}
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
-DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap->heap_object != NULL);
- duk_push_hobject(ctx, heap->heap_object);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, heap->heap_object);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_push_global_object(ctx);
- duk__push_stash(ctx);
+DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_global_object(thr);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- if (!target_ctx) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(target_thr == NULL)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return; /* not reached */
}
- duk_push_hobject(ctx, (duk_hobject *) target_ctx);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, (duk_hobject *) target_thr);
+ duk__push_stash(thr);
}
/* XXX: duk_ssize_t would be useful here */
-DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
+DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_UNREF(thr);
/* NUL terminator handling doesn't matter here */
len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
@@ -18445,8 +21589,7 @@ DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size
return -1;
}
-DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) {
duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
duk_bool_t pushed_buf = 0;
@@ -18454,13 +21597,13 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
duk_int_t len; /* XXX: duk_ssize_t */
const char *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* special handling of fmt==NULL */
if (!fmt) {
duk_hstring *h_str;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */
+ duk_push_hstring_empty(thr);
+ h_str = duk_known_hstring(thr, -1);
return (const char *) DUK_HSTRING_GET_DATA(h_str);
}
@@ -18481,14 +21624,14 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
buf = stack_buf;
} else if (!pushed_buf) {
pushed_buf = 1;
- buf = duk_push_dynamic_buffer(ctx, sz);
+ buf = duk_push_dynamic_buffer(thr, sz);
} else {
- buf = duk_resize_buffer(ctx, -1, sz);
+ buf = duk_resize_buffer(thr, -1, sz);
}
DUK_ASSERT(buf != NULL);
DUK_VA_COPY(ap_copy, ap);
- len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
+ len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy);
va_end(ap_copy);
if (len >= 0) {
break;
@@ -18496,157 +21639,174 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
/* failed, resize and try again */
sz = sz * 2;
- if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
- DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
+ if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) {
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
}
}
- /* Cannot use duk_to_string() on the buffer because it is usually
- * larger than 'len'. Also, 'buf' is usually a stack buffer.
+ /* Cannot use duk_buffer_to_string() on the buffer because it is
+ * usually larger than 'len'; 'buf' is also usually a stack buffer.
*/
- res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
+ res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
if (pushed_buf) {
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
return res;
}
-DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) {
va_list ap;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* allow fmt==NULL */
va_start(ap, fmt);
- ret = duk_push_vsprintf(ctx, fmt, ap);
+ ret = duk_push_vsprintf(thr, fmt, ap);
va_end(ap);
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
duk_tval *tv_slot;
duk_hobject *h;
- duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx == -1 ||
(prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ h = duk_hobject_alloc(thr, hobject_flags_and_class);
+ DUK_ASSERT(h != NULL);
DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, h);
DUK_HOBJECT_INCREF(thr, h); /* no side effects */
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
/* object is now reachable */
if (prototype_bidx >= 0) {
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]);
} else {
DUK_ASSERT(prototype_bidx == -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
}
- return ret;
+ return h;
}
-DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
+DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
- h = duk_get_hobject(ctx, -1);
+ h = duk_push_object_helper(thr, hobject_flags_and_class, -1);
DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
- return ret;
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto);
+ return h;
}
-DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
DUK_BIDX_OBJECT_PROTOTYPE);
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
+DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) {
+ duk_uint_t flags;
+ duk_harray *obj;
duk_idx_t ret;
+ duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_ARRAY_PART |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
- DUK_BIDX_ARRAY_PROTOTYPE);
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_ARRAY_PART |
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
- obj = duk_require_hobject(ctx, ret);
+ obj = duk_harray_alloc(thr, flags);
+ DUK_ASSERT(obj != NULL);
- /*
- * An array must have a 'length' property (E5 Section 15.4.5.2).
- * The special array behavior flag must only be enabled once the
- * length property has been added.
- *
- * The internal property must be a number (and preferably a
- * fastint if fastint support is enabled).
- */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
- duk_push_int(ctx, 0);
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1)));
-#endif
-
- duk_hobject_define_property_internal(thr,
- obj,
- DUK_HTHREAD_STRING_LENGTH(thr),
- DUK_PROPDESC_FLAGS_W);
- DUK_HOBJECT_SET_EXOTIC_ARRAY(obj);
+ tv_slot = thr->valstack_top;
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
+ DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ thr->valstack_top++;
+ DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */
return ret;
}
-DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) {
+ /* XXX: API call could do this directly, cast to void in API macro. */
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_array(thr);
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
+ a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
+ DUK_ASSERT(a != NULL);
+ return a;
+}
+
+/* Push a duk_harray with preallocated size (.length also set to match size).
+ * Caller may then populate array part of the duk_harray directly.
+ */
+DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) {
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray(thr);
+
+ duk_hobject_realloc_props(thr,
+ (duk_hobject *) a,
+ 0,
+ size,
+ 0,
+ 0);
+ a->length = size;
+ return a;
+}
+
+DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) {
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray_with_size(thr, size);
+ DUK_ASSERT(a != NULL);
+ return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
+}
+
+DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
duk_hthread *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- obj = duk_hthread_alloc(thr->heap,
+ obj = duk_hthread_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_THREAD |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ DUK_ASSERT(obj != NULL);
obj->state = DUK_HTHREAD_STATE_INACTIVE;
#if defined(DUK_USE_ROM_STRINGS)
/* Nothing to initialize, strs[] is in ROM. */
@@ -18667,8 +21827,8 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
thr->valstack_top++;
/* important to do this *after* pushing, to make the thread reachable for gc */
- if (!duk_hthread_init_stacks(thr->heap, obj)) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
/* initialize built-ins - either by copying or creating new ones */
@@ -18678,10 +21838,10 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
duk_hthread_copy_builtin_objects(thr, obj);
}
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
+ /* default prototype */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
- /* Initial stack size satisfies the stack spare constraints so there
+ /* Initial stack size satisfies the stack slack constraints so there
* is no need to require stack here.
*/
DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
@@ -18690,30 +21850,26 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hcompiledfunction *obj;
- duk_idx_t ret;
+DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
+ duk_hcompfunc *obj;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* Template functions are not strictly constructable (they don't
* have a "prototype" property for instance), so leave the
* DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
*/
- obj = duk_hcompiledfunction_alloc(thr->heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ obj = duk_hcompfunc_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_COMPFUNC |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
+ if (DUK_UNLIKELY(obj == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
@@ -18721,43 +21877,67 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
DUK_HOBJECT_INCREF(thr, obj);
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+ /* default prototype */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
- return ret;
+ return obj;
}
-DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hnativefunction *obj;
+DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
+ duk_hboundfunc *obj;
+ duk_tval *tv_slot;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK__CHECK_SPACE();
+ obj = duk_hboundfunc_alloc(thr->heap,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BOUNDFUNC |
+ DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
+ if (!obj) {
+ DUK_ERROR_ALLOC_FAILED(thr);
+ }
+
+ tv_slot = thr->valstack_top++;
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
+ DUK_HOBJECT_INCREF(thr, obj);
+
+ /* Prototype is left as NULL because the caller always sets it (and
+ * it depends on the target function).
+ */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+
+ return obj;
+}
+
+DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) {
+ duk_hnatfunc *obj;
duk_idx_t ret;
duk_tval *tv_slot;
duk_int16_t func_nargs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
- if (func == NULL) {
+ DUK__CHECK_SPACE();
+
+ if (DUK_UNLIKELY(func == NULL)) {
goto api_error;
}
- if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
+ if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) {
func_nargs = (duk_int16_t) nargs;
} else if (nargs == DUK_VARARGS) {
- func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
+ func_nargs = DUK_HNATFUNC_NARGS_VARARGS;
} else {
goto api_error;
}
- obj = duk_hnativefunction_alloc(thr->heap, flags);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ obj = duk_hnatfunc_alloc(thr, flags);
+ DUK_ASSERT(obj != NULL);
obj->func = func;
obj->nargs = func_nargs;
@@ -18771,75 +21951,80 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
+ DUK_ASSERT_BIDX_VALID(proto_bidx);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]);
return ret;
api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return 0; /* not reached */
}
-DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- return duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Default prototype is a Duktape specific %NativeFunctionPrototype%
+ * which provides .length and .name getters.
+ */
+ return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval tv_tmp;
+DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
duk_small_uint_t lf_flags;
+ duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
/* as is */
@@ -18848,44 +22033,40 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
} else {
goto api_error;
}
- if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
+ if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) {
goto api_error;
}
- if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
+ if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) {
goto api_error;
}
- lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
- DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
- duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
- DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
- return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs);
+ tv_slot = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot));
+ DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags);
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ return (duk_idx_t) (tv_slot - thr->valstack_bottom);
api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return 0; /* not reached */
}
-DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbufferobject *obj;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
+ duk_hbufobj *obj;
duk_tval *tv_slot;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx >= 0);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ obj = duk_hbufobj_alloc(thr, hobject_flags_and_class);
+ DUK_ASSERT(obj != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
- DUK_ASSERT_HBUFFEROBJECT_VALID(obj);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
+ DUK_ASSERT_HBUFOBJ_VALID(obj);
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
@@ -18894,165 +22075,181 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_
return obj;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* XXX: There's quite a bit of overlap with buffer creation handling in
* duk_bi_buffer.c. Look for overlap and refactor.
*/
-#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \
- (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview))
-
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \
+ (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray))
+
static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
-};
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/* Only allow Duktape.Buffer when support disabled. */
-static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */
+ /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
};
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#undef DUK__PACK_ARGS
-DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
+ duk_hobject *h_arraybuf;
duk_uint32_t tmp;
duk_uint_t classnum;
duk_uint_t protobidx;
duk_uint_t lookupidx;
duk_uint_t uint_offset, uint_length, uint_added;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- /* The underlying types for offset/length in duk_hbufferobject is
- * duk_uint_t; make sure argument values fit and that offset + length
- * does not wrap.
+ /* The underlying types for offset/length in duk_hbufobj is
+ * duk_uint_t; make sure argument values fit.
*/
uint_offset = (duk_uint_t) byte_offset;
uint_length = (duk_uint_t) byte_length;
if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
- if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
+ if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) {
goto range_error;
}
}
- uint_added = uint_offset + uint_length;
- if (uint_added < uint_offset) {
- goto range_error;
- }
- DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
- lookupidx = flags & 0x0f; /* 4 low bits */
- if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
+ lookupidx = flags;
+ if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) {
goto arg_error;
}
tmp = duk__bufobj_flags_lookup[lookupidx];
classnum = tmp >> 24;
protobidx = (tmp >> 16) & 0xff;
- h_val = duk_require_hbuffer(ctx, idx_buffer);
+ h_arraybuf = duk_get_hobject(thr, idx_buffer);
+ if (h_arraybuf != NULL && /* argument is an object */
+ flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */
+ DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) {
+ duk_uint_t tmp_offset;
+
+ DUK_ASSERT_HBUFOBJ_VALID((duk_hbufobj *) h_arraybuf);
+ h_val = ((duk_hbufobj *) h_arraybuf)->buf;
+ if (DUK_UNLIKELY(h_val == NULL)) {
+ goto arg_error;
+ }
+
+ tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset;
+ if (DUK_UNLIKELY(tmp_offset < uint_offset)) {
+ goto range_error;
+ }
+ uint_offset = tmp_offset;
+
+ /* Note intentional difference to new TypedArray(): we allow
+ * caller to create an uncovered typed array (which is memory
+ * safe); new TypedArray() rejects it.
+ */
+ } else {
+ /* Handle unexpected object arguments here too, for nice error
+ * messages.
+ */
+ h_arraybuf = NULL;
+ h_val = duk_require_hbuffer(thr, idx_buffer);
+ }
+
+ /* Wrap check for offset+length. */
+ uint_added = uint_offset + uint_length;
+ if (DUK_UNLIKELY(uint_added < uint_offset)) {
+ goto range_error;
+ }
+ DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
+
DUK_ASSERT(h_val != NULL);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
- protobidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
+ (duk_small_int_t) protobidx);
DUK_ASSERT(h_bufobj != NULL);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
+ h_bufobj->buf_prop = h_arraybuf;
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf);
h_bufobj->offset = uint_offset;
h_bufobj->length = uint_length;
h_bufobj->shift = (tmp >> 4) & 0x0f;
h_bufobj->elem_type = (tmp >> 8) & 0xff;
- h_bufobj->is_view = tmp & 0x0f;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_bufobj->is_typedarray = tmp & 0x0f;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* TypedArray views need an automatic ArrayBuffer which must be
- * provided as .buffer property of the view. Just create a new
- * ArrayBuffer sharing the same underlying buffer.
+ * provided as .buffer property of the view. The ArrayBuffer is
+ * referenced via duk_hbufobj->buf_prop and an inherited .buffer
+ * accessor returns it. The ArrayBuffer is created lazily on first
+ * access if necessary so we don't need to do anything more here.
*/
- if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
-
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = uint_offset;
- h_bufobj->length = uint_length;
- DUK_ASSERT(h_bufobj->shift == 0);
- h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8;
- DUK_ASSERT(h_bufobj->is_view == 0);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
- }
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
return;
range_error:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
return; /* not reached */
arg_error:
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
return; /* not reached */
}
+#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx_buffer);
+ DUK_UNREF(byte_offset);
+ DUK_UNREF(byte_length);
+ DUK_UNREF(flags);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
+DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
duk_hobject *proto;
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_bool_t noblame_fileline;
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ duk_small_uint_t augment_flags;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_UNREF(filename);
DUK_UNREF(line);
/* Error code also packs a tracedata related flag. */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ augment_flags = 0;
+ if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) {
+ augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE;
+ }
#endif
err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
/* error gets its 'name' from the prototype */
proto = duk_error_prototype_from_code(thr, err_code);
- ret = duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
- proto);
+ (void) duk_push_object_helper_proto(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
+ proto);
/* ... and its 'message' from an instance property */
if (fmt) {
- duk_push_vsprintf(ctx, fmt, ap);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_vsprintf(thr, fmt, ap);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
} else {
/* If no explicit message given, put error code into message field
* (as a number). This is not fully in keeping with the Ecmascript
@@ -19060,72 +22257,68 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod
* constructors use ToString() on their argument). However, it's
* probably more useful than having a separate 'code' property.
*/
- duk_push_int(ctx, err_code);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_int(thr, err_code);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* XXX: .code = err_code disabled, not sure if useful */
/* Creation time error augmentation */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
/* filename may be NULL in which case file/line is not recorded */
- duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
+ duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */
#endif
- return ret;
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
const char *filename = duk_api_global_filename;
duk_int_t line = duk_api_global_line;
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
duk_api_global_filename = NULL;
duk_api_global_line = 0;
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#endif /* DUK_USE_VARIADIC_MACROS */
-DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) {
duk_tval *tv_slot;
duk_hbuffer *h;
void *buf_data;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* Check for maximum buffer length. */
- if (size > DUK_HBUFFER_MAX_BYTELEN) {
+ if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
}
h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
tv_slot = thr->valstack_top;
@@ -19136,125 +22329,450 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm
return (void *) buf_data;
}
-DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO);
+}
+
+DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) {
+ void *ptr;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ptr = duk_push_buffer_raw(thr, len, 0);
+#if !defined(DUK_USE_ZERO_BUFFER_DATA)
+ /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
+ * is not set.
+ */
+ DUK_MEMZERO((void *) ptr, (size_t) len);
+#endif
+ return ptr;
+}
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ duk_hobject *h_target;
+ duk_hobject *h_handler;
+ duk_hproxy *h_proxy;
+ duk_tval *tv_slot;
+ duk_uint_t flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+
+ /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to
+ * value stack in-place.
+ */
+#if 0
+ DUK__CHECK_SPACE();
+#endif
+
+ /* Reject a proxy object as the target because it would need
+ * special handling in property lookups. (ES2015 has no such
+ * restriction.)
+ */
+ h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_target != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_target)) {
+ goto fail_args;
+ }
+
+ /* Reject a proxy object as the handler because it would cause
+ * potentially unbounded recursion. (ES2015 has no such
+ * restriction.)
+ *
+ * There's little practical reason to use a lightfunc or a plain
+ * buffer as the handler table: one could only provide traps via
+ * their prototype objects (Function.prototype and ArrayBuffer.prototype).
+ * Even so, as lightfuncs and plain buffers mimic their object
+ * counterparts, they're promoted and accepted here.
+ */
+ h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_handler != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_handler)) {
+ goto fail_args;
+ }
+
+ /* XXX: Proxy object currently has no prototype, so ToPrimitive()
+ * coercion fails which is a bit confusing.
+ */
+
+ /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial)
+ * target, see ES2015 Sections 9.5.15 and 9.5.13.
+ */
+ flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) &
+ (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE);
+ flags |= DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ;
+ if (flags & DUK_HOBJECT_FLAG_CALLABLE) {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) |
+ DUK_HOBJECT_FLAG_SPECIAL_CALL;
+ } else {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT);
+ }
+
+ h_proxy = duk_hproxy_alloc(thr, flags);
+ DUK_ASSERT(h_proxy != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL);
+
+ /* Initialize Proxy target and handler references; avoid INCREF
+ * by stealing the value stack refcounts via direct value stack
+ * manipulation. INCREF is needed for the Proxy itself however.
+ */
+ DUK_ASSERT(h_target != NULL);
+ h_proxy->target = h_target;
+ DUK_ASSERT(h_handler != NULL);
+ h_proxy->handler = h_handler;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
+
+ DUK_ASSERT(duk_get_hobject(thr, -2) == h_target);
+ DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler);
+ tv_slot = thr->valstack_top - 2;
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy);
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy);
+ tv_slot++;
+ DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */
+ thr->valstack_top = tv_slot; /* -> [ ... proxy ] */
+
+ DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1)));
+
+ return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1);
+
+ fail_args:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+}
+#else /* DUK_USE_ES6_PROXY */
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_ES6_PROXY */
+
+#if defined(DUK_USE_ASSERTIONS)
+DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) {
+ duk_heaphdr *h;
+ duk_heaphdr *curr;
+ duk_bool_t found = 0;
+
+ h = (duk_heaphdr *) ptr;
+ if (h == NULL) {
+ /* Allowed. */
+ return;
+ }
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
+
+ /* One particular problem case is where an object has been
+ * queued for finalization but the finalizer hasn't yet been
+ * executed.
+ *
+ * Corner case: we're running in a finalizer for object X, and
+ * user code calls duk_push_heapptr() for X itself. In this
+ * case X will be in finalize_list, and we can detect the case
+ * by seeing that X's FINALIZED flag is set (which is done before
+ * the finalizer starts executing).
+ */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ for (curr = thr->heap->finalize_list;
+ curr != NULL;
+ curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
+ /* FINALIZABLE is set for all objects on finalize_list
+ * except for an object being finalized right now. So
+ * can't assert here.
+ */
+#if 0
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr));
+#endif
+
+ if (curr == h) {
+ if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
+ /* Object is currently being finalized. */
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ } else {
+ /* Not being finalized but on finalize_list,
+ * allowed since Duktape 2.1.
+ */
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ }
+ }
+ }
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Because refzero_list is now processed to completion inline with
+ * no side effects, it's always empty here.
+ */
+ DUK_ASSERT(thr->heap->refzero_list == NULL);
+#endif
+
+ /* If not present in finalize_list (or refzero_list), it
+ * must be either in heap_allocated or the string table.
+ */
+ if (DUK_HEAPHDR_IS_STRING(h)) {
+ duk_uint32_t i;
+ duk_hstring *str;
+ duk_heap *heap = thr->heap;
+
+ DUK_ASSERT(found == 0);
+ for (i = 0; i < heap->st_size; i++) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
+#else
+ str = heap->strtable[i];
+#endif
+ while (str != NULL) {
+ if (str == (duk_hstring *) h) {
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ break;
+ }
+ str = str->hdr.h_next;
+ }
+ }
+ DUK_ASSERT(found != 0);
+ } else {
+ for (curr = thr->heap->heap_allocated;
+ curr != NULL;
+ curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
+ if (curr == h) {
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ }
+ }
+ DUK_ASSERT(found != 0);
+ }
+}
+#endif /* DUK_USE_ASSERTIONS */
+
+DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) {
duk_idx_t ret;
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* Reviving an object using a heap pointer is a dangerous API
+ * operation: if the application doesn't guarantee that the
+ * pointer target is always reachable, difficult-to-diagnose
+ * problems may ensue. Try to validate the 'ptr' argument to
+ * the extent possible.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+ duk__validate_push_heapptr(thr, ptr);
+#endif
+
+ DUK__CHECK_SPACE();
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ tv = thr->valstack_top++;
if (ptr == NULL) {
- goto push_undefined;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
+ return ret;
}
- switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
+ DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr);
+
+ /* If the argument is on finalize_list it has technically been
+ * unreachable before duk_push_heapptr() but it's still safe to
+ * push it. Starting from Duktape 2.1 allow application code to
+ * do so. There are two main cases:
+ *
+ * (1) The object is on the finalize_list and we're called by
+ * the finalizer for the object being finalized. In this
+ * case do nothing: finalize_list handling will deal with
+ * the object queueing. This is detected by the object not
+ * having a FINALIZABLE flag despite being on the finalize_list;
+ * the flag is cleared for the object being finalized only.
+ *
+ * (2) The object is on the finalize_list but is not currently
+ * being processed. In this case the object can be queued
+ * back to heap_allocated with a few flags cleared, in effect
+ * cancelling the finalizer.
+ */
+ if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) {
+ duk_heaphdr *curr;
+
+ DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue"));
+
+ curr = (duk_heaphdr *) ptr;
+ DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+
+ /* Because FINALIZED is set prior to finalizer call, it will
+ * be set for the object being currently finalized, but not
+ * for other objects on finalize_list.
+ */
+ DUK_HEAPHDR_CLEAR_FINALIZED(curr);
+
+ /* Dequeue object from finalize_list and queue it back to
+ * heap_allocated.
+ */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */
+ DUK_HEAPHDR_PREDEC_REFCOUNT(curr);
+#endif
+ DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr);
+ DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr);
+
+ /* Continue with the rest. */
+ }
+
+ switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
case DUK_HTYPE_STRING:
- duk_push_hstring(ctx, (duk_hstring *) ptr);
+ DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr);
break;
case DUK_HTYPE_OBJECT:
- duk_push_hobject(ctx, (duk_hobject *) ptr);
- break;
- case DUK_HTYPE_BUFFER:
- duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
+ DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr);
break;
default:
- goto push_undefined;
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER);
+ DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr);
+ break;
}
- return ret;
- push_undefined:
- duk_push_undefined(ctx);
+ DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr);
+
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) {
- return duk_push_object_helper(ctx,
+/* Push object with no prototype, i.e. a "bare" object. */
+DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
-1); /* no prototype */
+ return duk_get_top_index_unsafe(thr);
}
-DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
+DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_STRING(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
+DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+}
+
+DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
}
-DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
+DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_OBJECT(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
+DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_BUFFER(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
}
/*
* Poppers
*/
-DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) {
duk_tval *tv;
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_tval *tv_end;
+#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
- if (DUK_UNLIKELY(count < 0)) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
- return;
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ while (tv != tv_end) {
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
}
+ thr->valstack_top = tv;
+ DUK_REFZERO_CHECK_FAST(thr);
+#else
+ tv = thr->valstack_top;
+ while (count > 0) {
+ count--;
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED(tv);
+ }
+ thr->valstack_top = tv;
+#endif
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
- }
+}
- /*
- * Must be very careful here, every DECREF may cause reallocation
- * of our valstack.
- */
+DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- /* XXX: inlined DECREF macro would be nice here: no NULL check,
- * refzero queueing but no refzero algorithm run (= no pointer
- * instability), inline code.
- */
+ if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ return;
+ }
+ DUK_ASSERT(count >= 0);
- /* XXX: optimize loops */
+ duk__pop_n_unsafe_raw(thr, count);
+}
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, count);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_n_unsafe_raw(thr, count);
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+/* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */
#if defined(DUK_USE_REFERENCE_COUNTING)
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv points to element just below prev top */
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
- }
-#else
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
+
tv = thr->valstack_top;
while (count > 0) {
count--;
@@ -19263,64 +22781,360 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
DUK_TVAL_SET_UNDEFINED(tv);
}
thr->valstack_top = tv;
-#endif
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
+#else /* DUK_USE_REFERENCE_COUNTING */
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, count);
+}
+#endif /* DUK_USE_REFERENCE_COUNTING */
/* Popping one element is called so often that when footprint is not an issue,
* compile a specialized function for it.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 1);
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 1);
}
-#else
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 1);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 1);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+#else
+ DUK_TVAL_SET_UNDEFINED(tv);
+#endif
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
}
- tv = --thr->valstack_top; /* tv points to element just below prev top */
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ tv = --thr->valstack_top;
DUK_ASSERT(tv >= thr->valstack_bottom);
-#ifdef DUK_USE_REFERENCE_COUNTING
+ DUK_TVAL_SET_UNDEFINED(tv);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#endif /* !DUK_USE_PREFER_SIZE */
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_nodecref_unsafe(thr);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ thr->valstack_top--;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#endif /* !DUK_USE_PREFER_SIZE */
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 2);
+}
+#else
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
+
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
#else
DUK_TVAL_SET_UNDEFINED(tv);
#endif
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+#else
+ DUK_TVAL_SET_UNDEFINED(tv);
+#endif
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2));
+ thr->valstack_top -= 2;
+
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
#endif /* !DUK_USE_PREFER_SIZE */
-DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 2);
+DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 3);
+}
+
+DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 3);
}
-DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 3);
+DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 3);
+}
+
+/*
+ * Pack and unpack (pack value stack entries into an array and vice versa)
+ */
+
+/* XXX: pack index range? array index offset? */
+DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_tval *tv_curr;
+ duk_tval *tv_limit;
+ duk_idx_t top;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ DUK_ASSERT(top >= 0);
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
+ /* Also handles negative count. */
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ return;
+ }
+ DUK_ASSERT(count >= 0);
+
+ /* Wrapping is controlled by the check above: value stack top can be
+ * at most DUK_USE_VALSTACK_LIMIT which is low enough so that
+ * multiplying with sizeof(duk_tval) won't wrap.
+ */
+ DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT);
+ DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */
+
+ tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
+ DUK_ASSERT(count == 0 || tv_dst != NULL);
+
+ /* Copy value stack values directly to the array part without
+ * any refcount updates: net refcount changes are zero.
+ */
+
+ tv_src = thr->valstack_top - count - 1;
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
+
+ /* Overwrite result array to final value stack location and wipe
+ * the rest; no refcount operations needed.
+ */
+
+ tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */
+ tv_src = thr->valstack_top - 1;
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+
+ /* XXX: internal helper to wipe a value stack segment? */
+ tv_curr = tv_dst + 1;
+ tv_limit = thr->valstack_top;
+ while (tv_curr != tv_limit) {
+ /* Wipe policy: keep as 'undefined'. */
+ DUK_TVAL_SET_UNDEFINED(tv_curr);
+ tv_curr++;
+ }
+ thr->valstack_top = tv_dst + 1;
+}
+
+DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) {
+ duk_hobject *h;
+ duk_uint32_t len;
+ duk_uint32_t i;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ DUK_UNREF(h);
+
+#if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */
+ if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) &&
+ ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) {
+ duk_harray *h_arr;
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+
+ h_arr = (duk_harray *) h;
+ len = h_arr->length;
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_require_stack(thr, (duk_idx_t) len);
+
+ /* The potential allocation in duk_require_stack() may
+ * run a finalizer which modifies the argArray so that
+ * e.g. becomes sparse. So, we need to recheck that the
+ * array didn't change size and that there's still a
+ * valid backing array part.
+ *
+ * XXX: alternatively, could prevent finalizers for the
+ * duration.
+ */
+ if (DUK_UNLIKELY(len != h_arr->length ||
+ h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) {
+ goto skip_fast;
+ }
+
+ /* Main fast path: arguments array is almost always
+ * an actual array (though it might also be an arguments
+ * object).
+ */
+
+ DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length));
+ tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
+ tv_dst = thr->valstack_top;
+ while (len-- > 0) {
+ DUK_ASSERT(tv_dst < thr->valstack_end);
+ if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) {
+ /* Gaps are very unlikely. Skip over them,
+ * without an ancestor lookup (technically
+ * not compliant).
+ */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */
+ } else {
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+ DUK_TVAL_INCREF(thr, tv_dst);
+ }
+ tv_src++;
+ tv_dst++;
+ }
+ DUK_ASSERT(tv_dst <= thr->valstack_end);
+ thr->valstack_top = tv_dst;
+ return (duk_idx_t) h_arr->length;
+ }
+ skip_fast:
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+ /* Slow path: actual lookups. The initial 'length' lookup
+ * decides the output length, regardless of side effects that
+ * may resize or change the argArray while we read the
+ * indices.
+ */
+ idx = duk_normalize_index(thr, idx);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_pop_unsafe(thr);
+ DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len));
+
+ duk_require_stack(thr, (duk_idx_t) len);
+ for (i = 0; i < len; i++) {
+ duk_get_prop_index(thr, idx, (duk_uarridx_t) i);
+ }
+ return (duk_idx_t) len;
+ } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
+ return 0;
+ }
+
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return 0;
+
+ fail_over_2g:
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
+ return 0;
}
/*
* Error throwing
*/
-DUK_EXTERNAL void duk_throw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
+ duk_tval *tv_val;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- if (thr->valstack_top == thr->valstack_bottom) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
/* Errors are augmented when they are created, not when they are
@@ -19335,77 +23149,125 @@ DUK_EXTERNAL void duk_throw(duk_context *ctx) {
duk_hthread_sync_and_null_currpc(thr);
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+ tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_err_check_debugger_integration(thr);
+#endif
/* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
- * need to check that here. If the value is NULL, a panic occurs because
- * we can't return.
+ * need to check that here. If the value is NULL, a fatal error occurs
+ * because we can't return.
*/
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
-DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->fatal_func != NULL);
- DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s",
- (long) err_code, (const char *) err_msg));
+ DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL"));
/* fatal_func should be noreturn, but noreturn declarations on function
* pointers has a very spotty support apparently so it's not currently
* done.
*/
- thr->heap->fatal_func(ctx, err_code, err_msg);
+ thr->heap->fatal_func(thr->heap->heap_udata, err_msg);
- DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
+ /* If the fatal handler returns, all bets are off. It'd be nice to
+ * print something here but since we don't want to depend on stdio,
+ * there's no way to do so portably.
+ */
+ DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!"));
+ for (;;) {
+ /* loop forever, don't return (function marked noreturn) */
+ }
}
-DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
}
-DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
- duk_throw(ctx);
+ (void) duk_throw(thr);
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap));
+
+DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) {
const char *filename;
duk_int_t line;
- va_list ap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
filename = duk_api_global_filename;
line = duk_api_global_line;
duk_api_global_filename = NULL;
duk_api_global_line = 0;
- va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
+}
+
+#define DUK__ERROR_STASH_SHARED(code) do { \
+ va_list ap; \
+ va_start(ap, fmt); \
+ duk__throw_error_from_stash(thr, (code), fmt, ap); \
+ va_end(ap); \
+ /* Never reached; if return 0 here, gcc/clang will complain. */ \
+ } while (0)
+
+DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(err_code);
+}
+DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
}
#endif /* DUK_USE_VARIADIC_MACROS */
@@ -19413,14 +23275,13 @@ DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, cons
* Comparison
*/
-DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -19431,13 +23292,13 @@ DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t
return duk_js_equals(thr, tv1, tv2);
}
-DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -19446,14 +23307,29 @@ DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, du
return duk_js_strict_equals(tv1, tv2);
}
+DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
+ duk_tval *tv1, *tv2;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
+ if ((tv1 == NULL) || (tv2 == NULL)) {
+ return 0;
+ }
+
+ /* No coercions or other side effects, so safe */
+ return duk_js_samevalue(tv1, tv2);
+}
+
/*
* instanceof
*/
-DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Index validation is strict, which differs from duk_equals().
* The strict behavior mimics how instanceof itself works, e.g.
@@ -19461,23 +23337,19 @@ DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_i
* be somewhat inconsistent if rval would be allowed to be
* non-existent without a TypeError.
*/
- tv1 = duk_require_tval(ctx, index1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
- return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
+ return duk_js_instanceof(thr, tv1, tv2);
}
/*
* Lightfunc
*/
-DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
- duk_c_function func;
-
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
-
+DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
/* Lightfunc name, includes Duktape/C native function pointer, which
* can often be used to locate the function from a symbol table.
* The name also includes the 16-bit duk_tval flags field because it
@@ -19490,20 +23362,37 @@ DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
* is accessed).
*/
- func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv);
- duk_push_sprintf(ctx, "light_");
- duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
- duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv));
- duk_concat(ctx, 3);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_push_sprintf(thr, "light_");
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
+ duk_concat(thr, 3);
}
-DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
+DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) {
+ duk_c_function func;
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
- duk_push_string(ctx, "function ");
- duk_push_lightfunc_name(ctx, tv);
- duk_push_string(ctx, "() {\"light\"}");
- duk_concat(ctx, 3);
+ DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+}
+
+DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
+ duk_c_function func;
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
+
+ DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
+ duk_push_string(thr, "function ");
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_push_string(thr, "() { [lightfunc code] }");
+ duk_concat(thr, 3);
}
/*
@@ -19513,12 +23402,13 @@ DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
* bytes from memory.
*/
-DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
+DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) {
duk_uint8_t buf[32 * 2];
duk_uint8_t *p, *q;
duk_small_uint_t i;
duk_small_uint_t t;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
p = buf;
@@ -19537,10 +23427,9 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
*p++ = duk_lc_digits[t & 0x0f];
}
- duk_push_lstring(ctx, (const char *) buf, sz * 2);
+ duk_push_lstring(thr, (const char *) buf, sz * 2);
}
-#if !defined(DUK_USE_PARANOID_ERRORS)
/*
* Push readable string summarizing duk_tval. The operation is side effect
* free and will only throw from internal errors (e.g. out of memory).
@@ -19548,25 +23437,27 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
* and is not intended to be fast (but small and safe).
*/
-#define DUK__READABLE_STRING_MAXCHARS 32
+/* String limits for summary strings. */
+#define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */
+#define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */
+#define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */
/* String sanitizer which escapes ASCII control characters and a few other
* ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
* question marks. No errors are thrown for any input string, except in out
* of memory situations.
*/
-DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
- duk_hthread *thr;
+DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) {
const duk_uint8_t *p, *p_start, *p_end;
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
+ duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS +
2 /*quotes*/ + 3 /*periods*/];
duk_uint8_t *q;
duk_ucodepoint_t cp;
duk_small_uint_t nchars;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(h_input != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
@@ -19579,7 +23470,7 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
if (p >= p_end) {
break;
}
- if (nchars == DUK__READABLE_STRING_MAXCHARS) {
+ if (nchars == maxchars) {
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
@@ -19604,74 +23495,188 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
}
*q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf));
}
-DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) {
+ DUK_ASSERT_CTX_VALID(thr);
+ /* 'tv' may be NULL */
if (tv == NULL) {
- duk_push_string(ctx, "none");
+ duk_push_string(thr, "none");
} else {
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_STRING: {
- duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
+ duk_hstring *h = DUK_TVAL_GET_STRING(tv);
+ if (DUK_HSTRING_HAS_SYMBOL(h)) {
+ /* XXX: string summary produces question marks
+ * so this is not very ideal.
+ */
+ duk_push_string(thr, "[Symbol ");
+ duk_push_string(thr, duk__get_symbol_type_string(h));
+ duk_push_string(thr, " ");
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
+ duk_push_string(thr, "]");
+ duk_concat(thr, 5);
+ break;
+ }
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
break;
}
case DUK_TAG_OBJECT: {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- duk_push_hobject_class_string(ctx, h);
+
+ if (error_aware &&
+ duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
+ /* Get error message in a side effect free way if
+ * possible; if not, summarize as a generic object.
+ * Error message currently gets quoted.
+ */
+ /* XXX: better internal getprop call; get without side effects
+ * but traverse inheritance chain.
+ */
+ duk_tval *tv_msg;
+ tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr));
+ if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) {
+ /* It's critical to avoid recursion so
+ * only summarize a string .message.
+ */
+ duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS);
+ break;
+ }
+ }
+ duk_push_class_string_tval(thr, tv);
break;
}
case DUK_TAG_BUFFER: {
+ /* While plain buffers mimic Uint8Arrays, they summarize differently.
+ * This is useful so that the summarized string accurately reflects the
+ * internal type which may matter for figuring out bugs etc.
+ */
/* XXX: Hex encoded, length limited buffer summary here? */
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
+ duk_push_sprintf(thr, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
break;
}
case DUK_TAG_POINTER: {
/* Surround with parentheses like in JX, ensures NULL pointer
* is distinguishable from null value ("(null)" vs "null").
*/
- duk_push_tval(ctx, tv);
- duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
- duk_remove(ctx, -2);
+ duk_push_tval(thr, tv);
+ duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1));
+ duk_remove_m2(thr);
break;
}
default: {
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
break;
}
}
}
- return duk_to_string(ctx, -1);
+ return duk_to_string(thr, -1);
+}
+DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/);
+}
+
+DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx));
}
-DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
+DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/);
}
-#endif /* !DUK_USE_PARANOID_ERRORS */
+DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) {
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ const duk_uint8_t *q;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* .toString() */
+ duk_push_string(thr, "Symbol(");
+ p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ p_end = p + DUK_HSTRING_GET_BYTELEN(h);
+ DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
+ p++;
+ for (q = p; q < p_end; q++) {
+ if (*q == 0xffU) {
+ /* Terminate either at end-of-string (but NUL MUST
+ * be accepted without terminating description) or
+ * 0xFF, which is used to mark start of unique trailer
+ * (and cannot occur in CESU-8 / extended UTF-8).
+ */
+ break;
+ }
+ }
+ duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
+ duk_push_string(thr, ")");
+ duk_concat(thr, 3);
+}
+
+/*
+ * Functions
+ */
+
+#if 0 /* not used yet */
+DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) {
+ duk_c_function func;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h));
+
+ duk_push_sprintf(thr, "native_");
+ func = h->func;
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x_%04x",
+ (unsigned int) (duk_uint16_t) h->nargs,
+ (unsigned int) (duk_uint16_t) h->magic);
+ duk_concat(thr, 3);
+}
+#endif
+
+/*
+ * duk_tval slice copy
+ */
+
+DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+ DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
+
+ tv = tv_dst;
+ while (count-- > 0) {
+ DUK_TVAL_INCREF(thr, tv);
+ tv++;
+ }
+}
+
+/* automatic undefs */
+#undef DUK__ASSERT_SPACE
#undef DUK__CHECK_SPACE
+#undef DUK__ERROR_STASH_SHARED
#undef DUK__PACK_ARGS
+#undef DUK__READABLE_ERRMSG_MAXCHARS
#undef DUK__READABLE_STRING_MAXCHARS
-#line 1 "duk_api_string.c"
+#undef DUK__READABLE_SUMMARY_MAXCHARS
/*
* String manipulation
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
duk_uint_t count;
duk_uint_t i;
duk_size_t idx;
@@ -19679,22 +23684,22 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
duk_hstring *h;
duk_uint8_t *buf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
return;
}
DUK_ASSERT(count_in == 0);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_push_hstring_empty(thr);
return;
}
count = (duk_uint_t) count_in;
if (is_join) {
duk_size_t t1, t2, limit;
- h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
+ h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
DUK_ASSERT(h != NULL);
/* A bit tricky overflow test, see doc/code-issues.rst. */
@@ -19702,7 +23707,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
t2 = (duk_size_t) (count - 1);
limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
- /* Combined size of separators already overflows */
+ /* Combined size of separators already overflows. */
goto error_overflow;
}
len = (duk_size_t) (t1 * t2);
@@ -19712,8 +23717,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
for (i = count; i >= 1; i--) {
duk_size_t new_len;
- duk_to_string(ctx, -((duk_idx_t) i));
- h = duk_require_hstring(ctx, -((duk_idx_t) i));
+ h = duk_to_hstring(thr, -((duk_idx_t) i));
new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
/* Impose a string maximum length, need to handle overflow
@@ -19729,74 +23733,119 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
(unsigned long) count, (unsigned long) len));
- /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
+ /* Use stack allocated buffer to ensure reachability in errors
+ * (e.g. intern error).
+ */
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
- /* [... (sep) str1 str2 ... strN buf] */
+ /* [ ... (sep) str1 str2 ... strN buf ] */
idx = 0;
for (i = count; i >= 1; i--) {
if (is_join && i != count) {
- h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
- h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
DUK_ASSERT(idx == len);
- /* [... (sep) str1 str2 ... strN buf] */
+ /* [ ... (sep) str1 str2 ... strN buf ] */
- /* get rid of the strings early to minimize memory use before intern */
+ /* Get rid of the strings early to minimize memory use before intern. */
if (is_join) {
- duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
- duk_pop_n(ctx, count);
+ duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */
+ duk_pop_n(thr, (duk_idx_t) count);
} else {
- duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
- duk_pop_n(ctx, count-1);
+ duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */
+ duk_pop_n(thr, (duk_idx_t) (count - 1));
}
- /* [... buf] */
+ /* [ ... buf ] */
- (void) duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
- /* [... res] */
+ /* [ ... res ] */
return;
error_overflow:
- DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG);
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+}
+
+DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
+}
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_concat(thr, 2);
}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ duk_hstring *h1;
+ duk_hstring *h2;
+ duk_uint8_t *buf;
+ duk_size_t len1;
+ duk_size_t len2;
+ duk_size_t len;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */
+
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring(thr, -1);
+ len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
+ len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
+ len = len1 + len2;
+ if (DUK_UNLIKELY(len < len1 || /* wrapped */
+ len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
+ goto error_overflow;
+ }
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
+ DUK_ASSERT(buf != NULL);
+
+ DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
+ DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
+
+ /* [ ... str1 str2 buf ] */
-DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+ duk_replace(thr, -3);
+ duk_pop_unsafe(thr);
+ return;
- duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
+ error_overflow:
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
}
+#endif /* DUK_USE_PREFER_SIZE */
-DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
+ duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
}
/* XXX: could map/decode be unified with duk_unicode_support.c code?
* Case conversion needs also the character surroundings though.
*/
-DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
duk_hstring *h_input;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h_input = duk_require_hstring(ctx, index);
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
@@ -19807,28 +23856,27 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod
if (p >= p_end) {
break;
}
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
callback(udata, cp);
}
}
-DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_normalize_index(ctx, index);
+ idx = duk_normalize_index(thr, idx);
- h_input = duk_require_hstring(ctx, index);
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
+ DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
@@ -19842,32 +23890,33 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char
if (p >= p_end) {
break;
}
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
cp = callback(udata, cp);
DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
}
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
duk_hstring *h;
duk_hstring *res;
duk_size_t start_byte_offset;
duk_size_t end_byte_offset;
+ duk_size_t charlen;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
- if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
- end_offset = DUK_HSTRING_GET_CHARLEN(h);
+ charlen = DUK_HSTRING_GET_CHARLEN(h);
+ if (end_offset >= charlen) {
+ end_offset = charlen;
}
if (start_offset > end_offset) {
start_offset = end_offset;
@@ -19878,7 +23927,7 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st
DUK_ASSERT_DISABLE(end_offset >= 0);
DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
- /* guaranteed by string limits */
+ /* Guaranteed by string limits. */
DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
@@ -19886,31 +23935,30 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st
end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
DUK_ASSERT(end_byte_offset >= start_byte_offset);
- DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */
+ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */
- /* no size check is necessary */
- res = duk_heap_string_intern_checked(thr,
- DUK_HSTRING_GET_DATA(h) + start_byte_offset,
- (duk_uint32_t) (end_byte_offset - start_byte_offset));
+ /* No size check is necessary. */
+ res = duk_heap_strtable_intern_checked(thr,
+ DUK_HSTRING_GET_DATA(h) + start_byte_offset,
+ (duk_uint32_t) (end_byte_offset - start_byte_offset));
- duk_push_hstring(ctx, res);
- duk_replace(ctx, index);
+ duk_push_hstring(thr, res);
+ duk_replace(thr, idx);
}
/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
* forwards with a callback to process codepoints?
*/
-DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
p_start = DUK_HSTRING_GET_DATA(h);
@@ -19927,7 +23975,7 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
}
q_start = p;
if (p == p_end) {
- /* entire string is whitespace */
+ /* Entire string is whitespace. */
q_end = p;
goto scan_done;
}
@@ -19972,124 +24020,152 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
return;
}
- duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
- duk_replace(ctx, index);
+ duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
duk_hstring *h;
duk_ucodepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hstring(ctx, index);
+ /* XXX: Share code with String.prototype.charCodeAt? Main difference
+ * is handling of clamped offsets.
+ */
+
+ h = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h != NULL);
- DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */
+ DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
return 0;
}
- DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */
- cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset);
+ DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */
+ cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
return (duk_codepoint_t) cp;
}
-#line 1 "duk_api_var.c"
/*
- * Variable access
+ * Date/time.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_get_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
+ /* Ecmascript time, with millisecond fractions. Exposed via
+ * duk_get_now() for example.
+ */
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
+}
- h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
+ /* Ecmascript time without millisecond fractions. Exposed via
+ * the Date built-in which doesn't allow fractions.
+ */
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
+}
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> look up from global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
- }
+DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
+ DUK_UNREF(thr);
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+ return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
+#else
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
+#endif
+}
- /* [ ... varname val this ] (because throw_flag == 1, always resolved) */
+DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
- duk_pop(ctx);
- duk_remove(ctx, -2);
+ /* This API intentionally allows millisecond fractions. */
+ return duk_time_get_ecmascript_time(thr);
+}
- /* [ ... val ] */
+#if 0 /* XXX: worth exposing? */
+DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
- /* Return value would be pointless: because throw_flag==1, we always
- * throw if the identifier doesn't resolve.
- */
- return;
+ return duk_time_get_monotonic_time(thr);
}
+#endif
-DUK_EXTERNAL void duk_put_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_tval *tv_val;
- duk_small_int_t throw_flag;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
+ duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+ duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+ duk_uint_t flags;
- h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(comp != NULL); /* XXX: or check? */
+ DUK_UNREF(thr);
- tv_val = duk_require_tval(ctx, -1);
+ /* Convert as one-based, but change month to zero-based to match the
+ * Ecmascript Date built-in behavior 1:1.
+ */
+ flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
- throw_flag = duk_is_strict_call(ctx);
+ duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> put to global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
- }
+ /* XXX: sub-millisecond accuracy for the API */
- /* [ ... varname val ] */
+ DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
+ comp->year = dparts[DUK_DATE_IDX_YEAR];
+ comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
+ comp->day = dparts[DUK_DATE_IDX_DAY];
+ comp->hours = dparts[DUK_DATE_IDX_HOUR];
+ comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
+ comp->seconds = dparts[DUK_DATE_IDX_SECOND];
+ comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
+ comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
+}
- duk_pop_2(ctx);
+DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
+ duk_double_t d;
+ duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+ duk_uint_t flags;
- /* [ ... ] */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(comp != NULL); /* XXX: or check? */
+ DUK_UNREF(thr);
- return;
-}
+ /* Match Date constructor behavior (with UTC time). Month is given
+ * as zero-based. Day-of-month is given as one-based so normalize
+ * it to zero-based as the internal conversion helpers expects all
+ * components to be zero-based.
+ */
+ flags = 0;
-DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+ /* XXX: expensive conversion; use array format in API instead, or unify
+ * time provider and time API to use same struct?
+ */
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
-}
+ dparts[DUK_DATE_IDX_YEAR] = comp->year;
+ dparts[DUK_DATE_IDX_MONTH] = comp->month;
+ dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
+ dparts[DUK_DATE_IDX_HOUR] = comp->hours;
+ dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
+ dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
+ dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
+ dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
-DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+ d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
+ return d;
}
-#line 1 "duk_bi_array.c"
/*
* Array built-ins
*
- * Note that most Array built-ins are intentionally generic and work even
- * when the 'this' binding is not an Array instance. To ensure this,
- * Array algorithms do not assume "magical" Array behavior for the "length"
- * property, for instance.
+ * Most Array built-ins are intentionally generic in Ecmascript, and are
+ * intended to work even when the 'this' binding is not an Array instance.
+ * This Ecmascript feature is also used by much real world code. For this
+ * reason the implementations here don't assume exotic Array behavior or
+ * e.g. presence of a .length property. However, some algorithms have a
+ * fast path for duk_harray backed actual Array instances, enabled when
+ * footprint is not a concern.
*
* XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
* [[Delete]] operations, but it's currently false throughout. Go through
@@ -20102,7 +24178,6 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
* the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
* some intermediate values may be above 0xffffffff and this may not be always
* correctly handled now (duk_uint32_t is not enough for all algorithms).
- *
* For instance, push() can legitimately write entries beyond length 0xffffffff
* and cause a RangeError only at the end. To do this properly, the current
* push() implementation tracks the array index using a 'double' instead of a
@@ -20119,86 +24194,139 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
* Both "put" and "define" are used in the E5.1 specification; as a rule,
* "put" is used when modifying an existing array (or a non-array 'this'
* binding) and "define" for setting values into a fresh result array.
- *
- * Also note that Array instance 'length' should be writable, but not
- * enumerable and definitely not configurable: even Duktape code internally
- * assumes that an Array instance will always have a 'length' property.
- * Preventing deletion of the property is critical.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Perform an intermediate join when this many elements have been pushed
* on the value stack.
*/
#define DUK__ARRAY_MID_JOIN_LIMIT 4096
-/* Shared entry code for many Array built-ins. Note that length is left
- * on stack (it could be popped, but that's not necessary).
+#if defined(DUK_USE_ARRAY_BUILTIN)
+
+/*
+ * Shared helpers.
+ */
+
+/* Shared entry code for many Array built-ins: the 'this' binding is pushed
+ * on the value stack and object coerced, and the current .length is returned.
+ * Note that length is left on stack (it could be popped, but that's not
+ * usually necessary because call handling will clean it up automatically).
*/
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) {
duk_uint32_t len;
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
- len = duk_to_uint32(ctx, -1);
+ /* XXX: push more directly? */
+ (void) duk_push_this_coercible_to_object(thr);
+ DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(thr, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1);
/* -> [ ... ToObject(this) ToUint32(length) ] */
return len;
}
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
/* Range limited to [0, 0x7fffffff] range, i.e. range that can be
* represented with duk_int32_t. Use this when the method doesn't
* handle the full 32-bit unsigned range correctly.
*/
- duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
+ duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G);
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
}
return ret;
}
+#if defined(DUK_USE_ARRAY_FASTPATH)
+/* Check if 'this' binding is an Array instance (duk_harray) which satisfies
+ * a few other guarantees for fast path operation. The fast path doesn't
+ * need to handle all operations, even for duk_harrays, but must handle a
+ * significant fraction to improve performance. Return a non-NULL duk_harray
+ * pointer when all fast path criteria are met, NULL otherwise.
+ */
+DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hobject *h;
+ duk_uint_t flags_mask, flags_bits, flags_value;
+
+ DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */
+ tv = DUK_GET_THIS_TVAL_PTR(thr);
+
+ /* Fast path requires that 'this' is a duk_harray. Read only arrays
+ * (ROM backed) are also rejected for simplicity.
+ */
+ if (!DUK_TVAL_IS_OBJECT(tv)) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: not an object"));
+ return NULL;
+ }
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
+ DUK_HEAPHDR_FLAG_READONLY;
+ flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY;
+ flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h);
+ if ((flags_value & flags_mask) != flags_bits) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed"));
+ return NULL;
+ }
+
+ /* In some cases a duk_harray's 'length' may be larger than the
+ * current array part allocation. Avoid the fast path in these
+ * cases, so that all fast path code can safely assume that all
+ * items in the range [0,length[ are backed by the current array
+ * part allocation.
+ */
+ if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size"));
+ return NULL;
+ }
+
+ /* Guarantees for fast path. */
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL);
+ DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h));
+
+ DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h));
+ return (duk_harray *) h;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
/*
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) {
duk_idx_t nargs;
+ duk_harray *a;
duk_double_t d;
duk_uint32_t len;
- duk_idx_t i;
+ duk_uint32_t len_prealloc;
- nargs = duk_get_top(ctx);
- duk_push_array(ctx);
+ nargs = duk_get_top(thr);
- if (nargs == 1 && duk_is_number(ctx, 0)) {
+ if (nargs == 1 && duk_is_number(thr, 0)) {
/* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
- d = duk_get_number(ctx, 0);
- len = duk_to_uint32(ctx, 0);
+ d = duk_get_number(thr, 0);
+ len = duk_to_uint32(thr, 0);
if (((duk_double_t) len) != d) {
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
- /* XXX: if 'len' is low, may want to ensure array part is kept:
- * the caller is likely to want a dense array.
+ /* For small lengths create a dense preallocated array.
+ * For large arrays preallocate an initial part.
*/
- duk_push_u32(ctx, len);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
+ len_prealloc = len < 64 ? len : 64;
+ a = duk_push_harray_with_size(thr, len_prealloc);
+ DUK_ASSERT(a != NULL);
+ a->length = len;
return 1;
}
- /* XXX: optimize by creating array into correct size directly, and
- * operating on the array part directly; values can be memcpy()'d from
- * value stack directly as long as refcounts are increased.
- */
- for (i = 0; i < nargs; i++) {
- duk_dup(ctx, i);
- duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i);
- }
-
- duk_push_u32(ctx, (duk_uint32_t) nargs);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_pack(thr, nargs);
return 1;
}
@@ -20206,11 +24334,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
* isArray()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) {
duk_hobject *h;
- h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
- duk_push_boolean(ctx, (h != NULL));
+ h = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_ARRAY);
+ duk_push_boolean(thr, (h != NULL));
return 1;
}
@@ -20218,12 +24346,12 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
* toString()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN);
/* [ ... this func ] */
- if (!duk_is_callable(ctx, -1)) {
+ if (!duk_is_callable(thr, -1)) {
/* Fall back to the initial (original) Object.toString(). We don't
* currently have pointers to the built-in functions, only the top
* level global objects (like "Array") so this is now done in a bit
@@ -20235,20 +24363,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* but should have no visible side effects.
*/
DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
- duk_set_top(ctx, 0);
- return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
+ duk_set_top(thr, 0);
+ return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */
}
/* [ ... this func ] */
- duk_insert(ctx, -2);
+ duk_insert(thr, -2);
/* [ ... func this ] */
DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call_method(ctx, 0);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call_method(thr, 0);
return 1;
}
@@ -20257,7 +24385,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* concat()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
duk_idx_t i, n;
duk_uarridx_t idx, idx_last;
duk_uarridx_t j, len;
@@ -20268,10 +24396,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* (as the element is dup()'d anyway).
*/
- (void) duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- n = duk_get_top(ctx);
- duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_insert(thr, 0);
+ n = duk_get_top(thr);
+ duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */
/* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
* (which differs from the official algorithm). If no error is thrown, this
@@ -20283,14 +24411,14 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
idx = 0;
idx_last = 0;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
/* [ ToObject(this) item1 ... itemN arr ] */
- duk_dup(ctx, i);
- h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
+ duk_dup(thr, i);
+ h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY);
if (!h) {
- duk_xdef_prop_index_wec(ctx, -2, idx++);
+ duk_xdef_prop_index_wec(thr, -2, idx++);
idx_last = idx;
continue;
}
@@ -20300,15 +24428,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
/* XXX: an array can have length higher than 32 bits; this is not handled
* correctly now.
*/
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ len = (duk_uarridx_t) duk_get_length(thr, -1);
for (j = 0; j < len; j++) {
- if (duk_get_prop_index(ctx, -1, j)) {
+ if (duk_get_prop_index(thr, -1, j)) {
/* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
- duk_xdef_prop_index_wec(ctx, -3, idx++);
+ duk_xdef_prop_index_wec(thr, -3, idx++);
idx_last = idx;
} else {
idx++;
- duk_pop(ctx);
+ duk_pop_undefined(thr);
#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
/* According to E5.1 Section 15.4.4.4 nonexistent trailing
* elements do not affect 'length' of the result. Test262
@@ -20322,17 +24450,17 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
#endif
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
* in the end, but because we're operating with an internal value which
* is known to be an array, this should be equivalent.
*/
- duk_push_uarridx(ctx, idx_last);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_uarridx(thr, idx_last);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
return 1;
}
@@ -20349,53 +24477,54 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* There is no fancy handling; the prefix gets re-joined multiple times.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) {
duk_uint32_t len, count;
duk_uint32_t idx;
- duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
+ duk_small_int_t to_locale_string = duk_get_current_magic(thr);
duk_idx_t valstack_required;
/* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
* setting the top essentially pushes an undefined to the stack,
* thus defaulting to a comma separator.
*/
- duk_set_top(ctx, 1);
- if (duk_is_undefined(ctx, 0)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
+ duk_set_top(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
+ duk_pop_undefined(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA);
} else {
- duk_to_string(ctx, 0);
+ duk_to_string(thr, 0);
}
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
/* [ sep ToObject(this) len ] */
DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
(unsigned long) len));
/* The extra (+4) is tight. */
- valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
- DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
- duk_require_stack(ctx, valstack_required);
+ valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ?
+ DUK__ARRAY_MID_JOIN_LIMIT : len) + 4);
+ duk_require_stack(thr, valstack_required);
- duk_dup(ctx, 0);
+ duk_dup_0(thr);
/* [ sep ToObject(this) len sep ] */
count = 0;
idx = 0;
for (;;) {
+ DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx));
if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
idx >= len) { /* end of loop (careful with len==0) */
/* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
(long) count, (long) idx, (long) len));
- duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
- duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */
- duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
+ duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
+ duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */
+ duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */
count = 1;
}
if (idx >= len) {
@@ -20403,20 +24532,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
break;
}
- duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
- if (duk_is_null_or_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_get_prop_index(thr, 1, (duk_uarridx_t) idx);
+ if (duk_is_null_or_undefined(thr, -1)) {
+ duk_pop_nodecref_unsafe(thr);
+ duk_push_hstring_empty(thr);
} else {
if (to_locale_string) {
- duk_to_object(ctx, -1);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
- duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
- duk_call_method(ctx, 0);
- duk_to_string(ctx, -1);
- } else {
- duk_to_string(ctx, -1);
+ duk_to_object(thr, -1);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING);
+ duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */
+ duk_call_method(thr, 0);
}
+ duk_to_string(thr, -1);
}
count++;
@@ -20432,27 +24559,129 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
* pop(), push()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
+#if defined(DUK_USE_ARRAY_FASTPATH)
+DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) {
+ duk_tval *tv_arraypart;
+ duk_tval *tv_val;
+ duk_uint32_t len;
+
+ tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
+ len = h_arr->length;
+ if (len <= 0) {
+ /* nop, return undefined */
+ return 0;
+ }
+
+ len--;
+ h_arr->length = len;
+
+ /* Fast path doesn't check for an index property inherited from
+ * Array.prototype. This is quite often acceptable; if not,
+ * disable fast path.
+ */
+ DUK_ASSERT_VS_SPACE(thr);
+ tv_val = tv_arraypart + len;
+ if (DUK_TVAL_IS_UNUSED(tv_val)) {
+ /* No net refcount change. Value stack already has
+ * 'undefined' based on value stack init policy.
+ */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
+ DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val));
+ } else {
+ /* No net refcount change. */
+ DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val);
+ DUK_TVAL_SET_UNUSED(tv_val);
+ }
+ thr->valstack_top++;
+
+ /* XXX: there's no shrink check in the fast path now */
+
+ return 1;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t idx;
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ duk_harray *h_arr;
+#endif
+
+ DUK_ASSERT_TOP(thr, 0);
+
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ h_arr = duk__arraypart_fastpath_this(thr);
+ if (h_arr) {
+ return duk__array_pop_fastpath(thr, h_arr);
+ }
+#endif
- DUK_ASSERT_TOP(ctx, 0);
- len = duk__push_this_obj_len_u32(ctx);
+ /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
+
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
idx = len - 1;
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_push_u32(ctx, idx);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_push_u32(thr, idx);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
+#if defined(DUK_USE_ARRAY_FASTPATH)
+DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) {
+ duk_tval *tv_arraypart;
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_uint32_t len;
+ duk_idx_t i, n;
+
+ len = h_arr->length;
+ tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
+
+ n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ DUK_ASSERT(n >= 0);
+ DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX);
+ if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) {
+ DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */
+ }
+ if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
+ /* Array part would need to be extended. Rely on slow path
+ * for now.
+ *
+ * XXX: Rework hobject code a bit and add extend support.
+ */
+ return 0;
+ }
+
+ tv_src = thr->valstack_bottom;
+ tv_dst = tv_arraypart + len;
+ for (i = 0; i < n; i++) {
+ /* No net refcount change; reset value stack values to
+ * undefined to satisfy value stack init policy.
+ */
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+ DUK_TVAL_SET_UNDEFINED(tv_src);
+ tv_src++;
+ tv_dst++;
+ }
+ thr->valstack_top = thr->valstack_bottom;
+ len += (duk_uint32_t) n;
+ h_arr->length = len;
+
+ DUK_ASSERT((duk_uint_t) len == len);
+ duk_push_uint(thr, (duk_uint_t) len);
+ return 1;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) {
/* Note: 'this' is not necessarily an Array object. The push()
* algorithm is supposed to work for other kinds of objects too,
* so the algorithm has e.g. an explicit update for the 'length'
@@ -20461,9 +24690,24 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
duk_uint32_t len;
duk_idx_t i, n;
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ duk_harray *h_arr;
+#endif
- n = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ h_arr = duk__arraypart_fastpath_this(thr);
+ if (h_arr) {
+ duk_ret_t rc;
+ rc = duk__array_push_fastpath(thr, h_arr);
+ if (rc != 0) {
+ return rc;
+ }
+ DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case"));
+ }
+#endif
+
+ n = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* [ arg1 ... argN obj length ] */
@@ -20479,18 +24723,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
if (len + (duk_uint32_t) n < len) {
DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
for (i = 0; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, -3, len + i);
+ duk_dup(thr, i);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i));
}
- len += n;
+ len += (duk_uint32_t) n;
- duk_push_u32(ctx, len);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, len);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* [ arg1 ... argN obj length new_length ] */
return 1;
@@ -20506,7 +24750,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
* may use a negative offset.
*/
-DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
+DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) {
duk_bool_t have1, have2;
duk_bool_t undef1, undef2;
duk_small_int_t ret;
@@ -20535,12 +24779,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
return 0;
}
- have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
- have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
+ have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1);
+ have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2);
DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
(long) idx1, (long) idx2, (long) have1, (long) have2,
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
if (have1) {
if (have2) {
@@ -20559,8 +24803,8 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- undef1 = duk_is_undefined(ctx, -2);
- undef2 = duk_is_undefined(ctx, -1);
+ undef1 = duk_is_undefined(thr, -2);
+ undef2 = duk_is_undefined(thr, -1);
if (undef1) {
if (undef2) {
ret = 0;
@@ -20578,40 +24822,41 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- if (!duk_is_undefined(ctx, idx_fn)) {
+ if (!duk_is_undefined(thr, idx_fn)) {
duk_double_t d;
- /* no need to check callable; duk_call() will do that */
- duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
- duk_insert(ctx, -3); /* -> [ ... fn x y ] */
- duk_call(ctx, 2); /* -> [ ... res ] */
+ /* No need to check callable; duk_call() will do that. */
+ duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */
+ duk_insert(thr, -3); /* -> [ ... fn x y ] */
+ duk_call(thr, 2); /* -> [ ... res ] */
- /* The specification is a bit vague what to do if the return
- * value is not a number. Other implementations seem to
- * tolerate non-numbers but e.g. V8 won't apparently do a
- * ToNumber().
+ /* ES5 is a bit vague about what to do if the return value is
+ * not a number. ES2015 provides a concrete description:
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
*/
- /* XXX: best behavior for real world compatibility? */
-
- d = duk_to_number(ctx, -1);
+ d = duk_to_number_m1(thr);
if (d < 0.0) {
ret = -1;
} else if (d > 0.0) {
ret = 1;
} else {
+ /* Because NaN compares to false, NaN is handled here
+ * without an explicit check above.
+ */
ret = 0;
}
- duk_pop(ctx);
+ duk_pop_nodecref_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
return ret;
}
/* string compare is the default (a bit oddly) */
- h1 = duk_to_hstring(ctx, -2);
- h2 = duk_to_hstring(ctx, -1);
+ /* XXX: any special handling for plain array; causes repeated coercion now? */
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring_m1(thr);
DUK_ASSERT(h1 != NULL);
DUK_ASSERT(h2 != NULL);
@@ -20619,12 +24864,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
goto pop_ret;
pop_ret:
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
return ret;
}
-DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
+DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) {
duk_bool_t have_l, have_r;
duk_idx_t idx_obj = 1; /* fixed offset in valstack */
@@ -20633,32 +24878,32 @@ DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r)
}
/* swap elements; deal with non-existent elements correctly */
- have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r);
if (have_r) {
/* right exists, [[Put]] regardless whether or not left exists */
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ duk_pop_undefined(thr);
}
if (have_l) {
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r);
+ duk_pop_undefined(thr);
}
}
-#if defined(DUK_USE_DDDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
/* Debug print which visualizes the qsort partitioning process. */
-DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
+DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
char buf[4096];
char *ptr = buf;
duk_int_t i, n;
- n = (duk_int_t) duk_get_length(ctx, 1);
+ n = (duk_int_t) duk_get_length(thr, 1);
if (n > 4000) {
n = 4000;
}
@@ -20684,16 +24929,15 @@ DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int
}
#endif
-DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) {
duk_int_t p, l, r;
/* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
- (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
+ (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1)));
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* In some cases it may be that lo > hi, or hi < 0; these
* degenerate cases happen e.g. for empty arrays, and in
@@ -20709,15 +24953,14 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_ASSERT(hi - lo + 1 >= 2);
/* randomized pivot selection */
- p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */
+ p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1));
DUK_ASSERT(p >= lo && p <= hi);
- DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld",
- (long) lo, (long) hi, (long) p));
+ DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
/* move pivot out of the way */
- duk__array_sort_swap(ctx, p, lo);
+ duk__array_sort_swap(thr, p, lo);
p = lo;
- DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l = lo + 1;
r = hi;
@@ -20729,7 +24972,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (l >= hi) {
break;
}
- if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
+ if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */
break;
}
l++;
@@ -20740,7 +24983,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (r <= lo) {
break;
}
- if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
+ if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */
break;
}
r--;
@@ -20752,9 +24995,9 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
- duk__array_sort_swap(ctx, l, r);
+ duk__array_sort_swap(thr, l, r);
- DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l++;
r--;
}
@@ -20770,25 +25013,25 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
*/
/* move pivot to its final place */
- DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_sort_swap(ctx, lo, r);
+ DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_sort_swap(thr, lo, r);
-#if defined(DUK_USE_DDDPRINT)
- duk__debuglog_qsort_state(ctx, lo, hi, r);
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
+ duk__debuglog_qsort_state(thr, lo, hi, r);
#endif
- DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_qsort(ctx, lo, r - 1);
- duk__array_qsort(ctx, r + 1, hi);
+ DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_qsort(thr, lo, r - 1);
+ duk__array_qsort(thr, r + 1, hi);
}
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) {
duk_uint32_t len;
/* XXX: len >= 0x80000000 won't work below because a signed type
* is needed by qsort.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len = duk__push_this_obj_len_u32_limited(thr);
/* stack[0] = compareFn
* stack[1] = ToObject(this)
@@ -20797,11 +25040,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
if (len > 0) {
/* avoid degenerate cases, so that (len - 1) won't underflow */
- duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
+ duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1));
}
- DUK_ASSERT_TOP(ctx, 3);
- duk_pop(ctx);
+ DUK_ASSERT_TOP(thr, 3);
+ duk_pop_nodecref_unsafe(thr);
return 1; /* return ToObject(this) */
}
@@ -20818,9 +25061,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
* unshift is (close to?) <--> splice(0, 0, [items])?
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) {
duk_idx_t nargs;
- duk_uint32_t len;
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_bool_t have_delcount;
duk_int_t item_count;
duk_int_t act_start;
@@ -20829,9 +25073,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_UNREF(have_delcount);
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
if (nargs < 2) {
- duk_set_top(ctx, 2);
+ duk_set_top(thr, 2);
nargs = 2;
have_delcount = 0;
} else {
@@ -20841,19 +25085,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
- act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ act_start = duk_to_int_clamped(thr, 0, -len, len);
if (act_start < 0) {
act_start = len + act_start;
}
- DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
+ DUK_ASSERT(act_start >= 0 && act_start <= len);
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
+#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
if (have_delcount) {
#endif
- del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
+ del_count = duk_to_int_clamped(thr, 1, 0, len - act_start);
+#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
} else {
/* E5.1 standard behavior when deleteCount is not given would be
* to treat it just like if 'undefined' was given, which coerces
@@ -20867,16 +25113,16 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_ASSERT(nargs >= 2);
item_count = (duk_int_t) (nargs - 2);
- DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
- DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
+ DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
+ DUK_ASSERT(del_count + act_start <= len);
/* For now, restrict result array into 32-bit length range. */
if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
- duk_push_array(ctx);
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = deleteCount
@@ -20886,19 +25132,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* stack[nargs+2] = result array -1
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 9: copy elements-to-be-deleted into the result array */
for (i = 0; i < del_count; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
- duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) {
+ duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
}
- duk_push_u32(ctx, (duk_uint32_t) del_count);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, (duk_uint32_t) del_count);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
/* Steps 12 and 13: reorganize elements to make room for itemCount elements */
@@ -20909,27 +25155,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C F G H ] (actual result at this point, C will be replaced)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
n = len - del_count;
for (i = act_start; i < n; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
n = len - del_count + item_count;
for (i = len - 1; i >= n; i--) {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) i);
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else if (item_count > del_count) {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
* -> [ A B F G H ] (conceptual intermediate step)
@@ -20937,19 +25183,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F F G H ] (actual result at this point)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
for (i = len - del_count - 1; i >= act_start; i--) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
* -> [ A B F G H ] (conceptual intermediate step)
@@ -20957,24 +25203,24 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F G H ] (actual result at this point)
*/
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 15: insert itemCount elements into the hole made above */
for (i = 0; i < item_count; i++) {
- duk_dup(ctx, i + 2); /* args start at index 2 */
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
+ duk_dup(thr, i + 2); /* args start at index 2 */
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i));
}
/* Step 16: update length; note that the final length may be above 32 bit range
* (but we checked above that this isn't the case here)
*/
- duk_push_u32(ctx, len - del_count + item_count);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count));
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* result array is already at the top of stack */
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
return 1;
}
@@ -20982,13 +25228,13 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* reverse()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t middle;
duk_uint32_t lower, upper;
duk_bool_t have_lower, have_upper;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
middle = len / 2;
/* If len <= 1, middle will be 0 and for-loop bails out
@@ -20997,35 +25243,35 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
for (lower = 0; lower < middle; lower++) {
DUK_ASSERT(len >= 2);
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
DUK_ASSERT(len >= lower + 1);
upper = len - lower - 1;
- have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
- have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower);
+ have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper);
/* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
if (have_upper) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) lower);
} else {
- duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -4, (duk_uarridx_t) lower);
+ duk_pop_undefined(thr);
}
if (have_lower) {
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) upper);
} else {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) upper);
+ duk_pop_undefined(thr);
}
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
}
- DUK_ASSERT_TOP(ctx, 2);
- duk_pop(ctx); /* -> [ ToObject(this) ] */
+ DUK_ASSERT_TOP(thr, 2);
+ duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */
return 1;
}
@@ -21033,8 +25279,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
* slice()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
- duk_uint32_t len;
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) {
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_int_t start, end;
duk_int_t i;
duk_uarridx_t idx;
@@ -21043,8 +25290,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
- duk_push_array(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
+
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = end
@@ -21053,41 +25303,41 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* stack[4] = result array
*/
- start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ start = duk_to_int_clamped(thr, 0, -len, len);
if (start < 0) {
start = len + start;
}
/* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
* (the upper limit)?
*/
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end = len;
} else {
- end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
+ end = duk_to_int_clamped(thr, 1, -len, len);
if (end < 0) {
end = len + end;
}
}
- DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
- DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
+ DUK_ASSERT(start >= 0 && start <= len);
+ DUK_ASSERT(end >= 0 && end <= len);
idx = 0;
for (i = start; i < end; i++) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- duk_xdef_prop_index_wec(ctx, 4, idx);
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ duk_xdef_prop_index_wec(thr, 4, idx);
res_length = idx + 1;
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
idx++;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
}
@@ -21095,18 +25345,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* shift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
- duk_get_prop_index(ctx, 0, 0);
+ duk_get_prop_index(thr, 0, 0);
/* stack[0] = object (this)
* stack[1] = ToUint32(length)
@@ -21114,22 +25364,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
*/
for (i = 1; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 3);
- if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 3);
+ if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) {
/* fromPresent = true */
- duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
+ duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
} else {
/* fromPresent = false */
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
- duk_pop(ctx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
+ duk_pop_undefined(thr);
}
}
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1));
- duk_push_u32(ctx, (duk_uint32_t) (len - 1));
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
return 1;
}
@@ -21137,20 +25387,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
* unshift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) {
duk_idx_t nargs;
duk_uint32_t len;
duk_uint32_t i;
- nargs = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+ nargs = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* stack[0...nargs-1] = unshift args (vararg)
* stack[nargs] = ToObject(this)
* stack[nargs+1] = ToUint32(length)
*/
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
/* Note: unshift() may operate on indices above unsigned 32-bit range
* and the final length may be >= 2**32. However, we restrict the
@@ -21159,39 +25409,39 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
if (len + (duk_uint32_t) nargs < len) {
DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
i = len;
while (i > 0) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
i--;
/* k+argCount-1; note that may be above 32-bit range */
- if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
+ if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) {
/* fromPresent = true */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
} else {
/* fromPresent = false */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_pop(ctx);
- duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
for (i = 0; i < (duk_uint32_t) nargs; i++) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_push_u32(ctx, len + nargs);
- duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_push_u32(thr, len + (duk_uint32_t) nargs);
+ duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
return 1;
}
@@ -21199,22 +25449,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
* indexOf(), lastIndexOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_int_t i, len;
- duk_int_t from_index;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
+ duk_int_t from_idx;
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
/* lastIndexOf() needs to be a vararg function because we must distinguish
* between an undefined fromIndex and a "not given" fromIndex; indexOf() is
* made vararg for symmetry although it doesn't strictly need to be.
*/
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 2);
+ nargs = duk_get_top(thr);
+ duk_set_top(thr, 2);
/* XXX: must be able to represent -len */
- len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
+ len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr);
if (len == 0) {
goto not_found;
}
@@ -21241,22 +25491,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
* (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
*/
- from_index = duk_to_int_clamped(ctx,
- 1,
- (idx_step > 0 ? -len : -len - 1),
- (idx_step > 0 ? len : len - 1));
- if (from_index < 0) {
+ from_idx = duk_to_int_clamped(thr,
+ 1,
+ (idx_step > 0 ? -len : -len - 1),
+ (idx_step > 0 ? len : len - 1));
+ if (from_idx < 0) {
/* for lastIndexOf, result may be -1 (mark immediate termination) */
- from_index = len + from_index;
+ from_idx = len + from_idx;
}
} else {
/* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
* handle both indexOf and lastIndexOf specially here.
*/
if (idx_step > 0) {
- from_index = 0;
+ from_idx = 0;
} else {
- from_index = len - 1;
+ from_idx = len - 1;
}
}
@@ -21266,22 +25516,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* stack[3] = length (not needed, but not popped above)
*/
- for (i = from_index; i >= 0 && i < len; i += idx_step) {
- DUK_ASSERT_TOP(ctx, 4);
+ for (i = from_idx; i >= 0 && i < len; i += idx_step) {
+ DUK_ASSERT_TOP(thr, 4);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_strict_equals(ctx, 0, 4)) {
- duk_push_int(ctx, i);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_strict_equals(thr, 0, 4)) {
+ duk_push_int(thr, i);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
not_found:
- duk_push_int(ctx, -1);
+ duk_push_int(thr, -1);
return 1;
}
@@ -21300,25 +25550,25 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* 5 callers the net result is about 100 bytes / caller.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
duk_uarridx_t k;
duk_bool_t bval;
- duk_small_int_t iter_type = duk_get_current_magic(ctx);
+ duk_small_int_t iter_type = duk_get_current_magic(thr);
duk_uint32_t res_length = 0;
/* each call this helper serves has nargs==2 */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- len = duk__push_this_obj_len_u32(ctx);
- duk_require_callable(ctx, 0);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* if thisArg not supplied, behave as if undefined was supplied */
if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
- duk_push_array(ctx);
+ duk_push_array(thr);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* stack[0] = callback
@@ -21330,9 +25580,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
k = 0; /* result index for filter() */
for (i = 0; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
- if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
/* Real world behavior for map(): trailing non-existent
* elements don't invoke the user callback, but are still
@@ -21347,7 +25597,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* counted towards result 'length'.
*/
#endif
- duk_pop(ctx);
+ duk_pop_undefined(thr);
continue;
}
@@ -21356,23 +25606,23 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* effects.
*/
- duk_dup(ctx, 0);
- duk_dup(ctx, 1);
- duk_dup(ctx, -3);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */
- duk_call_method(ctx, 3); /* -> [ ... val retval ] */
+ duk_dup_0(thr);
+ duk_dup_1(thr);
+ duk_dup_m3(thr);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */
+ duk_call_method(thr, 3); /* -> [ ... val retval ] */
switch (iter_type) {
case DUK__ITER_EVERY:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (!bval) {
/* stack top contains 'false' */
return 1;
}
break;
case DUK__ITER_SOME:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
/* stack top contains 'true' */
return 1;
@@ -21382,15 +25632,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
/* nop */
break;
case DUK__ITER_MAP:
- duk_dup(ctx, -1);
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
+ duk_dup_top(thr);
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */
res_length = i + 1;
break;
case DUK__ITER_FILTER:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
- duk_dup(ctx, -2); /* orig value */
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
+ duk_dup_m2(thr); /* orig value */
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k);
k++;
res_length = k;
}
@@ -21399,27 +25649,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
DUK_UNREACHABLE();
break;
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
switch (iter_type) {
case DUK__ITER_EVERY:
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
case DUK__ITER_SOME:
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
case DUK__ITER_FOREACH:
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
case DUK__ITER_MAP:
case DUK__ITER_FILTER:
- DUK_ASSERT_TOP(ctx, 5);
- DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ DUK_ASSERT_TOP(thr, 5);
+ DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
break;
default:
DUK_UNREACHABLE();
@@ -21433,23 +25683,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* reduce(), reduceRight()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_bool_t have_acc;
duk_uint32_t i, len;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */
/* We're a varargs function because we need to detect whether
* initialValue was given or not.
*/
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
- duk_set_top(ctx, 2);
- len = duk__push_this_obj_len_u32(ctx);
- if (!duk_is_callable(ctx, 0)) {
- goto type_error;
- }
+ duk_set_top(thr, 2);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* stack[0] = callback fn
* stack[1] = initialValue
@@ -21460,11 +25708,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
have_acc = 0;
if (nargs >= 2) {
- duk_dup(ctx, 1);
+ duk_dup_1(thr);
have_acc = 1;
}
DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
- (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
+ (long) have_acc, (duk_tval *) duk_get_tval(thr, 3)));
/* For len == 0, i is initialized to len - 1 which underflows.
* The condition (i < len) will then exit the for-loop on the
@@ -21474,82 +25722,82 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
for (i = (idx_step >= 0 ? 0 : len - 1);
i < len; /* i >= 0 would always be true */
- i += idx_step) {
+ i += (duk_uint32_t) idx_step) {
DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
(long) i, (long) len, (long) have_acc,
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, 4)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, 4)));
- DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
- (!have_acc && duk_get_top(ctx) == 4));
+ DUK_ASSERT((have_acc && duk_get_top(thr) == 5) ||
+ (!have_acc && duk_get_top(thr) == 4));
- if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) {
continue;
}
if (!have_acc) {
- DUK_ASSERT_TOP(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
have_acc = 1;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
} else {
- DUK_ASSERT_TOP(ctx, 5);
- duk_dup(ctx, 0);
- duk_dup(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2);
+ DUK_ASSERT_TOP(thr, 5);
+ duk_dup_0(thr);
+ duk_dup(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr);
DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
- (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call(ctx, 4);
- DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, 4);
- DUK_ASSERT_TOP(ctx, 5);
+ (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4),
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call(thr, 4);
+ DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+ duk_replace(thr, 4);
+ DUK_ASSERT_TOP(thr, 5);
}
}
if (!have_acc) {
- goto type_error;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
}
-#undef DUK__ARRAY_MID_JOIN_LIMIT
+#endif /* DUK_USE_ARRAY_BUILTIN */
+/* automatic undefs */
+#undef DUK__ARRAY_MID_JOIN_LIMIT
#undef DUK__ITER_EVERY
-#undef DUK__ITER_SOME
+#undef DUK__ITER_FILTER
#undef DUK__ITER_FOREACH
#undef DUK__ITER_MAP
-#undef DUK__ITER_FILTER
-#line 1 "duk_bi_boolean.c"
+#undef DUK__ITER_SOME
/*
* Boolean built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_BOOLEAN_BUILTIN)
/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
* the primitive value to stack top, and optionally coerces with ToString().
*/
-DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h;
- duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
+ duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
/* XXX: there is room to use a shared helper here, many built-ins
* check the 'this' type, and if it's an object, check its class,
* then get its internal value, etc.
*/
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_get_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BOOLEAN(tv)) {
@@ -21559,58 +25807,73 @@ DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_boolean(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_boolean(thr, -1));
goto type_ok;
}
}
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ /* never here */
type_ok:
if (coerce_tostring) {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
duk_hobject *h_this;
- DUK_UNREF(thr);
+ duk_to_boolean(thr, 0);
- duk_to_boolean(ctx, 0);
-
- if (duk_is_constructor_call(ctx)) {
+ if (duk_is_constructor_call(thr)) {
/* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
- duk_push_this(ctx);
- h_this = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_this != NULL);
+ duk_push_this(thr);
+ h_this = duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
- duk_dup(ctx, 0); /* -> [ val obj val ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
+ duk_dup_0(thr); /* -> [ val obj val ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
} /* unbalanced stack */
return 1;
}
-#line 1 "duk_bi_buffer.c"
+
+#endif /* DUK_USE_BOOLEAN_BUILTIN */
/*
- * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins
+ * ES2015 TypedArray and Node.js Buffer built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
- * Misc helpers
+ * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number.
- * Sync with duk_hbufferobject.h and duk_hobject.h.
+/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the
+ * default internal prototype.
+ */
+static const duk_uint8_t duk__buffer_proto_from_classnum[] = {
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE,
+ DUK_BIDX_DATAVIEW_PROTOTYPE,
+ DUK_BIDX_INT8ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT8ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
+ DUK_BIDX_INT16ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT16ARRAY_PROTOTYPE,
+ DUK_BIDX_INT32ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT32ARRAY_PROTOTYPE,
+ DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
+ DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
+};
+
+/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number.
+ * Sync with duk_hbufobj.h and duk_hobject.h.
*/
static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
DUK_HOBJECT_CLASS_UINT8ARRAY,
@@ -21623,11 +25886,9 @@ static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
DUK_HOBJECT_CLASS_FLOAT32ARRAY,
DUK_HOBJECT_CLASS_FLOAT64ARRAY
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index.
- * Sync with duk_hbufferobject.h.
+/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index.
+ * Sync with duk_hbufobj.h.
*/
static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
DUK_BIDX_UINT8ARRAY_PROTOTYPE,
@@ -21640,11 +25901,8 @@ static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK__FLX_xxx to byte size.
- */
+/* Map DUK__FLD_xxx to byte size. */
static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
1, /* DUK__FLD_8BIT */
2, /* DUK__FLD_16BIT */
@@ -21653,191 +25911,192 @@ static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
8, /* DUK__FLD_DOUBLE */
0 /* DUK__FLD_VARINT; not relevant here */
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types
+/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types
* are compatible with a blind byte copy for the TypedArray set() method (also
* used for TypedArray constructor). Array index is target buffer elem type,
* bitfield indicates compatible source types. The types must have same byte
* size and they must be coercion compatible.
*/
+#if !defined(DUK_USE_PREFER_SIZE)
static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
+ (1U << DUK_HBUFOBJ_ELEM_INT8),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED
* Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
*/
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED),
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
+ (1U << DUK_HBUFOBJ_ELEM_INT8),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT16) |
+ (1U << DUK_HBUFOBJ_ELEM_INT16),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT16) |
+ (1U << DUK_HBUFOBJ_ELEM_INT16),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT32) |
+ (1U << DUK_HBUFOBJ_ELEM_INT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT32) |
+ (1U << DUK_HBUFOBJ_ELEM_INT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */
+ (1U << DUK_HBUFOBJ_ELEM_FLOAT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64)
+ /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */
+ (1U << DUK_HBUFOBJ_ELEM_FLOAT64)
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+#endif /* !DUK_USE_PREFER_SIZE */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared helper. */
-DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) {
- duk_hthread *thr;
+DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) {
+ duk_tval *tv_dst;
+ duk_hbufobj *res;
+
+ duk_push_this(thr);
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ res = (duk_hbufobj *) duk_to_hobject(thr, -1);
+ DUK_ASSERT_HBUFOBJ_VALID(res);
+ DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1)));
+
+ tv_dst = duk_get_borrowed_this_tval(thr);
+ DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
+ duk_pop(thr);
+
+ return res;
+}
+
+#define DUK__BUFOBJ_FLAG_THROW (1 << 0)
+#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1)
+
+/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is
+ * always a duk_hbufobj *. Without the flag the return value can also be a
+ * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
+ */
+DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) {
duk_tval *tv;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
- tv = duk_get_borrowed_this_tval(ctx);
+ tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
+
if (DUK_TVAL_IS_OBJECT(tv)) {
- h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
+ h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_this != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
- return h_this;
+ if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
+ return (duk_heaphdr *) h_this;
+ }
+ } else if (DUK_TVAL_IS_BUFFER(tv)) {
+ if (flags & DUK__BUFOBJ_FLAG_PROMOTE) {
+ /* Promote a plain buffer to a Uint8Array. This is very
+ * inefficient but allows plain buffer to be used wherever an
+ * Uint8Array is used with very small cost; hot path functions
+ * like index read/write calls should provide direct buffer
+ * support to avoid promotion.
+ */
+ /* XXX: make this conditional to a flag if call sites need it? */
+ h_this = duk__hbufobj_promote_this(thr);
+ DUK_ASSERT(h_this != NULL);
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
+ return (duk_heaphdr *) h_this;
+ } else {
+ /* XXX: ugly, share return pointer for duk_hbuffer. */
+ return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv);
}
}
- if (throw_flag) {
+ if (flags & DUK__BUFOBJ_FLAG_THROW) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
}
return NULL;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 0);
+/* Check that 'this' is a duk_hbufobj and return a pointer to it. */
+DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it
+/* Check that 'this' is a duk_hbufobj and return a pointer to it
* (NULL if not).
*/
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 1);
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that value is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr;
+/* Check that value is a duk_hbufobj and return a pointer to it. */
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- duk_hbufferobject *h_obj;
-
- thr = (duk_hthread *) ctx;
+ duk_hbufobj *h_obj;
/* Don't accept relative indices now. */
- DUK_ASSERT(index >= 0);
+ DUK_ASSERT(idx >= 0);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
- h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
+ h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_obj != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj);
+ if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_obj);
return h_obj;
}
+ } else if (DUK_TVAL_IS_BUFFER(tv)) {
+ h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx);
+ DUK_ASSERT(h_obj != NULL);
+ DUK_ASSERT_HBUFOBJ_VALID(h_obj);
+ return h_obj;
}
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
return NULL; /* not reachable */
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) {
- duk_hthread *thr;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- DUK_ASSERT(ctx != NULL);
+DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
DUK_ASSERT(h_val != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ DUK_UNREF(thr);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-}
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
- duk_hbuffer *h_val;
- duk_hbufferobject *h_bufobj;
-
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
+ DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
+ DUK_ASSERT(h_bufobj->is_typedarray == 0);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- return h_bufobj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared offset/length coercion helper. */
-DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
- duk_hbufferobject *h_bufarg,
+DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
+ duk_hbufobj *h_bufarg,
duk_idx_t idx_offset,
duk_idx_t idx_length,
duk_uint_t *out_offset,
duk_uint_t *out_length,
duk_bool_t throw_flag) {
- duk_hthread *thr;
duk_int_t offset_signed;
duk_int_t length_signed;
duk_uint_t offset;
duk_uint_t length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- offset_signed = duk_to_int(ctx, idx_offset);
+ offset_signed = duk_to_int(thr, idx_offset);
if (offset_signed < 0) {
goto fail_range;
}
@@ -21848,11 +26107,11 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
DUK_ASSERT(offset <= h_bufarg->length);
- if (duk_is_undefined(ctx, idx_length)) {
+ if (duk_is_undefined(thr, idx_length)) {
DUK_ASSERT(h_bufarg->length >= offset);
length = h_bufarg->length - offset; /* >= 0 */
} else {
- length_signed = duk_to_int(ctx, idx_length);
+ length_signed = duk_to_int(thr, idx_length);
if (length_signed < 0) {
goto fail_range;
}
@@ -21877,35 +26136,30 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
return;
fail_range:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared lenient buffer length clamping helper. No negative indices, no
* element/byte shifting.
*/
-DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
+DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr,
+ duk_int_t buffer_length,
duk_idx_t idx_start,
duk_idx_t idx_end,
duk_int_t *out_start_offset,
duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
duk_int_t start_offset;
duk_int_t end_offset;
DUK_ASSERT(out_start_offset != NULL);
DUK_ASSERT(out_end_offset != NULL);
- buffer_length = (duk_int_t) h_bufobj->length;
-
/* undefined coerces to zero which is correct */
- start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
- if (duk_is_undefined(ctx, idx_end)) {
+ start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length);
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
+ end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length);
}
DUK_ASSERT(start_offset >= 0);
@@ -21917,9 +26171,7 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
*out_start_offset = start_offset;
*out_end_offset = end_offset;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared lenient buffer length clamping helper. Indices are treated as
* element indices (though output values are byte offsets) which only
* really matters for TypedArray views as other buffer object have a zero
@@ -21927,35 +26179,34 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
* indices are clamped to zero length; and final indices are clamped
* against input slice. Used for e.g. ArrayBuffer slice().
*/
-DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
+DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr,
+ duk_int_t buffer_length,
+ duk_uint8_t buffer_shift,
duk_idx_t idx_start,
duk_idx_t idx_end,
duk_int_t *out_start_offset,
duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
duk_int_t start_offset;
duk_int_t end_offset;
DUK_ASSERT(out_start_offset != NULL);
DUK_ASSERT(out_end_offset != NULL);
- buffer_length = (duk_int_t) h_bufobj->length;
- buffer_length >>= h_bufobj->shift; /* as elements */
+ buffer_length >>= buffer_shift; /* as (full) elements */
/* Resolve start/end offset as element indices first; arguments
* at idx_start/idx_end are element offsets. Working with element
* indices first also avoids potential for wrapping.
*/
- start_offset = duk_to_int(ctx, idx_start);
+ start_offset = duk_to_int(thr, idx_start);
if (start_offset < 0) {
start_offset = buffer_length + start_offset;
}
- if (duk_is_undefined(ctx, idx_end)) {
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int(ctx, idx_end);
+ end_offset = duk_to_int(thr, idx_end);
if (end_offset < 0) {
end_offset = buffer_length + end_offset;
}
@@ -21979,60 +26230,98 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
DUK_ASSERT(start_offset <= end_offset);
/* Convert indices to byte offsets. */
- start_offset <<= h_bufobj->shift;
- end_offset <<= h_bufobj->shift;
+ start_offset <<= buffer_shift;
+ end_offset <<= buffer_shift;
*out_start_offset = start_offset;
*out_end_offset = end_offset;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/*
- * Indexed read/write helpers (also used from outside this file)
- */
+DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) {
+ if (duk_is_buffer(thr, idx)) {
+ duk_to_object(thr, idx);
+ }
+}
+
+DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
+ /* Push Uint8Array which will share the same underlying buffer as
+ * the plain buffer argument. Also create an ArrayBuffer with the
+ * same backing for the result .buffer property.
+ */
+
+ duk_push_hbuffer(thr, h_buf);
+ duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
+ duk_remove_m2(thr);
-DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+#if 0
+ /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
+ DUK_BIDX_UINT8ARRAY_PROTOTYPE);
+ DUK_ASSERT(h_bufobj != NULL);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_buf);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+
+ h_arrbuf = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ DUK_ASSERT(h_arrbuf != NULL);
+ duk__set_bufobj_buffer(thr, h_arrbuf, h_buf);
+ DUK_ASSERT(h_arrbuf->is_typedarray == 0);
+ DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
+
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
+ DUK_ASSERT(h_arrbuf != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
+ duk_pop(thr);
+#endif
+}
+
+/* Indexed read helper for buffer objects, also called from outside this file. */
+DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
-#endif
- duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
+ case DUK_HBUFOBJ_ELEM_UINT8:
+ case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
+ duk_push_uint(thr, (duk_uint_t) du.uc[0]);
break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
+ case DUK_HBUFOBJ_ELEM_INT8:
+ duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- duk_push_uint(ctx, (duk_uint_t) du.us[0]);
+ case DUK_HBUFOBJ_ELEM_UINT16:
+ duk_push_uint(thr, (duk_uint_t) du.us[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
+ case DUK_HBUFOBJ_ELEM_INT16:
+ duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
+ case DUK_HBUFOBJ_ELEM_UINT32:
+ duk_push_uint(thr, (duk_uint_t) du.ui[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
+ case DUK_HBUFOBJ_ELEM_INT32:
+ duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ case DUK_HBUFOBJ_ELEM_FLOAT32:
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- duk_push_number(ctx, (duk_double_t) du.d);
+ case DUK_HBUFOBJ_ELEM_FLOAT64:
+ duk_push_number(thr, (duk_double_t) du.d);
break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
default:
DUK_UNREACHABLE();
}
}
-DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+/* Indexed write helper for buffer objects, also called from outside this file. */
+DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
/* NOTE! Caller must ensure that any side effects from the
@@ -22044,36 +26333,33 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe
*/
switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
- du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT8:
+ du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1);
break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
- du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
+ du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT8:
+ du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT16:
+ du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT16:
+ du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT32:
+ du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT32:
+ du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- du.f[0] = (duk_float_t) duk_to_number(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_FLOAT32:
+ du.f[0] = (duk_float_t) duk_to_number_m1(thr);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- du.d = (duk_double_t) duk_to_number(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_FLOAT64:
+ du.d = (duk_double_t) duk_to_number_m1(thr);
break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
default:
DUK_UNREACHABLE();
}
@@ -22081,187 +26367,110 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe
DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
}
-/*
- * Duktape.Buffer: constructor
+/* Helper to create a fixed buffer from argument value at index 0.
+ * Node.js and allocPlain() compatible.
*/
-
-DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
+DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
+ duk_int_t len;
+ duk_int_t i;
duk_size_t buf_size;
- duk_small_int_t buf_dynamic;
- duk_uint8_t *buf_data;
- const duk_uint8_t *src_data;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /*
- * Constructor arguments are currently somewhat compatible with
- * (keep it that way if possible):
- *
- * http://nodejs.org/api/buffer.html
- *
- * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match
- * the constructor behavior.
- */
-
- buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */
+ duk_uint8_t *buf;
- switch (duk_get_type(ctx, 0)) {
+ switch (duk_get_type(thr, 0)) {
case DUK_TYPE_NUMBER: {
- /* new buffer of specified size */
- buf_size = (duk_size_t) duk_to_int(ctx, 0);
- (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
- break;
- }
- case DUK_TYPE_BUFFER: {
- /* return input buffer, converted to a Duktape.Buffer object
- * if called as a constructor (no change if called as a
- * function).
- */
- duk_set_top(ctx, 1);
+ len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX);
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
break;
}
- case DUK_TYPE_STRING: {
- /* new buffer with string contents */
- src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
- DUK_ASSERT(src_data != NULL); /* even for zero-length string */
- buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic);
- DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
- break;
+ case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
+ goto slow_copy;
}
case DUK_TYPE_OBJECT: {
- /* For all duk_hbufferobjects, get the plain buffer inside
- * without making a copy. This is compatible with Duktape 1.2
- * but means that a slice/view information is ignored and the
- * full underlying buffer is returned.
- *
- * If called as a constructor, a new Duktape.Buffer object
- * pointing to the same plain buffer is created below.
+ duk_hobject *h;
+ duk_hbufobj *h_bufobj;
+
+ /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer
+ * that shares allocated memory with the given ArrayBuffer."
+ * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
*/
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0);
- DUK_ASSERT(h_bufobj != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) {
- return DUK_RET_TYPE_ERROR;
- }
- if (h_bufobj->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
+
+ h = duk_known_hobject(thr, 0);
+ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
+ DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
+ h_bufobj = (duk_hbufobj *) h;
+ if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
+ /* No support for ArrayBuffers with slice
+ * offset/length.
+ */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ duk_push_hbuffer(thr, h_bufobj->buf);
+ return h_bufobj->buf;
}
- duk_push_hbuffer(ctx, h_bufobj->buf);
- break;
+ goto slow_copy;
}
- case DUK_TYPE_NONE:
- default: {
- return DUK_RET_TYPE_ERROR;
+ case DUK_TYPE_STRING: {
+ /* ignore encoding for now */
+ duk_require_hstring_notsymbol(thr, 0);
+ duk_dup_0(thr);
+ (void) duk_to_buffer(thr, -1, &buf_size);
+ break;
}
+ default:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
- DUK_ASSERT(duk_is_buffer(ctx, -1));
-
- /* stack is unbalanced, but: [ <something> buf ] */
-
- if (duk_is_constructor_call(ctx)) {
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
+ done:
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ return duk_known_hbuffer(thr, -1);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
+ slow_copy:
+ /* XXX: fast path for typed arrays and other buffer objects? */
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
+ len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX);
+ duk_pop(thr);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */
+ for (i = 0; i < len; i++) {
+ /* XXX: fast path for array or buffer arguments? */
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU);
+ duk_pop(thr);
}
- /* Note: unbalanced stack on purpose */
-
- return 1;
+ goto done;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
- * Node.js Buffer: constructor
+ * Node.js Buffer constructor
+ *
+ * Node.js Buffers are just Uint8Arrays with internal prototype set to
+ * Buffer.prototype so they're handled otherwise the same as Uint8Array.
+ * However, the constructor arguments are very different so a separate
+ * constructor entry point is used.
*/
-
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- /* Internal class is Object: Object.prototype.toString.call(new Buffer(0))
- * prints "[object Object]".
- */
- duk_int_t len;
- duk_int_t i;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
duk_hbuffer *h_buf;
- duk_hbufferobject *h_bufobj;
- duk_size_t buf_size;
-
- switch (duk_get_type(ctx, 0)) {
- case DUK_TYPE_BUFFER: {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
- duk_set_top(ctx, 1); /* -> [ buffer ] */
- break;
- }
- case DUK_TYPE_NUMBER: {
- len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- break;
- }
- case DUK_TYPE_OBJECT: {
- duk_uint8_t *buf;
- (void) duk_get_prop_string(ctx, 0, "length");
- len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
- duk_pop(ctx);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- for (i = 0; i < len; i++) {
- /* XXX: fast path for array arguments? */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
- duk_pop(ctx);
- }
- break;
- }
- case DUK_TYPE_STRING: {
- /* ignore encoding for now */
- duk_dup(ctx, 0);
- (void) duk_to_buffer(ctx, -1, &buf_size);
- break;
- }
- default:
- return DUK_RET_TYPE_ERROR;
- }
-
- DUK_ASSERT(duk_is_buffer(ctx, -1));
- h_buf = duk_get_hbuffer(ctx, -1);
+ h_buf = duk__hbufobj_fixed_from_argvalue(thr);
DUK_ASSERT(h_buf != NULL);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_buf;
- DUK_HBUFFER_INCREF(thr, h_buf);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
+ duk_push_buffer_object(thr,
+ -1,
+ 0,
+ DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf),
+ DUK_BUFOBJ_UINT8ARRAY);
+ duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
+ duk_set_prototype(thr, -2);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ /* XXX: a more direct implementation */
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -22269,84 +26478,53 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
+DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
+ duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- if (duk_is_buffer(ctx, 0)) {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
+ DUK_ASSERT_CTX_VALID(thr);
- h_val = duk_get_hbuffer(ctx, 0);
- DUK_ASSERT(h_val != NULL);
+ duk_require_constructor_call(thr);
- /* XXX: accept any duk_hbufferobject type as an input also? */
- } else {
- duk_int_t len;
- len = duk_to_int(ctx, 0);
- if (len < 0) {
- goto fail_length;
- }
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
-#endif
+ len = duk_to_int(thr, 0);
+ if (len < 0) {
+ goto fail_length;
}
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
+ h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
DUK_ASSERT(h_bufobj != NULL);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_val);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
fail_length:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Format of magic, bits:
* 0...1: elem size shift (0-3)
- * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx)
+ * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx)
+ *
+ * XXX: add prototype bidx explicitly to magic instead of using a mapping?
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h_obj;
- duk_hbufferobject *h_bufobj = NULL;
- duk_hbufferobject *h_bufarr = NULL;
- duk_hbufferobject *h_bufarg = NULL;
+ duk_hbufobj *h_bufobj = NULL;
+ duk_hbufobj *h_bufarg = NULL;
duk_hbuffer *h_val;
duk_small_uint_t magic;
duk_small_uint_t shift;
@@ -22360,23 +26538,21 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
duk_uint_t byte_length;
duk_small_uint_t copy_mode;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ /* XXX: The same copy helpers could be shared with at least some
+ * buffer functions.
+ */
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
+ duk_require_constructor_call(thr);
/* We could fit built-in index into magic but that'd make the magic
* number dependent on built-in numbering (genbuiltins.py doesn't
* handle that yet). So map both class and prototype from the
* element type.
*/
- magic = duk_get_current_magic(ctx);
- shift = magic & 0x03; /* bits 0...1: shift */
- elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
- elem_size = 1 << shift;
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ shift = magic & 0x03U; /* bits 0...1: shift */
+ elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */
+ elem_size = 1U << shift;
align_mask = elem_size - 1;
DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
@@ -22394,7 +26570,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* created.
*/
- tv = duk_get_tval(ctx, 0);
+ /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer:
+ * coerce to an ArrayBuffer object and use that as .buffer. The underlying
+ * buffer will be the same but result .buffer !== inputPlainBuffer.
+ */
+ duk_hbufobj_promote_plain(thr, 0);
+
+ tv = duk_get_tval(thr, 0);
DUK_ASSERT(tv != NULL); /* arg count */
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = DUK_TVAL_GET_OBJECT(tv);
@@ -22408,9 +26590,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
duk_int_t byte_offset_signed;
duk_uint_t byte_offset;
- h_bufarg = (duk_hbufferobject *) h_obj;
+ h_bufarg = (duk_hbufobj *) h_obj;
- byte_offset_signed = duk_to_int(ctx, 1);
+ byte_offset_signed = duk_to_int(thr, 1);
if (byte_offset_signed < 0) {
goto fail_arguments;
}
@@ -22420,7 +26602,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* Must be >= 0 and multiple of element size. */
goto fail_arguments;
}
- if (duk_is_undefined(ctx, 2)) {
+ if (duk_is_undefined(thr, 2)) {
DUK_ASSERT(h_bufarg->length >= byte_offset);
byte_length = h_bufarg->length - byte_offset;
if ((byte_length & align_mask) != 0) {
@@ -22431,7 +26613,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
}
elem_length = (byte_length >> shift);
} else {
- elem_length_signed = duk_to_int(ctx, 2);
+ elem_length_signed = duk_to_int(thr, 2);
if (elem_length_signed < 0) {
goto fail_arguments;
}
@@ -22455,14 +26637,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
DUK_ASSERT((elem_length << shift) == byte_length);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
+ (duk_small_int_t) proto_bidx);
h_val = h_bufarg->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -22470,25 +26652,26 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
h_bufobj->length = byte_length;
h_bufobj->shift = (duk_uint8_t) shift;
h_bufobj->elem_type = (duk_uint8_t) elem_type;
- h_bufobj->is_view = 1;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
/* Set .buffer to the argument ArrayBuffer. */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
+ DUK_ASSERT(h_bufarg != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_bufarg);
return 1;
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- /* TypedArray (or other non-ArrayBuffer duk_hbufferobject).
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ /* TypedArray (or other non-ArrayBuffer duk_hbufobj).
* Conceptually same behavior as for an Array-like argument,
* with a few fast paths.
*/
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
+ h_bufarg = (duk_hbufobj *) h_obj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
if (h_bufarg->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* Select copy mode. Must take into account element
@@ -22505,8 +26688,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
(long) (elem_length_signed << shift)));
copy_mode = 2; /* default is explicit index read/write copy */
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* With a size optimized build copy_mode 2 is enough.
+ * Modes 0 and 1 are faster but conceptually the same.
+ */
DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
@@ -22516,25 +26703,18 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
copy_mode = 1;
}
}
+#endif /* !DUK_USE_PREFER_SIZE */
} else {
/* Array or Array-like */
- elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
+ elem_length_signed = (duk_int_t) duk_get_length(thr, 0);
copy_mode = 2;
}
- } else if (DUK_TVAL_IS_BUFFER(tv)) {
- /* Accept plain buffer values like array initializers
- * (new in Duktape 1.4.0).
- */
- duk_hbuffer *h_srcbuf;
- h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
- elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
- copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
} else {
/* Non-object argument is simply int coerced, matches
* V8 behavior (except for "null", which we coerce to
* 0 but V8 TypeErrors).
*/
- elem_length_signed = duk_to_int(ctx, 0);
+ elem_length_signed = duk_to_int(thr, 0);
copy_mode = 3;
}
if (elem_length_signed < 0) {
@@ -22553,20 +26733,22 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* ArrayBuffer argument is handled specially above; the rest of the
* argument variants are handled by shared code below.
+ *
+ * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset.
+ * It will be automatically created by the .buffer accessor on
+ * first access.
*/
- /* Push a new ArrayBuffer (becomes view .buffer) */
- h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
- DUK_ASSERT(h_bufarr != NULL);
- h_val = h_bufarr->buf;
+ /* Push the resulting view object on top of a plain fixed buffer. */
+ (void) duk_push_fixed_buffer(thr, byte_length);
+ h_val = duk_known_hbuffer(thr, -1);
DUK_ASSERT(h_val != NULL);
- /* Push the resulting view object and attach the ArrayBuffer. */
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
+ (duk_small_int_t) proto_bidx);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -22574,13 +26756,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
h_bufobj->length = byte_length;
h_bufobj->shift = (duk_uint8_t) shift;
h_bufobj->elem_type = (duk_uint8_t) elem_type;
- h_bufobj->is_view = 1;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- /* Set .buffer */
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
/* Copy values, the copy method depends on the arguments.
*
@@ -22590,6 +26767,10 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
*/
DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
switch (copy_mode) {
+ /* Copy modes 0 and 1 can be omitted in size optimized build,
+ * copy mode 2 handles them (but more slowly).
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
case 0: {
/* Use byte copy. */
@@ -22598,13 +26779,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
DUK_ASSERT(h_bufarg != NULL);
DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
+ p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
(void *) p_src, (void *) p_dst, (long) byte_length));
@@ -22623,16 +26804,16 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
DUK_ASSERT(h_bufarg != NULL);
DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
- src_elem_size = 1 << h_bufarg->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
dst_elem_size = elem_size;
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
+ p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
p_src_end = p_src + h_bufarg->length;
DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
@@ -22647,14 +26828,15 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
break;
}
+#endif /* !DUK_USE_PREFER_SIZE */
case 2: {
/* Copy values by index reads and writes. Let virtual
* property handling take care of coercion.
@@ -22664,8 +26846,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("using slow copy"));
for (i = 0; i < elem_length; i++) {
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) i);
}
break;
}
@@ -22675,13 +26857,6 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* ambiguity with Float32/Float64 because zero bytes also
* represent 0.0.
*/
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
-#endif
DUK_DDD(DUK_DDDPRINT("using no copy"));
break;
@@ -22691,76 +26866,84 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
return 1;
fail_arguments:
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+/* When bufferobject support is disabled, new Uint8Array() could still be
+ * supported to create a plain fixed buffer. Disabled for now.
+ */
+#if 0
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
+ duk_int_t elem_length_signed;
+ duk_uint_t byte_length;
+
+ /* XXX: The same copy helpers could be shared with at least some
+ * buffer functions.
+ */
+
+ duk_require_constructor_call(thr);
+
+ elem_length_signed = duk_require_int(thr, 0);
+ if (elem_length_signed < 0) {
+ goto fail_arguments;
+ }
+ byte_length = (duk_uint_t) elem_length_signed;
+
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length);
+ return 1;
+
+ fail_arguments:
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
+#endif /* 0 */
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- duk_hbufferobject *h_bufarg;
- duk_hbufferobject *h_bufobj;
+DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) {
+ duk_hbufobj *h_bufarg;
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_uint_t offset;
duk_uint_t length;
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
+ duk_require_constructor_call(thr);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
+ h_bufarg = duk__require_bufobj_value(thr, 0);
DUK_ASSERT(h_bufarg != NULL);
+ if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ }
- duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
DUK_ASSERT(offset <= h_bufarg->length);
DUK_ASSERT(offset + length <= h_bufarg->length);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
- DUK_BIDX_DATAVIEW_PROTOTYPE);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
+ DUK_BIDX_DATAVIEW_PROTOTYPE);
h_val = h_bufarg->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->offset = h_bufarg->offset + offset;
h_bufobj->length = length;
DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
- h_bufobj->is_view = 1;
-
- /* The DataView .buffer property is ordinarily set to the argument
- * which is an ArrayBuffer. We accept any duk_hbufferobject as
- * an argument and .buffer will be set to the argument regardless
- * of what it is. This may be a bit confusing if the argument
- * is e.g. a DataView or another TypedArray view.
- *
- * XXX: Copy .buffer property from a DataView/TypedArray argument?
- * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer
- * arguments? See: test-bug-dataview-buffer-prop.js.
- */
+ DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
+ DUK_ASSERT(h_bufobj->is_typedarray == 0);
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
+ DUK_ASSERT(h_bufarg != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_bufarg);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -22768,139 +26951,123 @@ DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) {
duk_hobject *h_obj;
duk_bool_t ret = 0;
- h_obj = duk_get_hobject(ctx, 0);
- if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- ret = ((duk_hbufferobject *) h_obj)->is_view;
+ if (duk_is_buffer(thr, 0)) {
+ ret = 1;
+ } else {
+ h_obj = duk_get_hobject(thr, 0);
+ if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ /* DataView needs special casing: ArrayBuffer.isView() is
+ * true, but ->is_typedarray is 0.
+ */
+ ret = ((duk_hbufobj *) h_obj)->is_typedarray ||
+ (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
+ }
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
- * Node.js Buffer: toString([encoding], [start], [end])
+ * Uint8Array.allocPlain()
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_int_t start_offset, end_offset;
- duk_uint8_t *buf_slice;
- duk_size_t slice_length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__get_bufobj_this(ctx);
- if (h_this == NULL) {
- /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
- duk_push_string(ctx, "[object Object]");
- return 1;
- }
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
-
- /* ignore encoding for now */
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) {
+ duk__hbufobj_fixed_from_argvalue(thr);
+ return 1;
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset);
+/*
+ * Uint8Array.plainOf()
+ */
- slice_length = (duk_size_t) (end_offset - start_offset);
- buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length);
- DUK_ASSERT(buf_slice != NULL);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
- if (h_this->buf == NULL) {
- goto type_error;
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* Avoid churn if argument is already a plain buffer. */
+ if (duk_is_buffer(thr, 0)) {
+ return 1;
}
+#endif
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
- DUK_MEMCPY((void *) buf_slice,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- (size_t) slice_length);
+ /* Promotes plain buffers to ArrayBuffers, so for a plain buffer
+ * argument we'll create a pointless temporary (but still work
+ * correctly).
+ */
+ h_bufobj = duk__require_bufobj_value(thr, 0);
+ if (h_bufobj->buf == NULL) {
+ duk_push_undefined(thr);
} else {
- /* not covered, return all zeroes */
- ;
+ duk_push_hbuffer(thr, h_bufobj->buf);
}
-
- duk_to_string(ctx, -1);
return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
- * Duktape.Buffer: toString(), valueOf()
+ * Node.js Buffer: toString([encoding], [start], [end])
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
+ duk_hbufobj *h_this;
+ duk_int_t start_offset, end_offset;
+ duk_uint8_t *buf_slice;
+ duk_size_t slice_length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ h_this = duk__get_bufobj_this(thr);
+ if (h_this == NULL) {
+ /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
+ duk_push_string(thr, "[object Object]");
+ return 1;
+ }
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
- tv = duk_get_borrowed_this_tval(ctx);
- DUK_ASSERT(tv != NULL);
+ /* Ignore encoding for now. */
- if (DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h_buf;
- h_buf = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_buf != NULL);
- duk_push_hbuffer(ctx, h_buf);
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_hbufferobject *h_bufobj;
+ duk__clamp_startend_nonegidx_noshift(thr,
+ (duk_int_t) h_this->length,
+ 1 /*idx_start*/,
+ 2 /*idx_end*/,
+ &start_offset,
+ &end_offset);
- /* Accept any duk_hbufferobject, though we're only normally
- * called for Duktape.Buffer values.
- */
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object"));
- goto type_error;
- }
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ slice_length = (duk_size_t) (end_offset - start_offset);
+ buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */
+ DUK_ASSERT(buf_slice != NULL);
- if (h_bufobj->buf == NULL) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf"));
- goto type_error;
- }
- duk_push_hbuffer(ctx, h_bufobj->buf);
- } else {
- goto type_error;
+ /* Neutered or uncovered, TypeError. */
+ if (h_this->buf == NULL ||
+ !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- if (to_string) {
- duk_to_string(ctx, -1);
- }
- return 1;
+ /* XXX: ideally we wouldn't make a copy but a view into the buffer for the
+ * decoding process. Or the decoding helper could be changed to accept
+ * the slice info (a buffer pointer is NOT a good approach because guaranteeing
+ * its stability is difficult).
+ */
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
+ DUK_MEMCPY((void *) buf_slice,
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ (size_t) slice_length);
+
+ /* Use the equivalent of: new TextEncoder().encode(this) to convert the
+ * string. Result will be valid UTF-8; non-CESU-8 inputs are currently
+ * interpreted loosely. Value stack convention is a bit odd for now.
+ */
+ duk_replace(thr, 0);
+ duk_set_top(thr, 1);
+ return duk_textdecoder_decode_utf8_nodejs(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -22909,48 +27076,40 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx)
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_uint8_t *buf;
- duk_uint_t i;
+ duk_uint_t i, n;
+ duk_tval *tv;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
- if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
+ if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Serialize uncovered backing buffer as a null; doesn't
* really matter as long we're memory safe.
*/
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
- duk_push_object(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE);
+ duk_push_object(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE);
- duk_push_array(ctx);
- for (i = 0; i < h_this->length; i++) {
- /* XXX: regetting the pointer may be overkill - we're writing
- * to a side-effect free array here.
- */
- DUK_ASSERT(h_this->buf != NULL);
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
- duk_push_uint(ctx, (duk_uint_t) buf[i]);
- duk_put_prop_index(ctx, -2, (duk_idx_t) i);
+ /* XXX: uninitialized would be OK */
+ DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
+
+ DUK_ASSERT(h_this->buf != NULL);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
+ for (i = 0, n = h_this->length; i < n; i++) {
+ DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */
}
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -22960,24 +27119,22 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) {
duk_small_uint_t magic;
- duk_hbufferobject *h_bufarg1;
- duk_hbufferobject *h_bufarg2;
+ duk_hbufobj *h_bufarg1;
+ duk_hbufobj *h_bufarg2;
duk_small_int_t comp_res;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ /* XXX: keep support for plain buffers and non-Node.js buffers? */
- magic = duk_get_current_magic(ctx);
- if (magic & 0x02) {
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ if (magic & 0x02U) {
/* Static call style. */
- h_bufarg1 = duk__require_bufobj_value(ctx, 0);
- h_bufarg2 = duk__require_bufobj_value(ctx, 1);
+ h_bufarg1 = duk__require_bufobj_value(thr, 0);
+ h_bufarg2 = duk__require_bufobj_value(thr, 1);
} else {
- h_bufarg1 = duk__require_bufobj_this(ctx);
- h_bufarg2 = duk__require_bufobj_value(ctx, 0);
+ h_bufarg1 = duk__require_bufobj_this(thr);
+ h_bufarg2 = duk__require_bufobj_value(thr, 0);
}
DUK_ASSERT(h_bufarg1 != NULL);
DUK_ASSERT(h_bufarg2 != NULL);
@@ -22988,8 +27145,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
* matters is to be memory safe.
*/
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) &&
+ DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) {
comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
(const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
(duk_size_t) h_bufarg1->length,
@@ -22998,21 +27155,16 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
comp_res = -1; /* either nonzero value is ok */
}
- if (magic & 0x01) {
+ if (magic & 0x01U) {
/* compare: similar to string comparison but for buffer data. */
- duk_push_int(ctx, comp_res);
+ duk_push_int(thr, comp_res);
} else {
/* equals */
- duk_push_boolean(ctx, (comp_res == 0));
+ duk_push_boolean(thr, (comp_res == 0));
}
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23020,9 +27172,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
+ duk_hbufobj *h_this;
const duk_uint8_t *fill_str_ptr;
duk_size_t fill_str_len;
duk_uint8_t fill_value;
@@ -23031,29 +27182,32 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
duk_size_t fill_length;
duk_uint8_t *p;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
if (h_this->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* [ value offset end ] */
- if (duk_is_string(ctx, 0)) {
- fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
+ if (duk_is_string_notsymbol(thr, 0)) {
+ fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len);
DUK_ASSERT(fill_str_ptr != NULL);
} else {
- fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ /* Symbols get ToNumber() coerced and cause TypeError. */
+ fill_value = (duk_uint8_t) duk_to_uint32(thr, 0);
fill_str_ptr = (const duk_uint8_t *) &fill_value;
fill_str_len = 1;
}
/* Fill offset handling is more lenient than in Node.js. */
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end);
+ duk__clamp_startend_nonegidx_noshift(thr,
+ (duk_int_t) h_this->length,
+ 1 /*idx_start*/,
+ 2 /*idx_end*/,
+ &fill_offset,
+ &fill_end);
DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
(unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
@@ -23061,7 +27215,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
DUK_ASSERT(fill_end - fill_offset >= 0);
DUK_ASSERT(h_this->buf != NULL);
- p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
+ p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
fill_length = (duk_size_t) (fill_end - fill_offset);
if (fill_str_len == 1) {
/* Handle single character fills as memset() even when
@@ -23071,7 +27225,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
} else if (fill_str_len > 1) {
duk_size_t i, n, t;
- for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
+ for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) {
p[i] = fill_str_ptr[t++];
if (t >= fill_str_len) {
t = 0;
@@ -23082,14 +27236,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
}
/* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
- duk_push_this(ctx);
+ duk_push_this(thr);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23097,24 +27246,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_uint_t offset;
duk_uint_t length;
const duk_uint8_t *str_data;
duk_size_t str_len;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ /* XXX: very inefficient support for plain buffers */
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
/* Argument must be a string, e.g. a buffer is not allowed. */
- str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len);
+ str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len);
- duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
DUK_ASSERT(offset <= h_this->length);
DUK_ASSERT(offset + length <= h_this->length);
@@ -23124,23 +27270,18 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
length = (duk_uint_t) str_len;
}
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Cannot overlap. */
- DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset),
+ DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
(const void *) str_data,
(size_t) length);
} else {
DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
}
- duk_push_uint(ctx, length);
+ duk_push_uint(thr, length);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23148,10 +27289,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufarg;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
+ duk_hbufobj *h_this;
+ duk_hbufobj *h_bufarg;
duk_int_t source_length;
duk_int_t target_length;
duk_int_t target_start, source_start, source_end;
@@ -23160,22 +27300,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
/* [ targetBuffer targetStart sourceStart sourceEnd ] */
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
+ h_this = duk__require_bufobj_this(thr);
+ h_bufarg = duk__require_bufobj_value(thr, 0);
DUK_ASSERT(h_this != NULL);
DUK_ASSERT(h_bufarg != NULL);
source_length = (duk_int_t) h_this->length;
target_length = (duk_int_t) h_bufarg->length;
- target_start = duk_to_int(ctx, 1);
- source_start = duk_to_int(ctx, 2);
- if (duk_is_undefined(ctx, 3)) {
+ target_start = duk_to_int(thr, 1);
+ source_start = duk_to_int(thr, 2);
+ if (duk_is_undefined(thr, 3)) {
source_end = source_length;
} else {
- source_end = duk_to_int(ctx, 3);
+ source_end = duk_to_int(thr, 3);
}
DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
@@ -23199,7 +27336,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
}
if (source_uend >= (duk_uint_t) source_length) {
/* Source end clamped silently to available length. */
- source_uend = source_length;
+ source_uend = (duk_uint_t) source_length;
}
copy_size = source_uend - source_ustart;
if (target_ustart + copy_size > (duk_uint_t) target_length) {
@@ -23228,13 +27365,13 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
/* Ensure copy is covered by underlying buffers. */
DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
DUK_ASSERT(h_this->buf != NULL); /* length check */
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
- DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
+ if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
+ DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
/* Must use memmove() because copy area may overlap (source and target
* buffer may be the same, or from different slices.
*/
- DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
+ DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
(size_t) copy_size);
} else {
DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
@@ -23245,16 +27382,11 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
* The return value matters because of code like:
* "off += buf.copy(...)".
*/
- duk_push_uint(ctx, copy_size);
+ duk_push_uint(thr, copy_size);
return 1;
fail_bounds:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -23295,59 +27427,58 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_hobject *h_obj;
duk_uarridx_t i, n;
duk_int_t offset_signed;
duk_uint_t offset_elems;
duk_uint_t offset_bytes;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
if (h_this->buf == NULL) {
DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
return 0;
}
- h_obj = duk_require_hobject(ctx, 0);
- DUK_ASSERT(h_obj != NULL);
+ duk_hbufobj_promote_plain(thr, 0);
+ h_obj = duk_require_hobject(thr, 0);
/* XXX: V8 throws a TypeError for negative values. Would it
* be more useful to interpret negative offsets here from the
* end of the buffer too?
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
if (offset_signed < 0) {
- return DUK_RET_TYPE_ERROR;
+ /* For some reason this is a TypeError (at least in V8). */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
offset_elems = (duk_uint_t) offset_signed;
offset_bytes = offset_elems << h_this->shift;
if ((offset_bytes >> h_this->shift) != offset_elems) {
/* Byte length would overflow. */
/* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
if (offset_bytes > h_this->length) {
/* Equality may be OK but >length not. Checking
* this explicitly avoids some overflow cases
* below.
*/
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
DUK_ASSERT(offset_bytes <= h_this->length);
- /* Fast path: source is a TypedArray (or any bufferobject). */
+ /* Fast path: source is a TypedArray (or any bufobj). */
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- duk_hbufferobject *h_bufarg;
+ if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ duk_hbufobj *h_bufarg;
+#if !defined(DUK_USE_PREFER_SIZE)
duk_uint16_t comp_mask;
+#endif
duk_small_int_t no_overlap = 0;
duk_uint_t src_length;
duk_uint_t dst_length;
@@ -23360,8 +27491,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_small_uint_t src_elem_size;
duk_small_uint_t dst_elem_size;
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
+ h_bufarg = (duk_hbufobj *) h_obj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
if (h_bufarg->buf == NULL) {
DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
@@ -23375,7 +27506,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
if ((dst_length >> h_this->shift) != dst_length_elems) {
/* Byte length would overflow. */
/* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
(long) src_length, (long) dst_length));
@@ -23385,22 +27516,22 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* side and guaranteed to be >= 0.
*/
DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
- if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
+ if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
return 0;
}
- p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
+ p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
/* Check actual underlying buffers for validity and that they
* cover the copy. No side effects are allowed after the check
* so that the validity status doesn't change.
*/
- if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) ||
- !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
+ if (!DUK_HBUFOBJ_VALID_SLICE(h_this) ||
+ !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
/* The condition could be more narrow and check for the
* copy area only, but there's no need for fine grained
* behavior when the underlying buffer is misconfigured.
@@ -23420,6 +27551,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* and destination element sizes are necessarily equal.
*/
+#if !defined(DUK_USE_PREFER_SIZE)
DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
if (comp_mask & (1 << h_bufarg->elem_type)) {
@@ -23430,6 +27562,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
return 0;
}
DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
+#endif /* !DUK_USE_PREFER_SIZE */
/* We want to avoid making a copy to process set() but that's
* not always possible: the source and the target may overlap
@@ -23466,7 +27599,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_uint8_t *p_src_copy;
DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
- p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length);
+ p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
DUK_ASSERT(p_src_copy != NULL);
DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
@@ -23478,7 +27611,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
"p_dst_base=%p, dst_length=%ld, valstack top=%ld",
(void *) p_src_base, (long) src_length,
(void *) p_dst_base, (long) dst_length,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
/* Ready to make the copy. We must proceed element by element
* and must avoid any side effects that might cause the buffer
@@ -23488,8 +27621,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* numbers are handled which should be side effect safe.
*/
- src_elem_size = 1 << h_bufarg->shift;
- dst_elem_size = 1 << h_this->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
+ dst_elem_size = (duk_small_uint_t) (1U << h_this->shift);
p_src = p_src_base;
p_dst = p_dst_base;
p_src_end = p_src_base + src_length;
@@ -23501,9 +27634,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
@@ -23514,19 +27647,19 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* to write coerce target values. We don't need to worry about overlap
* here because the source is not a TypedArray.
*
- * We could use the bufferobject write coercion helper but since the
+ * We could use the bufobj write coercion helper but since the
* property read may have arbitrary side effects, full validity checks
* would be needed for every element anyway.
*/
- n = (duk_uarridx_t) duk_get_length(ctx, 0);
+ n = (duk_uarridx_t) duk_get_length(thr, 0);
DUK_ASSERT(offset_bytes <= h_this->length);
if ((n << h_this->shift) > h_this->length - offset_bytes) {
/* Overflow not an issue because subtraction is used on the right
* side and guaranteed to be >= 0.
*/
DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
/* There's no need to check for buffer validity status for the
@@ -23536,28 +27669,26 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* the results anyway.
*/
- DUK_ASSERT_TOP(ctx, 2);
- duk_push_this(ctx);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_push_this(thr);
for (i = 0; i < n; i++) {
- duk_get_prop_index(ctx, 0, i);
- duk_put_prop_index(ctx, 2, offset_elems + i);
+ duk_get_prop_index(thr, 0, i);
+ duk_put_prop_index(thr, 2, offset_elems + i);
}
}
return 0;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+
+ fail_args:
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
* Node.js Buffer.prototype.slice([start], [end])
* ArrayBuffer.prototype.slice(begin, [end])
- * TypedArray.prototype.slice(begin, [end])
+ * TypedArray.prototype.subarray(begin, [end])
*
* The API calls are almost identical; negative indices are counted from end
* of buffer, and final indices are clamped (allowing crossed indices). Main
@@ -23570,27 +27701,86 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* call (or 'this' argument)
*
* - TypedArray .subarray() arguments are element indices, not byte offsets
+ *
+ * - Plain buffer argument creates a plain buffer slice
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) {
+ duk_int_t start_offset, end_offset;
+ duk_uint_t slice_length;
+ duk_uint8_t *p_copy;
+ duk_size_t copy_length;
+
+ duk__clamp_startend_negidx_shifted(thr,
+ (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
+ 0 /*buffer_shift*/,
+ 0 /*idx_start*/,
+ 1 /*idx_end*/,
+ &start_offset,
+ &end_offset);
+ DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val));
+ DUK_ASSERT(start_offset >= 0);
+ DUK_ASSERT(end_offset >= start_offset);
+ slice_length = (duk_uint_t) (end_offset - start_offset);
+
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length);
+ DUK_ASSERT(p_copy != NULL);
+ copy_length = slice_length;
+
+ DUK_MEMCPY((void *) p_copy,
+ (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
+ copy_length);
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+/* Shared helper for slice/subarray operation.
+ * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
duk_small_int_t magic;
duk_small_uint_t res_class_num;
- duk_hobject *res_proto;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufobj;
+ duk_small_int_t res_proto_bidx;
+ duk_hbufobj *h_this;
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_int_t start_offset, end_offset;
duk_uint_t slice_length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ duk_tval *tv;
/* [ start end ] */
- magic = duk_get_current_magic(ctx);
- h_this = duk__require_bufobj_this(ctx);
+ magic = duk_get_current_magic(thr);
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_BUFFER(tv)) {
+ /* For plain buffers return a plain buffer slice. */
+ h_val = DUK_TVAL_GET_BUFFER(tv);
+ DUK_ASSERT(h_val != NULL);
+
+ if (magic & 0x02) {
+ /* Make copy: ArrayBuffer.prototype.slice() uses this. */
+ duk__arraybuffer_plain_slice(thr, h_val);
+ return 1;
+ } else {
+ /* View into existing buffer: cannot be done if the
+ * result is a plain buffer because there's no slice
+ * info. So return an ArrayBuffer instance; coerce
+ * the 'this' binding into an object and behave as if
+ * the original call was for an Object-coerced plain
+ * buffer (handled automatically by duk__require_bufobj_this()).
+ */
+
+ DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object"));
+ /* fall through */
+ }
+ }
+ tv = NULL; /* No longer valid nor needed. */
+
+ h_this = duk__require_bufobj_this(thr);
/* Slice offsets are element (not byte) offsets, which only matters
* for TypedArray views, Node.js Buffer and ArrayBuffer have shift
@@ -23601,40 +27791,53 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
* against the underlying buffer here.
*/
- duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset);
+ duk__clamp_startend_negidx_shifted(thr,
+ (duk_int_t) h_this->length,
+ (duk_uint8_t) h_this->shift,
+ 0 /*idx_start*/,
+ 1 /*idx_end*/,
+ &start_offset,
+ &end_offset);
DUK_ASSERT(end_offset >= start_offset);
+ DUK_ASSERT(start_offset >= 0);
+ DUK_ASSERT(end_offset >= 0);
slice_length = (duk_uint_t) (end_offset - start_offset);
/* The resulting buffer object gets the same class and prototype as
- * the buffer in 'this', e.g. if the input is a Node.js Buffer the
- * result is a Node.js Buffer; if the input is a Float32Array, the
- * result is a Float32Array.
+ * the buffer in 'this', e.g. if the input is a Uint8Array the
+ * result is a Uint8Array; if the input is a Float32Array, the
+ * result is a Float32Array. The result internal prototype should
+ * be the default prototype for the class (e.g. initial value of
+ * Uint8Array.prototype), not copied from the argument (Duktape 1.x
+ * did that).
*
- * For the class number this seems correct. The internal prototype
- * is not so clear: if 'this' is a bufferobject with a non-standard
- * prototype object, that value gets copied over into the result
- * (instead of using the standard prototype for that object type).
+ * Node.js Buffers have special handling: they're Uint8Arrays as far
+ * as the internal class is concerned, so the new Buffer should also
+ * be an Uint8Array but inherit from Buffer.prototype.
*/
-
res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
- DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */
+ DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */
+ DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX);
+ res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN];
+ if (magic & 0x04) {
+ res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
+ }
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
+ res_proto_bidx);
DUK_ASSERT(h_bufobj != NULL);
- res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto);
- h_bufobj->length = slice_length;
+ DUK_ASSERT(h_bufobj->length == 0);
h_bufobj->shift = h_this->shift; /* inherit */
h_bufobj->elem_type = h_this->elem_type; /* inherit */
- h_bufobj->is_view = magic & 0x01;
- DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1);
+ h_bufobj->is_typedarray = magic & 0x01;
+ DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1);
h_val = h_this->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
if (magic & 0x02) {
@@ -23642,53 +27845,45 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
duk_uint8_t *p_copy;
duk_size_t copy_length;
- p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length);
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
DUK_ASSERT(p_copy != NULL);
/* Copy slice, respecting underlying buffer limits; remainder
* is left as zero.
*/
- copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length);
+ copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
DUK_MEMCPY((void *) p_copy,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
copy_length);
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
+ h_val = duk_known_hbuffer(thr, -1);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
+ h_bufobj->length = slice_length;
DUK_ASSERT(h_bufobj->offset == 0);
- duk_pop(ctx); /* reachable so pop OK */
+ duk_pop(thr); /* reachable so pop OK */
} else {
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
+ h_bufobj->length = slice_length;
+ h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset;
/* Copy the .buffer property, needed for TypedArray.prototype.subarray().
*
* XXX: limit copy only for TypedArray classes specifically?
*/
- duk_push_this(ctx);
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) {
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_pop(ctx);
- } else {
- duk_pop_2(ctx);
- }
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop);
}
/* unbalanced stack on purpose */
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23696,21 +27891,16 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) {
const char *encoding;
/* only accept lowercase 'utf8' now. */
- encoding = duk_to_string(ctx, 0);
- DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
- duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
+ encoding = duk_to_string(thr, 0);
+ DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */
+ duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23718,40 +27908,26 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) {
duk_hobject *h;
duk_hobject *h_proto;
duk_bool_t ret = 0;
- thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
+ DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */
+ h = duk_get_hobject(thr, 0);
+ if (h != NULL) {
h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
DUK_ASSERT(h_proto != NULL);
h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- if (h) {
+ if (h != NULL) {
ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
}
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23759,7 +27935,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) {
const char *str;
duk_size_t len;
@@ -23768,16 +27944,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
* unconditionally.
*/
- str = duk_to_lstring(ctx, 0, &len);
+ /* XXX: to be revised; Old Node.js behavior just coerces any buffer
+ * values to string:
+ * $ node
+ * > Buffer.byteLength(new Uint32Array(10))
+ * 20
+ * > Buffer.byteLength(new Uint32Array(100))
+ * 20
+ * (The 20 comes from '[object Uint32Array]'.length
+ */
+
+ str = duk_to_lstring(thr, 0, &len);
DUK_UNREF(str);
- duk_push_size_t(ctx, len);
+ duk_push_size_t(thr, len);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23785,81 +27966,77 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
duk_hobject *h_arg;
- duk_int_t total_length = 0;
- duk_hbufferobject *h_bufobj;
- duk_hbufferobject *h_bufres;
+ duk_uint_t total_length;
+ duk_hbufobj *h_bufobj;
+ duk_hbufobj *h_bufres;
duk_hbuffer *h_val;
duk_uint_t i, n;
duk_uint8_t *p;
duk_size_t space_left;
duk_size_t copy_size;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* Node.js accepts only actual Arrays. */
- h_arg = duk_require_hobject(ctx, 0);
+ h_arg = duk_require_hobject(thr, 0);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* Compute result length and validate argument buffers. */
- n = (duk_uint_t) duk_get_length(ctx, 0);
+ n = (duk_uint_t) duk_get_length(thr, 0);
+ total_length = 0;
for (i = 0; i < n; i++) {
/* Neutered checks not necessary here: neutered buffers have
* zero 'length' so we'll effectively skip them.
*/
- DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
- h_bufobj = duk__require_bufobj_value(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
+ h_bufobj = duk__require_bufobj_value(thr, 2);
DUK_ASSERT(h_bufobj != NULL);
total_length += h_bufobj->length;
- duk_pop(ctx);
- }
- if (n == 1) {
- /* For the case n==1 Node.js doesn't seem to type check
- * the sole member but we do it before returning it.
- * For this case only the original buffer object is
- * returned (not a copy).
- */
- duk_get_prop_index(ctx, 0, 0);
- return 1;
+ if (DUK_UNLIKELY(total_length < h_bufobj->length)) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */
+ }
+ duk_pop(thr);
}
+ /* In Node.js v0.12.1 a 1-element array is special and won't create a
+ * copy, this was fixed later so an explicit check no longer needed.
+ */
/* User totalLength overrides a computed length, but we'll check
- * every copy in the copy loop. Note that duk_to_uint() can
+ * every copy in the copy loop. Note that duk_to_int() can
* technically have arbitrary side effects so we need to recheck
* the buffers in the copy loop.
*/
- if (!duk_is_undefined(ctx, 1) && n > 0) {
+ if (!duk_is_undefined(thr, 1) && n > 0) {
/* For n == 0, Node.js ignores totalLength argument and
* returns a zero length buffer.
*/
- total_length = duk_to_int(ctx, 1);
- }
- if (total_length < 0) {
- return DUK_RET_RANGE_ERROR;
+ duk_int_t total_length_signed;
+ total_length_signed = duk_to_int(thr, 1);
+ if (total_length_signed < 0) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+ }
+ total_length = (duk_uint_t) total_length_signed;
}
- h_bufres = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
+ h_bufres = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
+ DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
DUK_ASSERT(h_bufres != NULL);
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length);
+ p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */
DUK_ASSERT(p != NULL);
- space_left = total_length;
+ space_left = (duk_size_t) total_length;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
+ DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- h_bufobj = duk__require_bufobj_value(ctx, 4);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ h_bufobj = duk__require_bufobj_value(thr, 4);
DUK_ASSERT(h_bufobj != NULL);
copy_size = h_bufobj->length;
@@ -23868,9 +28045,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
}
if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj),
+ (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
copy_size);
} else {
/* Just skip, leaving zeroes in the result. */
@@ -23879,24 +28056,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
p += copy_size;
space_left -= copy_size;
- duk_pop(ctx);
+ duk_pop(thr);
}
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
+ h_val = duk_known_hbuffer(thr, -1);
- duk__set_bufobj_buffer(ctx, h_bufres, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres);
+ duk__set_bufobj_buffer(thr, h_bufres, h_val);
+ h_bufres->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufres);
- duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
+ duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */
return 1; /* return h_bufres */
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23924,15 +28096,14 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
#define DUK__FLD_TYPEDARRAY (1 << 5)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
duk_small_int_t magic_typedarray;
duk_small_int_t endswap;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
duk_bool_t no_assert;
duk_int_t offset_signed;
duk_uint_t offset;
@@ -23941,15 +28112,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
duk_uint8_t *buf;
duk_double_union du;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -23961,12 +28129,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 1); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 1); /* 1=little endian */
#endif
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -23978,7 +28146,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 0);
+ offset_signed = duk_to_int(thr, 0);
offset = (duk_uint_t) offset_signed;
if (offset_signed < 0) {
goto fail_bounds;
@@ -23995,12 +28163,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
* takes into account the underlying buffer. This value will be
* potentially invalidated by any side effect.
*/
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
+ check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
(long) buffer_length, (long) check_length));
if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
} else {
/* Neutered. We could go into the switch-case safely with
* buf == NULL because check_length == 0. To avoid scanbuild
@@ -24019,9 +28187,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
}
tmp = buf[offset];
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24036,9 +28204,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP16(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24053,9 +28221,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24070,7 +28238,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
du.ui[0] = tmp;
}
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
}
case DUK__FLD_DOUBLE: {
@@ -24081,7 +28249,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
- duk_push_number(ctx, (duk_double_t) du.d);
+ duk_push_number(thr, (duk_double_t) du.d);
break;
}
case DUK__FLD_VARINT: {
@@ -24099,7 +28267,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
#endif
const duk_uint8_t *p;
- field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
+ field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */
if (field_bytelen < 1 || field_bytelen > 6) {
goto fail_field_length;
}
@@ -24135,11 +28303,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_signed) {
/* Shift to sign extend. */
- shift_tmp = 64 - (field_bytelen * 8);
+ shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
tmp = (tmp << shift_tmp) >> shift_tmp;
}
- duk_push_i64(ctx, tmp);
+ duk_push_i64(thr, tmp);
#else
highbyte = p[i];
if (magic_signed && (highbyte & 0x80) != 0) {
@@ -24157,7 +28325,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = (tmp * 256.0) + (duk_double_t) p[i];
}
- duk_push_number(ctx, tmp);
+ duk_push_number(thr, tmp);
#endif
break;
}
@@ -24175,30 +28343,23 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
/* Node.js return value for noAssert out-of-bounds reads is
* usually (but not always) NaN. Return NaN consistently.
*/
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
-
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
duk_small_int_t magic_typedarray;
duk_small_int_t endswap;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
duk_bool_t no_assert;
duk_int_t offset_signed;
duk_uint_t offset;
@@ -24208,16 +28369,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
duk_double_union du;
duk_int_t nbytes = 0;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
DUK_UNREF(magic_signed);
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -24229,13 +28387,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 2); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 2); /* 1=little endian */
#endif
- duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
+ duk_swap(thr, 0, 1); /* offset/value order different from Node.js */
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -24247,7 +28405,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
offset = (duk_uint_t) offset_signed;
/* We need 'nbytes' even for a failed offset; return value must be
@@ -24257,7 +28415,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
} else {
- nbytes = duk_get_int(ctx, 2);
+ nbytes = duk_get_int(thr, 2);
if (nbytes < 1 || nbytes > 6) {
goto fail_field_length;
}
@@ -24272,7 +28430,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
"magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
"endswap=%d",
- duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
+ duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert,
(unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
(int) (magic_signed >> 4), (int) endswap));
@@ -24280,18 +28438,18 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* the field type specific coercion below can't have side effects
* that would invalidate check_length.
*/
- duk_to_number(ctx, 0);
+ duk_to_number(thr, 0);
/* Update 'buffer_length' to be the effective, safe limit which
* takes into account the underlying buffer. This value will be
* potentially invalidated by any side effect.
*/
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
+ check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
(long) buffer_length, (long) check_length));
if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
} else {
/* Neutered. We could go into the switch-case safely with
* buf == NULL because check_length == 0. To avoid scanbuild
@@ -24308,7 +28466,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
goto fail_bounds;
}
/* sign doesn't matter when writing */
- buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0);
break;
}
case DUK__FLD_16BIT: {
@@ -24316,7 +28474,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 2U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint16_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP16(tmp);
}
@@ -24330,7 +28488,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint32_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP32(tmp);
}
@@ -24344,7 +28502,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
+ du.f[0] = (duk_float_t) duk_to_number(thr, 0);
if (endswap) {
tmp = du.ui[0];
tmp = DUK_BSWAP32(tmp);
@@ -24358,7 +28516,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 8U > check_length) {
goto fail_bounds;
}
- du.d = (duk_double_t) duk_to_number(ctx, 0);
+ du.d = (duk_double_t) duk_to_number(thr, 0);
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
@@ -24408,7 +28566,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
#if defined(DUK_USE_64BIT_OPS)
- tmp = (duk_int64_t) duk_to_number(ctx, 0);
+ tmp = (duk_int64_t) duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -24417,7 +28575,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
tmp = tmp >> 8; /* unnecessary shift for last byte */
} while (i != i_end);
#else
- tmp = duk_to_number(ctx, 0);
+ tmp = duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -24439,11 +28597,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
if (magic_typedarray) {
/* For TypedArrays 'undefined' return value is specified
- * by ES6 (matches V8).
+ * by ES2015 (matches V8).
*/
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
fail_neutered:
@@ -24459,28 +28617,154 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
}
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+/*
+ * Accessors for .buffer, .byteLength, .byteOffset
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) {
+ duk_hbufobj *h_res;
+
+ h_res = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ DUK_ASSERT(h_res != NULL);
+ DUK_UNREF(h_res);
+
+ duk__set_bufobj_buffer(thr, h_res, h_buf);
+ DUK_ASSERT_HBUFOBJ_VALID(h_res);
+ DUK_ASSERT(h_res->buf_prop == NULL);
+ return h_res;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer"));
+ (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj);
+ return 1;
+ } else {
+ if (h_bufobj->buf_prop == NULL &&
+ DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER &&
+ h_bufobj->buf != NULL) {
+ duk_hbufobj *h_arrbuf;
+
+ DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView"));
+ h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf);
+
+ if (h_bufobj->buf_prop == NULL) {
+ /* Must recheck buf_prop, in case ArrayBuffer
+ * alloc had a side effect which already filled
+ * it!
+ */
+
+ /* Set ArrayBuffer's .byteOffset and .byteLength based
+ * on the view so that Arraybuffer[view.byteOffset]
+ * matches view[0].
+ */
+ h_arrbuf->offset = 0;
+ DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */
+ h_arrbuf->length = h_bufobj->offset + h_bufobj->length;
+ DUK_ASSERT(h_arrbuf->buf_prop == NULL);
+
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
+ DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */
+ }
+
+ /* Left on stack; pushed for the second time below (OK). */
+ }
+ if (h_bufobj->buf_prop) {
+ duk_push_hobject(thr, h_bufobj->buf_prop);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ duk_push_uint(thr, 0);
+ } else {
+ /* If neutered must return 0; offset is zeroed during
+ * neutering.
+ */
+ duk_push_uint(thr, h_bufobj->offset);
+ }
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ duk_hbuffer *h_buf;
+
+ h_buf = (duk_hbuffer *) h_bufobj;
+ DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */
+ duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
+ } else {
+ /* If neutered must return 0; length is zeroed during
+ * neutering.
+ */
+ duk_push_uint(thr, h_bufobj->length);
+ }
+ return 1;
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+/* No .buffer getter without ArrayBuffer support. */
+#if 0
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
+ return 0;
+}
+#endif
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
+ duk_push_uint(thr, 0);
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
+ duk_hbuffer *h_buf;
+
+ /* XXX: helper? */
+ duk_push_this(thr);
+ h_buf = duk_require_hbuffer(thr, -1);
+ duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf));
+ return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#undef DUK__FLD_8BIT
-#undef DUK__FLD_16BIT
-#undef DUK__FLD_32BIT
-#undef DUK__FLD_FLOAT
-#undef DUK__FLD_DOUBLE
-#undef DUK__FLD_VARINT
-#undef DUK__FLD_BIGENDIAN
-#undef DUK__FLD_SIGNED
-#undef DUK__FLD_TYPEDARRAY
-#line 1 "duk_bi_date.c"
+/* automatic undefs */
+#undef DUK__BUFOBJ_FLAG_PROMOTE
+#undef DUK__BUFOBJ_FLAG_THROW
+#undef DUK__FLD_16BIT
+#undef DUK__FLD_32BIT
+#undef DUK__FLD_8BIT
+#undef DUK__FLD_BIGENDIAN
+#undef DUK__FLD_DOUBLE
+#undef DUK__FLD_FLOAT
+#undef DUK__FLD_SIGNED
+#undef DUK__FLD_TYPEDARRAY
+#undef DUK__FLD_VARINT
/*
* Date built-ins
*
@@ -24494,16 +28778,18 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */
/*
* Forward declarations
*/
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
-DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags);
+DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val);
+DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags);
/*
* Other file level defines
@@ -24544,7 +28830,7 @@ DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk
#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
#if 1
- /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py):
+ /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py):
* http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
*/
@@ -24571,7 +28857,6 @@ DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
#endif
};
-#undef DUK__YEAR
/*
* ISO 8601 subset parser.
@@ -24668,7 +28953,7 @@ DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
*/
};
-DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) {
duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -24708,7 +28993,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
goto reject;
}
- if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
+ if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) {
/* ignore millisecond fractions after 3 */
} else {
accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
@@ -24716,7 +29001,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
} else {
duk_uint_fast32_t match_val;
- duk_small_int_t sep_idx;
+ duk_small_uint_t sep_idx;
if (ndigits <= 0) {
goto reject;
@@ -24840,7 +29125,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -24863,7 +29148,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
* UTC and '2012/01/01' as local time.
*/
-DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) {
/* XXX: there is a small risk here: because the ISO 8601 parser is
* very loose, it may end up parsing some datetime values which
* would be better parsed with a platform specific parser.
@@ -24872,7 +29157,7 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
DUK_ASSERT(str != NULL);
DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
- if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
+ if (duk__parse_string_iso8601_subset(thr, str) != 0) {
return 1;
}
@@ -24882,14 +29167,14 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
* - Don't push anything on stack and return 0
*/
- if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
+ if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) {
return 1;
}
#else
/* No platform-specific parsing, this is not an error. */
#endif
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
@@ -25082,9 +29367,9 @@ DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_
return (duk_double_t) day_num + day;
}
-/* Split time value into parts. The time value is assumed to be an internal
- * one, i.e. finite, no fractions. Possible local time adjustment has already
- * been applied when reading the time value.
+/* Split time value into parts. The time value may contain fractions (it may
+ * come from duk_time_to_components() API call) which are truncated. Possible
+ * local time adjustment has already been applied when reading the time value.
*/
DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d1, d2;
@@ -25103,7 +29388,8 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
duk_small_int_t arridx;
DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
+ d = DUK_FLOOR(d); /* remove fractions if present */
+ DUK_ASSERT(DUK_FLOOR(d) == d);
/* The timevalue must be in valid Ecmascript range, but since a local
* time offset can be applied, we need to allow a +/- 24h leeway to
@@ -25113,7 +29399,7 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
- /* these computations are guaranteed to be exact for the valid
+ /* These computations are guaranteed to be exact for the valid
* E5 time value range, assuming milliseconds without fractions.
*/
d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
@@ -25369,21 +29655,20 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dpar
* internal time value. At the end, stack is: [ ... this timeval ].
* Returns the time value. Local time adjustment is done if requested.
*/
-DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
duk_hobject *h;
duk_double_t d;
duk_int_t tzoffset = 0;
- duk_push_this(ctx);
- h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
+ duk_push_this(thr);
+ h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */
if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
DUK_ERROR_TYPE(thr, "expected Date");
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- d = duk_to_number(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ d = duk_to_number_m1(thr);
+ duk_pop(thr);
if (DUK_ISNAN(d)) {
if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
@@ -25411,23 +29696,23 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk
return d;
}
-DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
- return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
+DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) {
+ return duk__push_this_get_timeval_tzoffset(thr, flags, NULL);
}
/* Set timeval to 'this' from dparts, push the new time value onto the
* value stack and return 1 (caller can then tail call us). Expects
* the value stack to contain 'this' on the stack top.
*/
-DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d;
/* [ ... this ] */
d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
- duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
- duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
+ duk_push_number(thr, d); /* -> [ ... this timeval_new ] */
+ duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE);
/* stack top: new time value, return 1 to allow tail calls */
return 1;
@@ -25457,13 +29742,23 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
/* tzoffset seconds are dropped; 16 bits suffice for
* time offset in minutes
*/
+ const char *fmt;
+ duk_small_int_t tmp, arg_hours, arg_minutes;
+
if (tzoffset >= 0) {
- duk_small_int_t tmp = tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = tzoffset;
+ fmt = "+%02d:%02d";
} else {
- duk_small_int_t tmp = -tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = -tzoffset;
+ fmt = "-%02d:%02d";
}
+ tmp = tmp / 60;
+ arg_hours = tmp / 60;
+ arg_minutes = tmp % 60;
+ DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */
+ arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */
+
+ DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes);
tzstr[sizeof(tzstr) - 1] = (char) 0;
} else {
tzstr[0] = DUK_ASC_UC_Z;
@@ -25494,7 +29789,7 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
* internal time value, and format date and/or time in a few formats.
* Return value allows tail calls.
*/
-DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
@@ -25503,9 +29798,9 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
DUK_UNREF(rc); /* unreferenced with some options */
- d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
+ d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset);
if (DUK_ISNAN(d)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -25526,7 +29821,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* - Don't push anything and return 0
*/
- rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
+ rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags);
if (rc != 0) {
return 1;
}
@@ -25541,7 +29836,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* is shared.
*/
duk__format_parts_iso8601(parts, tzoffset, flags, buf);
- duk_push_string(ctx, (const char *) buf);
+ duk_push_string(thr, (const char *) buf);
return 1;
}
@@ -25550,7 +29845,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* local time), push a specified component as a return value to the
* value stack and return 1 (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
+DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
@@ -25558,9 +29853,9 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
- d = duk__push_this_get_timeval(ctx, flags_and_idx);
+ d = duk__push_this_get_timeval(thr, flags_and_idx);
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -25571,7 +29866,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* only in certain cases. The legacy getYear() getter applies -1900
* unconditionally.
*/
- duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
+ duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
return 1;
}
@@ -25582,7 +29877,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* new time value as a return value to the value stack and return 1
* (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
+DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
@@ -25591,8 +29886,8 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
duk_small_uint_t idx_first, idx;
duk_small_uint_t i;
- nargs = duk_get_top(ctx);
- d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
+ nargs = duk_get_top(thr);
+ d = duk__push_this_get_timeval(thr, flags_and_maxnargs);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISFINITE(d)) {
@@ -25647,10 +29942,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
- duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
+ duk__twodigit_year_fixup(thr, (duk_idx_t) i);
}
- dparts[idx] = duk_to_number(ctx, i);
+ dparts[idx] = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Day-of-month is one-based in the API, but zero-based
@@ -25670,10 +29965,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
* for part setters.
*/
if (DUK_ISFINITE(d)) {
- return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
+ return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs);
} else {
/* Internal timevalue is already NaN, so don't touch it. */
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
}
@@ -25681,7 +29976,7 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
* 1900 and replace value at idx_val.
*/
-DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
+DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) {
duk_double_t d;
/* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
@@ -25689,25 +29984,25 @@ DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
*/
/* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
- duk_to_number(ctx, idx_val);
- if (duk_is_nan(ctx, idx_val)) {
+ duk_to_number(thr, idx_val);
+ if (duk_is_nan(thr, idx_val)) {
return;
}
- duk_dup(ctx, idx_val);
- duk_to_int(ctx, -1);
- d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
+ duk_dup(thr, idx_val);
+ duk_to_int(thr, -1);
+ d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */
if (d >= 0.0 && d <= 99.0) {
d += 1900.0;
- duk_push_number(ctx, d);
- duk_replace(ctx, idx_val);
+ duk_push_number(thr, d);
+ duk_replace(thr, idx_val);
}
- duk_pop(ctx);
+ duk_pop(thr);
}
/* Set datetime parts from stack arguments, defaulting any missing values.
* Day-of-week is not set; it is not required when setting the time value.
*/
-DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
+DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) {
duk_double_t d;
duk_small_uint_t i;
duk_small_uint_t idx;
@@ -25715,7 +30010,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Causes a ToNumber() coercion, but doesn't break coercion order since
* year is coerced first anyway.
*/
- duk__twodigit_year_fixup(ctx, 0);
+ duk__twodigit_year_fixup(thr, 0);
/* There are at most 7 args, but we use 8 here so that also
* DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
@@ -25725,7 +30020,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Note: rely on index ordering */
idx = DUK_DATE_IDX_YEAR + i;
if ((duk_idx_t) i < nargs) {
- d = duk_to_number(ctx, (duk_idx_t) i);
+ d = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Convert day from one-based to zero-based (internal). This may
* cause the day part to be negative, which is OK.
@@ -25750,27 +30045,6 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
}
/*
- * Helper to format a time value into caller buffer, used by logging.
- * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
- */
-
-DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
-
- duk_bi_date_timeval_to_parts(timeval,
- parts,
- NULL,
- DUK_DATE_FLAG_ONEBASED);
-
- duk__format_parts_iso8601(parts,
- 0 /*tzoffset*/,
- DUK_DATE_FLAG_TOSTRING_DATE |
- DUK_DATE_FLAG_TOSTRING_TIME |
- DUK_DATE_FLAG_SEP_T /*flags*/,
- out_buf);
-}
-
-/*
* Indirect magic value lookup for Date methods.
*
* Date methods don't put their control flags into the function magic value
@@ -25903,69 +30177,73 @@ static duk_uint16_t duk__date_magics[] = {
DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
};
-DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
- duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
- DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
+DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) {
+ duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr);
+ DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
return (duk_small_uint_t) duk__date_magics[magicidx];
}
+#if defined(DUK_USE_DATE_BUILTIN)
/*
* Constructor calls
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
- duk_bool_t is_cons = duk_is_constructor_call(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
+ duk_bool_t is_cons = duk_is_constructor_call(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
- DUK_BIDX_DATE_PROTOTYPE);
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
+ DUK_BIDX_DATE_PROTOTYPE);
/* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
* is mutable.
*/
if (nargs == 0 || !is_cons) {
- d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr));
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
if (!is_cons) {
/* called as a normal function: return new Date().toString() */
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
} else if (nargs == 1) {
- duk_to_primitive(ctx, 0, DUK_HINT_NONE);
- if (duk_is_string(ctx, 0)) {
- duk__parse_string(ctx, duk_to_string(ctx, 0));
- duk_replace(ctx, 0); /* may be NaN */
- }
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ const char *str;
+ duk_to_primitive(thr, 0, DUK_HINT_NONE);
+ str = duk_get_string_notsymbol(thr, 0);
+ if (str) {
+ duk__parse_string(thr, str);
+ duk_replace(thr, 0); /* may be NaN */
+ }
+ d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
return 1;
}
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
/* Parts are in local time, convert when setting. */
- (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
- duk_pop(ctx); /* -> [ ... this ] */
+ (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
+ duk_pop(thr); /* -> [ ... this ] */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
- return duk__parse_string(ctx, duk_to_string(ctx, 0));
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) {
+ return duk__parse_string(thr, duk_to_string(thr, 0));
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -25974,21 +30252,21 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
*/
if (nargs < 2) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
duk_double_t d;
- d = DUK_USE_DATE_GET_NOW(ctx);
+ d = duk_time_get_ecmascript_time_nofrac(thr);
DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -26026,44 +30304,44 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
* toISOString() requires a RangeError for invalid date values.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
- duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
- return duk__to_string_helper(ctx, flags);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) {
+ duk_small_uint_t flags = duk__date_get_indirect_magic(thr);
+ return duk__to_string_helper(thr, flags);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) {
/* This native function is also used for Date.prototype.getTime()
* as their behavior is identical.
*/
- duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
+ duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) {
/* Note: toJSON() is a generic function which works even if 'this'
* is not a Date. The sole argument is ignored.
*/
- duk_push_this(ctx);
- duk_to_object(ctx, -1);
+ duk_push_this(thr);
+ duk_to_object(thr, -1);
- duk_dup_top(ctx);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- if (duk_is_number(ctx, -1)) {
- duk_double_t d = duk_get_number(ctx, -1);
+ duk_dup_top(thr);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
+ if (duk_is_number(thr, -1)) {
+ duk_double_t d = duk_get_number(thr, -1);
if (!DUK_ISFINITE(d)) {
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop(thr);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
- duk_dup(ctx, -2); /* -> [ O toIsoString O ] */
- duk_call_method(ctx, 0);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING);
+ duk_dup_m2(thr); /* -> [ O toIsoString O ] */
+ duk_call_method(thr, 0);
return 1;
}
@@ -26108,12 +30386,12 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
* function (duk_bi_date_prototype_value_of).
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
- return duk__get_part_helper(ctx, flags_and_idx);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr);
+ return duk__get_part_helper(thr, flags_and_idx);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) {
/*
* Return (t - LocalTime(t)) in minutes:
*
@@ -26132,14 +30410,14 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
duk_int_t tzoffset;
/* Note: DST adjustment is determined using UTC time. */
- d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
+ d = duk__push_this_get_timeval(thr, 0 /*flags*/);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
DUK_ASSERT(DUK_ISFINITE(d));
tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
- duk_push_int(ctx, -tzoffset / 60);
+ duk_push_int(thr, -tzoffset / 60);
}
return 1;
}
@@ -26193,30 +30471,80 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
* the year will be set regardless of actual argument count.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
- return duk__set_part_helper(ctx, flags_and_maxnargs);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr);
+ return duk__set_part_helper(thr, flags_and_maxnargs);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
duk_double_t d;
- (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
+ (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */
+ d = duk__timeclip(duk_to_number(thr, 0));
+ duk_push_number(thr, d);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
return 1;
}
-#line 1 "duk_bi_date_unix.c"
+
+#endif /* DUK_USE_DATE_BUILTIN */
+
+/* automatic undefs */
+#undef DUK__CF_ACCEPT
+#undef DUK__CF_ACCEPT_NUL
+#undef DUK__CF_NEG
+#undef DUK__DPRINT_DPARTS
+#undef DUK__DPRINT_PARTS
+#undef DUK__DPRINT_PARTS_AND_DPARTS
+#undef DUK__LOCAL_TZOFFSET_MAXITER
+#undef DUK__NUM_ISO8601_PARSER_PARTS
+#undef DUK__PACK_RULE
+#undef DUK__PI_DAY
+#undef DUK__PI_HOUR
+#undef DUK__PI_MILLISECOND
+#undef DUK__PI_MINUTE
+#undef DUK__PI_MONTH
+#undef DUK__PI_SECOND
+#undef DUK__PI_TZHOUR
+#undef DUK__PI_TZMINUTE
+#undef DUK__PI_YEAR
+#undef DUK__PM_DAY
+#undef DUK__PM_HOUR
+#undef DUK__PM_MILLISECOND
+#undef DUK__PM_MINUTE
+#undef DUK__PM_MONTH
+#undef DUK__PM_SECOND
+#undef DUK__PM_TZHOUR
+#undef DUK__PM_TZMINUTE
+#undef DUK__PM_YEAR
+#undef DUK__RULE_MASK_PART_SEP
+#undef DUK__SI_COLON
+#undef DUK__SI_MINUS
+#undef DUK__SI_NUL
+#undef DUK__SI_PERIOD
+#undef DUK__SI_PLUS
+#undef DUK__SI_SPACE
+#undef DUK__SI_T
+#undef DUK__SI_Z
+#undef DUK__SM_COLON
+#undef DUK__SM_MINUS
+#undef DUK__SM_NUL
+#undef DUK__SM_PERIOD
+#undef DUK__SM_PLUS
+#undef DUK__SM_SPACE
+#undef DUK__SM_T
+#undef DUK__SM_Z
+#undef DUK__UNPACK_RULE
+#undef DUK__WEEKDAY_MOD_ADDER
+#undef DUK__YEAR
/*
* Unix-like Date providers
*
* Generally useful Unix / POSIX / ANSI Date providers.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* The necessary #includes are in place in duk_config.h. */
@@ -26228,18 +30556,18 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
struct timeval tv;
duk_double_t d;
if (gettimeofday(&tv, NULL) != 0) {
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_D(DUK_DPRINT("gettimeofday() failed"));
+ return 0.0;
}
+ /* As of Duktape 2.2.0 allow fractions. */
d = ((duk_double_t) tv.tv_sec) * 1000.0 +
- ((duk_double_t) (tv.tv_usec / 1000));
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
+ ((duk_double_t) tv.tv_usec) / 1000.0;
return d;
}
@@ -26247,23 +30575,26 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_TIME)
/* Not a very good provider: only full seconds are available. */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
time_t t;
- DUK_UNREF(ctx);
t = time(NULL);
+ if (t == (time_t) -1) {
+ DUK_D(DUK_DPRINT("time() failed"));
+ return 0.0;
+ }
return ((duk_double_t) t) * 1000.0;
}
#endif /* DUK_USE_DATE_NOW_TIME */
-#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
+#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
time_t t, t1, t2;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
struct tm tms[2];
-#ifdef DUK_USE_DATE_TZO_GMTIME
+#if defined(DUK_USE_DATE_TZO_GMTIME)
struct tm *tm_ptr;
#endif
@@ -26346,6 +30677,9 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#if defined(DUK_USE_DATE_TZO_GMTIME_R)
(void) gmtime_r(&t, &tms[0]);
(void) localtime_r(&t, &tms[1]);
+#elif defined(DUK_USE_DATE_TZO_GMTIME_S)
+ (void) gmtime_s(&t, &tms[0]);
+ (void) localtime_s(&t, &tms[1]);
#elif defined(DUK_USE_DATE_TZO_GMTIME)
tm_ptr = gmtime(&t);
DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
@@ -26380,7 +30714,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
* an mktime() error return is the cast above. See e.g.:
* http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
*/
- goto error;
+ goto mktime_error;
}
DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
@@ -26396,7 +30730,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#endif
return (duk_int_t) difftime(t2, t1);
- error:
+ mktime_error:
/* XXX: return something more useful, so that caller can throw? */
DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
return 0;
@@ -26404,12 +30738,12 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#endif /* DUK_USE_DATE_TZO_GMTIME */
#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
struct tm tm;
time_t t;
char buf[DUK__STRPTIME_BUF_SIZE];
- /* copy to buffer with spare to avoid Valgrind gripes from strptime */
+ /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
DUK_ASSERT(str != NULL);
DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
@@ -26429,7 +30763,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
+ duk_push_number(thr, ((duk_double_t) t) * 1000.0);
return 1;
}
}
@@ -26439,7 +30773,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
#endif /* DUK_USE_DATE_PRS_STRPTIME */
#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
struct tm tm;
duk_small_int_t rc;
time_t t;
@@ -26456,7 +30790,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, (duk_double_t) t);
+ duk_push_number(thr, (duk_double_t) t);
return 1;
}
}
@@ -26466,7 +30800,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
#endif /* DUK_USE_DATE_PRS_GETDATE */
#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
+DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
char buf[DUK__STRFTIME_BUF_SIZE];
struct tm tm;
const char *fmt;
@@ -26485,7 +30819,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
* supporting a large time range (the full Ecmascript range).
*/
if (sizeof(time_t) < 8 &&
- (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
+ (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
/* be paranoid for 32-bit time values (even avoiding negative ones) */
return 0;
}
@@ -26512,14 +30846,27 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
(void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
- duk_push_string(ctx, buf);
+ duk_push_string(thr, buf);
return 1;
}
#endif /* DUK_USE_DATE_FMT_STRFTIME */
-#undef DUK__STRPTIME_BUF_SIZE
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
+ } else {
+ DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
+ return 0.0;
+ }
+}
+#endif
+
+/* automatic undefs */
#undef DUK__STRFTIME_BUF_SIZE
-#line 1 "duk_bi_date_windows.c"
+#undef DUK__STRPTIME_BUF_SIZE
/*
* Windows Date providers
*
@@ -26528,7 +30875,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
* - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* The necessary #includes are in place in duk_config.h. */
@@ -26544,6 +30891,12 @@ DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEG
res->HighPart = ft.dwHighDateTime;
}
}
+
+DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
+ res->LowPart = ft->dwLowDateTime;
+ res->HighPart = ft->dwHighDateTime;
+}
+
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
DUK_MEMZERO((void *) st, sizeof(*st));
st->wYear = 1970;
@@ -26557,30 +30910,52 @@ DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
}
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
-#ifdef DUK_USE_DATE_NOW_WINDOWS
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
+#if defined(DUK_USE_DATE_NOW_WINDOWS)
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
*/
SYSTEMTIME st1, st2;
ULARGE_INTEGER tmp1, tmp2;
- DUK_UNREF(ctx);
-
GetSystemTime(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
- /* Difference is in 100ns units, convert to milliseconds w/o fractions */
- return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0. This is only theoretical because
+ * SYSTEMTIME is limited to milliseconds.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
+ /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
+ * for more accuracy.
+ */
+ FILETIME ft1;
+ SYSTEMTIME st2;
+ ULARGE_INTEGER tmp1, tmp2;
+
+ GetSystemTimePreciseAsFileTime(&ft1);
+ duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
+
+ duk__set_systime_jan1970(&st2);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
+
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
+}
+#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
SYSTEMTIME st3;
@@ -26615,258 +30990,152 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
/* Positive if local time ahead of UTC. */
- return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
+ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */
-#line 1 "duk_bi_duktape.c"
-/*
- * Duktape built-ins
- *
- * Size optimization note: it might seem that vararg multipurpose functions
- * like fin(), enc(), and dec() are not very size optimal, but using a single
- * user-visible Ecmascript function saves a lot of run-time footprint; each
- * Function instance takes >100 bytes. Using a shared native helper and a
- * 'magic' value won't save much if there are multiple Function instances
- * anyway.
- */
-/* include removed: duk_internal.h */
+#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
+ SYSTEMTIME st1;
+ SYSTEMTIME st2;
+ FILETIME ft1;
+ FILETIME ft2;
+ ULARGE_INTEGER tmp1;
+ ULARGE_INTEGER tmp2;
-/* Raw helper to extract internal information / statistics about a value.
- * The return values are version specific and must not expose anything
- * that would lead to security issues (e.g. exposing compiled function
- * 'data' buffer might be an issue). Currently only counts and sizes and
- * such are given so there should not be a security impact.
- */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_heaphdr *h;
- duk_int_t i, n;
+ /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
+ * but without accounting for daylight savings time. Use this on
+ * Windows platforms (like Durango) that don't support the
+ * SystemTimeToTzSpecificLocalTime() call.
+ */
- DUK_UNREF(thr);
+ /* current time not needed for this computation */
+ DUK_UNREF(d);
- /* result array */
- duk_push_array(ctx); /* -> [ val arr ] */
+ duk__set_systime_jan1970(&st1);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
- /* type tag (public) */
- duk_push_int(ctx, duk_get_type(ctx, 0));
+ ft1.dwLowDateTime = tmp1.LowPart;
+ ft1.dwHighDateTime = tmp1.HighPart;
+ FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
- /* address */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL); /* because arg count is 1 */
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- h = DUK_TVAL_GET_HEAPHDR(tv);
- duk_push_pointer(ctx, (void *) h);
- } else {
- /* internal type tag */
- duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
- goto done;
- }
- DUK_ASSERT(h != NULL);
+ FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
- /* refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
-#else
- duk_push_undefined(ctx);
-#endif
+ return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
+}
+#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
+ LARGE_INTEGER count, freq;
- /* heaphdr size and additional allocation size, followed by
- * type specific stuff (with varying value count)
+ /* There are legacy issues with QueryPerformanceCounter():
+ * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
+ * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
+ *
+ * We avoid these by enabling QPC by default only for Vista or later.
*/
- switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING: {
- duk_hstring *h_str = (duk_hstring *) h;
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
- break;
- }
- case DUK_HTYPE_OBJECT: {
- duk_hobject *h_obj = (duk_hobject *) h;
- duk_small_uint_t hdr_size;
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
- } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject);
-#endif
- } else {
- hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
- }
- duk_push_uint(ctx, (duk_uint_t) hdr_size);
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
- /* Note: e_next indicates the number of gc-reachable entries
- * in the entry part, and also indicates the index where the
- * next new property would be inserted. It does *not* indicate
- * the number of non-NULL keys present in the object. That
- * value could be counted separately but requires a pass through
- * the key list.
+
+ if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
+ /* XXX: QueryPerformanceFrequency() can be cached */
+ return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
+ } else {
+ /* MSDN: "On systems that run Windows XP or later, the function
+ * will always succeed and will thus never return zero."
+ * Provide minimal error path just in case user enables this
+ * feature in pre-XP Windows.
*/
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
- if (h_data) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
- } else {
- duk_push_uint(ctx, 0);
- }
- }
- break;
+ return 0.0;
}
- case DUK_HTYPE_BUFFER: {
- duk_hbuffer *h_buf = (duk_hbuffer *) h;
- if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
- if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
- } else {
- /* When alloc_size == 0 the second allocation may not
- * actually exist.
- */
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
- }
- duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
- } else {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
- }
- break;
+}
+#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
+/*
+ * Duktape built-ins
+ *
+ * Size optimization note: it might seem that vararg multipurpose functions
+ * like fin(), enc(), and dec() are not very size optimal, but using a single
+ * user-visible Ecmascript function saves a lot of run-time footprint; each
+ * Function instance takes >100 bytes. Using a shared native helper and a
+ * 'magic' value won't save much if there are multiple Function instances
+ * anyway.
+ */
- }
- }
+/* #include duk_internal.h -> already included */
- done:
- /* set values into ret array */
- /* XXX: primitive to make array from valstack slice */
- n = duk_get_top(ctx);
- for (i = 2; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, 1, i - 2);
- }
- duk_dup(ctx, 1);
+#if defined(DUK_USE_DUKTAPE_BUILTIN)
+
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
+ duk_inspect_value(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_uint_fast32_t pc;
- duk_uint_fast32_t line;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
duk_int_t level;
- /* -1 = top callstack entry, callstack[callstack_top - 1]
- * -callstack_top = bottom callstack entry, callstack[0]
- */
- level = duk_to_int(ctx, 0);
- if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
- return 0;
- }
- DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
- act = thr->callstack + thr->callstack_top + level;
-
- duk_push_object(ctx);
-
- duk_push_tval(ctx, &act->tv_func);
-
- /* Relevant PC is just before current one because PC is
- * post-incremented. This should match what error augment
- * code does.
- */
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_push_uint(ctx, (duk_uint_t) pc);
-
-#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -2, pc);
-#else
- line = 0;
-#endif
- duk_push_uint(ctx, (duk_uint_t) line);
-
- /* Providing access to e.g. act->lex_env would be dangerous: these
- * internal structures must never be accessible to the application.
- * Duktape relies on them having consistent data, and this consistency
- * is only asserted for, not checked for.
- */
-
- /* [ level obj func pc line ] */
-
- /* XXX: version specific array format instead? */
- duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
- duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
+ level = duk_to_int(thr, 0);
+ duk_inspect_callstack_entry(thr, level);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
duk_small_uint_t flags;
- duk_bool_t rc;
- flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
- rc = duk_heap_mark_and_sweep(thr->heap, flags);
+ flags = (duk_small_uint_t) duk_get_uint(thr, 0);
+ duk_heap_mark_and_sweep(thr->heap, flags);
/* XXX: Not sure what the best return value would be in the API.
- * Return a boolean for now. Note that rc == 0 is success (true).
+ * Return true for now.
*/
- duk_push_boolean(ctx, !rc);
+ duk_push_true(thr);
return 1;
-#else
- DUK_UNREF(ctx);
- return 0;
-#endif
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
- (void) duk_require_hobject(ctx, 0);
- if (duk_get_top(ctx) >= 2) {
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
+ (void) duk_require_hobject(thr, 0);
+ if (duk_get_top(thr) >= 2) {
/* Set: currently a finalizer is disabled by setting it to
* undefined; this does not remove the property at the moment.
* The value could be type checked to be either a function
* or something else; if something else, the property could
- * be deleted.
+ * be deleted. Must use duk_set_finalizer() to keep
+ * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
*/
- duk_set_top(ctx, 2);
- (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+ duk_set_top(thr, 2);
+ duk_set_finalizer(thr, 0);
return 0;
} else {
/* Get. */
- DUK_ASSERT(duk_get_top(ctx) == 1);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+ DUK_ASSERT(duk_get_top(thr) == 1);
+ duk_get_finalizer(thr, 0);
return 1;
}
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
+ duk_set_top(thr, 2);
+ duk_base64_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -26874,9 +31143,9 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -26884,49 +31153,46 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
#endif
} else {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
+ duk_set_top(thr, 2);
+ duk_base64_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
#endif
} else {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
@@ -26935,19 +31201,556 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
* Compact an object
*/
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 1);
- duk_compact(ctx, 0);
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 1);
+ duk_compact(thr, 0);
return 1; /* return the argument object */
}
-#line 1 "duk_bi_error.c"
+
+#endif /* DUK_USE_DUKTAPE_BUILTIN */
+/*
+ * WHATWG Encoding API built-ins
+ *
+ * API specification: https://encoding.spec.whatwg.org/#api
+ * Web IDL: https://www.w3.org/TR/WebIDL/
+ */
+
+/* #include duk_internal.h -> already included */
+
+/*
+ * Data structures for encoding/decoding
+ */
+
+typedef struct {
+ duk_uint8_t *out; /* where to write next byte(s) */
+ duk_codepoint_t lead; /* lead surrogate */
+} duk__encode_context;
+
+typedef struct {
+ /* UTF-8 decoding state */
+ duk_codepoint_t codepoint; /* built up incrementally */
+ duk_uint8_t upper; /* max value of next byte (decode error otherwise) */
+ duk_uint8_t lower; /* min value of next byte (ditto) */
+ duk_uint8_t needed; /* how many more bytes we need */
+ duk_uint8_t bom_handled; /* BOM seen or no longer expected */
+
+ /* Decoder configuration */
+ duk_uint8_t fatal;
+ duk_uint8_t ignore_bom;
+} duk__decode_context;
+
+/* The signed duk_codepoint_t type is used to signal a decoded codepoint
+ * (>= 0) or various other states using negative values.
+ */
+#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */
+#define DUK__CP_ERROR (-2) /* decoding error */
+#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */
+
+/*
+ * Raw helpers for encoding/decoding
+ */
+
+/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
+DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
+ *ptr++ = 0xef;
+ *ptr++ = 0xbf;
+ *ptr++ = 0xbd;
+ return ptr;
+}
+
+DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
+ /* (Re)init the decoding state of 'dec_ctx' but leave decoder
+ * configuration fields untouched.
+ */
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->upper = 0xbf;
+ dec_ctx->lower = 0x80;
+ dec_ctx->needed = 0;
+ dec_ctx->bom_handled = 0;
+}
+
+DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
+ /*
+ * UTF-8 algorithm based on the Encoding specification:
+ * https://encoding.spec.whatwg.org/#utf-8-decoder
+ *
+ * Two main states: decoding initial byte vs. decoding continuation
+ * bytes. Shortest length encoding is validated by restricting the
+ * allowed range of first continuation byte using 'lower' and 'upper'.
+ */
+
+ if (dec_ctx->needed == 0) {
+ /* process initial byte */
+ if (x <= 0x7f) {
+ /* U+0000-U+007F, 1 byte (ASCII) */
+ return (duk_codepoint_t) x;
+ } else if (x >= 0xc2 && x <= 0xdf) {
+ /* U+0080-U+07FF, 2 bytes */
+ dec_ctx->needed = 1;
+ dec_ctx->codepoint = x & 0x1f;
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ return DUK__CP_CONTINUE;
+ } else if (x >= 0xe0 && x <= 0xef) {
+ /* U+0800-U+FFFF, 3 bytes */
+ if (x == 0xe0) {
+ dec_ctx->lower = 0xa0;
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ } else if (x == 0xed) {
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ dec_ctx->upper = 0x9f;
+ }
+ dec_ctx->needed = 2;
+ dec_ctx->codepoint = x & 0x0f;
+ return DUK__CP_CONTINUE;
+ } else if (x >= 0xf0 && x <= 0xf4) {
+ /* U+010000-U+10FFFF, 4 bytes */
+ if (x == 0xf0) {
+ dec_ctx->lower = 0x90;
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ } else if (x == 0xf4) {
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ dec_ctx->upper = 0x8f;
+ }
+ dec_ctx->needed = 3;
+ dec_ctx->codepoint = x & 0x07;
+ return DUK__CP_CONTINUE;
+ } else {
+ /* not a legal initial byte */
+ return DUK__CP_ERROR;
+ }
+ } else {
+ /* process continuation byte */
+ if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
+ dec_ctx->lower = 0x80;
+ dec_ctx->upper = 0xbf;
+ dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
+ if (--dec_ctx->needed > 0) {
+ /* need more bytes */
+ return DUK__CP_CONTINUE;
+ } else {
+ /* got a codepoint */
+ duk_codepoint_t ret;
+ DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */
+ ret = dec_ctx->codepoint;
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->needed = 0;
+ return ret;
+ }
+ } else {
+ /* We just encountered an illegal UTF-8 continuation byte. This might
+ * be the initial byte of the next character; if we return a plain
+ * error status and the decoder is in replacement mode, the character
+ * will be masked. We still need to alert the caller to the error
+ * though.
+ */
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->needed = 0;
+ dec_ctx->lower = 0x80;
+ dec_ctx->upper = 0xbf;
+ return DUK__CP_RETRY;
+ }
+ }
+}
+
+#if defined(DUK_USE_ENCODING_BUILTINS)
+DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
+ duk__encode_context *enc_ctx;
+
+ DUK_ASSERT(codepoint >= 0);
+ enc_ctx = (duk__encode_context *) udata;
+ DUK_ASSERT(enc_ctx != NULL);
+
+#if !defined(DUK_USE_PREFER_SIZE)
+ if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
+ /* Fast path for ASCII. */
+ *enc_ctx->out++ = (duk_uint8_t) codepoint;
+ return;
+ }
+#endif
+
+ if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
+ /* cannot legally encode in UTF-8 */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
+ if (codepoint <= 0xdbffL) {
+ /* high surrogate */
+ duk_codepoint_t prev_lead = enc_ctx->lead;
+ enc_ctx->lead = codepoint;
+ if (prev_lead == 0x0000L) {
+ /* high surrogate, no output */
+ return;
+ } else {
+ /* consecutive high surrogates, consider first one unpaired */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ }
+ } else {
+ /* low surrogate */
+ if (enc_ctx->lead != 0x0000L) {
+ codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
+ enc_ctx->lead = 0x0000L;
+ } else {
+ /* unpaired low surrogate */
+ DUK_ASSERT(enc_ctx->lead == 0x0000L);
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ }
+ }
+ } else {
+ if (enc_ctx->lead != 0x0000L) {
+ /* unpaired high surrogate: emit replacement character and the input codepoint */
+ enc_ctx->lead = 0x0000L;
+ enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
+ }
+ }
+
+ /* Codepoint may be original input, a decoded surrogate pair, or may
+ * have been replaced with U+FFFD.
+ */
+ enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
+}
+#endif /* DUK_USE_ENCODING_BUILTINS */
+
+/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
+ * decoder.
+ */
+DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
+ const duk_uint8_t *input;
+ duk_size_t len = 0;
+ duk_size_t len_tmp;
+ duk_bool_t stream = 0;
+ duk_codepoint_t codepoint;
+ duk_uint8_t *output;
+ const duk_uint8_t *in;
+ duk_uint8_t *out;
+
+ DUK_ASSERT(dec_ctx != NULL);
+
+ /* Careful with input buffer pointer: any side effects involving
+ * code execution (e.g. getters, coercion calls, and finalizers)
+ * may cause a resize and invalidate a pointer we've read. This
+ * is why the pointer is actually looked up at the last minute.
+ * Argument validation must still happen first to match WHATWG
+ * required side effect order.
+ */
+
+ if (duk_is_undefined(thr, 0)) {
+ duk_push_fixed_buffer_nozero(thr, 0);
+ duk_replace(thr, 0);
+ }
+ (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */
+
+ if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
+ DUK_TYPE_MASK_NULL |
+ DUK_TYPE_MASK_NONE)) {
+ /* Use defaults, treat missing value like undefined. */
+ } else {
+ duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
+ DUK_TYPE_MASK_NULL |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER |
+ DUK_TYPE_MASK_OBJECT);
+ if (duk_get_prop_string(thr, 1, "stream")) {
+ stream = duk_to_boolean(thr, -1);
+ }
+ }
+
+ /* Allowance is 3*len in the general case because all bytes may potentially
+ * become U+FFFD. If the first byte completes a non-BMP codepoint it will
+ * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
+ * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because
+ * the 4->6 expansion is well under the 3x allowance.
+ *
+ * XXX: As with TextEncoder, need a better buffer allocation strategy here.
+ */
+ if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ }
+ output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
+
+ input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
+ DUK_ASSERT(input != NULL || len == 0);
+ if (DUK_UNLIKELY(len != len_tmp)) {
+ /* Very unlikely but possible: source buffer was resized by
+ * a side effect when fixed buffer was pushed. Output buffer
+ * may not be large enough to hold output, so just fail if
+ * length has changed.
+ */
+ DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
+ goto fail_type;
+ }
+
+ /* From this point onwards it's critical that no side effect occur
+ * which may disturb 'input': finalizer execution, property accesses,
+ * active coercions, etc. Even an allocation related mark-and-sweep
+ * may affect the pointer because it may trigger a pending finalizer.
+ */
+
+ in = input;
+ out = output;
+ while (in < input + len) {
+ codepoint = duk__utf8_decode_next(dec_ctx, *in++);
+ if (codepoint < 0) {
+ if (codepoint == DUK__CP_CONTINUE) {
+ continue;
+ }
+
+ /* Decoding error with or without retry. */
+ DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
+ if (codepoint == DUK__CP_RETRY) {
+ --in; /* retry last byte */
+ }
+ /* replacement mode: replace with U+FFFD */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ if (dec_ctx->fatal) {
+ /* fatal mode: throw a TypeError */
+ goto fail_type;
+ }
+ /* Continue with 'codepoint', Unicode replacement. */
+ }
+ DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
+
+ if (!dec_ctx->bom_handled) {
+ dec_ctx->bom_handled = 1;
+ if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
+ continue;
+ }
+ }
+
+ out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
+ DUK_ASSERT(out <= output + (3 + (3 * len)));
+ }
+
+ if (!stream) {
+ if (dec_ctx->needed != 0) {
+ /* truncated sequence at end of buffer */
+ if (dec_ctx->fatal) {
+ goto fail_type;
+ } else {
+ out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
+ DUK_ASSERT(out <= output + (3 + (3 * len)));
+ }
+ }
+ duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */
+ }
+
+ /* Output buffer is fixed and thus stable even if there had been
+ * side effects (which there shouldn't be).
+ */
+ duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
+ return 1;
+
+ fail_type:
+ DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
+ DUK_UNREACHABLE();
+}
+
+/*
+ * Built-in bindings
+ */
+
+#if defined(DUK_USE_ENCODING_BUILTINS)
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
+ /* TextEncoder currently requires no persistent state, so the constructor
+ * does nothing on purpose.
+ */
+
+ duk_require_constructor_call(thr);
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
+ duk_push_string(thr, "utf-8");
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
+ duk__encode_context enc_ctx;
+ duk_size_t len;
+ duk_size_t final_len;
+ duk_uint8_t *output;
+
+ DUK_ASSERT_TOP(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
+ len = 0;
+ } else {
+ duk_hstring *h_input;
+
+ h_input = duk_to_hstring(thr, 0);
+ DUK_ASSERT(h_input != NULL);
+
+ len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
+ if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ }
+ }
+
+ /* Allowance is 3*len because all bytes can potentially be replaced with
+ * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
+ * Rely on dynamic buffer data pointer stability: no other code has
+ * access to the data pointer.
+ *
+ * XXX: The buffer allocation strategy used here is rather inefficient.
+ * Maybe switch to a chunk-based strategy, or preprocess the string to
+ * figure out the space needed ahead of time?
+ */
+ DUK_ASSERT(3 * len >= len);
+ output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
+
+ if (len > 0) {
+ DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
+
+ /* XXX: duk_decode_string() is used to process the input
+ * string. For standard Ecmascript strings, represented
+ * internally as CESU-8, this is fine. However, behavior
+ * beyond CESU-8 is not very strict: codepoints using an
+ * extended form of UTF-8 are also accepted, and invalid
+ * codepoint sequences (which are allowed in Duktape strings)
+ * are not handled as well as they could (e.g. invalid
+ * continuation bytes may mask following codepoints).
+ * This is how Ecmascript code would also see such strings.
+ * Maybe replace duk_decode_string() with an explicit strict
+ * CESU-8 decoder here?
+ */
+ enc_ctx.lead = 0x0000L;
+ enc_ctx.out = output;
+ duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
+ if (enc_ctx.lead != 0x0000L) {
+ /* unpaired high surrogate at end of string */
+ enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
+ DUK_ASSERT(enc_ctx.out <= output + (3 * len));
+ }
+
+ /* The output buffer is usually very much oversized, so shrink it to
+ * actually needed size. Pointer stability assumed up to this point.
+ */
+ DUK_ASSERT_TOP(thr, 2);
+ DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
+
+ final_len = (duk_size_t) (enc_ctx.out - output);
+ duk_resize_buffer(thr, -1, final_len);
+ /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
+ } else {
+ final_len = 0;
+ }
+
+ /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
+ * be backed by a dynamic buffer which differs from e.g. Uint8Arrays
+ * created as 'new Uint8Array(N)'. Ecmascript code won't see the
+ * difference but C code will. When bufferobjects are not supported,
+ * returns a plain dynamic buffer.
+ */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
+#endif
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_bool_t fatal = 0;
+ duk_bool_t ignore_bom = 0;
+
+ DUK_ASSERT_TOP(thr, 2);
+ duk_require_constructor_call(thr);
+ if (!duk_is_undefined(thr, 0)) {
+ /* XXX: For now ignore 'label' (encoding identifier). */
+ duk_to_string(thr, 0);
+ }
+ if (!duk_is_null_or_undefined(thr, 1)) {
+ if (duk_get_prop_string(thr, 1, "fatal")) {
+ fatal = duk_to_boolean(thr, -1);
+ }
+ if (duk_get_prop_string(thr, 1, "ignoreBOM")) {
+ ignore_bom = duk_to_boolean(thr, -1);
+ }
+ }
+
+ duk_push_this(thr);
+
+ /* The decode context is not assumed to be zeroed; all fields are
+ * initialized explicitly.
+ */
+ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
+ dec_ctx->fatal = (duk_uint8_t) fatal;
+ dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
+ duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
+
+ duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
+ return 0;
+}
+
+/* Get TextDecoder context from 'this'; leaves garbage on stack. */
+DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_push_this(thr);
+ duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
+ dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
+ DUK_ASSERT(dec_ctx != NULL);
+ return dec_ctx;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_int_t magic;
+
+ dec_ctx = duk__get_textdecoder_context(thr);
+ magic = duk_get_current_magic(thr);
+ switch (magic) {
+ case 0:
+ /* Encoding is now fixed, so _Context lookup is only needed to
+ * validate the 'this' binding (TypeError if not TextDecoder-like).
+ */
+ duk_push_string(thr, "utf-8");
+ break;
+ case 1:
+ duk_push_boolean(thr, dec_ctx->fatal);
+ break;
+ default:
+ duk_push_boolean(thr, dec_ctx->ignore_bom);
+ break;
+ }
+
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+
+ dec_ctx = duk__get_textdecoder_context(thr);
+ return duk__decode_helper(thr, dec_ctx);
+}
+#endif /* DUK_USE_ENCODING_BUILTINS */
+
+/*
+ * Internal helper for Node.js Buffer
+ */
+
+/* Internal helper used for Node.js Buffer .toString(). Value stack convention
+ * is currently odd: it mimics TextDecoder .decode() so that argument must be at
+ * index 0, and decode options (not present for Buffer) at index 1. Return value
+ * is a Duktape/C function return value.
+ */
+DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
+ duk__decode_context dec_ctx;
+
+ dec_ctx.fatal = 0; /* use replacement chars */
+ dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
+ duk__utf8_decode_init(&dec_ctx);
+
+ return duk__decode_helper(thr, &dec_ctx);
+}
+
+/* automatic undefs */
+#undef DUK__CP_CONTINUE
+#undef DUK__CP_ERROR
+#undef DUK__CP_RETRY
/*
* Error built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
/* Behavior for constructor and non-constructor call is
* the same except for augmenting the created error. When
* called as a constructor, the caller (duk_new()) will handle
@@ -26955,53 +31758,51 @@ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
* it here.
*/
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
+ duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
/* same for both error and each subclass like TypeError */
duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
- DUK_UNREF(thr);
-
- duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
+ (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
/* If message is undefined, the own property 'message' is not set at
* all to save property space. An empty message is inherited anyway.
*/
- if (!duk_is_undefined(ctx, 0)) {
- duk_to_string(ctx, 0);
- duk_dup(ctx, 0); /* [ message error message ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ if (!duk_is_undefined(thr, 0)) {
+ duk_to_string(thr, 0);
+ duk_dup_0(thr); /* [ message error message ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* Augment the error if called as a normal function. __FILE__ and __LINE__
* are not desirable in this case.
*/
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- if (!duk_is_constructor_call(ctx)) {
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (!duk_is_constructor_call(thr)) {
+ duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
}
#endif
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
/* XXX: optimize with more direct internal access */
- duk_push_this(ctx);
- (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
+ duk_push_this(thr);
+ (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
/* [ ... this ] */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "Error");
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_string(thr, "Error");
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name ] */
@@ -27010,28 +31811,28 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
* accident or are they actually needed? The first ToString()
* could conceivably return 'undefined'.
*/
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "");
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name message ] */
- if (duk_get_length(ctx, -2) == 0) {
+ if (duk_get_length(thr, -2) == 0) {
/* name is empty -> return message */
return 1;
}
- if (duk_get_length(ctx, -1) == 0) {
+ if (duk_get_length(thr, -1) == 0) {
/* message is empty -> return name */
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
}
- duk_push_string(ctx, ": ");
- duk_insert(ctx, -2); /* ... name ': ' message */
- duk_concat(ctx, 3);
+ duk_push_string(thr, ": ");
+ duk_insert(thr, -2); /* ... name ': ' message */
+ duk_concat(thr, 3);
return 1;
}
@@ -27057,8 +31858,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
#define DUK__OUTPUT_TYPE_FILENAME 0
#define DUK__OUTPUT_TYPE_LINENUMBER 1
-DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
duk_idx_t idx_td;
duk_small_int_t i; /* traceback depth fits into 16 bits */
duk_small_int_t t; /* stack type fits into 16 bits */
@@ -27070,39 +31870,38 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
const char *str_directeval = " directeval";
const char *str_empty = "";
- DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
- DUK_UNREF(thr);
+ DUK_ASSERT_TOP(thr, 0); /* fixed arg count */
- duk_push_this(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
- idx_td = duk_get_top_index(ctx);
+ duk_push_this(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
+ idx_td = duk_get_top_index(thr);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
- duk_push_this(ctx);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
+ duk_push_this(thr);
/* [ ... this tracedata sep this ] */
/* XXX: skip null filename? */
- if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
+ if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
/* Current tracedata contains 2 entries per callstack entry. */
for (i = 0; ; i += 2) {
duk_int_t pc;
- duk_int_t line;
- duk_int_t flags;
+ duk_uint_t line;
+ duk_uint_t flags;
duk_double_t d;
const char *funcname;
const char *filename;
duk_hobject *h_func;
duk_hstring *h_name;
- duk_require_stack(ctx, 5);
- duk_get_prop_index(ctx, idx_td, i);
- duk_get_prop_index(ctx, idx_td, i + 1);
- d = duk_to_number(ctx, -1);
+ duk_require_stack(thr, 5);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
+ d = duk_to_number_m1(thr);
pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
- flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
- t = (duk_small_int_t) duk_get_type(ctx, -2);
+ flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
+ t = (duk_small_int_t) duk_get_type(thr, -2);
if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
/*
@@ -27113,13 +31912,15 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* [ ... v1(func) v2(pc+flags) ] */
- h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
+ /* These may be systematically omitted by Duktape
+ * with certain config options, but allow user to
+ * set them on a case-by-case basis.
+ */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
+ duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
+ line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
#else
line = 0;
#endif
@@ -27129,35 +31930,37 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* When looking for .fileName/.lineNumber, blame first
* function which has a .fileName.
*/
- if (duk_is_string(ctx, -1)) {
+ if (duk_is_string_notsymbol(thr, -1)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, line);
+ duk_push_uint(thr, line);
return 1;
}
}
/* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
/* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
- h_name = duk_get_hstring(ctx, -2); /* may be NULL */
+ h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */
funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
"[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
- filename = duk_get_string(ctx, -1);
+ filename = duk_get_string_notsymbol(thr, -1);
filename = filename ? filename : "";
DUK_ASSERT(funcname != NULL);
DUK_ASSERT(filename != NULL);
+ h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */
+
if (h_func == NULL) {
- duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
(const char *) funcname,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
- duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
+ } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
+ duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
@@ -27166,19 +31969,21 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else {
- duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
- (long) line,
+ (unsigned long) line,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
}
- duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
- duk_pop_n(ctx, 3); /* -> [ ... str ] */
+ duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
+ duk_pop_3(thr); /* -> [ ... str ] */
} else if (t == DUK_TYPE_STRING) {
+ const char *str_file;
+
/*
* __FILE__ / __LINE__ entry, here 'pc' is line number directly.
* Sometimes __FILE__ / __LINE__ is reported as the source for
@@ -27192,21 +31997,27 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
*/
if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, pc);
+ duk_push_int(thr, pc);
return 1;
}
}
- duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
- (const char *) duk_get_string(ctx, -2), (long) pc);
- duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
- duk_pop(ctx); /* -> [ ... str ] */
+ /* Tracedata is trusted but avoid any risk of using a NULL
+ * for %s format because it has undefined behavior. Symbols
+ * don't need to be explicitly rejected as they pose no memory
+ * safety issues.
+ */
+ str_file = (const char *) duk_get_string(thr, -2);
+ duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
+ (const char *) (str_file ? str_file : "null"), (long) pc);
+ duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
+ duk_pop(thr); /* -> [ ... str ] */
} else {
/* unknown, ignore */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
break;
}
}
@@ -27216,7 +32027,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* marker so this is the best we can do.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
}
}
@@ -27229,7 +32040,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* duk_join() automatically. We don't want to do that
* coercion when providing .fileName or .lineNumber (GH-254).
*/
- duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
+ duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
return 1;
}
}
@@ -27238,22 +32049,18 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* save space. For setters the stridx could be encoded into 'magic'.
*/
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
}
-#undef DUK__OUTPUT_TYPE_TRACEBACK
-#undef DUK__OUTPUT_TYPE_FILENAME
-#undef DUK__OUTPUT_TYPE_LINENUMBER
-
#else /* DUK_USE_TRACEBACKS */
/*
@@ -27268,26 +32075,26 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx
* of the error so this makes sense.
*/
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
/* XXX: remove this native function and map 'stack' accessor
* to the toString() implementation directly.
*/
- return duk_bi_error_prototype_to_string(ctx);
+ return duk_bi_error_prototype_to_string(thr);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
#endif /* DUK_USE_TRACEBACKS */
-DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
+DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) {
/* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
* user code called Object.defineProperty() to create an overriding
* own property. This allows user code to overwrite .fileName etc
@@ -27295,102 +32102,118 @@ DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t
* See https://github.com/svaarala/duktape/issues/387.
*/
- DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
+ DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */
- duk_push_this(ctx);
- duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
- duk_dup(ctx, 0);
+ duk_push_this(thr);
+ duk_push_hstring_stridx(thr, stridx_key);
+ duk_dup_0(thr);
/* [ ... obj key value ] */
DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
- duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
+ duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
+ duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_STACK);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
}
-#line 1 "duk_bi_function.c"
+
+/* automatic undefs */
+#undef DUK__OUTPUT_TYPE_FILENAME
+#undef DUK__OUTPUT_TYPE_LINENUMBER
+#undef DUK__OUTPUT_TYPE_TRACEBACK
/*
* Function built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Needed even when Function built-in is disabled. */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
+ /* ignore arguments, return undefined (E5 Section 15.3.4) */
+ DUK_UNREF(thr);
+ return 0;
+}
+
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
duk_hstring *h_sourcecode;
duk_idx_t nargs;
duk_idx_t i;
duk_small_uint_t comp_flags;
- duk_hcompiledfunction *func;
+ duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
/* normal and constructor calls have identical semantics */
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
for (i = 0; i < nargs; i++) {
- duk_to_string(ctx, i);
+ duk_to_string(thr, i); /* Rejects Symbols during coercion. */
}
if (nargs == 0) {
- duk_push_string(ctx, "");
- duk_push_string(ctx, "");
+ duk_push_hstring_empty(thr);
+ duk_push_hstring_empty(thr);
} else if (nargs == 1) {
/* XXX: cover this with the generic >1 case? */
- duk_push_string(ctx, "");
+ duk_push_hstring_empty(thr);
} else {
- duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
- duk_push_string(ctx, ",");
- duk_insert(ctx, 1);
- duk_join(ctx, nargs - 1);
+ duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
+ duk_push_string(thr, ",");
+ duk_insert(thr, 1);
+ duk_join(thr, nargs - 1);
}
/* [ body formals ], formals is comma separated list that needs to be parsed */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
/* XXX: this placeholder is not always correct, but use for now.
* It will fail in corner cases; see test-dev-func-cons-args.js.
*/
- duk_push_string(ctx, "function(");
- duk_dup(ctx, 1);
- duk_push_string(ctx, "){");
- duk_dup(ctx, 0);
- duk_push_string(ctx, "}");
- duk_concat(ctx, 5);
+ duk_push_string(thr, "function(");
+ duk_dup_1(thr);
+ duk_push_string(thr, "){");
+ duk_dup_0(thr);
+ duk_push_string(thr, "\n}"); /* Newline is important to handle trailing // comment. */
+ duk_concat(thr, 5);
/* [ body formals source ] */
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* strictness is not inherited, intentional */
- comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
+ comp_flags = DUK_COMPILE_FUNCEXPR;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
- h_sourcecode = duk_require_hstring(ctx, -2);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
+ h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
+
+ /* Force .name to 'anonymous' (ES2015). */
+ duk_push_string(thr, "anonymous");
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
/* [ body formals source template ] */
@@ -27407,36 +32230,34 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
return 1;
}
+#endif /* DUK_USE_FUNCTION_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
- /* ignore arguments, return undefined (E5 Section 15.3.4) */
- DUK_UNREF(ctx);
- return 0;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
/*
* E5 Section 15.3.4.2 places few requirements on the output of
- * this function:
+ * this function: the result is implementation dependent, must
+ * follow FunctionDeclaration syntax (in particular, must have a
+ * name even for anonymous functions or functions with empty name).
+ * The output does NOT need to compile into anything useful.
+ *
+ * E6 Section 19.2.3.5 changes the requirements completely: the
+ * result must either eval() to a functionally equivalent object
+ * OR eval() to a SyntaxError.
*
- * - The result is an implementation dependent representation
- * of the function; in particular
+ * We opt for the SyntaxError approach for now, with a syntax that
+ * mimics V8's native function syntax:
*
- * - The result must follow the syntax of a FunctionDeclaration.
- * In particular, the function must have a name (even in the
- * case of an anonymous function or a function with an empty
- * name).
+ * 'function cos() { [native code] }'
*
- * - Note in particular that the output does NOT need to compile
- * into anything useful.
+ * but extended with [ecmascript code], [bound code], and
+ * [lightfunc code].
*/
-
- /* XXX: faster internal way to get this */
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
@@ -27444,33 +32265,31 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
const char *func_name;
/* Function name: missing/undefined is mapped to empty string,
- * otherwise coerce to string.
- */
- /* XXX: currently no handling for non-allowed identifier characters,
- * e.g. a '{' in the function name.
+ * otherwise coerce to string. No handling for invalid identifier
+ * characters or e.g. '{' in the function name. This doesn't
+ * really matter as long as a SyntaxError results. Technically
+ * if the name contained a suitable prefix followed by '//' it
+ * might cause the result to parse without error.
*/
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
func_name = "";
} else {
- func_name = duk_to_string(ctx, -1);
+ func_name = duk_to_string(thr, -1);
DUK_ASSERT(func_name != NULL);
}
- /* Indicate function type in the function body using a dummy
- * directive.
- */
- if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
+ if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
+ } else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
} else {
goto type_error;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
} else {
goto type_error;
}
@@ -27478,205 +32297,292 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
return 1;
type_error:
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
+#endif
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
- duk_idx_t len;
- duk_idx_t i;
-
- DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
+/* Always present because the native function pointer is needed in call
+ * handling.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
+ /* .call() is dealt with in call handling by simulating its
+ * effects so this function is actually never called.
+ */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
- }
- duk_insert(ctx, 0);
- DUK_ASSERT_TOP(ctx, 3);
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
+DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- /* [ func thisArg argArray ] */
+DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- if (duk_is_null_or_undefined(ctx, 2)) {
- DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
- len = 0;
- } else if (!duk_is_object(ctx, 2)) {
- goto type_error;
- } else {
- DUK_DDD(DUK_DDDPRINT("argArray is an object"));
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+/* Create a bound function which points to a target function which may
+ * be bound or non-bound. If the target is bound, the argument lists
+ * and 'this' binding of the functions are merged and the resulting
+ * function points directly to the non-bound target.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
+ duk_hboundfunc *h_bound;
+ duk_idx_t nargs; /* bound args, not counting 'this' binding */
+ duk_idx_t bound_nargs;
+ duk_int_t bound_len;
+ duk_tval *tv_prevbound;
+ duk_idx_t n_prevbound;
+ duk_tval *tv_res;
+ duk_tval *tv_tmp;
- /* XXX: make this an internal helper */
- duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
- len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
- duk_pop(ctx);
+ /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
- duk_require_stack(ctx, len);
+ /* Vararg function, careful arg handling, e.g. thisArg may not
+ * be present.
+ */
+ nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */
+ if (nargs < 0) {
+ nargs++;
+ duk_push_undefined(thr);
+ }
+ DUK_ASSERT(nargs >= 0);
- DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
- for (i = 0; i < len; i++) {
- duk_get_prop_index(ctx, 2, i);
- }
+ /* Limit 'nargs' for bound functions to guarantee arithmetic
+ * below will never wrap.
+ */
+ if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
}
- duk_remove(ctx, 2);
- DUK_ASSERT_TOP(ctx, 2 + len);
- /* [ func thisArg arg1 ... argN ] */
+ duk_push_this(thr);
+ duk_require_callable(thr, -1);
- DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) len));
- duk_call_method(ctx, len);
- return 1;
+ /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */
+ DUK_ASSERT_TOP(thr, nargs + 2);
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
+ /* Create bound function object. */
+ h_bound = duk_push_hboundfunc(thr);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
- duk_idx_t nargs;
+ /* [ thisArg arg1 ... argN func boundFunc ] */
- /* Step 1 is not necessary because duk_call_method() will take
- * care of it.
+ /* If the target is a bound function, argument lists must be
+ * merged. The 'this' binding closest to the target function
+ * wins because in call handling the 'this' gets replaced over
+ * and over again until we call the non-bound function.
*/
+ tv_prevbound = NULL;
+ n_prevbound = 0;
+ tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
+ tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
+ DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
- /* vararg function, thisArg needs special handling */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
+ if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
+ duk_hobject *h_target;
+ duk_hobject *bound_proto;
- /* [ thisArg arg1 ... argN ] */
+ h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
+ DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
- duk_push_this(ctx); /* 'func' in the algorithm */
- duk_insert(ctx, 0);
+ /* Internal prototype must be copied from the target.
+ * For lightfuncs Function.prototype is used and is already
+ * in place.
+ */
+ bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
- /* [ func thisArg arg1 ... argN ] */
+ /* The 'strict' flag is copied to get the special [[Get]] of E5.1
+ * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
+ * function. Not sure if this is correct, because the specification
+ * is a bit ambiguous on this point but it would make sense.
+ */
+ /* Strictness is inherited from target. */
+ if (DUK_HOBJECT_HAS_STRICT(h_target)) {
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ }
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) (nargs - 1),
- (long) duk_get_top(ctx)));
- duk_call_method(ctx, nargs - 1);
- return 1;
-}
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
+ duk_hboundfunc *h_boundtarget;
-/* XXX: the implementation now assumes "chained" bound functions,
- * whereas "collapsed" bound functions (where there is ever only
- * one bound function which directly points to a non-bound, final
- * function) would require a "collapsing" implementation which
- * merges argument lists etc here.
- */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
- duk_hobject *h_bound;
- duk_hobject *h_target;
- duk_idx_t nargs;
- duk_idx_t i;
+ h_boundtarget = (duk_hboundfunc *) h_target;
- /* vararg function, careful arg handling (e.g. thisArg may not be present) */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
+ /* The final function should always be non-bound, unless
+ * there's a bug in the internals. Assert for it.
+ */
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
+ (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
+ !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
+ DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
+
+ tv_prevbound = h_boundtarget->args;
+ n_prevbound = h_boundtarget->nargs;
+ }
+ } else {
+ /* Lightfuncs are always strict. */
+ duk_hobject *bound_proto;
+
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
}
- /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
- DUK_ASSERT_TOP(ctx, nargs + 1);
+ DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */
+ DUK_TVAL_INCREF(thr, &h_bound->this_binding);
- /* create bound function object */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BOUND |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
- DUK_BIDX_FUNCTION_PROTOTYPE);
- h_bound = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_bound != NULL);
+ bound_nargs = n_prevbound + nargs;
+ if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
+ }
+ tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
+ DUK_ASSERT(tv_res != NULL);
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ h_bound->args = tv_res;
+ h_bound->nargs = bound_nargs;
+
+ DUK_ASSERT(n_prevbound >= 0);
+ duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
+ DUK_ASSERT(nargs >= 0);
+ duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
/* [ thisArg arg1 ... argN func boundFunc ] */
- duk_dup(ctx, -2); /* func */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_dup(ctx, 0); /* thisArg */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
+ /* Bound function 'length' property is interesting.
+ * For lightfuncs, simply read the virtual property.
+ */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
+ bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */
+ if (bound_len < nargs) {
+ bound_len = 0;
+ } else {
+ bound_len -= nargs;
+ }
+ if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
+ bound_len = (duk_int_t) DUK_UINT32_MAX;
+ }
+ duk_pop(thr);
+ DUK_ASSERT(bound_len >= 0);
+ tv_tmp = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
+ DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
+
+ /* XXX: could these be virtual? */
+ /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
+
+ /* Function name and fileName (non-standard). */
+ duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */
+ duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
+ if (!duk_is_string_notsymbol(thr, -1)) {
+ /* ES2015 has requirement to check that .name of target is a string
+ * (also must check for Symbol); if not, targetName should be the
+ * empty string. ES2015 19.2.3.2.
+ */
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
+ }
+ duk_concat(thr, 2);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+#endif
- duk_push_array(ctx);
+ DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
- /* [ thisArg arg1 ... argN func boundFunc argArray ] */
+ return 1;
+}
+#endif /* DUK_USE_FUNCTION_BUILTIN */
- for (i = 0; i < nargs - 1; i++) {
- duk_dup(ctx, 1 + i);
- duk_put_prop_index(ctx, -2, i);
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
+/* %NativeFunctionPrototype% .length getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
+ duk_int16_t func_nargs;
- /* [ thisArg arg1 ... argN func boundFunc ] */
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
- /* bound function 'length' property is interesting */
- h_target = duk_get_hobject(ctx, -2);
- if (h_target == NULL || /* lightfunc */
- DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
- /* For lightfuncs, simply read the virtual property. */
- duk_int_t tmp;
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
- tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
- duk_pop(ctx);
- duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+ func_nargs = h->nargs;
+ duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_small_uint_t lf_flags;
+ duk_small_uint_t lf_len;
+
+ lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
+ lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ duk_push_uint(thr, lf_len);
} else {
- duk_push_int(ctx, 0);
+ goto fail_type;
}
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
+ return 1;
- /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+}
- /* these non-standard properties are copied for convenience */
- /* XXX: 'copy properties' API call? */
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
+/* %NativeFunctionPrototype% .name getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
- /* The 'strict' flag is copied to get the special [[Get]] of E5.1
- * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
- * function. Not sure if this is correct, because the specification
- * is a bit ambiguous on this point but it would make sense.
- */
- if (h_target == NULL) {
- /* Lightfuncs are always strict. */
- DUK_HOBJECT_SET_STRICT(h_bound);
- } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
- DUK_HOBJECT_SET_STRICT(h_bound);
- }
- DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+#if 0
+ duk_push_hnatfunc_name(thr, h);
+#endif
+ duk_push_hstring_empty(thr);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_push_lightfunc_name(thr, tv);
+ } else {
+ goto fail_type;
+ }
return 1;
- type_error:
- return DUK_RET_TYPE_ERROR;
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
-#line 1 "duk_bi_global.c"
/*
* Global object built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Encoding/decoding helpers
@@ -27744,7 +32650,7 @@ DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
};
-#ifdef DUK_USE_SECTION_B
+#if defined(DUK_USE_SECTION_B)
/* E5.1 Section B.2.2, step 7. */
DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
@@ -27758,8 +32664,6 @@ DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
};
#endif /* DUK_USE_SECTION_B */
-#undef DUK__MKBITS
-
typedef struct {
duk_hthread *thr;
duk_hstring *h_str;
@@ -27789,15 +32693,14 @@ DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small
return t;
}
-DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) {
duk__transform_context tfm_ctx_alloc;
duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
duk_codepoint_t cp;
tfm_ctx->thr = thr;
- tfm_ctx->h_str = duk_to_hstring(ctx, 0);
+ tfm_ctx->h_str = duk_to_hstring(thr, 0);
DUK_ASSERT(tfm_ctx->h_str != NULL);
DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
@@ -27813,7 +32716,7 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca
DUK_BW_COMPACT(thr, &tfm_ctx->bw);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */
return 1;
}
@@ -27846,7 +32749,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
goto uri_error;
}
cp1 = cp;
- cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
+ cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
} else if (cp > 0x10ffffL) {
/* Although we can allow non-BMP characters (they'll decode
* back into surrogate pairs), we don't allow extended UTF-8
@@ -27865,7 +32768,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
for (i = 0; i < len; i++) {
- t = (int) xutf8_buf[i];
+ t = (duk_small_int_t) xutf8_buf[i];
DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
&tfm_ctx->bw,
DUK_ASC_PERCENT,
@@ -27876,7 +32779,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
return;
uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
+ DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -28004,7 +32907,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
DUK_ASSERT(cp < 0x100000L);
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
+ DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L));
} else {
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
@@ -28014,10 +32917,10 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
return;
uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
+ DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
-#ifdef DUK_USE_SECTION_B
+#if defined(DUK_USE_SECTION_B)
DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
DUK_UNREF(udata);
@@ -28054,7 +32957,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, c
return;
esc_error:
- DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input");
+ DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -28092,22 +32995,22 @@ DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx,
* calling activation at all which needs careful handling.
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
duk_hstring *h;
duk_activation *act_caller;
duk_activation *act_eval;
- duk_activation *act;
- duk_hcompiledfunction *func;
+ duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
duk_bool_t this_to_global = 1;
duk_small_uint_t comp_flags;
duk_int_t level = -2;
+ duk_small_uint_t call_flags;
- DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
+ DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
- DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
(thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
/*
@@ -28118,8 +33021,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* activation doesn't exist, call must be indirect.
*/
- h = duk_get_hstring(ctx, 0);
+ h = duk_get_hstring_notsymbol(thr, 0);
if (!h) {
+ /* Symbol must be returned as is, like any non-string values. */
return 1; /* return arg as-is */
}
@@ -28128,89 +33032,85 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* for an Ecmascript eval().
*/
DUK_ASSERT(level == -2); /* by default, use caller's environment */
- if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
- level = duk_get_int(ctx, 1);
+ if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
+ level = duk_get_int(thr, 1);
}
DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
#endif
/* [ source ] */
- comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
- act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
- if (thr->callstack_top >= (duk_size_t) -level) {
+ comp_flags = DUK_COMPILE_EVAL;
+ act_eval = thr->callstack_curr; /* this function */
+ DUK_ASSERT(act_eval != NULL);
+ act_caller = duk_hthread_get_activation_for_level(thr, level);
+ if (act_caller != NULL) {
/* Have a calling activation, check for direct eval (otherwise
* assume indirect eval.
*/
- act_caller = thr->callstack + thr->callstack_top + level; /* caller */
if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
(act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
/* Only direct eval inherits strictness from calling code
* (E5.1 Section 10.1.1).
*/
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
+ comp_flags |= DUK_COMPILE_STRICT;
}
} else {
DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
}
- act_caller = NULL; /* avoid dereference after potential callstack realloc */
- act_eval = NULL;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
/* [ source template ] */
/* E5 Section 10.4.2 */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1; /* this function */
- if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
+ DUK_ASSERT(act_caller != NULL);
+ if (act_caller->lex_env == NULL) {
+ DUK_ASSERT(act_caller->var_env == NULL);
DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
/* this may have side effects, so re-lookup act */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top + level;
+ duk_js_init_activation_environment_records_delayed(thr, act_caller);
}
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
+ DUK_ASSERT(act_caller->lex_env != NULL);
+ DUK_ASSERT(act_caller->var_env != NULL);
this_to_global = 0;
if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
- duk_hobject *new_env;
+ duk_hdecenv *new_env;
duk_hobject *act_lex_env;
DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
"var_env and lex_env to a fresh env, "
"this_binding to caller's this_binding"));
- act = thr->callstack + thr->callstack_top + level; /* caller */
- act_lex_env = act->lex_env;
- act = NULL; /* invalidated */
+ act_lex_env = act_caller->lex_env;
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- act_lex_env);
- new_env = duk_require_hobject(ctx, -1);
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
- DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
- (duk_heaphdr *) new_env));
+ duk_push_hobject(thr, (duk_hobject *) new_env);
+
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env);
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env);
+ DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
- outer_lex_env = new_env;
- outer_var_env = new_env;
+ outer_lex_env = (duk_hobject *) new_env;
+ outer_var_env = (duk_hobject *) new_env;
- duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
+ duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
/* compiler's responsibility */
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -28219,8 +33119,8 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
"var_env and lex_env to caller's envs, "
"this_binding to caller's this_binding"));
- outer_lex_env = act->lex_env;
- outer_var_env = act->var_env;
+ outer_lex_env = act_caller->lex_env;
+ outer_var_env = act_caller->var_env;
/* compiler's responsibility */
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -28233,35 +33133,44 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
- act = NULL;
/* Eval code doesn't need an automatic .prototype object. */
duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
- /* [ source template closure ] */
+ /* [ env? source template closure ] */
if (this_to_global) {
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
} else {
duk_tval *tv;
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
+ DUK_ASSERT(act_caller != NULL);
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */
DUK_ASSERT(tv >= thr->valstack);
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
}
DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
(duk_heaphdr *) outer_lex_env,
(duk_heaphdr *) outer_var_env,
- duk_get_tval(ctx, -1)));
+ duk_get_tval(thr, -1)));
- /* [ source template closure this ] */
+ /* [ env? source template closure this ] */
- duk_call_method(ctx, 0);
+ call_flags = 0;
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ /* Set DIRECT_EVAL flag for the call; it's not strictly
+ * needed for the 'inner' eval call (the eval body) but
+ * current new.target implementation expects to find it
+ * so it can traverse direct eval chains up to the real
+ * calling function.
+ */
+ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ }
+ duk_handle_call_unprotected_nargs(thr, 0, call_flags);
- /* [ source template result ] */
+ /* [ env? source template result ] */
return 1;
}
@@ -28270,15 +33179,19 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* Parsing of ints and floats
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
duk_int32_t radix;
duk_small_uint_t s2n_flags;
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, 0);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, 0); /* Reject symbols. */
- radix = duk_to_int32(ctx, 1);
+ radix = duk_to_int32(thr, 1);
+ /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
+ * ES2015 0o123 or 0b10001.
+ */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
DUK_S2N_FLAG_ALLOW_GARBAGE |
DUK_S2N_FLAG_ALLOW_PLUS |
@@ -28304,23 +33217,22 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
radix = 10;
}
- duk_dup(ctx, 0);
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_dup_0(thr);
+ duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags);
return 1;
ret_nan:
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
duk_small_uint_t s2n_flags;
- duk_int32_t radix;
- DUK_ASSERT_TOP(ctx, 1);
- duk_to_string(ctx, 0);
-
- radix = 10;
+ DUK_ASSERT_TOP(thr, 1);
+ duk_to_string(thr, 0); /* Reject symbols. */
/* XXX: check flags */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
@@ -28334,633 +33246,66 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* Number checkers
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISNAN(d));
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d));
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISFINITE(d));
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d));
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* URI handling
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
}
-#ifdef DUK_USE_SECTION_B
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
-}
-#else /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+#if defined(DUK_USE_SECTION_B)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL);
}
#endif /* DUK_USE_SECTION_B */
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t magic;
- duk_idx_t nargs;
- const duk_uint8_t *buf;
- duk_size_t sz_buf;
- const char nl = (const char) DUK_ASC_LF;
-#ifndef DUK_USE_PREFER_SIZE
- duk_uint8_t buf_stack[256];
-#endif
-#ifdef DUK_USE_FILE_IO
- duk_file *f_out;
-#endif
-
- DUK_UNREF(thr);
-
- magic = duk_get_current_magic(ctx);
- DUK_UNREF(magic);
-
- nargs = duk_get_top(ctx);
-
- /* If argument count is 1 and first argument is a buffer, write the buffer
- * as raw data into the file without a newline; this allows exact control
- * over stdout/stderr without an additional entrypoint (useful for now).
- *
- * Otherwise current print/alert semantics are to ToString() coerce
- * arguments, join them with a single space, and append a newline.
- */
-
- if (nargs == 1 && duk_is_buffer(ctx, 0)) {
- buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf);
- DUK_ASSERT(buf != NULL);
- } else if (nargs > 0) {
-#ifdef DUK_USE_PREFER_SIZE
- /* Compact but lots of churn. */
- duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE);
- duk_insert(ctx, 0);
- duk_join(ctx, nargs);
- duk_push_string(thr, "\n");
- duk_concat(ctx, 2);
- buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf);
- DUK_ASSERT(buf != NULL);
-#else /* DUK_USE_PREFER_SIZE */
- /* Higher footprint, less churn. */
- duk_idx_t i;
- duk_size_t sz_str;
- const duk_uint8_t *p_str;
- duk_uint8_t *p;
-
- sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */
- for (i = 0; i < nargs; i++) {
- (void) duk_to_lstring(ctx, i, &sz_str);
- sz_buf += sz_str;
- }
-
- if (sz_buf <= sizeof(buf_stack)) {
- p = (duk_uint8_t *) buf_stack;
- } else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
- DUK_ASSERT(p != NULL);
- }
-
- buf = (const duk_uint8_t *) p;
- for (i = 0; i < nargs; i++) {
- p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
- DUK_ASSERT(p_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) p_str, sz_str);
- p += sz_str;
- *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE);
- }
- DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf);
-#endif /* DUK_USE_PREFER_SIZE */
- } else {
- buf = (const duk_uint8_t *) &nl;
- sz_buf = 1;
- }
-
- /* 'buf' contains the string to write, 'sz_buf' contains the length
- * (which may be zero).
- */
- DUK_ASSERT(buf != NULL);
-
- if (sz_buf == 0) {
- return 0;
- }
-
-#ifdef DUK_USE_FILE_IO
- f_out = (magic ? DUK_STDERR : DUK_STDOUT);
- DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out);
- DUK_FFLUSH(f_out);
-#endif
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT);
- duk_debug_write_string(thr, (const char *) buf, sz_buf);
- duk_debug_write_eom(thr);
- }
-#endif
- return 0;
-}
-#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return 0;
-}
-#else /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* print provider */
-
-/*
- * CommonJS require() and modules support
- */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT];
- duk_uint8_t *p;
- duk_uint8_t *q;
- duk_uint8_t *q_last; /* last component */
- duk_int_t int_rc;
-
- DUK_ASSERT(req_id != NULL);
- /* mod_id may be NULL */
-
- /*
- * A few notes on the algorithm:
- *
- * - Terms are not allowed to begin with a period unless the term
- * is either '.' or '..'. This simplifies implementation (and
- * is within CommonJS modules specification).
- *
- * - There are few output bound checks here. This is on purpose:
- * the resolution input is length checked and the output is never
- * longer than the input. The resolved output is written directly
- * over the input because it's never longer than the input at any
- * point in the algorithm.
- *
- * - Non-ASCII characters are processed as individual bytes and
- * need no special treatment. However, U+0000 terminates the
- * algorithm; this is not an issue because U+0000 is not a
- * desirable term character anyway.
- */
-
- /*
- * Set up the resolution input which is the requested ID directly
- * (if absolute or no current module path) or with current module
- * ID prepended (if relative and current module path exists).
- *
- * Suppose current module is 'foo/bar' and relative path is './quux'.
- * The 'bar' component must be replaced so the initial input here is
- * 'foo/bar/.././quux'.
- */
-
- if (mod_id != NULL && req_id[0] == '.') {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
- } else {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id);
- }
- if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
- /* Potentially truncated, NUL not guaranteed in any case.
- * The (int_rc < 0) case should not occur in practice.
- */
- DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer"));
- goto resolve_error;
- }
- DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
-
- DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf));
-
- /*
- * Resolution loop. At the top of the loop we're expecting a valid
- * term: '.', '..', or a non-empty identifier not starting with a period.
- */
-
- p = buf;
- q = buf;
- for (;;) {
- duk_uint_fast8_t c;
-
- /* Here 'p' always points to the start of a term.
- *
- * We can also unconditionally reset q_last here: if this is
- * the last (non-empty) term q_last will have the right value
- * on loop exit.
- */
-
- DUK_ASSERT(p >= q); /* output is never longer than input during resolution */
-
- DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p",
- (const char *) p, (void *) q, (void *) buf));
-
- q_last = q;
-
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '.')) {
- c = *p++;
- if (c == '/') {
- /* Term was '.' and is eaten entirely (including dup slashes). */
- goto eat_dup_slashes;
- }
- if (c == '.' && *p == '/') {
- /* Term was '..', backtrack resolved name by one component.
- * q[-1] = previous slash (or beyond start of buffer)
- * q[-2] = last char of previous component (or beyond start of buffer)
- */
- p++; /* eat (first) input slash */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
- goto resolve_error;
- }
- DUK_ASSERT(*(q - 1) == '/');
- q--; /* backtrack to last output slash (dups already eliminated) */
- for (;;) {
- /* Backtrack to previous slash or start of buffer. */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- break;
- }
- if (*(q - 1) == '/') {
- break;
- }
- q--;
- }
- goto eat_dup_slashes;
- }
- DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '/')) {
- /* e.g. require('/foo'), empty terms not allowed */
- DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
- goto resolve_error;
- } else {
- for (;;) {
- /* Copy term name until end or '/'. */
- *q++ = c;
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- /* This was the last term, and q_last was
- * updated to match this term at loop top.
- */
- goto loop_done;
- } else if (DUK_UNLIKELY(c == '/')) {
- *q++ = '/';
- break;
- } else {
- /* write on next loop */
- }
- }
- }
-
- eat_dup_slashes:
- for (;;) {
- /* eat dup slashes */
- c = *p;
- if (DUK_LIKELY(c != '/')) {
- break;
- }
- p++;
- }
- }
- loop_done:
- /* Output #1: resolved absolute name */
- DUK_ASSERT(q >= buf);
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
-
- /* Output #2: last component name */
- DUK_ASSERT(q >= q_last);
- DUK_ASSERT(q_last >= buf);
- duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
-
- DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p",
- (void *) buf, (void *) q_last, (void *) q));
- return;
-
- resolve_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id);
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-/* Stack indices for better readability */
-#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */
-#define DUK__IDX_REQUIRE 1 /* Current require() function */
-#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */
-#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */
-#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */
-#define DUK__IDX_DUKTAPE 5 /* Duktape object */
-#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
-#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
-#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */
-#define DUK__IDX_EXPORTS 9 /* Default exports table */
-#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- const char *str_req_id; /* requested identifier */
- const char *str_mod_id; /* require.id of current module */
- duk_int_t pcall_rc;
-
- /* NOTE: we try to minimize code size by avoiding unnecessary pops,
- * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
- * assertions are used to ensure stack configuration is correct at each
- * step.
- */
-
- /*
- * Resolve module identifier into canonical absolute form.
- */
-
- str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
- duk_push_current_function(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID);
- str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
- DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID)));
- duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id);
- str_req_id = NULL;
- str_mod_id = NULL;
- DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* [ requested_id require require.id resolved_id last_comp ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
-
- /*
- * Cached module check.
- *
- * If module has been loaded or its loading has already begun without
- * finishing, return the same cached value ('exports'). The value is
- * registered when module load starts so that circular references can
- * be supported to some extent.
- */
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE);
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */
- (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED);
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
-
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
- DUK_DD(DUK_DDPRINT("module already loaded: %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID)));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */
- return 1;
- }
- DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
-
- /*
- * Module not loaded (and loading not started previously).
- *
- * Create a new require() function with 'id' set to resolved ID
- * of module being loaded. Also create 'exports' and 'module'
- * tables but don't register exports to the loaded table yet.
- * We don't want to do that unless the user module search callbacks
- * succeeds in finding the module.
- */
-
- DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* Fresh require: require.id is left configurable (but not writable)
- * so that is not easy to accidentally tweak it, but it can still be
- * done with Object.defineProperty().
- *
- * XXX: require.id could also be just made non-configurable, as there
- * is no practical reason to touch it.
- */
- duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */
-
- /* Module table:
- * - module.exports: initial exports table (may be replaced by user)
- * - module.id is non-writable and non-configurable, as the CommonJS
- * spec suggests this if possible
- * - module.filename: not set, defaults to resolved ID if not explicitly
- * set by modSearch() (note capitalization, not .fileName, matches Node.js)
- * - module.name: not set, defaults to last component of resolved ID if
- * not explicitly set by modSearch()
- */
- duk_push_object(ctx); /* exports */
- duk_push_object(ctx); /* module */
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */
- duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
-
- DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE)));
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
-
- /* Register the module table early to modLoaded[] so that we can
- * support circular references even in modSearch(). If an error
- * is thrown, we'll delete the reference.
- */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_MODULE);
- duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
-
- /*
- * Call user provided module search function and build the wrapped
- * module source code (if necessary). The module search function
- * can be used to implement pure Ecmacsript, pure C, and mixed
- * Ecmascript/C modules.
- *
- * The module search function can operate on the exports table directly
- * (e.g. DLL code can register values to it). It can also return a
- * string which is interpreted as module source code (if a non-string
- * is returned the module is assumed to be a pure C one). If a module
- * cannot be found, an error must be thrown by the user callback.
- *
- * Because Duktape.modLoaded[] already contains the module being
- * loaded, circular references for C modules should also work
- * (although expected to be quite rare).
- */
-
- duk_push_string(ctx, "(function(require,exports,module){");
-
- /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
- pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
-
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Delete entry in Duktape.modLoaded[] and rethrow. */
- goto delete_rethrow;
- }
-
- /* If user callback did not return source code, module loading
- * is finished (user callback initialized exports table directly).
- */
- if (!duk_is_string(ctx, -1)) {
- /* User callback did not return source code, so module loading
- * is finished: just update modLoaded with final module.exports
- * and we're done.
- */
- goto return_exports;
- }
-
- /* Finish the wrapped module source. Force module.filename as the
- * function .fileName so it gets set for functions defined within a
- * module. This also ensures loggers created within the module get
- * the module ID (or overridden filename) as their default logger name.
- * (Note capitalization: .filename matches Node.js while .fileName is
- * used elsewhere in Duktape.)
- */
- duk_push_string(ctx, "})");
- duk_concat(ctx, 3);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) {
- /* module.filename for .fileName, default to resolved ID if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- }
- duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
-
- /* Module has now evaluated to a wrapped module function. Force its
- * .name to match module.name (defaults to last component of resolved
- * ID) so that it is shown in stack traces too. Note that we must not
- * introduce an actual name binding into the function scope (which is
- * usually the case with a named function) because it would affect the
- * scope seen by the module and shadow accesses to globals of the same name.
- * This is now done by compiling the function as anonymous and then forcing
- * its .name without setting a "has name binding" flag.
- */
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) {
- /* module.name for .name, default to last component if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_LASTCOMP);
- }
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
-
- /*
- * Call the wrapped module function.
- *
- * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
- * even if the module throws an error.
- */
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */
- duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
-
- pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Module loading failed. Node.js will forget the module
- * registration so that another require() will try to load
- * the module again. Mimic that behavior.
- */
- goto delete_rethrow;
- }
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- /* fall through */
-
- return_exports:
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS);
- duk_compact(ctx, -1); /* compact the exports table */
- return 1; /* return module.exports */
-
- delete_rethrow:
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
- duk_throw(ctx); /* rethrow original error */
- return 0; /* not reachable */
-}
-
-#undef DUK__IDX_REQUESTED_ID
-#undef DUK__IDX_REQUIRE
-#undef DUK__IDX_REQUIRE_ID
-#undef DUK__IDX_RESOLVED_ID
-#undef DUK__IDX_LASTCOMP
-#undef DUK__IDX_DUKTAPE
-#undef DUK__IDX_MODLOADED
-#undef DUK__IDX_UNDEFINED
-#undef DUK__IDX_FRESH_REQUIRE
-#undef DUK__IDX_EXPORTS
-#undef DUK__IDX_MODULE
-#else
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
-#line 1 "duk_bi_json.c"
+/* automatic undefs */
+#undef DUK__CHECK_BITMASK
+#undef DUK__MKBITS
/*
* JSON built-ins.
*
@@ -28977,7 +33322,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
* indeed correct!
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_JSON_SUPPORT)
/*
* Local defines and forward declarations.
@@ -28991,13 +33338,15 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
+#if defined(DUK_USE_JX)
DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
+#endif
DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
@@ -29032,11 +33381,16 @@ DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
#endif
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
-DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
+#endif
+#endif
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
#endif
-DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
+DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
/*
* Helper tables
@@ -29200,10 +33554,12 @@ DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
js_ctx->p = p;
}
+#if defined(DUK_USE_JX)
DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
return *js_ctx->p;
}
+#endif
DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
@@ -29233,7 +33589,7 @@ DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx,
DUK_ASSERT(duk_hex_dectab[0] == -1);
t = duk_hex_dectab[x & 0xff];
if (DUK_LIKELY(t >= 0)) {
- res = (res * 16) + t;
+ res = (res * 16) + (duk_uint_fast32_t) t;
} else {
/* catches EOF and invalid digits */
goto syntax_error;
@@ -29259,8 +33615,7 @@ DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t st
* have internal NULs.
*/
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_STRIDX_VALID(stridx);
h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
DUK_ASSERT(h != NULL);
@@ -29295,7 +33650,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
* will match the default case (syntax error).
*/
cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
- switch ((int) cp) {
+ switch (cp) {
case DUK_ASC_BACKSLASH: break;
case DUK_ASC_DOUBLEQUOTE: break;
case DUK_ASC_SLASH: break;
@@ -29308,7 +33663,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
cp = duk__dec_decode_hex_escape(js_ctx, 4);
break;
}
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
case DUK_ASC_UC_U: {
if (js_ctx->flag_ext_custom) {
cp = duk__dec_decode_hex_escape(js_ctx, 8);
@@ -29338,7 +33693,6 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
duk_uint8_t *q;
@@ -29431,7 +33785,7 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */
/* [ ... str ] */
@@ -29442,13 +33796,12 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
DUK_UNREACHABLE();
}
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
/* Decode a plain string consisting entirely of identifier characters.
* Used to parse plain keys (e.g. "foo: 123").
*/
DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
@@ -29481,17 +33834,16 @@ DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
p++;
}
- duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
+ duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
js_ctx->p = p;
/* [ ... str ] */
}
#endif /* DUK_USE_JX */
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
void *voidptr;
@@ -29529,7 +33881,7 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
voidptr = NULL;
(void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
- duk_push_pointer(ctx, voidptr);
+ duk_push_pointer(thr, voidptr);
js_ctx->p = p + 1; /* skip ')' */
/* [ ... ptr ] */
@@ -29542,10 +33894,9 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
}
#endif /* DUK_USE_JX */
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_uint8_t *buf;
duk_size_t src_len;
@@ -29582,11 +33933,12 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
p++;
}
+ /* XXX: this is not very nice; unnecessary copy is made. */
src_len = (duk_size_t) (p - js_ctx->p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
- duk_hex_decode(ctx, -1);
+ duk_hex_decode(thr, -1);
js_ctx->p = p + 1; /* skip '|' */
@@ -29602,7 +33954,7 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
/* Parse a number, other than NaN or +/- Infinity */
DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
const duk_uint8_t *p_start;
const duk_uint8_t *p;
duk_uint8_t x;
@@ -29647,35 +33999,35 @@ DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
js_ctx->p = p;
DUK_ASSERT(js_ctx->p > p_start);
- duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
+ duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start));
s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
DUK_S2N_FLAG_ALLOW_FRAC;
DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- if (duk_is_nan(ctx, -1)) {
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
+ if (duk_is_nan(thr, -1)) {
duk__dec_syntax_error(js_ctx);
}
- DUK_ASSERT(duk_is_number(ctx, -1));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... num ] */
}
DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
+ duk_hthread *thr = js_ctx->thr;
+ duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
/* c recursion check */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
}
js_ctx->recursion_depth++;
}
@@ -29689,7 +34041,7 @@ DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_int_t key_count; /* XXX: a "first" flag would suffice */
duk_uint8_t x;
@@ -29697,7 +34049,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_object(ctx);
+ duk_push_object(thr);
/* Initial '{' has been checked and eaten by caller. */
@@ -29706,7 +34058,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) key_count));
/* handle comma and closing brace */
@@ -29731,7 +34083,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
if (x == DUK_ASC_DOUBLEQUOTE) {
duk__dec_string(js_ctx);
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
} else if (js_ctx->flag_ext_custom &&
duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
duk__dec_plain_string(js_ctx);
@@ -29751,7 +34103,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj key val ] */
- duk_xdef_prop_wec(ctx, -3);
+ duk_xdef_prop_wec(thr, -3);
/* [ ... obj ] */
@@ -29761,7 +34113,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj ] */
DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -29772,7 +34124,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uarridx_t arr_idx;
duk_uint8_t x;
@@ -29780,7 +34132,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_array(ctx);
+ duk_push_array(thr);
/* Initial '[' has been checked and eaten by caller. */
@@ -29789,7 +34141,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) arr_idx));
/* handle comma and closing bracket */
@@ -29816,7 +34168,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
/* [ ... arr val ] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
+ duk_xdef_prop_index_wec(thr, -2, arr_idx);
arr_idx++;
}
@@ -29824,12 +34176,12 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
* set the values.
*/
- duk_set_length(ctx, -1, arr_idx);
+ duk_set_length(thr, -1, arr_idx);
/* [ ... arr ] */
DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -29840,7 +34192,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uint8_t x;
x = duk__dec_get_nonwhite(js_ctx);
@@ -29852,10 +34204,10 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
if (x == DUK_ASC_DOUBLEQUOTE) {
duk__dec_string(js_ctx);
} else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
- duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, -DUK_DOUBLE_INFINITY);
} else {
#else
{ /* unconditional block */
@@ -29866,23 +34218,23 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
}
} else if (x == DUK_ASC_LC_T) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
- duk_push_true(ctx);
+ duk_push_true(thr);
} else if (x == DUK_ASC_LC_F) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
- duk_push_false(ctx);
+ duk_push_false(thr);
} else if (x == DUK_ASC_LC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
- duk_push_null(ctx);
-#ifdef DUK_USE_JX
+ duk_push_null(thr);
+#if defined(DUK_USE_JX)
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
- duk_push_number(ctx, DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, DUK_DOUBLE_INFINITY);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
duk__dec_pointer(js_ctx);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
@@ -29912,67 +34264,65 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
* there is a reasonable limit on C recursion depth and hence object depth.
*/
DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_dup_top(ctx);
- duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
+ duk_dup_top(thr);
+ duk_get_prop(thr, -3); /* -> [ ... holder name val ] */
- h = duk_get_hobject(ctx, -1);
+ h = duk_get_hobject(thr, -1);
if (h != NULL) {
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, -1);
for (i = 0; i < arr_len; i++) {
/* [ ... holder name val ] */
DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
- (long) duk_get_top(ctx), (long) i, (long) arr_len,
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* XXX: push_uint_string / push_u32_string */
- duk_dup_top(ctx);
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */
+ (long) duk_get_top(thr), (long) i, (long) arr_len,
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+
+ duk_dup_top(thr);
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -1, i);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop_index(thr, -1, i);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
* not hold (e.g. that previous property is not an accessor).
*/
- duk_put_prop_index(ctx, -2, i);
+ duk_put_prop_index(thr, -2, i);
}
}
} else {
/* [ ... holder name val ] */
- duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
+ duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
+ while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
- (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5),
+ (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3),
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... holder name val enum obj_key ] */
- duk_dup(ctx, -3);
- duk_dup(ctx, -2);
+ duk_dup_m3(thr);
+ duk_dup_m2(thr);
/* [ ... holder name val enum obj_key val obj_key ] */
duk__dec_reviver_walk(js_ctx);
/* [ ... holder name val enum obj_key new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop(ctx, -3);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop(thr, -3);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
@@ -29983,21 +34333,21 @@ DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
* does not happen normally, but a clever reviver can trigger
* that, see complex reviver case in: test-bug-json-parse-__proto__.js.
*/
- duk_put_prop(ctx, -4);
+ duk_put_prop(thr, -4);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
}
}
/* [ ... holder name val ] */
- duk_dup(ctx, js_ctx->idx_reviver);
- duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
- duk_call_method(ctx, 2); /* -> [ ... res ] */
+ duk_dup(thr, js_ctx->idx_reviver);
+ duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */
+ duk_call_method(thr, 2); /* -> [ ... res ] */
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
}
/*
@@ -30034,8 +34384,7 @@ DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
duk_hstring *h;
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_STRIDX_VALID(stridx);
h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
DUK_ASSERT(h != NULL);
@@ -30066,9 +34415,9 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
* (nybble_count << 16) | (escape_char1) | (escape_char2)
*/
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
if (DUK_LIKELY(cp < 0x100UL)) {
- if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
+ if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
} else {
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
@@ -30078,8 +34427,8 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
if (DUK_LIKELY(cp < 0x10000UL)) {
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
} else {
-#ifdef DUK_USE_JX
- if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
+#if defined(DUK_USE_JX)
+ if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
} else
#endif
@@ -30272,7 +34621,7 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
p = p_tmp + 1;
}
-#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
+#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029)
if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
#else
if (js_ctx->flag_ascii_only) {
@@ -30296,7 +34645,6 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
*/
DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
duk_hthread *thr;
- duk_context *ctx;
duk_tval *tv;
duk_double_t d;
duk_small_int_t c;
@@ -30308,10 +34656,9 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
DUK_ASSERT(js_ctx != NULL);
thr = js_ctx->thr;
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
/* Caller must ensure 'tv' is indeed a double and not a fastint! */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
d = DUK_TVAL_GET_DOUBLE(tv);
@@ -30328,16 +34675,15 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
*/
if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
(js_ctx->flag_ext_custom_or_compatible))) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */
} else
#endif /* DUK_USE_JX || DUK_USE_JC */
{
n2s_flags = 0;
/* [ ... number ] -> [ ... string ] */
- duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
+ duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags);
}
- h_str = duk_to_hstring(ctx, -1);
- DUK_ASSERT(h_str != NULL);
+ h_str = duk_known_hstring(thr, -1);
DUK__EMIT_HSTR(js_ctx, h_str);
return;
}
@@ -30479,8 +34825,8 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d
* variants is to be as useful to a programmer as possible.
*/
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
+ /* The #if defined() clutter here needs to handle the three
+ * cases: (1) JX+JC, (2) JX only, (3) JC only.
*/
/* Note: space must cater for both JX and JC. */
@@ -30517,13 +34863,60 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d
DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
}
-DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
duk__enc_buffer_data(js_ctx,
(duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
(duk_size_t) DUK_HBUFFER_GET_SIZE(h));
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+ duk_size_t i, n;
+ const duk_uint8_t *buf;
+ duk_uint8_t *q;
+
+ n = DUK_HBUFFER_GET_SIZE(h);
+ if (n == 0) {
+ DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY);
+ return;
+ }
+
+ DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
+
+ /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18,
+ * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack.
+ *
+ * Note that because the output buffer is reallocated from time to time,
+ * side effects (such as finalizers) affecting the buffer 'h' must be
+ * disabled. This is the case in the JSON.stringify() fast path.
+ */
+
+ buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h);
+ if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
+ for (i = 0; i < n; i++) {
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
+ q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32);
+ q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]);
+ DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
+ }
+ } else {
+ q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw);
+ for (i = 0; i < n; i++) {
+ q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q);
+ q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]);
+ }
+ DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
+ }
+ DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
+
+ if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+ }
+ DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
+}
+#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
+
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
char buf[64]; /* XXX: how to figure correct size? */
@@ -30534,8 +34927,8 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
DUK_MEMZERO(buf, sizeof(buf));
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
+ /* The #if defined() clutter here needs to handle the three
+ * cases: (1) JX+JC, (2) JX only, (3) JC only.
*/
#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
if (js_ctx->flag_ext_custom)
@@ -30561,26 +34954,28 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
- if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
} else {
/* Handle both full and partial slice (as long as covered). */
duk__enc_buffer_data(js_ctx,
- (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
+ (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
(duk_size_t) h_bufobj->length);
}
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
* directly related to indent depth.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
DUK_ASSERT(js_ctx->h_gap != NULL);
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
@@ -30590,7 +34985,7 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
}
}
#else /* DUK_USE_PREFER_SIZE */
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
const duk_uint8_t *gap_data;
duk_size_t gap_len;
duk_size_t avail_bytes; /* bytes of indent available for copying */
@@ -30644,20 +35039,19 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
/* Shared entry handling for object/array serialization. */
DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
duk_uint_fast32_t i, n;
- *entry_top = duk_get_top(ctx);
+ *entry_top = duk_get_top(thr);
- duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
+ duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
/* Loop check using a hybrid approach: a fixed-size visited[] array
* with overflow in a loop check object.
*/
- h_target = duk_get_hobject(ctx, -1); /* object or array */
- DUK_ASSERT(h_target != NULL);
+ h_target = duk_known_hobject(thr, -1); /* object or array */
n = js_ctx->recursion_depth;
if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
@@ -30666,37 +35060,37 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
for (i = 0; i < n; i++) {
if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
DUK_DD(DUK_DDPRINT("slow path loop detect"));
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
}
}
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
js_ctx->visiting[js_ctx->recursion_depth] = h_target;
} else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
- if (duk_has_prop(ctx, js_ctx->idx_loop)) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_dup_top(thr); /* -> [ ... voidp voidp ] */
+ if (duk_has_prop(thr, js_ctx->idx_loop)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
}
- duk_push_true(ctx); /* -> [ ... voidp true ] */
- duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_true(thr); /* -> [ ... voidp true ] */
+ duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* C recursion check. */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
}
js_ctx->recursion_depth++;
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
}
/* Shared exit handling for object/array serialization. */
DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
/* C recursion check. */
@@ -30707,21 +35101,20 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
/* Loop check. */
- h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
- DUK_ASSERT(h_target != NULL);
+ h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
/* Previous entry was inside visited[], nothing to do. */
} else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* Restore stack top after unbalanced code paths. */
- duk_set_top(ctx, *entry_top);
+ duk_set_top(thr, *entry_top);
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
}
/* The JO(value) operation: encode object.
@@ -30729,7 +35122,7 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
* Stack policy: [ object ] -> [ object ].
*/
DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hstring *h_key;
duk_idx_t entry_top;
duk_idx_t idx_obj;
@@ -30738,7 +35131,7 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
duk_uarridx_t arr_len, i;
duk_size_t prev_size;
- DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -30748,14 +35141,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
idx_keys = js_ctx->idx_proplist;
} else {
/* XXX: would be nice to enumerate an object at specified index */
- duk_dup(ctx, idx_obj);
- (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
- idx_keys = duk_require_normalize_index(ctx, -1);
+ duk_dup(thr, idx_obj);
+ (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
+ idx_keys = duk_require_normalize_index(thr, -1);
/* leave stack unbalanced on purpose */
}
DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
- (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
+ (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys)));
/* Steps 8-10 have been merged to avoid a "partial" variable. */
@@ -30767,17 +35160,18 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* that it can be reallocated).
*/
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys);
emitted = 0;
for (i = 0; i < arr_len; i++) {
- duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
+ duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */
DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
- (duk_tval *) duk_get_tval(ctx, idx_obj),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, idx_obj),
+ (duk_tval *) duk_get_tval(thr, -1)));
- h_key = duk_get_hstring(ctx, -1);
+ h_key = duk_known_hstring(thr, -1);
DUK_ASSERT(h_key != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */
prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
@@ -30809,14 +35203,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The JA(value) operation: encode array.
@@ -30824,14 +35218,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ array ] -> [ array ].
*/
DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_idx_t entry_top;
duk_idx_t idx_arr;
duk_bool_t emitted;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -30841,11 +35235,11 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr);
emitted = 0;
for (i = 0; i < arr_len; i++) {
DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_arr),
+ (duk_tval *) duk_get_tval(thr, idx_arr),
(long) i, (long) arr_len));
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
@@ -30853,9 +35247,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
- /* XXX: duk_push_uint_string() */
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... key ] */
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */
/* [ ... key ] */
@@ -30877,14 +35269,14 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The Str(key, holder) operation.
@@ -30892,165 +35284,157 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ ... key ] -> [ ... ]
*/
DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_tmp;
+ duk_hthread *thr = js_ctx->thr;
duk_tval *tv;
duk_tval *tv_holder;
duk_tval *tv_key;
duk_small_int_t c;
DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
- (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
+ (duk_tval *) duk_get_tval(thr, -1)));
- DUK_UNREF(thr);
-
- tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
+ tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder);
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
- tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */
(void) duk_hobject_getprop(thr, tv_holder, tv_key);
/* -> [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1);
- if (h_tmp != NULL) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
- h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */
-
- if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) {
+ /* Standard JSON checks for .toJSON() only for actual objects; for
+ * example, setting Number.prototype.toJSON and then serializing a
+ * number won't invoke the .toJSON() method. However, lightfuncs and
+ * plain buffers mimic objects so we check for their .toJSON() method.
+ */
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER)) {
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON);
+ if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */
DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
- /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
- duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */
- duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */
- duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
+ /* XXX: duk_dup_unvalidated(thr, -2) etc. */
+ duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */
+ duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */
+ duk_call_method(thr, 1); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
} else {
- duk_pop(ctx); /* -> [ ... key val ] */
+ duk_pop(thr); /* -> [ ... key val ] */
}
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
if (js_ctx->h_replacer) {
/* XXX: Here a "slice copy" would be useful. */
DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
- duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
- duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */
- duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
+ duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
+ duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */
+ duk_call_method(thr, 2); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h;
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- /* Conceptually we'd extract the plain underlying buffer
- * or its slice and then do a type mask check below to
- * see if we should reject it. Do the mask check here
- * instead to avoid making a copy of the buffer slice.
- */
-
- if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) {
- DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)"));
- goto pop2_undef;
- }
- DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly"));
- duk__enc_bufferobject(js_ctx, h_bufobj);
+ if (DUK_HOBJECT_IS_BUFOBJ(h) &&
+ js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) {
+ /* With JX/JC a bufferobject gets serialized specially. */
+ duk_hbufobj *h_bufobj;
+ h_bufobj = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ duk__enc_bufobj(js_ctx, h_bufobj);
goto pop2_emitted;
-#else
- DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined"));
- goto pop2_undef;
-#endif
- } else {
- c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
- switch ((int) c) {
- case DUK_HOBJECT_CLASS_NUMBER: {
- DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
- duk_to_number(ctx, -1);
- /* The coercion potentially invokes user .valueOf() and .toString()
- * but can't result in a function value because [[DefaultValue]] would
- * reject such a result: test-dev-json-stringify-coercion-1.js.
- */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
- case DUK_HOBJECT_CLASS_STRING: {
- DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
- duk_to_string(ctx, -1);
- /* Same coercion behavior as for Number. */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
+ }
+ /* Otherwise bufferobjects get serialized as normal objects. */
+#endif /* JX || JC */
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ switch (c) {
+ case DUK_HOBJECT_CLASS_NUMBER: {
+ DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
+ duk_to_number_m1(thr);
+ /* The coercion potentially invokes user .valueOf() and .toString()
+ * but can't result in a function value because ToPrimitive() would
+ * reject such a result: test-dev-json-stringify-coercion-1.js.
+ */
+ DUK_ASSERT(!duk_is_callable(thr, -1));
+ break;
+ }
+ case DUK_HOBJECT_CLASS_STRING: {
+ DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
+ duk_to_string(thr, -1);
+ /* Same coercion behavior as for Number. */
+ DUK_ASSERT(!duk_is_callable(thr, -1));
+ break;
+ }
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- case DUK_HOBJECT_CLASS_POINTER:
+ case DUK_HOBJECT_CLASS_POINTER:
#endif
- case DUK_HOBJECT_CLASS_BOOLEAN: {
- DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- duk_remove(ctx, -2);
- break;
- }
- default: {
- /* Normal object which doesn't get automatically coerced to a
- * primitive value. Functions are checked for specially. The
- * primitive value coercions for Number, String, Pointer, and
- * Boolean can't result in functions so suffices to check here.
- */
- DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_CALLABLE(h)) {
+ case DUK_HOBJECT_CLASS_BOOLEAN: {
+ DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ duk_remove_m2(thr);
+ break;
+ }
+ default: {
+ /* Normal object which doesn't get automatically coerced to a
+ * primitive value. Functions are checked for specially. The
+ * primitive value coercions for Number, String, Pointer, and
+ * Boolean can't result in functions so suffices to check here.
+ * Symbol objects are handled like plain objects (their primitive
+ * value is NOT looked up like for e.g. String objects).
+ */
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_IS_CALLABLE(h)) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_EXT_COMPATIBLE)) {
- /* We only get here when doing non-standard JSON encoding */
- DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
- goto pop2_emitted;
- } else {
- DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
- goto pop2_undef;
- }
-#else /* DUK_USE_JX || DUK_USE_JC */
+ if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
+ DUK_JSON_FLAG_EXT_COMPATIBLE)) {
+ /* We only get here when doing non-standard JSON encoding */
+ DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
+ DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
+ goto pop2_emitted;
+ } else {
DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
goto pop2_undef;
-#endif /* DUK_USE_JX || DUK_USE_JC */
}
+#else /* DUK_USE_JX || DUK_USE_JC */
+ DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
+ goto pop2_undef;
+#endif /* DUK_USE_JX || DUK_USE_JC */
}
- } /* end switch */
}
+ } /* end switch */
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
+ if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) {
/* will result in undefined */
DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
goto pop2_undef;
}
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
switch (DUK_TVAL_GET_TAG(tv)) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31079,7 +35463,9 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
-
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ goto pop2_undef;
+ }
duk__enc_quote_string(js_ctx, h);
break;
}
@@ -31099,13 +35485,27 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
}
break;
}
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* When JX/JC not in use, the type mask above will avoid this case if needed. */
+ /* Because plain buffers mimics Uint8Array, they have enumerable
+ * index properties [0,byteLength[. Because JSON only serializes
+ * enumerable own properties, no properties can be serialized for
+ * plain buffers (all virtual properties are non-enumerable). However,
+ * there may be a .toJSON() method which was already handled above.
+ */
case DUK_TAG_BUFFER: {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom_or_compatible) {
+ duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ break;
+ }
+#endif
+
+ /* Could implement a fastpath, but the fast path would need
+ * to handle realloc side effects correctly.
+ */
+ duk_to_object(thr, -1);
+ duk__enc_object(js_ctx);
break;
}
-#endif /* DUK_USE_JX || DUK_USE_JC */
case DUK_TAG_LIGHTFUNC: {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
/* We only get here when doing non-standard JSON encoding */
@@ -31137,24 +35537,37 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
}
}
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
pop2_emitted:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+#endif
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 1; /* emitted */
pop2_undef:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 0; /* not emitted */
}
/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
- duk_hobject *h;
duk_small_int_t c;
+ /* XXX: some kind of external internal type checker?
+ * - type mask; symbol flag; class mask
+ */
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
+ if (DUK_TVAL_IS_STRING(tv)) {
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 0;
+ }
+ return 1;
+ } else if (DUK_TVAL_IS_NUMBER(tv)) {
return 1;
} else if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
@@ -31214,9 +35627,11 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
case DUK_TAG_STRING: {
duk_hstring *h;
-
h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ goto emit_undefined;
+ }
duk__enc_quote_string(js_ctx, h);
break;
}
@@ -31225,7 +35640,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
duk_tval *tv_val;
duk_bool_t emitted = 0;
duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
- c_func, c_bufobj, c_object;
+ c_func, c_bufobj, c_object, c_abort;
/* For objects JSON.stringify() only looks for own, enumerable
* properties which is nice for the fast path here.
@@ -31258,7 +35673,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* it (though it's OK to abort the fast path).
*/
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_DD(DUK_DDPRINT("fast path recursion limit"));
@@ -31290,7 +35705,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* but does at the moment, probably not worth fixing.
*/
if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
- DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
+ DUK_HOBJECT_IS_PROXY(obj)) {
DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
goto abort_fastpath;
}
@@ -31311,11 +35726,12 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
c_unbox = DUK_HOBJECT_CMASK_NUMBER |
DUK_HOBJECT_CMASK_STRING |
DUK_HOBJECT_CMASK_BOOLEAN |
- DUK_HOBJECT_CMASK_POINTER;
+ DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */
c_func = DUK_HOBJECT_CMASK_FUNCTION;
- c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
+ c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
c_undef = 0;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ c_abort = 0;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
}
else
#endif
@@ -31324,16 +35740,20 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
c_array = DUK_HOBJECT_CMASK_ARRAY;
c_unbox = DUK_HOBJECT_CMASK_NUMBER |
DUK_HOBJECT_CMASK_STRING |
- DUK_HOBJECT_CMASK_BOOLEAN;
+ DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */
c_func = 0;
c_bufobj = 0;
c_undef = DUK_HOBJECT_CMASK_FUNCTION |
- DUK_HOBJECT_CMASK_POINTER |
- DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ DUK_HOBJECT_CMASK_POINTER;
+ /* As the fast path doesn't currently properly support
+ * duk_hbufobj virtual properties, abort fast path if
+ * we encounter them in plain JSON mode.
+ */
+ c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
}
- c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
+ c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj);
if (c_bit & c_object) {
/* All other object types. */
DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
@@ -31355,6 +35775,15 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
if (!k) {
continue;
}
+ if (DUK_HSTRING_HAS_ARRIDX(k)) {
+ /* If an object has array index keys we would need
+ * to sort them into the ES2015 enumeration order to
+ * be consistent with the slow path. Abort the fast
+ * path and handle in the slow path for now.
+ */
+ DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path"));
+ goto abort_fastpath;
+ }
if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
continue;
}
@@ -31365,7 +35794,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
goto abort_fastpath;
}
- if (DUK_HSTRING_HAS_INTERNAL(k)) {
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
continue;
}
@@ -31391,8 +35820,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
/* If any non-Array value had enumerable virtual own
- * properties, they should be serialized here. Standard
- * types don't.
+ * properties, they should be serialized here (actually,
+ * before the explicit properties). Standard types don't.
*/
if (emitted) {
@@ -31400,7 +35829,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
@@ -31416,62 +35845,58 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
goto abort_fastpath;
}
- arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
+ arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
- if (arr_len > asize) {
- /* Array length is larger than 'asize'. This shouldn't
- * happen in practice. Bail out just in case.
- */
- DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path"));
- goto abort_fastpath;
- }
/* Array part may be larger than 'length'; if so, iterate
- * only up to array 'length'.
+ * only up to array 'length'. Array part may also be smaller
+ * than 'length' in some cases.
*/
for (i = 0; i < arr_len; i++) {
- DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj));
-
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
+ duk_tval *tv_arrval;
+ duk_hstring *h_tmp;
+ duk_bool_t has_inherited;
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
- if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
- /* Gap in array; check for inherited property,
- * bail out if one exists. This should be enough
- * to support gappy arrays for all practical code.
- */
- duk_hstring *h_tmp;
- duk_bool_t has_inherited;
-
- /* XXX: refactor into an internal helper, pretty awkward */
- duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i);
- h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1);
- DUK_ASSERT(h_tmp != NULL);
- has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
- duk_pop((duk_context *) js_ctx->thr);
-
- if (has_inherited) {
- DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
- goto abort_fastpath;
+ if (DUK_LIKELY(i < asize)) {
+ tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
+ if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) {
+ /* Expected case: element is present. */
+ if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) {
+ DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+ }
+ goto elem_done;
}
+ }
- /* Ordinary gap, undefined encodes to 'null' in
- * standard JSON (and no JX/JC support here now).
- */
- DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
+ /* Gap in array; check for inherited property,
+ * bail out if one exists. This should be enough
+ * to support gappy arrays for all practical code.
+ */
+
+ h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i);
+ has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
+ duk_pop(js_ctx->thr);
+ if (has_inherited) {
+ DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
+ goto abort_fastpath;
+ }
+
+ /* Ordinary gap, undefined encodes to 'null' in
+ * standard JSON, but JX/JC use their form for
+ * undefined to better preserve the typing.
+ */
+ DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
#if defined(DUK_USE_JX)
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
#else
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+ DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
#endif
- } else {
- if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- }
- }
+ /* fall through */
+ elem_done:
DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
emitted = 1;
}
@@ -31481,7 +35906,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
@@ -31490,6 +35915,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* automatic unboxing. Rely on internal value being
* sane (to avoid infinite recursion).
*/
+ DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */
+
#if 1
/* The code below is incorrect if .toString() or .valueOf() have
* have been overridden. The correct approach would be to look up
@@ -31519,9 +35946,14 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
} else if (c_bit & c_func) {
DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
} else if (c_bit & c_bufobj) {
- duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
+ duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj);
+#endif
#endif
+ } else if (c_bit & c_abort) {
+ DUK_DD(DUK_DDPRINT("abort fast path for unsupported type"));
+ goto abort_fastpath;
} else {
DUK_ASSERT((c_bit & c_undef) != 0);
@@ -31538,16 +35970,34 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
break;
}
case DUK_TAG_BUFFER: {
+ /* Plain buffers are treated like Uint8Arrays: they have
+ * enumerable indices. Other virtual properties are not
+ * enumerable, and inherited properties are not serialized.
+ * However, there can be a replacer (not relevant here) or
+ * a .toJSON() method (which we need to check for explicitly).
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ if (duk_hobject_hasprop_raw(js_ctx->thr,
+ js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE],
+ DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) {
+ DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path"));
+ goto abort_fastpath;
+ }
+#endif
+
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
if (js_ctx->flag_ext_custom_or_compatible) {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
break;
- } else {
- goto emit_undefined;
}
-#else
- goto emit_undefined;
#endif
+
+ /* Plain buffers mimic Uint8Arrays, and have enumerable index
+ * properties.
+ */
+ duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ break;
}
case DUK_TAG_POINTER: {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31586,9 +36036,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
/* XXX: Stack discipline is annoying, could be changed in numconv. */
- duk_push_tval((duk_context *) js_ctx->thr, tv);
+ duk_push_tval(js_ctx->thr, tv);
duk__enc_double(js_ctx);
- duk_pop((duk_context *) js_ctx->thr);
+ duk_pop(js_ctx->thr);
#if 0
/* Could also rely on native sprintf(), but it will handle
@@ -31613,24 +36063,24 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
abort_fastpath:
/* Error message doesn't matter: the error is ignored anyway. */
DUK_DD(DUK_DDPRINT("aborting fast path"));
- DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr);
+ DUK_ERROR_INTERNAL(js_ctx->thr);
return 0; /* unreachable */
}
-DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
+DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
duk_json_enc_ctx *js_ctx;
duk_tval *tv;
- DUK_ASSERT(ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
- DUK_ASSERT(DUK_TVAL_IS_POINTER(tv));
- js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(udata != NULL);
+
+ js_ctx = (duk_json_enc_ctx *) udata;
DUK_ASSERT(js_ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
- return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */
}
return 0;
@@ -31642,16 +36092,15 @@ DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
*/
DUK_INTERNAL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_dec_ctx js_ctx_alloc;
duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
duk_hstring *h_text;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top = duk_get_top(ctx);
+#if defined(DUK_USE_ASSERTIONS)
+ duk_idx_t entry_top = duk_get_top(thr);
#endif
/* negative top-relative indices not allowed now */
@@ -31659,14 +36108,14 @@ void duk_bi_json_parse_helper(duk_context *ctx,
DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
/* nothing now */
#endif
js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
@@ -31687,7 +36136,7 @@ void duk_bi_json_parse_helper(duk_context *ctx,
js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
#endif
- h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
+ h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */
DUK_ASSERT(h_text != NULL);
/* JSON parsing code is allowed to read [p_start,p_end]: p_end is
@@ -31710,47 +36159,46 @@ void duk_bi_json_parse_helper(duk_context *ctx,
duk__dec_syntax_error(js_ctx);
}
- if (duk_is_callable(ctx, idx_reviver)) {
+ if (duk_is_callable(thr, idx_reviver)) {
DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
js_ctx->idx_reviver = idx_reviver;
- duk_push_object(ctx);
- duk_dup(ctx, -2); /* -> [ ... val root val ] */
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
+ duk_push_object(thr);
+ duk_dup_m2(thr); /* -> [ ... val root val ] */
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
- duk_remove(ctx, -2); /* -> [ ... val' ] */
+ duk_remove_m2(thr); /* -> [ ... val' ] */
} else {
DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
}
/* Final result is at stack top. */
DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
DUK_INTERNAL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_enc_ctx js_ctx_alloc;
duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
duk_hobject *h;
@@ -31763,13 +36211,13 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
/*
* Context init
@@ -31777,7 +36225,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
js_ctx->h_replacer = NULL;
js_ctx->h_gap = NULL;
#endif
@@ -31790,17 +36238,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
js_ctx->flags = flags;
js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JC)
js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
#endif
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
#endif
- /* The #ifdef clutter here handles the JX/JC enable/disable
+ /* The #if defined() clutter here handles the JX/JC enable/disable
* combinations properly.
*/
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31839,15 +36287,19 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
else
#endif /* DUK_USE_JX || DUK_USE_JC */
{
+ /* Plain buffer is treated like ArrayBuffer and serialized.
+ * Lightfuncs are treated like objects, but JSON explicitly
+ * skips serializing Function objects so we can just reject
+ * lightfuncs here.
+ */
js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_POINTER |
- DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_LIGHTFUNC;
}
DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
- js_ctx->idx_loop = duk_push_object_internal(ctx);
+ js_ctx->idx_loop = duk_push_bare_object(thr);
DUK_ASSERT(js_ctx->idx_loop >= 0);
/* [ ... buf loop ] */
@@ -31856,7 +36308,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process replacer/proplist (2nd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_replacer);
+ h = duk_get_hobject(thr, idx_replacer);
if (h != NULL) {
if (DUK_HOBJECT_IS_CALLABLE(h)) {
js_ctx->h_replacer = h;
@@ -31870,30 +36322,30 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
duk_uarridx_t plist_idx = 0;
duk_small_uint_t enum_flags;
- js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
+ js_ctx->idx_proplist = duk_push_array(thr); /* XXX: array internal? */
enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
- duk_enum(ctx, idx_replacer, enum_flags);
- while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
+ duk_enum(thr, idx_replacer, enum_flags);
+ while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
/* [ ... proplist enum_obj key val ] */
- if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
+ if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) {
/* XXX: duplicates should be eliminated here */
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_to_string(ctx, -1); /* extra coercion of strings is OK */
- duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_to_string(thr, -1); /* extra coercion of strings is OK */
+ duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
plist_idx++;
- duk_pop(ctx);
+ duk_pop(thr);
} else {
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_pop_2(thr);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
/* [ ... proplist ] */
}
@@ -31905,17 +36357,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process space (3rd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_space);
+ h = duk_get_hobject(thr, idx_space);
if (h != NULL) {
- int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
if (c == DUK_HOBJECT_CLASS_NUMBER) {
- duk_to_number(ctx, idx_space);
+ duk_to_number(thr, idx_space);
} else if (c == DUK_HOBJECT_CLASS_STRING) {
- duk_to_string(ctx, idx_space);
+ duk_to_string(thr, idx_space);
}
}
- if (duk_is_number(ctx, idx_space)) {
+ if (duk_is_number(thr, idx_space)) {
duk_small_int_t nspace;
/* spaces[] must be static to allow initializer with old compilers like BCC */
static const char spaces[10] = {
@@ -31925,25 +36377,26 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
}; /* XXX: helper */
/* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
- nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
+ nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/);
DUK_ASSERT(nspace >= 0 && nspace <= 10);
- duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
- DUK_ASSERT(js_ctx->h_gap != NULL);
- } else if (duk_is_string(ctx, idx_space)) {
- /* XXX: substring in-place at idx_place? */
- duk_dup(ctx, idx_space);
- duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
+ duk_push_lstring(thr, spaces, (duk_size_t) nspace);
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
DUK_ASSERT(js_ctx->h_gap != NULL);
+ } else if (duk_is_string_notsymbol(thr, idx_space)) {
+ duk_dup(thr, idx_space);
+ duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
} else {
/* nop */
}
if (js_ctx->h_gap != NULL) {
- /* if gap is empty, behave as if not given at all */
- if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
+ /* If gap is empty, behave as if not given at all. Check
+ * against byte length because character length is more
+ * expensive.
+ */
+ if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) {
js_ctx->h_gap = NULL;
}
}
@@ -31959,9 +36412,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
js_ctx->idx_proplist == -1) { /* proplist is very rare */
duk_int_t pcall_rc;
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
+ duk_small_uint_t prev_ms_base_flags;
DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
@@ -31980,22 +36431,21 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* limited loop detection).
*/
- duk_push_pointer(ctx, (void *) js_ctx);
- duk_dup(ctx, idx_value);
+ duk_dup(thr, idx_value);
-#if defined(DUK_USE_MARK_AND_SWEEP)
/* Must prevent finalizers which may have arbitrary side effects. */
- prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
- thr->heap->mark_and_sweep_base_flags |=
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
-#endif
+ prev_ms_base_flags = thr->heap->ms_base_flags;
+ thr->heap->ms_base_flags |=
+ DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */
+ thr->heap->pf_prevent_count++; /* Prevent finalizers. */
+ DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
- pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
+ pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
+
+ DUK_ASSERT(thr->heap->pf_prevent_count > 0);
+ thr->heap->pf_prevent_count--;
+ thr->heap->ms_base_flags = prev_ms_base_flags;
-#if defined(DUK_USE_MARK_AND_SWEEP)
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
if (pcall_rc == DUK_EXEC_SUCCESS) {
DUK_DD(DUK_DDPRINT("fast path successful"));
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
@@ -32017,22 +36467,22 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Create wrapper object and serialize
*/
- idx_holder = duk_push_object(ctx);
- duk_dup(ctx, idx_value);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
+ idx_holder = duk_push_object(thr);
+ duk_dup(thr, idx_value);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);
DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
+ (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* serialize the wrapper with empty string key */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_push_hstring_empty(thr);
/* [ ... buf loop (proplist) (gap) holder "" ] */
@@ -32041,7 +36491,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
/* Result is undefined. */
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else {
/* Convert buffer to result string. */
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
@@ -32050,11 +36500,11 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
+ (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, idx_holder)));
+ (duk_tval *) duk_get_tval(thr, idx_holder)));
/* The stack has a variable shape here, so force it to the
* desired one explicitly.
@@ -32063,35 +36513,37 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
replace_finished:
#endif
- duk_replace(ctx, entry_top);
- duk_set_top(ctx, entry_top + 1);
+ duk_replace(thr, entry_top);
+ duk_set_top(thr, entry_top + 1);
DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
"flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
+#if defined(DUK_USE_JSON_BUILTIN)
+
/*
* Entry points
*/
-DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
- duk_bi_json_parse_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) {
+ duk_bi_json_parse_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
0 /*flags*/);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
- duk_bi_json_stringify_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) {
+ duk_bi_json_stringify_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
2 /*idx_space*/,
@@ -32099,318 +36551,28 @@ DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
return 1;
}
+#endif /* DUK_USE_JSON_BUILTIN */
+
+#endif /* DUK_USE_JSON_SUPPORT */
+
+/* automatic undefs */
+#undef DUK__EMIT_1
+#undef DUK__EMIT_2
+#undef DUK__EMIT_CSTR
+#undef DUK__EMIT_HSTR
+#undef DUK__EMIT_STRIDX
#undef DUK__JSON_DECSTR_BUFSIZE
#undef DUK__JSON_DECSTR_CHUNKSIZE
#undef DUK__JSON_ENCSTR_CHUNKSIZE
-#undef DUK__JSON_STRINGIFY_BUFSIZE
#undef DUK__JSON_MAX_ESC_LEN
-#line 1 "duk_bi_logger.c"
-/*
- * Logging support
- */
-
-/* include removed: duk_internal.h */
-
-/* 3-letter log level strings */
-DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = {
- (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
- (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
- (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
- (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
- (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
- (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
-};
-
-/* Constructor */
-DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t nargs;
-
- /* Calling as a non-constructor is not meaningful. */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 1);
-
- duk_push_this(ctx);
-
- /* [ name this ] */
-
- if (nargs == 0) {
- /* Automatic defaulting of logger name from caller. This would
- * work poorly with tail calls, but constructor calls are currently
- * never tail calls, so tail calls are not an issue now.
- */
-
- if (thr->callstack_top >= 2) {
- duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
- duk_hobject *func_caller;
-
- func_caller = DUK_ACT_GET_FUNC(act_caller);
- if (func_caller) {
- /* Stripping the filename might be a good idea
- * ("/foo/bar/quux.js" -> logger name "quux"),
- * but now used verbatim.
- */
- duk_push_hobject(ctx, func_caller);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk_replace(ctx, 0);
- }
- }
- }
- /* the stack is unbalanced here on purpose; we only rely on the
- * initial two values: [ name this ].
- */
-
- if (duk_is_string(ctx, 0)) {
- duk_dup(ctx, 0);
- duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
- } else {
- /* don't set 'n' at all, inherited value is used as name */
- }
-
- duk_compact(ctx, 1);
-
- return 0; /* keep default instance */
-}
-
-/* Default function to format objects. Tries to use toLogString() but falls
- * back to toString(). Any errors are propagated out without catching.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
- if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
- /* [ arg toLogString ] */
-
- duk_dup(ctx, 0);
- duk_call_method(ctx, 0);
-
- /* [ arg result ] */
- return 1;
- }
-
- /* [ arg undefined ] */
- duk_pop(ctx);
- duk_to_string(ctx, 0);
- return 1;
-}
-
-/* Default function to write a formatted log line. Writes to stderr,
- * appending a newline to the log line.
- *
- * The argument is a buffer whose visible size contains the log message.
- * This function should avoid coercing the buffer to a string to avoid
- * string table traffic.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
- const char *data;
- duk_size_t data_len;
-
- DUK_UNREF(ctx);
- DUK_UNREF(data);
- DUK_UNREF(data_len);
-
-#ifdef DUK_USE_FILE_IO
- data = (const char *) duk_require_buffer(ctx, 0, &data_len);
- DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR);
- DUK_FPUTC((int) '\n', DUK_STDERR);
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* nop */
-#endif
- return 0;
-}
-
-/* Log frontend shared helper, magic value indicates log level. Provides
- * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
- * This needs to have small footprint, reasonable performance, minimal
- * memory churn, etc.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_double_t now;
- duk_small_int_t entry_lev = duk_get_current_magic(ctx);
- duk_small_int_t logger_lev;
- duk_int_t nargs;
- duk_int_t i;
- duk_size_t tot_len;
- const duk_uint8_t *arg_str;
- duk_size_t arg_len;
- duk_uint8_t *buf, *p;
- const duk_uint8_t *q;
- duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
- duk_size_t date_len;
- duk_small_int_t rc;
-
- DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
- DUK_UNREF(thr);
-
- /* XXX: sanitize to printable (and maybe ASCII) */
- /* XXX: better multiline */
-
- /*
- * Logger arguments are:
- *
- * magic: log level (0-5)
- * this: logger
- * stack: plain log args
- *
- * We want to minimize memory churn so a two-pass approach
- * is used: first pass formats arguments and computes final
- * string length, second pass copies strings either into a
- * pre-allocated and reused buffer (short messages) or into a
- * newly allocated fixed buffer. If the backend function plays
- * nice, it won't coerce the buffer to a string (and thus
- * intern it).
- */
-
- nargs = duk_get_top(ctx);
-
- /* [ arg1 ... argN this ] */
-
- /*
- * Log level check
- */
-
- duk_push_this(ctx);
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
- logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
- if (entry_lev < logger_lev) {
- return 0;
- }
- /* log level could be popped but that's not necessary */
-
- now = DUK_USE_DATE_GET_NOW(ctx);
- duk_bi_date_format_timeval(now, date_buf);
- date_len = DUK_STRLEN((const char *) date_buf);
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
- duk_to_string(ctx, -1);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- /* [ arg1 ... argN this loggerLevel loggerName ] */
-
- /*
- * Pass 1
- */
-
- /* Line format: <time> <entryLev> <loggerName>: <msg> */
-
- tot_len = 0;
- tot_len += 3 + /* separators: space, space, colon */
- 3 + /* level string */
- date_len + /* time */
- duk_get_length(ctx, -1); /* loggerName */
-
- for (i = 0; i < nargs; i++) {
- /* When formatting an argument to a string, errors may happen from multiple
- * causes. In general we want to catch obvious errors like a toLogString()
- * throwing an error, but we don't currently try to catch every possible
- * error. In particular, internal errors (like out of memory or stack) are
- * not caught. Also, we expect Error toString() to not throw an error.
- */
- if (duk_is_object(ctx, i)) {
- /* duk_pcall_prop() may itself throw an error, but we're content
- * in catching the obvious errors (like toLogString() throwing an
- * error).
- */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT);
- duk_dup(ctx, i);
- /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
- /* call: this.fmt(arg) */
- rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
- if (rc) {
- /* Keep the error as the result (coercing it might fail below,
- * but we don't catch that now).
- */
- ;
- }
- duk_replace(ctx, i);
- }
- (void) duk_to_lstring(ctx, i, &arg_len);
- tot_len++; /* sep (even before first one) */
- tot_len += arg_len;
- }
-
- /*
- * Pass 2
- */
-
- /* XXX: There used to be a shared log buffer here, but it was removed
- * when dynamic buffer spare was removed. The problem with using
- * bufwriter is that, without the spare, the buffer gets passed on
- * as an argument to the raw() call so it'd need to be resized
- * (reallocated) anyway. If raw() call convention is changed, this
- * could be made more efficient.
- */
-
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
- DUK_ASSERT(buf != NULL);
- p = buf;
-
- DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len);
- p += date_len;
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- q = duk__log_level_strings + (entry_lev * 3);
- DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3);
- p += 3;
-
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
- DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
- p += arg_len;
-
- *p++ = (duk_uint8_t) DUK_ASC_COLON;
-
- for (i = 0; i < nargs; i++) {
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
- DUK_ASSERT(arg_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
- p += arg_len;
- }
- DUK_ASSERT(buf + tot_len == p);
-
- /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_LOGGING)
- /* Do debugger forwarding before raw() because the raw() function
- * doesn't get the log level right now.
- */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- const char *log_buf;
- duk_size_t sz_buf;
- log_buf = (const char *) duk_get_buffer(ctx, -1, &sz_buf);
- DUK_ASSERT(log_buf != NULL);
- duk_debug_write_notify(thr, DUK_DBG_CMD_LOG);
- duk_debug_write_int(thr, (duk_int32_t) entry_lev);
- duk_debug_write_string(thr, (const char *) log_buf, sz_buf);
- duk_debug_write_eom(thr);
- }
-#endif
-
- /* Call this.raw(msg); look up through the instance allows user to override
- * the raw() function in the instance or in the prototype for maximum
- * flexibility.
- */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW);
- duk_dup(ctx, -2);
- /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
- duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */
-
- return 0;
-}
-#line 1 "duk_bi_math.c"
+#undef DUK__JSON_STRINGIFY_BUFSIZE
+#undef DUK__MKESC
+#undef DUK__UNEMIT_1
/*
* Math built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_MATH_BUILTIN)
@@ -32426,8 +36588,8 @@ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
typedef double (*duk__one_arg_func)(double);
typedef double (*duk__two_arg_func)(double, double);
-DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
- duk_idx_t n = duk_get_top(ctx);
+DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) {
+ duk_idx_t n = duk_get_top(thr);
duk_idx_t i;
duk_double_t res = initial;
duk_double_t t;
@@ -32444,7 +36606,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk
*/
for (i = 0; i < n; i++) {
- t = duk_to_number(ctx, i);
+ t = duk_to_number(thr, i);
if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
/* Note: not normalized, but duk_push_number() will normalize */
res = (duk_double_t) DUK_DOUBLE_NAN;
@@ -32453,7 +36615,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk
}
}
- duk_push_number(ctx, res);
+ duk_push_number(thr, res);
return 1;
}
@@ -32462,18 +36624,26 @@ DUK_LOCAL double duk__fmin_fixed(double x, double y) {
* -0 as Ecmascript requires.
*/
if (x == 0 && y == 0) {
+ duk_double_union du1, du2;
+ du1.d = x;
+ du2.d = y;
+
+ /* Already checked to be zero so these must hold, and allow us
+ * to check for "x is -0 or y is -0" by ORing the high parts
+ * for comparison.
+ */
+ DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
+ DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
+
/* XXX: what's the safest way of creating a negative zero? */
- if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) {
+ if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) {
+ /* Enter here if either x or y (or both) is -0. */
return -0.0;
} else {
return +0.0;
}
}
-#ifdef DUK_USE_MATH_FMIN
- return DUK_FMIN(x, y);
-#else
- return (x < y ? x : y);
-#endif
+ return duk_double_fmin(x, y);
}
DUK_LOCAL double duk__fmax_fixed(double x, double y) {
@@ -32487,12 +36657,61 @@ DUK_LOCAL double duk__fmax_fixed(double x, double y) {
return -0.0;
}
}
-#ifdef DUK_USE_MATH_FMAX
- return DUK_FMAX(x, y);
+ return duk_double_fmax(x, y);
+}
+
+#if defined(DUK_USE_ES6)
+DUK_LOCAL double duk__cbrt(double x) {
+ /* cbrt() is C99. To avoid hassling embedders with the need to provide a
+ * cube root function, we can get by with pow(). The result is not
+ * identical, but that's OK: ES2015 says it's implementation-dependent.
+ */
+
+#if defined(DUK_CBRT)
+ /* cbrt() matches ES2015 requirements. */
+ return DUK_CBRT(x);
#else
- return (x > y ? x : y);
+ duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
+
+ /* pow() does not, however. */
+ if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
+ return x;
+ }
+ if (DUK_SIGNBIT(x)) {
+ return -DUK_POW(-x, 1.0 / 3.0);
+ } else {
+ return DUK_POW(x, 1.0 / 3.0);
+ }
+#endif
+}
+
+DUK_LOCAL double duk__log2(double x) {
+#if defined(DUK_LOG2)
+ return DUK_LOG2(x);
+#else
+ return DUK_LOG(x) * DUK_DOUBLE_LOG2E;
+#endif
+}
+
+DUK_LOCAL double duk__log10(double x) {
+#if defined(DUK_LOG10)
+ return DUK_LOG10(x);
+#else
+ return DUK_LOG(x) * DUK_DOUBLE_LOG10E;
+#endif
+}
+
+DUK_LOCAL double duk__trunc(double x) {
+#if defined(DUK_TRUNC)
+ return DUK_TRUNC(x);
+#else
+ /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor()
+ * is required to return -0 when the argument is -0.
+ */
+ return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x);
#endif
}
+#endif /* DUK_USE_ES6 */
DUK_LOCAL double duk__round_fixed(double x) {
/* Numbers half-way between integers must be rounded towards +Infinity,
@@ -32535,70 +36754,6 @@ DUK_LOCAL double duk__round_fixed(double x) {
return DUK_FLOOR(x + 0.5);
}
-DUK_LOCAL double duk__pow_fixed(double x, double y) {
- /* The ANSI C pow() semantics differ from Ecmascript.
- *
- * E.g. when x==1 and y is +/- infinite, the Ecmascript required
- * result is NaN, while at least Linux pow() returns 1.
- */
-
- duk_small_int_t cx, cy, sx;
-
- DUK_UNREF(cx);
- DUK_UNREF(sx);
- cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
-
- if (cy == DUK_FP_NAN) {
- goto ret_nan;
- }
- if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
- goto ret_nan;
- }
-#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
- /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
- * correctly handle some cases where x=+/-0. Specific fixes to these
- * here.
- */
- cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
- if (cx == DUK_FP_ZERO && y < 0.0) {
- sx = (duk_small_int_t) DUK_SIGNBIT(x);
- if (sx == 0) {
- /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
- * returns -Infinity instead when y is <0 and finite. The
- * if-clause also catches y == -Infinity (which works even
- * without the fix).
- */
- return DUK_DOUBLE_INFINITY;
- } else {
- /* Math.pow(-0,y) where y<0 should be:
- * - -Infinity if y<0 and an odd integer
- * - Infinity otherwise
- * NetBSD pow() returns -Infinity for all finite y<0. The
- * if-clause also catches y == -Infinity (which works even
- * without the fix).
- */
-
- /* fmod() return value has same sign as input (negative) so
- * the result here will be in the range ]-2,0], 1 indicates
- * odd. If x is -Infinity, NaN is returned and the odd check
- * always concludes "not odd" which results in desired outcome.
- */
- double tmp = DUK_FMOD(y, 2);
- if (tmp == -1.0) {
- return -DUK_DOUBLE_INFINITY;
- } else {
- /* Not odd, or y == -Infinity */
- return DUK_DOUBLE_INFINITY;
- }
- }
- }
-#endif
- return DUK_POW(x, y);
-
- ret_nan:
- return DUK_DOUBLE_NAN;
-}
-
/* Wrappers for calling standard math library methods. These may be required
* on platforms where one or more of the math built-ins are defined as macros
* or inline functions and are thus not suitable to be used as function pointers.
@@ -32640,7 +36795,34 @@ DUK_LOCAL double duk__sqrt(double x) {
DUK_LOCAL double duk__tan(double x) {
return DUK_TAN(x);
}
-DUK_LOCAL double duk__atan2(double x, double y) {
+DUK_LOCAL double duk__atan2_fixed(double x, double y) {
+#if defined(DUK_USE_ATAN2_WORKAROUNDS)
+ /* Specific fixes to common atan2() implementation issues:
+ * - test-bug-mingw-math-issues.js
+ */
+ if (DUK_ISINF(x) && DUK_ISINF(y)) {
+ if (DUK_SIGNBIT(x)) {
+ if (DUK_SIGNBIT(y)) {
+ return -2.356194490192345;
+ } else {
+ return -0.7853981633974483;
+ }
+ } else {
+ if (DUK_SIGNBIT(y)) {
+ return 2.356194490192345;
+ } else {
+ return 0.7853981633974483;
+ }
+ }
+ }
+#else
+ /* Some ISO C assumptions. */
+ DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == 0.7853981633974483);
+ DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == -0.7853981633974483);
+ DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == 2.356194490192345);
+ DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == -2.356194490192345);
+#endif
+
return DUK_ATAN2(x, y);
}
#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
@@ -32660,8 +36842,14 @@ DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
duk__round_fixed,
duk__sin,
duk__sqrt,
- duk__tan
-#else
+ duk__tan,
+#if defined(DUK_USE_ES6)
+ duk__cbrt,
+ duk__log2,
+ duk__log10,
+ duk__trunc
+#endif
+#else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
DUK_FABS,
DUK_ACOS,
DUK_ASIN,
@@ -32674,128 +36862,270 @@ DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
duk__round_fixed,
DUK_SIN,
DUK_SQRT,
- DUK_TAN
+ DUK_TAN,
+#if defined(DUK_USE_ES6)
+ duk__cbrt,
+ duk__log2,
+ duk__log10,
+ duk__trunc
#endif
+#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
};
/* order must match constants in genbuiltins.py */
DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
- duk__atan2,
- duk__pow_fixed
+ duk__atan2_fixed,
+ duk_js_arith_pow
#else
- DUK_ATAN2,
- duk__pow_fixed
+ duk__atan2_fixed,
+ duk_js_arith_pow
#endif
};
-DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) {
+ duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__one_arg_func fun;
+ duk_double_t arg1;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
+ arg1 = duk_to_number(thr, 0);
fun = duk__one_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0)));
+ duk_push_number(thr, (duk_double_t) fun((double) arg1));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) {
+ duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__two_arg_func fun;
+ duk_double_t arg1;
+ duk_double_t arg2;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
+ arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */
+ arg2 = duk_to_number(thr, 1);
fun = duk__two_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1)));
+ duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
- return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) {
+ return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
- return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) {
+ return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
- duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx));
+DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) {
+ duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr));
return 1;
}
-#else /* DUK_USE_MATH_BUILTIN */
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) {
+ /*
+ * E6 Section 20.2.2.18: Math.hypot
+ *
+ * - If no arguments are passed, the result is +0.
+ * - If any argument is +inf, the result is +inf.
+ * - If any argument is -inf, the result is +inf.
+ * - If no argument is +inf or -inf, and any argument is NaN, the result is
+ * NaN.
+ * - If all arguments are either +0 or -0, the result is +0.
+ */
-/* A stubbed built-in is useful for e.g. compilation torture testing with BCC. */
+ duk_idx_t nargs;
+ duk_idx_t i;
+ duk_bool_t found_nan;
+ duk_double_t max;
+ duk_double_t sum, summand;
+ duk_double_t comp, prelim;
+ duk_double_t t;
-DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
+ nargs = duk_get_top(thr);
-DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
+ /* Find the highest value. Also ToNumber() coerces. */
+ max = 0.0;
+ found_nan = 0;
+ for (i = 0; i < nargs; i++) {
+ t = DUK_FABS(duk_to_number(thr, i));
+ if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
+ found_nan = 1;
+ } else {
+ max = duk_double_fmax(max, t);
+ }
+ }
+
+ /* Early return cases. */
+ if (max == DUK_DOUBLE_INFINITY) {
+ duk_push_number(thr, DUK_DOUBLE_INFINITY);
+ return 1;
+ } else if (found_nan) {
+ duk_push_number(thr, DUK_DOUBLE_NAN);
+ return 1;
+ } else if (max == 0.0) {
+ duk_push_number(thr, 0.0);
+ /* Otherwise we'd divide by zero. */
+ return 1;
+ }
+
+ /* Use Kahan summation and normalize to the highest value to minimize
+ * floating point rounding error and avoid overflow.
+ *
+ * https://en.wikipedia.org/wiki/Kahan_summation_algorithm
+ */
+ sum = 0.0;
+ comp = 0.0;
+ for (i = 0; i < nargs; i++) {
+ t = DUK_FABS(duk_get_number(thr, i)) / max;
+ summand = (t * t) - comp;
+ prelim = sum + summand;
+ comp = (prelim - sum) - summand;
+ sum = prelim;
+ }
+
+ duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max);
+ return 1;
}
+#endif /* DUK_USE_ES6 */
-DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) {
+ duk_double_t d;
+
+ d = duk_to_number(thr, 0);
+ if (duk_double_is_nan(d)) {
+ DUK_ASSERT(duk_is_nan(thr, -1));
+ return 1; /* NaN input -> return NaN */
+ }
+ if (d == 0.0) {
+ /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */
+ return 1;
+ }
+ duk_push_int(thr, (d > 0.0 ? 1 : -1));
+ return 1;
}
+#endif /* DUK_USE_ES6 */
-DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) {
+ duk_uint32_t x;
+ duk_small_uint_t i;
+
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_uint32_t mask;
+
+ x = duk_to_uint32(thr, 0);
+ for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) {
+ if (x & mask) {
+ break;
+ }
+ i++;
+ }
+ DUK_ASSERT(i <= 32);
+ duk_push_uint(thr, i);
+ return 1;
+#else /* DUK_USE_PREFER_SIZE */
+ i = 0;
+ x = duk_to_uint32(thr, 0);
+ if (x & 0xffff0000UL) {
+ x >>= 16;
+ } else {
+ i += 16;
+ }
+ if (x & 0x0000ff00UL) {
+ x >>= 8;
+ } else {
+ i += 8;
+ }
+ if (x & 0x000000f0UL) {
+ x >>= 4;
+ } else {
+ i += 4;
+ }
+ if (x & 0x0000000cUL) {
+ x >>= 2;
+ } else {
+ i += 2;
+ }
+ if (x & 0x00000002UL) {
+ x >>= 1;
+ } else {
+ i += 1;
+ }
+ if (x & 0x00000001UL) {
+ ;
+ } else {
+ i += 1;
+ }
+ DUK_ASSERT(i <= 32);
+ duk_push_uint(thr, i);
+ return 1;
+#endif /* DUK_USE_PREFER_SIZE */
}
+#endif /* DUK_USE_ES6 */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) {
+ duk_uint32_t x, y, z;
-DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
+ x = duk_to_uint32(thr, 0);
+ y = duk_to_uint32(thr, 1);
+ z = x * y;
+
+ /* While arguments are ToUint32() coerced and the multiplication
+ * is unsigned as such, the final result is curiously interpreted
+ * as a signed 32-bit value.
+ */
+ duk_push_i32(thr, (duk_int32_t) z);
+ return 1;
}
+#endif /* DUK_USE_ES6 */
#endif /* DUK_USE_MATH_BUILTIN */
-#line 1 "duk_bi_number.c"
/*
* Number built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_NUMBER_BUILTIN)
-DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
+DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
duk_hobject *h;
/* Number built-in accepts a plain number or a Number object (whose
* internal value is operated on). Other types cause TypeError.
*/
- duk_push_this(ctx);
- if (duk_is_number(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ duk_push_this(thr);
+ if (duk_is_number(thr, -1)) {
+ DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
goto done;
}
- h = duk_get_hobject(ctx, -1);
+ h = duk_get_hobject(thr, -1);
if (!h ||
(DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
- DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
+ DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_ERROR_TYPE(thr, "number expected");
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
- duk_remove(ctx, -2);
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
+ duk_remove_m2(thr);
done:
- return duk_get_number(ctx, -1);
+ return duk_get_number(thr, -1);
}
-DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) {
duk_idx_t nargs;
duk_hobject *h_this;
- DUK_UNREF(thr);
-
/*
* The Number constructor uses ToNumber(arg) for number coercion
* (coercing an undefined argument to NaN). However, if the
@@ -32803,15 +37133,15 @@ DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
* this, a vararg function is used.
*/
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
if (nargs == 0) {
- duk_push_int(ctx, 0);
+ duk_push_int(thr, 0);
}
- duk_to_number(ctx, 0);
- duk_set_top(ctx, 1);
- DUK_ASSERT_TOP(ctx, 1);
+ duk_to_number(thr, 0);
+ duk_set_top(thr, 1);
+ DUK_ASSERT_TOP(thr, 1);
- if (!duk_is_constructor_call(ctx)) {
+ if (!duk_is_constructor_call(thr)) {
return 1;
}
@@ -32829,51 +37159,50 @@ DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
*/
/* XXX: helper */
- duk_push_this(ctx);
- h_this = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_this != NULL);
+ duk_push_this(thr);
+ h_this = duk_known_hobject(thr, -1);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
- duk_dup(ctx, 0); /* -> [ val obj val ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup_0(thr); /* -> [ val obj val ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
return 0; /* no return value -> don't replace created value */
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
- (void) duk__push_this_number_plain(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) {
+ (void) duk__push_this_number_plain(thr);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) {
duk_small_int_t radix;
duk_small_uint_t n2s_flags;
- (void) duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
+ (void) duk__push_this_number_plain(thr);
+ if (duk_is_undefined(thr, 0)) {
radix = 10;
} else {
- radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
+ radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36);
}
DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
n2s_flags = 0;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
radix /*radix*/,
0 /*digits*/,
n2s_flags /*flags*/);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) {
/* XXX: just use toString() for now; permitted although not recommended.
* nargs==1, so radix is passed to toString().
*/
- return duk_bi_number_prototype_to_string(ctx);
+ return duk_bi_number_prototype_to_string(thr);
}
/*
@@ -32882,14 +37211,14 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx
/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
- d = duk__push_this_number_plain(ctx);
+ frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
+ d = duk__push_this_number_plain(thr);
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
@@ -32903,53 +37232,53 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_FRACTION_DIGITS;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits /*digits*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) {
duk_bool_t frac_undefined;
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- d = duk__push_this_number_plain(ctx);
+ d = duk__push_this_number_plain(thr);
- frac_undefined = duk_is_undefined(ctx, 0);
- duk_to_int(ctx, 0); /* for side effects */
+ frac_undefined = duk_is_undefined(thr, 0);
+ duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
+ frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
(frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits + 1 /*leading digit + fractions*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
/* The specification has quite awkward order of coercion and
* checks for toPrecision(). The operations below are a bit
* reordered, within constraints of observable side effects.
@@ -32960,27 +37289,27 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT_TOP(thr, 1);
- d = duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
+ d = duk__push_this_number_plain(thr);
+ if (duk_is_undefined(thr, 0)) {
goto use_to_string;
}
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- duk_to_int(ctx, 0); /* for side effects */
+ duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
- prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
+ prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21);
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_NO_ZERO_PAD;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
prec /*digits*/,
n2s_flags /*flags*/);
@@ -32991,194 +37320,135 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
* and +/- infinity (-> "Infinity", "-Infinity").
*/
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
-#line 1 "duk_bi_object.c"
+
+#endif /* DUK_USE_NUMBER_BUILTIN */
/*
* Object built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
- if (!duk_is_constructor_call(ctx) &&
- !duk_is_null_or_undefined(ctx, 0)) {
- duk_to_object(ctx, 0);
- return 1;
- }
+/* Needed even when Object built-in disabled. */
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
+ duk_tval *tv;
+ tv = DUK_HTHREAD_THIS_PTR(thr);
+ /* XXX: This is not entirely correct anymore; in ES2015 the
+ * default lookup should use @@toStringTag to come up with
+ * e.g. [object Symbol].
+ */
+ duk_push_class_string_tval(thr, tv);
+ return 1;
+}
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) {
+ duk_uint_t arg_mask;
+
+ arg_mask = duk_get_type_mask(thr, 0);
- if (duk_is_object(ctx, 0)) {
+ if (!duk_is_constructor_call(thr) && /* not a constructor call */
+ ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */
+ duk_to_object(thr, 0);
return 1;
}
/* Pointer and buffer primitive values are treated like other
* primitives values which have a fully fledged object counterpart:
- * promote to an object value. Lightfuncs are coerced with
- * ToObject() even they could also be returned as is.
- */
- if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
- DUK_TYPE_MASK_BOOLEAN |
- DUK_TYPE_MASK_NUMBER |
- DUK_TYPE_MASK_POINTER |
- DUK_TYPE_MASK_BUFFER |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- duk_to_object(ctx, 0);
+ * promote to an object value. Lightfuncs and plain buffers are
+ * coerced with ToObject() even they could also be returned as is.
+ */
+ if (arg_mask & (DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_STRING |
+ DUK_TYPE_MASK_BOOLEAN |
+ DUK_TYPE_MASK_NUMBER |
+ DUK_TYPE_MASK_POINTER |
+ DUK_TYPE_MASK_BUFFER |
+ DUK_TYPE_MASK_LIGHTFUNC)) {
+ /* For DUK_TYPE_OBJECT the coercion is a no-op and could
+ * be checked for explicitly, but Object(obj) calls are
+ * not very common so opt for minimal footprint.
+ */
+ duk_to_object(thr, 0);
return 1;
}
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- DUK_BIDX_OBJECT_PROTOTYPE);
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
+ DUK_BIDX_OBJECT_PROTOTYPE);
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN */
-/* Shared helper to implement Object.getPrototypeOf and the ES6
- * Object.prototype.__proto__ getter.
- *
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_hobject *proto;
-
- DUK_UNREF(thr);
-
- /* magic: 0=getter call, 1=Object.getPrototypeOf */
- if (duk_get_current_magic(ctx) == 0) {
- duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- }
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- /* h is NULL for lightfunc */
-
- /* XXX: should the API call handle this directly, i.e. attempt
- * to duk_push_hobject(ctx, null) would push a null instead?
- * (On the other hand 'undefined' would be just as logical, but
- * not wanted here.)
- */
-
- if (h == NULL) {
- duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE);
- } else {
- proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- if (proto) {
- duk_push_hobject(ctx, proto);
- } else {
- duk_push_null(ctx);
- }
- }
- return 1;
-}
+#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) {
+ duk_idx_t nargs;
+ duk_int_t idx;
-/* Shared helper to implement ES6 Object.setPrototypeOf and
- * Object.prototype.__proto__ setter.
- *
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_obj;
- duk_hobject *h_new_proto;
- duk_hobject *h_curr;
- duk_ret_t ret_success = 1; /* retval for success path */
+ nargs = duk_get_top_require_min(thr, 1 /*min_top*/);
- /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
- * magic: 0=setter call, 1=Object.setPrototypeOf
- */
- if (duk_get_current_magic(ctx) == 0) {
- duk_push_this_check_object_coercible(ctx);
- duk_insert(ctx, 0);
- if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
- return 0;
+ duk_to_object(thr, 0);
+ for (idx = 1; idx < nargs; idx++) {
+ /* E7 19.1.2.1 (step 4a) */
+ if (duk_is_null_or_undefined(thr, idx)) {
+ continue;
}
- /* __proto__ setter returns 'undefined' on success unlike the
- * setPrototypeOf() call which returns the target object.
+ /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
+ * convenient here.
+ */
+ duk_to_object(thr, idx);
+ duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
+ while (duk_next(thr, -1, 1 /*get_value*/)) {
+ /* [ target ... enum key value ] */
+ duk_put_prop(thr, 0);
+ /* [ target ... enum ] */
+ }
+ /* Could pop enumerator, but unnecessary because of duk_set_top()
+ * below.
*/
- ret_success = 0;
- } else {
- duk_require_object_coercible(ctx, 0);
- duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
- }
-
- h_new_proto = duk_get_hobject(ctx, 1);
- /* h_new_proto may be NULL */
- if (duk_is_lightfunc(ctx, 0)) {
- if (h_new_proto == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]) {
- goto skip;
- }
- goto fail_nonextensible;
- }
- h_obj = duk_get_hobject(ctx, 0);
- if (!h_obj) {
- goto skip;
- }
- DUK_ASSERT(h_obj != NULL);
-
- /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
- /* TODO: implement Proxy object support here */
-
- if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
- goto skip;
- }
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
- goto fail_nonextensible;
- }
- for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
- /* Loop prevention */
- if (h_curr == h_obj) {
- goto fail_loop;
- }
}
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
- /* fall thru */
-
- skip:
- duk_set_top(ctx, 1);
- return ret_success;
- fail_nonextensible:
- fail_loop:
- return DUK_RET_TYPE_ERROR;
+ duk_set_top(thr, 1);
+ return 1;
}
+#endif
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
- /* XXX: no need for indirect call */
- return duk_hobject_object_get_own_property_descriptor(ctx);
+#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2);
+ duk_push_boolean(thr, duk_samevalue(thr, 0, 1));
+ return 1;
}
+#endif
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
- duk_tval *tv;
- duk_hobject *proto = NULL;
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) {
+ duk_hobject *proto;
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_NULL(tv)) {
- ;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- proto = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(proto != NULL);
- } else {
- return DUK_RET_TYPE_ERROR;
- }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ duk_hbufobj_promote_plain(thr, 0);
+#endif
+ proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL);
+ DUK_ASSERT(proto != NULL || duk_is_null(thr, 0));
- (void) duk_push_object_helper_proto(ctx,
+ (void) duk_push_object_helper_proto(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
proto);
- if (!duk_is_undefined(ctx, 1)) {
+ if (!duk_is_undefined(thr, 1)) {
/* [ O Properties obj ] */
- duk_replace(ctx, 0);
+ duk_replace(thr, 0);
/* [ obj Properties ] */
@@ -33186,85 +37456,17 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
* finish up.
*/
- return duk_bi_object_constructor_define_properties(ctx);
+ return duk_bi_object_constructor_define_properties(thr);
}
/* [ O Properties obj ] */
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
- duk_hobject *obj;
- duk_hstring *key;
- duk_hobject *get;
- duk_hobject *set;
- duk_idx_t idx_value;
- duk_uint_t defprop_flags;
-
- DUK_ASSERT(ctx != NULL);
-
- DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
- (void *) ctx,
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
-
- /* [ obj key desc ] */
-
- /* Lightfuncs are currently supported by coercing to a temporary
- * Function object; changes will be allowed (the coerced value is
- * extensible) but will be lost.
- */
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- (void) duk_to_string(ctx, 1);
- key = duk_require_hstring(ctx, 1);
- (void) duk_require_hobject(ctx, 2);
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
-
- /*
- * Validate and convert argument property descriptor (an Ecmascript
- * object) into a set of defprop_flags and possibly property value,
- * getter, and/or setter values on the value stack.
- *
- * Lightfunc set/get values are coerced to full Functions.
- */
-
- duk_hobject_prepare_property_descriptor(ctx,
- 2 /*idx_desc*/,
- &defprop_flags,
- &idx_value,
- &get,
- &set);
-
- /*
- * Use Object.defineProperty() helper for the actual operation.
- */
-
- duk_hobject_define_property_helper(ctx,
- defprop_flags,
- obj,
- key,
- idx_value,
- get,
- set);
-
- /* Ignore the normalize/validate helper outputs on the value stack,
- * they're popped automatically.
- */
-
- /*
- * Return target object.
- */
-
- duk_push_hobject(ctx, obj);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) {
duk_small_uint_t pass;
duk_uint_t defprop_flags;
duk_hobject *obj;
@@ -33272,15 +37474,15 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
duk_hobject *get;
duk_hobject *set;
- /* Lightfunc handling by ToObject() coercion. */
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0); /* target */
+ /* Lightfunc and plain buffer handling by ToObject() coercion. */
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
DUK_ASSERT(obj != NULL);
- duk_to_object(ctx, 1); /* properties object */
+ duk_to_object(thr, 1); /* properties object */
DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
/*
* Two pass approach to processing the property descriptors.
@@ -33293,49 +37495,51 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
*/
for (pass = 0; pass < 2; pass++) {
- duk_set_top(ctx, 2); /* -> [ hobject props ] */
- duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
+ duk_set_top(thr, 2); /* -> [ hobject props ] */
+ duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
for (;;) {
duk_hstring *key;
/* [ hobject props enum(props) ] */
- duk_set_top(ctx, 3);
+ duk_set_top(thr, 3);
- if (!duk_next(ctx, 2, 1 /*get_value*/)) {
+ if (!duk_next(thr, 2, 1 /*get_value*/)) {
break;
}
DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [ hobject props enum(props) key desc ] */
- duk_hobject_prepare_property_descriptor(ctx,
+ duk_hobject_prepare_property_descriptor(thr,
4 /*idx_desc*/,
&defprop_flags,
&idx_value,
&get,
&set);
- /* [ hobject props enum(props) key desc value? getter? setter? ] */
+ /* [ hobject props enum(props) key desc [multiple values] ] */
if (pass == 0) {
continue;
}
- key = duk_get_hstring(ctx, 3);
+ /* This allows symbols on purpose. */
+ key = duk_known_hstring(thr, 3);
DUK_ASSERT(key != NULL);
- duk_hobject_define_property_helper(ctx,
+ duk_hobject_define_property_helper(thr,
defprop_flags,
obj,
key,
idx_value,
get,
- set);
+ set,
+ 1 /*throw_flag*/);
}
}
@@ -33343,269 +37547,654 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
* Return target object
*/
- duk_dup(ctx, 0);
+ duk_dup_0(thr);
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 1);
+
+ duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/);
+ return 1;
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) {
duk_hobject *h;
- duk_bool_t is_freeze;
+ duk_bool_t is_frozen;
+ duk_uint_t mask;
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- /* Lightfunc, always success. */
+ is_frozen = (duk_bool_t) duk_get_current_magic(thr);
+ mask = duk_get_type_mask(thr, 0);
+ if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
+ DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
+ duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
+ 1 : /* lightfunc always frozen and sealed */
+ (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
+ } else {
+ /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
+ * is considered to be already sealed and frozen.
+ */
+ h = duk_get_hobject(thr, 0);
+ duk_push_boolean(thr, (h == NULL) ||
+ duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/));
+ }
+ return 1;
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 0);
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING);
+#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
+ duk_require_callable(thr, 1);
+#endif
+ duk_dup_0(thr); /* -> [ O toString O ] */
+ duk_call_method(thr, 0); /* XXX: call method tail call? */
+ return 1;
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) {
+ /* For lightfuncs and plain buffers, returns Object() coerced. */
+ (void) duk_push_this_coercible_to_object(thr);
+ return 1;
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) {
+ duk_hobject *h_v;
+ duk_hobject *h_obj;
+
+ DUK_ASSERT_TOP(thr, 1);
+
+ h_v = duk_get_hobject(thr, 0);
+ if (!h_v) {
+ duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */
return 1;
}
- is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
- duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
+ h_obj = duk_push_this_coercible_to_object(thr);
+ DUK_ASSERT(h_obj != NULL);
- /* Sealed and frozen objects cannot gain any more properties,
- * so this is a good time to compact them.
+ /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
+ * Prototype loops should cause an error to be thrown.
*/
- duk_hobject_compact_props(thr, h);
-
+ duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) {
+ return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/);
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) {
+ return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
+}
+#endif /* DUK_USE_OBJECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+/* Shared helper to implement Object.getPrototypeOf,
+ * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf.
+ *
+ * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
+ */
+DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) {
+ /*
+ * magic = 0: __proto__ getter
+ * magic = 1: Object.getPrototypeOf()
+ * magic = 2: Reflect.getPrototypeOf()
+ */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h;
+ duk_hobject *proto;
+ duk_tval *tv;
+ duk_int_t magic;
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- /* Lightfunc, always success. */
+ magic = duk_get_current_magic(thr);
+
+ if (magic == 0) {
+ DUK_ASSERT_TOP(thr, 0);
+ duk_push_this_coercible_to_object(thr);
+ }
+ DUK_ASSERT(duk_get_top(thr) >= 1);
+ if (magic < 2) {
+ /* ES2015 Section 19.1.2.9, step 1 */
+ duk_to_object(thr, 0);
+ }
+ tv = DUK_GET_TVAL_POSIDX(thr, 0);
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_BUFFER:
+ proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
+ break;
+ case DUK_TAG_LIGHTFUNC:
+ proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ break;
+ case DUK_TAG_OBJECT:
+ h = DUK_TVAL_GET_OBJECT(tv);
+ proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
+ break;
+ default:
+ /* This implicitly handles CheckObjectCoercible() caused
+ * TypeError.
+ */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ }
+ if (proto != NULL) {
+ duk_push_hobject(thr, proto);
+ } else {
+ duk_push_null(thr);
+ }
+ return 1;
+}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+/* Shared helper to implement ES2015 Object.setPrototypeOf,
+ * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
+ *
+ * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
+ * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
+ */
+DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
+ /*
+ * magic = 0: __proto__ setter
+ * magic = 1: Object.setPrototypeOf()
+ * magic = 2: Reflect.setPrototypeOf()
+ */
+
+ duk_hobject *h_obj;
+ duk_hobject *h_new_proto;
+ duk_hobject *h_curr;
+ duk_ret_t ret_success = 1; /* retval for success path */
+ duk_uint_t mask;
+ duk_int_t magic;
+
+ /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
+ magic = duk_get_current_magic(thr);
+ if (magic == 0) {
+ duk_push_this_check_object_coercible(thr);
+ duk_insert(thr, 0);
+ if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
+ return 0;
+ }
+
+ /* __proto__ setter returns 'undefined' on success unlike the
+ * setPrototypeOf() call which returns the target object.
+ */
+ ret_success = 0;
+ } else {
+ if (magic == 1) {
+ duk_require_object_coercible(thr, 0);
+ } else {
+ duk_require_hobject_accept_mask(thr, 0,
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER);
+ }
+ duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
+ }
+
+ h_new_proto = duk_get_hobject(thr, 1);
+ /* h_new_proto may be NULL */
+
+ mask = duk_get_type_mask(thr, 0);
+ if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
+ duk_hobject *curr_proto;
+ curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
+ DUK_BIDX_FUNCTION_PROTOTYPE :
+ DUK_BIDX_UINT8ARRAY_PROTOTYPE];
+ if (h_new_proto == curr_proto) {
+ goto skip;
+ }
+ goto fail_nonextensible;
+ }
+ h_obj = duk_get_hobject(thr, 0);
+ if (h_obj == NULL) {
+ goto skip;
+ }
+ DUK_ASSERT(h_obj != NULL);
+
+ /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
+ /* TODO: implement Proxy object support here */
+
+ if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
+ goto skip;
+ }
+ if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
+ goto fail_nonextensible;
+ }
+ for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
+ /* Loop prevention. */
+ if (h_curr == h_obj) {
+ goto fail_loop;
+ }
+ }
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
+ /* fall thru */
+
+ skip:
+ duk_set_top(thr, 1);
+ if (magic == 2) {
+ duk_push_true(thr);
+ }
+ return ret_success;
+
+ fail_nonextensible:
+ fail_loop:
+ if (magic != 2) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ } else {
+ duk_push_false(thr);
return 1;
}
- DUK_ASSERT(h != NULL);
+}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
- DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) {
+ /*
+ * magic = 0: Object.defineProperty()
+ * magic = 1: Reflect.defineProperty()
+ */
- /* A non-extensible object cannot gain any more properties,
- * so this is a good time to compact.
+ duk_hobject *obj;
+ duk_hstring *key;
+ duk_hobject *get;
+ duk_hobject *set;
+ duk_idx_t idx_value;
+ duk_uint_t defprop_flags;
+ duk_small_uint_t magic;
+ duk_bool_t throw_flag;
+ duk_bool_t ret;
+
+ DUK_ASSERT(thr != NULL);
+
+ DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
+ (void *) thr,
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
+ (duk_tval *) duk_get_tval(thr, 2)));
+
+ /* [ obj key desc ] */
+
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+
+ /* Lightfuncs are currently supported by coercing to a temporary
+ * Function object; changes will be allowed (the coerced value is
+ * extensible) but will be lost. Same for plain buffers.
*/
- duk_hobject_compact_props(thr, h);
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(obj != NULL);
+ key = duk_to_property_key_hstring(thr, 1);
+ (void) duk_require_hobject(thr, 2);
+
+ DUK_ASSERT(obj != NULL);
+ DUK_ASSERT(key != NULL);
+ DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
+
+ /*
+ * Validate and convert argument property descriptor (an Ecmascript
+ * object) into a set of defprop_flags and possibly property value,
+ * getter, and/or setter values on the value stack.
+ *
+ * Lightfunc set/get values are coerced to full Functions.
+ */
+
+ duk_hobject_prepare_property_descriptor(thr,
+ 2 /*idx_desc*/,
+ &defprop_flags,
+ &idx_value,
+ &get,
+ &set);
+
+ /*
+ * Use Object.defineProperty() helper for the actual operation.
+ */
+
+ DUK_ASSERT(magic == 0U || magic == 1U);
+ throw_flag = magic ^ 1U;
+ ret = duk_hobject_define_property_helper(thr,
+ defprop_flags,
+ obj,
+ key,
+ idx_value,
+ get,
+ set,
+ throw_flag);
+ /* Ignore the normalize/validate helper outputs on the value stack,
+ * they're popped automatically.
+ */
+
+ if (magic == 0U) {
+ /* Object.defineProperty(): return target object. */
+ duk_push_hobject(thr, obj);
+ } else {
+ /* Reflect.defineProperty(): return success/fail. */
+ duk_push_boolean(thr, ret);
+ }
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
- duk_hobject *h;
- duk_bool_t is_frozen;
- duk_bool_t rc;
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2);
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- duk_push_true(ctx); /* frozen and sealed */
- } else {
- is_frozen = duk_get_current_magic(ctx);
- rc = duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/);
- duk_push_boolean(ctx, rc);
+ /* ES2015 Section 19.1.2.6, step 1 */
+ if (duk_get_current_magic(thr) == 0) {
+ duk_to_object(thr, 0);
}
+
+ /* [ obj key ] */
+
+ duk_hobject_object_get_own_property_descriptor(thr, -2);
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) {
+ /*
+ * magic = 0: Object.isExtensible()
+ * magic = 1: Reflect.isExtensible()
+ */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
duk_hobject *h;
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- duk_push_false(ctx);
+ if (duk_get_current_magic(thr) == 0) {
+ h = duk_get_hobject(thr, 0);
} else {
- duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
+ /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
+ * and plain buffers here because they pretend to be objects.
+ */
+ h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
}
+
+ duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+/* Shared helper for various key/symbol listings, magic:
+ * 0=Object.keys()
+ * 1=Object.getOwnPropertyNames(),
+ * 2=Object.getOwnPropertySymbols(),
+ * 3=Reflect.ownKeys()
+ */
+DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
+ /* Object.keys() */
+ DUK_ENUM_OWN_PROPERTIES_ONLY |
+ DUK_ENUM_NO_PROXY_BEHAVIOR,
+
+ /* Object.getOwnPropertyNames() */
+ DUK_ENUM_INCLUDE_NONENUMERABLE |
+ DUK_ENUM_OWN_PROPERTIES_ONLY |
+ DUK_ENUM_NO_PROXY_BEHAVIOR,
+
+ /* Object.getOwnPropertySymbols() */
+ DUK_ENUM_INCLUDE_SYMBOLS |
+ DUK_ENUM_OWN_PROPERTIES_ONLY |
+ DUK_ENUM_EXCLUDE_STRINGS |
+ DUK_ENUM_INCLUDE_NONENUMERABLE |
+ DUK_ENUM_NO_PROXY_BEHAVIOR,
+
+ /* Reflect.ownKeys() */
+ DUK_ENUM_INCLUDE_SYMBOLS |
+ DUK_ENUM_OWN_PROPERTIES_ONLY |
+ DUK_ENUM_INCLUDE_NONENUMERABLE |
+ DUK_ENUM_NO_PROXY_BEHAVIOR
+};
-/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
- * Magic: 0=getOwnPropertyNames, 1=Object.keys.
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
duk_hobject *obj;
#if defined(DUK_USE_ES6_PROXY)
duk_hobject *h_proxy_target;
duk_hobject *h_proxy_handler;
duk_hobject *h_trap_result;
- duk_uarridx_t i, len, idx;
#endif
duk_small_uint_t enum_flags;
+ duk_int_t magic;
- DUK_ASSERT_TOP(ctx, 1);
- DUK_UNREF(thr);
+ DUK_ASSERT_TOP(thr, 1);
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
+ magic = duk_get_current_magic(thr);
+ if (magic == 3) {
+ /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs
+ * and plain buffers pretend to be objects, so accept those too.
+ */
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ } else {
+ /* ES2015: ToObject coerce. */
+ obj = duk_to_hobject(thr, 0);
+ }
DUK_ASSERT(obj != NULL);
DUK_UNREF(obj);
+ /* XXX: proxy chains */
+
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- obj,
+ /* XXX: better sharing of code between proxy target call sites */
+ if (DUK_LIKELY(!duk_hobject_proxy_check(obj,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
}
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
+ duk_push_hobject(thr, h_proxy_handler);
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* Careful with reachability here: don't pop 'obj' before pushing
* proxy target.
*/
DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
- duk_pop_2(ctx);
- duk_push_hobject(ctx, h_proxy_target);
- duk_replace(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
+ duk_pop_2(thr);
+ duk_push_hobject(thr, h_proxy_target);
+ duk_replace(thr, 0);
+ DUK_ASSERT_TOP(thr, 1);
goto skip_proxy;
}
/* [ obj handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
+ duk_insert(thr, -2);
+ duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */
+ duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */
+ h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
- idx = 0;
- duk_push_array(ctx);
- for (i = 0; i < len; i++) {
- /* [ obj trap_result res_arr ] */
- if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
- /* XXX: for Object.keys() we should check enumerability of key */
- /* [ obj trap_result res_arr propname ] */
- duk_put_prop_index(ctx, -2, idx);
- idx++;
- } else {
- duk_pop(ctx);
- }
- }
-
- /* XXX: missing trap result validation for non-configurable target keys
- * (must be present), for non-extensible target all target keys must be
- * present and no extra keys can be present.
- * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
- */
+ magic = duk_get_current_magic(thr);
+ DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
+ enum_flags = duk__object_keys_enum_flags[magic];
- /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
- * should be filtered so that only enumerable keys remain. Enumerability
- * should be checked with [[GetOwnProperty]] on the original object
- * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor
- * trap, it should be triggered for every property. If the proxy doesn't have
- * the trap, enumerability should be checked against the target object instead.
- * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
- * return the same result now for proxy traps. We still do clean up the trap
- * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
- * clean array of strings without gaps.
- */
+ duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
return 1;
skip_proxy:
#endif /* DUK_USE_ES6_PROXY */
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT_TOP(thr, 1);
+ magic = duk_get_current_magic(thr);
+ DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
+ enum_flags = duk__object_keys_enum_flags[magic];
+ return duk_hobject_get_enumerated_keys(thr, enum_flags);
+}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
+
+#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) {
+ /*
+ * magic = 0: Object.preventExtensions()
+ * magic = 1: Reflect.preventExtensions()
+ */
- if (duk_get_current_magic(ctx)) {
- /* Object.keys */
- enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
- DUK_ENUM_NO_PROXY_BEHAVIOR;
- } else {
- /* Object.getOwnPropertyNames */
- enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
- DUK_ENUM_OWN_PROPERTIES_ONLY |
- DUK_ENUM_NO_PROXY_BEHAVIOR;
+ duk_hobject *h;
+ duk_uint_t mask;
+ duk_int_t magic;
+
+ magic = duk_get_current_magic(thr);
+
+ /* Silent success for lightfuncs and plain buffers always. */
+ mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
+
+ /* Object.preventExtensions() silent success for non-object. */
+ if (magic == 0) {
+ mask |= DUK_TYPE_MASK_UNDEFINED |
+ DUK_TYPE_MASK_NULL |
+ DUK_TYPE_MASK_BOOLEAN |
+ DUK_TYPE_MASK_NUMBER |
+ DUK_TYPE_MASK_STRING |
+ DUK_TYPE_MASK_POINTER;
}
- return duk_hobject_get_enumerated_keys(ctx, enum_flags);
-}
+ if (duk_check_type_mask(thr, 0, mask)) {
+ /* Not an object, already non-extensible so always success. */
+ goto done;
+ }
+ h = duk_require_hobject(thr, 0);
+ DUK_ASSERT(h != NULL);
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
- duk_push_this(ctx);
- duk_to_object_class_string_top(ctx);
- return 1;
-}
+ DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
- if (!duk_is_callable(ctx, 1)) {
- return DUK_RET_TYPE_ERROR;
+ /* A non-extensible object cannot gain any more properties,
+ * so this is a good time to compact.
+ */
+ duk_hobject_compact_props(thr, h);
+
+ done:
+ if (magic == 1) {
+ duk_push_true(thr);
}
- duk_dup(ctx, 0); /* -> [ O toString O ] */
- duk_call_method(ctx, 0); /* XXX: call method tail call? */
return 1;
}
+#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- return 1;
-}
+/*
+ * __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
+ */
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_v;
- duk_hobject *h_obj;
+#if defined(DUK_USE_ES8)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) {
+ duk_push_this(thr);
+ duk_insert(thr, 0);
+ duk_to_object(thr, 0);
+ duk_require_callable(thr, 2);
- DUK_ASSERT_TOP(ctx, 1);
+ /* [ ToObject(this) key getter/setter ] */
- h_v = duk_get_hobject(ctx, 0);
- if (!h_v) {
- duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
- return 1;
- }
+ /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */
+ duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE |
+ (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER));
+ return 0;
+}
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) {
+ duk_uint_t sanity;
- h_obj = duk_push_this_coercible_to_object(ctx);
- DUK_ASSERT(h_obj != NULL);
+ duk_push_this(thr);
+ duk_to_object(thr, -1);
- /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
- * Prototype loops should cause an error to be thrown.
+ /* XXX: Prototype walk (with sanity) should be a core property
+ * operation, could add a flag to e.g. duk_get_prop_desc().
*/
- duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
+
+ /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */
+ sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
+ while (!duk_is_undefined(thr, -1)) {
+ /* [ key obj ] */
+ duk_dup(thr, 0);
+ duk_get_prop_desc(thr, 1, 0 /*flags*/);
+ if (!duk_is_undefined(thr, -1)) {
+ duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET));
+ return 1;
+ }
+ duk_pop(thr);
+
+ if (DUK_UNLIKELY(sanity-- == 0)) {
+ DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ }
+
+ duk_get_prototype(thr, -1);
+ duk_remove(thr, -2);
+ }
return 1;
}
+#endif /* DUK_USE_ES8 */
+/*
+ * High resolution time API (performance.now() et al)
+ *
+ * API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/
+ */
+
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
+#if defined(DUK_USE_PERFORMANCE_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) {
+ /* From API spec:
+ * The DOMHighResTimeStamp type is used to store a time value in
+ * milliseconds, measured relative from the time origin, global
+ * monotonic clock, or a time value that represents a duration
+ * between two DOMHighResTimeStamp's.
+ */
+ duk_push_number(thr, duk_time_get_monotonic_time(thr));
+ return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
+#if 0 /* Missing until semantics decided. */
+DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) {
+ /* No decision yet how to handle timeOrigins, e.g. should one be
+ * initialized per heap, or per global object set. See
+ * https://www.w3.org/TR/hr-time/#time-origin.
+ */
+ duk_push_uint(thr, 0);
+ return 1;
}
-#line 1 "duk_bi_pointer.c"
+#endif /* 0 */
+#endif /* DUK_USE_PERFORMANCE_BUILTIN */
/*
* Pointer built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) {
/* XXX: this behavior is quite useless now; it would be nice to be able
* to create pointer values from e.g. numbers or strings. Numbers are
* problematic on 64-bit platforms though. Hex encoded strings?
*/
- if (duk_get_top(ctx) == 0) {
- duk_push_pointer(ctx, NULL);
+ if (duk_get_top(thr) == 0) {
+ duk_push_pointer(thr, NULL);
} else {
- duk_to_pointer(ctx, 0);
+ duk_to_pointer(thr, 0);
}
- DUK_ASSERT(duk_is_pointer(ctx, 0));
- duk_set_top(ctx, 1);
+ DUK_ASSERT(duk_is_pointer(thr, 0));
+ duk_set_top(thr, 1);
- if (duk_is_constructor_call(ctx)) {
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
- DUK_BIDX_POINTER_PROTOTYPE);
+ if (duk_is_constructor_call(thr)) {
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
+ DUK_BIDX_POINTER_PROTOTYPE);
/* Pointer object internal value is immutable */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup_0(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
}
/* Note: unbalanced stack on purpose */
@@ -33616,12 +38205,12 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
* toString(), valueOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
+ duk_small_int_t to_string = duk_get_current_magic(thr);
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_require_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_POINTER(tv)) {
@@ -33635,121 +38224,291 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx
goto type_error;
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
} else {
goto type_error;
}
if (to_string) {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
type_error:
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+}
+/*
+ * Promise built-in
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_PROMISE_BUILTIN)
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
}
-#line 1 "duk_bi_proxy.c"
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+#endif /* DUK_USE_PROMISE_BUILTIN */
/*
- * Proxy built-in (ES6)
+ * Proxy built-in (ES2015)
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
+/* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up
+ * array of valid result keys (strings or symbols). TypeError for invalid
+ * values. Flags are shared with duk_enum().
+ */
+DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
+ duk_uarridx_t i, len, idx;
+ duk_propdesc desc;
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(h_proxy_target != NULL);
+
+ len = (duk_uarridx_t) duk_get_length(thr, -1);
+ idx = 0;
+ duk_push_array(thr);
+ /* XXX: preallocated dense array, fill in directly */
+ for (i = 0; i < len; i++) {
+ duk_hstring *h;
+
+ /* [ obj trap_result res_arr ] */
+ (void) duk_get_prop_index(thr, -2, i);
+ h = duk_get_hstring(thr, -1);
+ if (h == NULL) {
+ DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
+ }
+
+ if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
+ /* No support for 'getOwnPropertyDescriptor' trap yet,
+ * so check enumerability always from target object
+ * descriptor.
+ */
+ if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
+ if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
+ DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
+ goto skip_key;
+ }
+ } else {
+ DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
+ goto skip_key;
+ }
+ }
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
+ DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
+ goto skip_key;
+ }
+ if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
+ DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
+ goto skip_key;
+ }
+ } else {
+ if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
+ DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
+ goto skip_key;
+ }
+ }
+
+ /* [ obj trap_result res_arr propname ] */
+ duk_put_prop_index(thr, -2, idx++);
+ continue;
+
+ skip_key:
+ duk_pop(thr);
+ continue;
}
- /* Reject a proxy object as the target because it would need
- * special handler in property lookups. (ES6 has no such restriction)
+ /* XXX: Missing trap result validation for non-configurable target keys
+ * (must be present), for non-extensible target all target keys must be
+ * present and no extra keys can be present.
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
*/
- h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- DUK_ASSERT(h_target != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
- return DUK_RET_TYPE_ERROR;
- }
- /* Reject a proxy object as the handler because it would cause
- * potentially unbounded recursion. (ES6 has no such restriction)
+ /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor"
+ * trap which has not yet been implemented. In the absence of such a trap,
+ * the enumerability should be checked from the target object; this is
+ * handled above.
*/
- h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1);
- DUK_ASSERT(h_handler != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
- return DUK_RET_TYPE_ERROR;
+}
+#endif /* DUK_USE_ES6_PROXY */
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */
+
+ duk_require_constructor_call(thr);
+ duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */
+ return 1; /* replacement */
+}
+#endif /* DUK_USE_ES6_PROXY */
+/*
+ * 'Reflect' built-in (ES2016 Section 26.1)
+ * http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object
+ *
+ * Many Reflect built-in functions are provided by shared helpers in
+ * duk_bi_object.c or duk_bi_function.c.
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_REFLECT_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) {
+ duk_tval *tv_obj;
+ duk_tval *tv_key;
+ duk_bool_t ret;
+
+ DUK_ASSERT_TOP(thr, 2);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
+
+ /* [ target key ] */
+
+ DUK_ASSERT(thr != NULL);
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
+ ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
+ duk_push_boolean(thr, ret);
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
+ duk_tval *tv_obj;
+ duk_tval *tv_key;
+ duk_idx_t nargs;
+
+ DUK_ASSERT(thr != NULL);
+ nargs = duk_get_top_require_min(thr, 2 /*min_top*/);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
+ if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
+ /* XXX: [[Get]] receiver currently unsupported */
+ DUK_ERROR_UNSUPPORTED(thr);
}
- /* XXX: the returned value is exotic in ES6, but we use a
- * simple object here with no prototype. Without a prototype,
- * [[DefaultValue]] coercion fails which is abit confusing.
- * No callable check/handling in the current Proxy subset.
- */
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- NULL);
- DUK_ASSERT_TOP(ctx, 3);
+ /* [ target key receiver? ...? ] */
- /* Make _Target and _Handler non-configurable and non-writable.
- * They can still be forcibly changed by C code (both user and
- * Duktape internal), but not by Ecmascript code.
- */
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
+ (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */
+ return 1;
+}
- /* Proxy target */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) {
+ duk_tval *tv_obj;
+ duk_tval *tv_key;
+ duk_bool_t ret;
- /* Proxy handler */
- duk_dup(ctx, 1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_TOP(thr, 2);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
- return 1; /* replacement handler */
+ /* [ target key ] */
+
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
+ ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
+ duk_push_boolean(thr, ret);
+ return 1;
}
-#else /* DUK_USE_ES6_PROXY */
-DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
+ duk_tval *tv_obj;
+ duk_tval *tv_key;
+ duk_tval *tv_val;
+ duk_idx_t nargs;
+ duk_bool_t ret;
+
+ DUK_ASSERT(thr != NULL);
+ nargs = duk_get_top_require_min(thr, 3 /*min_top*/);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
+ if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
+ /* XXX: [[Set]] receiver currently unsupported */
+ DUK_ERROR_UNSUPPORTED(thr);
+ }
+
+ /* [ target key value receiver? ...? ] */
+
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
+ tv_val = DUK_GET_TVAL_POSIDX(thr, 2);
+ ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
+ duk_push_boolean(thr, ret);
+ return 1;
}
-#endif /* DUK_USE_ES6_PROXY */
-#line 1 "duk_bi_regexp.c"
+#endif /* DUK_USE_REFLECT_BUILTIN */
/*
* RegExp built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
-DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
+DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) {
duk_hobject *h;
- duk_push_this(ctx);
- h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
+ duk_push_this(thr);
+ h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP);
DUK_ASSERT(h != NULL);
DUK_UNREF(h);
- duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
+ duk_insert(thr, 0); /* prepend regexp to valstack 0 index */
}
/* XXX: much to improve (code size) */
-DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) {
duk_hobject *h_pattern;
- DUK_ASSERT_TOP(ctx, 2);
- h_pattern = duk_get_hobject(ctx, 0);
+ DUK_ASSERT_TOP(thr, 2);
+ h_pattern = duk_get_hobject(thr, 0);
- if (!duk_is_constructor_call(ctx) &&
+ if (!duk_is_constructor_call(thr) &&
h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
- duk_is_undefined(ctx, 1)) {
+ duk_is_undefined(thr, 1)) {
/* Called as a function, pattern has [[Class]] "RegExp" and
* flags is undefined -> return object as is.
*/
- duk_dup(ctx, 0);
+ /* XXX: ES2015 has a NewTarget SameValue() check which is not
+ * yet implemented.
+ */
+ duk_dup_0(thr);
return 1;
}
@@ -33759,44 +38518,40 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
if (h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
- if (duk_is_undefined(ctx, 1)) {
- duk_bool_t flag_g, flag_i, flag_m;
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
- flag_g = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
- flag_i = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL);
- flag_m = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL);
-
- duk_push_sprintf(ctx, "%s%s%s",
- (const char *) (flag_g ? "g" : ""),
- (const char *) (flag_i ? "i" : ""),
- (const char *) (flag_m ? "m" : ""));
-
- /* [ ... pattern flags ] */
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE);
+ if (duk_is_undefined(thr, 1)) {
+ /* In ES5 one would need to read the flags individually;
+ * in ES2015 just read .flags.
+ */
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
} else {
- return DUK_RET_TYPE_ERROR;
+ /* In ES2015 allowed; overrides argument RegExp flags. */
+ duk_dup_1(thr);
}
} else {
- if (duk_is_undefined(ctx, 0)) {
- duk_push_string(ctx, "");
+ if (duk_is_undefined(thr, 0)) {
+ duk_push_hstring_empty(thr);
} else {
- duk_dup(ctx, 0);
- duk_to_string(ctx, -1);
+ duk_dup_0(thr);
+ duk_to_string(thr, -1); /* Rejects Symbols. */
}
- if (duk_is_undefined(ctx, 1)) {
- duk_push_string(ctx, "");
+ if (duk_is_undefined(thr, 1)) {
+ duk_push_hstring_empty(thr);
} else {
- duk_dup(ctx, 1);
- duk_to_string(ctx, -1);
+ duk_dup_1(thr);
+ duk_to_string(thr, -1); /* Rejects Symbols. */
}
/* [ ... pattern flags ] */
}
DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
- /* [ ... pattern flags ] */
+ /* [ ... pattern flags ] (both uncoerced) */
+ duk_to_string(thr, -2);
+ duk_to_string(thr, -1);
duk_regexp_compile(thr);
/* [ ... bytecode escaped_source ] */
@@ -33808,126 +38563,148 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
- duk__get_this_regexp(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) {
+ duk__get_this_regexp(thr);
/* [ regexp input ] */
- duk_regexp_match((duk_hthread *) ctx);
+ duk_regexp_match(thr);
/* [ result ] */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
- duk__get_this_regexp(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) {
+ duk__get_this_regexp(thr);
/* [ regexp input ] */
/* result object is created and discarded; wasteful but saves code space */
- duk_regexp_match((duk_hthread *) ctx);
+ duk_regexp_match(thr);
/* [ result ] */
- duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
+ duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
- duk_hstring *h_bc;
- duk_small_int_t re_flags;
-
-#if 0
- /* A little tricky string approach to provide the flags string.
- * This depends on the specific flag values in duk_regexp.h,
- * which needs to be asserted for. In practice this doesn't
- * produce more compact code than the easier approach in use.
- */
-
- const char *flag_strings = "gim\0gi\0gm\0g\0";
- duk_uint8_t flag_offsets[8] = {
- (duk_uint8_t) 3, /* flags: "" */
- (duk_uint8_t) 10, /* flags: "g" */
- (duk_uint8_t) 5, /* flags: "i" */
- (duk_uint8_t) 4, /* flags: "gi" */
- (duk_uint8_t) 2, /* flags: "m" */
- (duk_uint8_t) 7, /* flags: "gm" */
- (duk_uint8_t) 1, /* flags: "im" */
- (duk_uint8_t) 0, /* flags: "gim" */
- };
- DUK_ASSERT(DUK_RE_FLAG_GLOBAL == 1);
- DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE == 2);
- DUK_ASSERT(DUK_RE_FLAG_MULTILINE == 4);
-#endif
-
- duk__get_this_regexp(ctx);
-
- /* [ regexp ] */
-
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_BYTECODE);
- h_bc = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_bc != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);
- DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
- DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);
- re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
-
- /* [ regexp source bytecode ] */
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
+ /* This must be generic in ES2015 and later. */
+ DUK_ASSERT_TOP(thr, 0);
+ duk_push_this(thr);
+ duk_push_string(thr, "/");
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
+ duk_dup_m2(thr); /* another "/" */
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
+ duk_concat(thr, 4);
+ return 1;
+}
-#if 1
- /* This is a cleaner approach and also produces smaller code than
- * the other alternative. Use duk_require_string() for format
- * safety (although the source property should always exist).
- */
- duk_push_sprintf(ctx, "/%s/%s%s%s",
- (const char *) duk_require_string(ctx, -2), /* require to be safe */
- (re_flags & DUK_RE_FLAG_GLOBAL) ? "g" : "",
- (re_flags & DUK_RE_FLAG_IGNORE_CASE) ? "i" : "",
- (re_flags & DUK_RE_FLAG_MULTILINE) ? "m" : "");
-#else
- /* This should not be necessary because no-one should tamper with the
- * regexp bytecode, but is prudent to avoid potential segfaults if that
- * were to happen for some reason.
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) {
+ /* .flags is ES2015 but present even when ES2015 bindings are
+ * disabled because the constructor relies on it.
*/
- re_flags &= 0x07;
- DUK_ASSERT(re_flags >= 0 && re_flags <= 7); /* three flags */
- duk_push_sprintf(ctx, "/%s/%s",
- (const char *) duk_require_string(ctx, -2),
- (const char *) (flag_strings + flag_offsets[re_flags]));
-#endif
+ duk_uint8_t buf[8]; /* enough for all flags + NUL */
+ duk_uint8_t *p = buf;
+ /* .flags is generic and works on any object. */
+ duk_push_this(thr);
+ (void) duk_require_hobject(thr, -1);
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) {
+ *p++ = DUK_ASC_LC_G;
+ }
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
+ *p++ = DUK_ASC_LC_I;
+ }
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) {
+ *p++ = DUK_ASC_LC_M;
+ }
+ /* .unicode: to be added */
+ /* .sticky: to be added */
+ *p++ = DUK_ASC_NUL;
+ DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
+
+ duk_push_string(thr, (const char *) buf);
return 1;
}
-#else /* DUK_USE_REGEXP_SUPPORT */
+/* Shared helper for providing .source, .global, .multiline, etc getters. */
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
+ duk_hstring *h_bc;
+ duk_small_uint_t re_flags;
+ duk_hobject *h;
+ duk_int_t magic;
-DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
+ DUK_ASSERT_TOP(thr, 0);
+
+ duk_push_this(thr);
+ h = duk_require_hobject(thr, -1);
+ magic = duk_get_current_magic(thr);
+
+ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE);
+ h_bc = duk_require_hstring(thr, -1);
+ re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
+ duk_pop(thr);
+ } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
+ /* In ES2015 and ES2016 a TypeError would be thrown here.
+ * However, this had real world issues so ES2017 draft
+ * allows RegExp.prototype specifically, returning '(?:)'
+ * for .source and undefined for all flags.
+ */
+ if (magic != 16 /* .source */) {
+ return 0;
+ }
+ duk_push_string(thr, "(?:)"); /* .source handled by switch-case */
+ re_flags = 0;
+ } else {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ }
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
+ /* [ regexp source ] */
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
+ switch (magic) {
+ case 0: { /* global */
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL));
+ break;
+ }
+ case 1: { /* ignoreCase */
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
+ break;
+ }
+ case 2: { /* multiline */
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE));
+ break;
+ }
+#if 0
+ /* Don't provide until implemented to avoid interfering with feature
+ * detection in user code.
+ */
+ case 3: /* sticky */
+ case 4: { /* unicode */
+ duk_push_false(thr);
+ break;
+ }
+#endif
+ default: { /* source */
+ /* leave 'source' on top */
+ break;
+ }
+ }
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ return 1;
}
#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_bi_string.c"
/*
* String built-ins
+ *
+ * Most String built-ins must only accept strings (or String objects).
+ * Symbols, represented internally as strings, must be generally rejected.
+ * The duk_push_this_coercible_to_string() helper does this automatically.
*/
/* XXX: There are several limitations in the current implementation for
@@ -33939,43 +38716,147 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
* offsets/lengths.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_STRING_BUILTIN)
+
+/*
+ * Helpers
+ */
+
+DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ h = duk_to_hstring(thr, idx);
+ DUK_ASSERT(h != NULL);
+
+ return h;
+}
+
+DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) {
+ duk_int_t cpos;
+ duk_int_t bpos;
+ const duk_uint8_t *p_start, *p_end, *p;
+ const duk_uint8_t *q_start;
+ duk_int_t q_blen;
+ duk_uint8_t firstbyte;
+ duk_uint8_t t;
+
+ cpos = start_cpos;
+
+ /* Empty searchstring always matches; cpos must be clamped here.
+ * (If q_blen were < 0 due to clamped coercion, it would also be
+ * caught here.)
+ */
+ q_start = DUK_HSTRING_GET_DATA(h_search);
+ q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
+ if (q_blen <= 0) {
+ return cpos;
+ }
+ DUK_ASSERT(q_blen > 0);
+
+ bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
+
+ p_start = DUK_HSTRING_GET_DATA(h_this);
+ p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
+ p = p_start + bpos;
+
+ /* This loop is optimized for size. For speed, there should be
+ * two separate loops, and we should ensure that memcmp() can be
+ * used without an extra "will searchstring fit" check. Doing
+ * the preconditioning for 'p' and 'p_end' is easy but cpos
+ * must be updated if 'p' is wound back (backward scanning).
+ */
+
+ firstbyte = q_start[0]; /* leading byte of match string */
+ while (p <= p_end && p >= p_start) {
+ t = *p;
+
+ /* For Ecmascript strings, this check can only match for
+ * initial UTF-8 bytes (not continuation bytes). For other
+ * strings all bets are off.
+ */
+
+ if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
+ DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
+ if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
+ return cpos;
+ }
+ }
+
+ /* track cpos while scanning */
+ if (backwards) {
+ /* when going backwards, we decrement cpos 'early';
+ * 'p' may point to a continuation byte of the char
+ * at offset 'cpos', but that's OK because we'll
+ * backtrack all the way to the initial byte.
+ */
+ if ((t & 0xc0) != 0x80) {
+ cpos--;
+ }
+ p--;
+ } else {
+ if ((t & 0xc0) != 0x80) {
+ cpos++;
+ }
+ p++;
+ }
+ }
+
+ /* Not found. Empty string case is handled specially above. */
+ return -1;
+}
/*
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) {
+ duk_hstring *h;
+ duk_uint_t flags;
+
/* String constructor needs to distinguish between an argument not given at all
* vs. given as 'undefined'. We're a vararg function to handle this properly.
*/
- if (duk_get_top(ctx) == 0) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ /* XXX: copy current activation flags to thr, including current magic,
+ * is_constructor_call etc. This takes a few bytes in duk_hthread but
+ * makes call sites smaller (there are >30 is_constructor_call and get
+ * current magic call sites.
+ */
+
+ if (duk_get_top(thr) == 0) {
+ duk_push_hstring_empty(thr);
} else {
- duk_to_string(ctx, 0);
+ h = duk_to_hstring_acceptsymbol(thr, 0);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) {
+ duk_push_symbol_descriptive_string(thr, h);
+ duk_replace(thr, 0);
+ }
}
- DUK_ASSERT(duk_is_string(ctx, 0));
- duk_set_top(ctx, 1);
-
- if (duk_is_constructor_call(ctx)) {
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING),
- DUK_BIDX_STRING_PROTOTYPE);
+ duk_to_string(thr, 0); /* catches symbol argument for constructor call */
+ DUK_ASSERT(duk_is_string(thr, 0));
+ duk_set_top(thr, 1); /* Top may be 1 or larger. */
+ if (duk_is_constructor_call(thr)) {
/* String object internal value is immutable */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
+ duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE);
+ duk_dup_0(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
}
/* Note: unbalanced stack on purpose */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) {
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
duk_idx_t i, n;
@@ -33987,50 +38868,75 @@ DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx
* build a string from a duk_tval number sequence in one go?).
*/
- n = duk_get_top(ctx);
+ n = duk_get_top(thr);
bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
+ DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n); /* initial estimate for ASCII only codepoints */
for (i = 0; i < n; i++) {
/* XXX: could improve bufwriter handling to write multiple codepoints
* with one ensure call but the relative benefit would be quite small.
*/
+ if (nonbmp) {
+ /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and
+ * (2) cp >= 0 and cp <= 0x10ffff. This check does not
+ * implement the steps exactly but the outcome should be
+ * the same.
+ */
+ duk_int32_t i32 = 0;
+ if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) ||
+ i32 < 0 || i32 > 0x10ffffL) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+ }
+ DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL);
+ cp = (duk_ucodepoint_t) i32;
+ DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
+ } else {
#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
- /* ToUint16() coercion is mandatory in the E5.1 specification, but
- * this non-compliant behavior makes more sense because we support
- * non-BMP codepoints. Don't use CESU-8 because that'd create
- * surrogate pairs.
- */
-
- cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
- DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
+ /* ToUint16() coercion is mandatory in the E5.1 specification, but
+ * this non-compliant behavior makes more sense because we support
+ * non-BMP codepoints. Don't use CESU-8 because that'd create
+ * surrogate pairs.
+ */
+ cp = (duk_ucodepoint_t) duk_to_uint32(thr, i);
+ DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
#else
- cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
- DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
+ cp = (duk_ucodepoint_t) duk_to_uint16(thr, i);
+ DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL);
+ DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
#endif
+ }
}
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */
return 1;
}
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) {
+ return duk__construct_from_codepoints(thr, 0 /*nonbmp*/);
+}
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) {
+ return duk__construct_from_codepoints(thr, 1 /*nonbmp*/);
+}
+#endif
+
/*
* toString(), valueOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_require_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_STRING(tv)) {
/* return as is */
- return 1;
} else if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
@@ -34040,59 +38946,73 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
goto type_error;
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- return 1;
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_string(thr, -1));
} else {
goto type_error;
}
- /* never here, but fall through */
+ (void) duk_require_hstring_notsymbol(thr, -1); /* Reject symbols (and wrapped symbols). */
+ return 1;
type_error:
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/*
* Character and charcode access
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) {
duk_int_t pos;
/* XXX: faster implementation */
- (void) duk_push_this_coercible_to_string(ctx);
- pos = duk_to_int(ctx, 0);
- duk_substring(ctx, -1, pos, pos + 1);
+ (void) duk_push_this_coercible_to_string(thr);
+ pos = duk_to_int(thr, 0);
+ duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) (pos + 1));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Magic: 0=charCodeAt, 1=codePointAt */
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) {
duk_int_t pos;
duk_hstring *h;
duk_bool_t clamped;
+ duk_uint32_t cp;
+ duk_int_t magic;
/* XXX: faster implementation */
- DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
+ DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(thr, 0)));
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
- pos = duk_to_int_clamped_raw(ctx,
+ pos = duk_to_int_clamped_raw(thr,
0 /*index*/,
0 /*min(incl)*/,
- DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
+ (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
&clamped /*out_clamped*/);
+#if defined(DUK_USE_ES6)
+ magic = duk_get_current_magic(thr);
+#else
+ DUK_ASSERT(duk_get_current_magic(thr) == 0);
+ magic = 0;
+#endif
if (clamped) {
- duk_push_number(ctx, DUK_DOUBLE_NAN);
- return 1;
+ /* For out-of-bounds indices .charCodeAt() returns NaN and
+ * .codePointAt() returns undefined.
+ */
+ if (magic != 0) {
+ return 0;
+ }
+ duk_push_nan(thr);
+ } else {
+ DUK_ASSERT(pos >= 0);
+ cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/);
+ duk_push_u32(thr, cp);
}
-
- duk_push_u32(ctx, (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos));
return 1;
}
@@ -34104,22 +39024,22 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
* different algorithms so that footprint would be reduced?
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
/* [ start end str ] */
- start_pos = duk_to_int_clamped(ctx, 0, 0, len);
- if (duk_is_undefined(ctx, 1)) {
+ start_pos = duk_to_int_clamped(thr, 0, 0, len);
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
- end_pos = duk_to_int_clamped(ctx, 1, 0, len);
+ end_pos = duk_to_int_clamped(thr, 1, 0, len);
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
DUK_ASSERT(end_pos >= 0 && end_pos <= len);
@@ -34132,12 +39052,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
-#ifdef DUK_USE_SECTION_B
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
+#if defined(DUK_USE_SECTION_B)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
@@ -34146,8 +39066,8 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
* specification will happily coerce undefined and null to strings
* ("undefined" and "null").
*/
- duk_push_this(ctx);
- h = duk_to_hstring(ctx, -1);
+ duk_push_this(thr);
+ h = duk_to_hstring_m1(thr); /* Reject Symbols. */
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
@@ -34159,52 +39079,47 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
*/
/* combines steps 2 and 5; -len ensures max() not needed for step 5 */
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
+ start_pos = duk_to_int_clamped(thr, 0, -len, len);
if (start_pos < 0) {
start_pos = len + start_pos;
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
/* combines steps 3, 6; step 7 is not needed */
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
DUK_ASSERT(start_pos <= len);
- end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
+ end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos);
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
DUK_ASSERT(end_pos >= 0 && end_pos <= len);
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
-#else /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
/* [ start end str ] */
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
+ start_pos = duk_to_int_clamped(thr, 0, -len, len);
if (start_pos < 0) {
start_pos = len + start_pos;
}
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
- end_pos = duk_to_int_clamped(ctx, 1, -len, len);
+ end_pos = duk_to_int_clamped(thr, 1, -len, len);
if (end_pos < 0) {
end_pos = len + end_pos;
}
@@ -34218,7 +39133,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
@@ -34226,11 +39141,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
* Case conversion
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t uppercase = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) {
+ duk_small_int_t uppercase = duk_get_current_magic(thr);
- (void) duk_push_this_coercible_to_string(ctx);
+ (void) duk_push_this_coercible_to_string(thr);
duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
return 1;
}
@@ -34239,101 +39153,33 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx)
* indexOf() and lastIndexOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) {
duk_hstring *h_this;
duk_hstring *h_search;
duk_int_t clen_this;
duk_int_t cpos;
- duk_int_t bpos;
- const duk_uint8_t *p_start, *p_end, *p;
- const duk_uint8_t *q_start;
- duk_int_t q_blen;
- duk_uint8_t firstbyte;
- duk_uint8_t t;
- duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
+ duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr); /* 0=indexOf, 1=lastIndexOf */
- h_this = duk_push_this_coercible_to_string(ctx);
+ h_this = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_this != NULL);
clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
- h_search = duk_to_hstring(ctx, 0);
+ h_search = duk_to_hstring(thr, 0);
DUK_ASSERT(h_search != NULL);
- q_start = DUK_HSTRING_GET_DATA(h_search);
- q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
- duk_to_number(ctx, 1);
- if (duk_is_nan(ctx, 1) && is_lastindexof) {
+ duk_to_number(thr, 1);
+ if (duk_is_nan(thr, 1) && is_lastindexof) {
/* indexOf: NaN should cause pos to be zero.
* lastIndexOf: NaN should cause pos to be +Infinity
* (and later be clamped to len).
*/
cpos = clen_this;
} else {
- cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
- }
-
- /* Empty searchstring always matches; cpos must be clamped here.
- * (If q_blen were < 0 due to clamped coercion, it would also be
- * caught here.)
- */
- if (q_blen <= 0) {
- duk_push_int(ctx, cpos);
- return 1;
+ cpos = duk_to_int_clamped(thr, 1, 0, clen_this);
}
- DUK_ASSERT(q_blen > 0);
- bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
-
- p_start = DUK_HSTRING_GET_DATA(h_this);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
- p = p_start + bpos;
-
- /* This loop is optimized for size. For speed, there should be
- * two separate loops, and we should ensure that memcmp() can be
- * used without an extra "will searchstring fit" check. Doing
- * the preconditioning for 'p' and 'p_end' is easy but cpos
- * must be updated if 'p' is wound back (backward scanning).
- */
-
- firstbyte = q_start[0]; /* leading byte of match string */
- while (p <= p_end && p >= p_start) {
- t = *p;
-
- /* For Ecmascript strings, this check can only match for
- * initial UTF-8 bytes (not continuation bytes). For other
- * strings all bets are off.
- */
-
- if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
- DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- duk_push_int(ctx, cpos);
- return 1;
- }
- }
-
- /* track cpos while scanning */
- if (is_lastindexof) {
- /* when going backwards, we decrement cpos 'early';
- * 'p' may point to a continuation byte of the char
- * at offset 'cpos', but that's OK because we'll
- * backtrack all the way to the initial byte.
- */
- if ((t & 0xc0) != 0x80) {
- cpos--;
- }
- p--;
- } else {
- if ((t & 0xc0) != 0x80) {
- cpos++;
- }
- p++;
- }
- }
-
- /* Not found. Empty string case is handled specially above. */
- duk_push_int(ctx, -1);
+ cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/);
+ duk_push_int(thr, cpos);
return 1;
}
@@ -34352,35 +39198,34 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx)
* - API call to get_prop and to_boolean
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) {
duk_hstring *h_input;
duk_hstring *h_match;
duk_hstring *h_search;
duk_hobject *h_re;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
duk_bool_t is_regexp;
duk_bool_t is_global;
#endif
duk_bool_t is_repl_func;
duk_uint32_t match_start_coff, match_start_boff;
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
duk_int_t match_caps;
#endif
duk_uint32_t prev_match_end_boff;
const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
duk_size_t tmp_sz;
- DUK_ASSERT_TOP(ctx, 2);
- h_input = duk_push_this_coercible_to_string(ctx);
+ DUK_ASSERT_TOP(thr, 2);
+ h_input = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
/* stack[0] = search value
* stack[1] = replace value
@@ -34388,29 +39233,29 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* stack[3] = result buffer
*/
- h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
+ h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP);
if (h_re) {
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 1;
- is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
+ is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
if (is_global) {
/* start match from beginning */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
#else /* DUK_USE_REGEXP_SUPPORT */
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_UNSUPPORTED(thr);
#endif /* DUK_USE_REGEXP_SUPPORT */
} else {
- duk_to_string(ctx, 0);
-#ifdef DUK_USE_REGEXP_SUPPORT
+ duk_to_string(thr, 0); /* rejects symbols */
+#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 0;
is_global = 0;
#endif
}
- if (duk_is_function(ctx, 1)) {
+ if (duk_is_function(thr, 1)) {
is_repl_func = 1;
r_start = NULL;
r_end = NULL;
@@ -34418,7 +39263,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
duk_hstring *h_repl;
is_repl_func = 0;
- h_repl = duk_to_hstring(ctx, 1);
+ h_repl = duk_to_hstring(thr, 1); /* reject symbols */
DUK_ASSERT(h_repl != NULL);
r_start = DUK_HSTRING_GET_DATA(h_repl);
r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
@@ -34450,28 +39295,27 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* are made? See: test-bi-string-proto-replace.js for discussion.
*/
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_dup(ctx, 0);
- duk_dup(ctx, 2);
+ duk_dup_0(thr);
+ duk_dup_2(thr);
duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_start_coff = duk_get_uint(thr, -1);
+ duk_pop(thr);
- duk_get_prop_index(ctx, -1, 0);
- DUK_ASSERT(duk_is_string(ctx, -1));
- h_match = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_match != NULL);
- duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
+ duk_get_prop_index(thr, -1, 0);
+ DUK_ASSERT(duk_is_string(thr, -1));
+ h_match = duk_known_hstring(thr, -1);
+ duk_pop(thr); /* h_match is borrowed, remains reachable through match_obj */
if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
/* This should be equivalent to match() algorithm step 8.f.iii.2:
@@ -34479,17 +39323,17 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
*/
duk_uint32_t last_index;
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ last_index = (duk_uint32_t) duk_get_uint(thr, -1);
DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
(long) last_index, (long) (last_index + 1)));
- duk_pop(ctx);
- duk_push_int(ctx, last_index + 1);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_pop(thr);
+ duk_push_uint(thr, (duk_uint_t) (last_index + 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
- DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
- match_caps = (duk_int_t) duk_get_length(ctx, -1);
+ DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX); /* string limits */
+ match_caps = (duk_int_t) duk_get_length(thr, -1);
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
{ /* unconditionally */
@@ -34498,7 +39342,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
const duk_uint8_t *q_start; /* match string */
duk_size_t q_blen;
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_ASSERT(!is_global); /* single match always */
#endif
@@ -34506,8 +39350,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
- h_search = duk_get_hstring(ctx, 0);
- DUK_ASSERT(h_search != NULL);
+ h_search = duk_known_hstring(thr, 0);
q_start = DUK_HSTRING_GET_DATA(h_search);
q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
@@ -34518,10 +39361,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
while (p <= p_end) {
DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- duk_dup(ctx, 0);
- h_match = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_match != NULL);
-#ifdef DUK_USE_REGEXP_SUPPORT
+ duk_dup_0(thr);
+ h_match = duk_known_hstring(thr, -1);
+#if defined(DUK_USE_REGEXP_SUPPORT)
match_caps = 0;
#endif
goto found;
@@ -34546,7 +39388,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* stack[4] = regexp match OR match string
*/
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
+ match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
@@ -34559,43 +39401,43 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
/* regexp res_obj is at index 4 */
- duk_dup(ctx, 1);
- idx_args = duk_get_top(ctx);
+ duk_dup_1(thr);
+ idx_args = duk_get_top(thr);
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
duk_int_t idx;
- duk_require_stack(ctx, match_caps + 2);
+ duk_require_stack(thr, match_caps + 2);
for (idx = 0; idx < match_caps; idx++) {
/* match followed by capture(s) */
- duk_get_prop_index(ctx, 4, idx);
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) idx);
}
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
{ /* unconditionally */
#endif /* DUK_USE_REGEXP_SUPPORT */
/* match == search string, by definition */
- duk_dup(ctx, 0);
+ duk_dup_0(thr);
}
- duk_push_int(ctx, match_start_coff);
- duk_dup(ctx, 2);
+ duk_push_uint(thr, (duk_uint_t) match_start_coff);
+ duk_dup_2(thr);
/* [ ... replacer match [captures] match_char_offset input ] */
- duk_call(ctx, duk_get_top(ctx) - idx_args);
- h_repl = duk_to_hstring(ctx, -1); /* -> [ ... repl_value ] */
+ duk_call(thr, duk_get_top(thr) - idx_args);
+ h_repl = duk_to_hstring_m1(thr); /* -> [ ... repl_value ] */
DUK_ASSERT(h_repl != NULL);
DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
- duk_pop(ctx); /* repl_value */
+ duk_pop(thr); /* repl_value */
} else {
r = r_start;
while (r < r_end) {
duk_int_t ch1;
duk_int_t ch2;
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
duk_int_t ch3;
#endif
duk_size_t left;
@@ -34604,14 +39446,15 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
if (ch1 != DUK_ASC_DOLLAR) {
goto repl_write;
}
- left = r_end - r;
+ DUK_ASSERT(r <= r_end);
+ left = (duk_size_t) (r_end - r);
if (left <= 0) {
goto repl_write;
}
ch2 = r[0];
- switch ((int) ch2) {
+ switch (ch2) {
case DUK_ASC_DOLLAR: {
ch1 = (1 << 8) + DUK_ASC_DOLLAR;
goto repl_write;
@@ -34633,9 +39476,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
/* Use match charlen instead of bytelen, just in case the input and
* match codepoint encodings would have different lengths.
*/
- match_end_boff = duk_heap_strcache_offset_char2byte(thr,
- h_input,
- match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
+ /* XXX: charlen computed here, and also in char2byte helper. */
+ match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr,
+ h_input,
+ match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match));
tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
@@ -34643,7 +39487,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
continue;
}
default: {
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
duk_int_t capnum, captmp, capadv;
/* XXX: optional check, match_caps is zero if no regexp,
* so dollar will be interpreted literally anyway.
@@ -34674,18 +39518,17 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
/* regexp res_obj is at offset 4 */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
- if (duk_is_string(ctx, -1)) {
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum);
+ if (duk_is_string(thr, -1)) {
duk_hstring *h_tmp_str;
- h_tmp_str = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_tmp_str != NULL);
+ h_tmp_str = duk_known_hstring(thr, -1);
DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
} else {
/* undefined -> skip (replaced with empty) */
}
- duk_pop(ctx);
+ duk_pop(thr);
r += capadv;
continue;
} else {
@@ -34705,9 +39548,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
} /* while repl */
} /* if (is_repl_func) */
- duk_pop(ctx); /* pop regexp res_obj or match string */
+ duk_pop(thr); /* pop regexp res_obj or match string */
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (!is_global) {
#else
{ /* unconditionally; is_global==0 */
@@ -34720,9 +39563,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
return 1;
}
@@ -34734,13 +39577,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* used so compiler doesn't complain).
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) {
duk_hstring *h_input;
duk_hstring *h_sep;
duk_uint32_t limit;
duk_uint32_t arr_idx;
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
duk_bool_t is_regexp;
#endif
duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
@@ -34748,17 +39590,15 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
duk_uint32_t match_start_boff, match_start_coff;
duk_uint32_t match_end_boff, match_end_coff;
- DUK_UNREF(thr);
-
- h_input = duk_push_this_coercible_to_string(ctx);
+ h_input = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_input != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
limit = 0xffffffffUL;
} else {
- limit = duk_to_uint32(ctx, 1);
+ limit = duk_to_uint32(thr, 1);
}
if (limit == 0) {
@@ -34771,28 +39611,28 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* which will use global-style matching even when the RegExp itself is non-global.
*/
- if (duk_is_undefined(ctx, 0)) {
+ if (duk_is_undefined(thr, 0)) {
/* The spec algorithm first does "R = ToString(separator)" before checking
* whether separator is undefined. Since this is side effect free, we can
* skip the ToString() here.
*/
- duk_dup(ctx, 2);
- duk_put_prop_index(ctx, 3, 0);
+ duk_dup_2(thr);
+ duk_put_prop_index(thr, 3, 0);
return 1;
- } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup(ctx, 0);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, 0);
+ } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
+#if defined(DUK_USE_REGEXP_SUPPORT)
+ duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
+ duk_dup_0(thr);
+ duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
+ duk_replace(thr, 0);
/* lastIndex is initialized to zero by new RegExp() */
is_regexp = 1;
#else
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_UNSUPPORTED(thr);
#endif
} else {
- duk_to_string(ctx, 0);
-#ifdef DUK_USE_REGEXP_SUPPORT
+ duk_to_string(thr, 0);
+#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 0;
#endif
}
@@ -34816,42 +39656,42 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* special variant which forces global-like behavior for matching.
*/
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_dup(ctx, 0);
- duk_dup(ctx, 2);
+ duk_dup_0(thr);
+ duk_dup_2(thr);
duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
matched = 1;
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_start_coff = duk_get_uint(thr, -1);
+ match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
+ duk_pop(thr);
if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
/* don't allow an empty match at the end of the string */
- duk_pop(ctx);
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_end_coff = duk_get_int(ctx, -1);
- match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_end_coff = duk_get_uint(thr, -1);
+ match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
+ duk_pop(thr);
/* empty match -> bump and continue */
if (prev_match_end_boff == match_end_boff) {
- duk_push_int(ctx, match_end_coff + 1);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_pop(ctx);
+ duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ duk_pop(thr);
continue;
}
} else {
@@ -34866,8 +39706,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start + prev_match_end_boff;
- h_sep = duk_get_hstring(ctx, 0);
- DUK_ASSERT(h_sep != NULL);
+ h_sep = duk_known_hstring(thr, 0); /* symbol already rejected above */
q_start = DUK_HSTRING_GET_DATA(h_sep);
q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
@@ -34944,31 +39783,31 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
(long) match_end_boff, (long) match_end_coff,
(long) prev_match_end_boff, (long) prev_match_end_coff));
- duk_push_lstring(ctx,
+ duk_push_lstring(thr,
(const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
(duk_size_t) (match_start_boff - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_put_prop_index(thr, 3, arr_idx);
arr_idx++;
if (arr_idx >= limit) {
goto hit_limit;
}
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
duk_size_t i, len;
- len = duk_get_length(ctx, 4);
+ len = duk_get_length(thr, 4);
for (i = 1; i < len; i++) {
DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) i);
+ duk_put_prop_index(thr, 3, arr_idx);
arr_idx++;
if (arr_idx >= limit) {
goto hit_limit;
}
}
- duk_pop(ctx);
+ duk_pop(thr);
/* lastIndex already set up for next match */
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
@@ -34987,25 +39826,25 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
(long) prev_match_end_boff, (long) prev_match_end_coff));
- if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
+ if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) {
/* Add trailer if:
* a) non-empty input
* b) empty input and no (zero size) match found (step 11)
*/
- duk_push_lstring(ctx,
+ duk_push_lstring(thr,
(const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
(duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_put_prop_index(thr, 3, arr_idx);
/* No arr_idx update or limit check */
}
return 1;
hit_limit:
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_pop(ctx);
+ duk_pop(thr);
}
#endif
@@ -35016,36 +39855,34 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* Various
*/
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) {
+#if defined(DUK_USE_REGEXP_SUPPORT)
+DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) {
duk_hobject *h;
/* Shared helper for match() steps 3-4, search() steps 3-4. */
- DUK_ASSERT(index >= 0);
+ DUK_ASSERT(idx >= 0);
if (force_new) {
goto do_new;
}
- h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
+ h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP);
if (!h) {
goto do_new;
}
return;
do_new:
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup(ctx, index);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, index);
+ duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
+ duk_dup(thr, idx);
+ duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
+ duk_replace(thr, idx);
}
#endif /* DUK_USE_REGEXP_SUPPORT */
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
+#if defined(DUK_USE_REGEXP_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) {
/* Easiest way to implement the search required by the specification
* is to do a RegExp test() with lastIndex forced to zero. To avoid
* side effects on the argument, "clone" the RegExp if a RegExp was
@@ -35056,9 +39893,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
* equivalent effect.
*/
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
- duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
+ DUK_ASSERT_TOP(thr, 1);
+ (void) duk_push_this_coercible_to_string(thr); /* at index 1 */
+ duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/);
/* stack[0] = regexp
* stack[1] = string
@@ -35068,39 +39905,33 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
* configurable and may have been changed.
*/
- duk_dup(ctx, 0);
- duk_dup(ctx, 1); /* [ ... re_obj input ] */
+ duk_dup_0(thr);
+ duk_dup_1(thr); /* [ ... re_obj input ] */
duk_regexp_match(thr); /* -> [ ... res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_push_int(ctx, -1);
+ if (!duk_is_object(thr, -1)) {
+ duk_push_int(thr, -1);
return 1;
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
return 1;
}
-#else /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_REGEXP_SUPPORT */
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+#if defined(DUK_USE_REGEXP_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) {
duk_bool_t global;
duk_int_t prev_last_index;
duk_int_t this_index;
duk_int_t arr_idx;
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx);
- duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
- global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 1);
+ (void) duk_push_this_coercible_to_string(thr);
+ duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/);
+ global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
+ DUK_ASSERT_TOP(thr, 2);
/* stack[0] = regexp
* stack[1] = string
@@ -35115,9 +39946,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
/* [ regexp string ] */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_push_array(ctx);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_array(thr);
/* [ regexp string res_arr ] */
@@ -35125,65 +39956,158 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
arr_idx = 0;
for (;;) {
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
- duk_dup(ctx, 0);
- duk_dup(ctx, 1);
+ duk_dup_0(thr);
+ duk_dup_1(thr);
duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- this_index = duk_get_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ this_index = duk_get_int(thr, -1);
+ duk_pop(thr);
if (this_index == prev_last_index) {
this_index++;
- duk_push_int(ctx, this_index);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, this_index);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
prev_last_index = this_index;
- duk_get_prop_index(ctx, -1, 0); /* match string */
- duk_put_prop_index(ctx, 2, arr_idx);
+ duk_get_prop_index(thr, -1, 0); /* match string */
+ duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx);
arr_idx++;
- duk_pop(ctx); /* res_obj */
+ duk_pop(thr); /* res_obj */
}
if (arr_idx == 0) {
- duk_push_null(ctx);
+ duk_push_null(thr);
}
return 1; /* return 'res_arr' or 'null' */
}
-#else /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) {
/* duk_concat() coerces arguments with ToString() in correct order */
- (void) duk_push_this_coercible_to_string(ctx);
- duk_insert(ctx, 0); /* this is relatively expensive */
- duk_concat(ctx, duk_get_top(ctx));
+ (void) duk_push_this_coercible_to_string(thr);
+ duk_insert(thr, 0); /* this is relatively expensive */
+ duk_concat(thr, duk_get_top(thr));
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 0);
+ (void) duk_push_this_coercible_to_string(thr);
+ duk_trim(thr, 0);
+ DUK_ASSERT_TOP(thr, 1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_string(ctx);
- duk_trim(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
+ duk_hstring *h_input;
+ duk_size_t input_blen;
+ duk_size_t result_len;
+ duk_int_t count_signed;
+ duk_uint_t count;
+ const duk_uint8_t *src;
+ duk_uint8_t *buf;
+ duk_uint8_t *p;
+ duk_double_t d;
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_size_t copy_size;
+ duk_uint8_t *p_end;
+#endif
+
+ DUK_ASSERT_TOP(thr, 1);
+ h_input = duk_push_this_coercible_to_string(thr);
+ DUK_ASSERT(h_input != NULL);
+ input_blen = DUK_HSTRING_GET_BYTELEN(h_input);
+
+ /* Count is ToNumber() coerced; +Infinity must be always rejected
+ * (even if input string is zero length), as well as negative values
+ * and -Infinity. -Infinity doesn't require an explicit check
+ * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected
+ * as a negative value (regardless of input string length).
+ */
+ d = duk_to_number(thr, 0);
+ if (duk_double_is_posinf(d)) {
+ goto fail_range;
+ }
+ count_signed = duk_get_int(thr, 0);
+ if (count_signed < 0) {
+ goto fail_range;
+ }
+ count = (duk_uint_t) count_signed;
+
+ /* Overflow check for result length. */
+ result_len = count * input_blen;
+ if (count != 0 && result_len / count != input_blen) {
+ goto fail_range;
+ }
+
+ /* Temporary fixed buffer, later converted to string. */
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
+ src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+
+#if defined(DUK_USE_PREFER_SIZE)
+ p = buf;
+ while (count-- > 0) {
+ DUK_MEMCPY((void *) p, (const void *) src, input_blen); /* copy size may be zero */
+ p += input_blen;
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ /* Take advantage of already copied pieces to speed up the process
+ * especially for small repeated strings.
+ */
+ p = buf;
+ p_end = p + result_len;
+ copy_size = input_blen;
+ for (;;) {
+ duk_size_t remain = (duk_size_t) (p_end - p);
+ DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld",
+ (long) remain, (long) copy_size, (long) input_blen,
+ (long) result_len));
+ if (remain <= copy_size) {
+ /* If result_len is zero, this case is taken and does
+ * a zero size copy.
+ */
+ DUK_MEMCPY((void *) p, (const void *) src, remain);
+ break;
+ } else {
+ DUK_MEMCPY((void *) p, (const void *) src, copy_size);
+ p += copy_size;
+ }
+
+ src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */
+ copy_size = (duk_size_t) (p - buf);
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+
+ /* XXX: It would be useful to be able to create a duk_hstring with
+ * a certain byte size whose data area wasn't initialized and which
+ * wasn't in the string table yet. This would allow a string to be
+ * constructed directly without a buffer temporary and when it was
+ * finished, it could be injected into the string table. Currently
+ * this isn't possible because duk_hstrings are only tracked by the
+ * intern table (they are not in heap_allocated).
+ */
+
+ duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
return 1;
+
+ fail_range:
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
+#endif /* DUK_USE_ES6 */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) {
duk_hstring *h1;
duk_hstring *h2;
duk_size_t h1_len, h2_len, prefix_len;
@@ -35202,10 +40126,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx)
/* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
- h1 = duk_push_this_coercible_to_string(ctx);
+ h1 = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h1 != NULL);
- h2 = duk_to_hstring(ctx, 0);
+ h2 = duk_to_hstring(thr, 0);
DUK_ASSERT(h2 != NULL);
h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
@@ -35237,43 +40161,304 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx)
goto done;
done:
- duk_push_int(ctx, (duk_int_t) ret);
+ duk_push_int(thr, (duk_int_t) ret);
return 1;
}
-#line 1 "duk_bi_thread.c"
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) {
+ duk_int_t magic;
+ duk_hstring *h;
+ duk_hstring *h_search;
+ duk_size_t blen_search;
+ const duk_uint8_t *p_cmp_start;
+ duk_bool_t result;
+
+ h = duk_push_this_coercible_to_string(thr);
+ DUK_ASSERT(h != NULL);
+
+ h_search = duk__str_tostring_notregexp(thr, 0);
+ DUK_ASSERT(h_search != NULL);
+
+ magic = duk_get_current_magic(thr);
+
+ p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ blen_search = DUK_HSTRING_GET_BYTELEN(h_search);
+
+ if (duk_is_undefined(thr, 1)) {
+ if (magic) {
+ p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search;
+ } else {
+ /* p_cmp_start already OK */
+ }
+ } else {
+ duk_int_t len;
+ duk_int_t pos;
+
+ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
+ len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
+ pos = duk_to_int_clamped(thr, 1, 0, len);
+ DUK_ASSERT(pos >= 0 && pos <= len);
+
+ if (magic) {
+ p_cmp_start -= blen_search; /* Conceptually subtracted last, but do already here. */
+ }
+ DUK_ASSERT(pos >= 0 && pos <= len);
+
+ p_cmp_start += duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) pos);
+ }
+
+ /* The main comparison can be done using a memcmp() rather than
+ * doing codepoint comparisons: for CESU-8 strings there is a
+ * canonical representation for every codepoint. But we do need
+ * to deal with the char/byte offset translation to find the
+ * comparison range.
+ */
+
+ result = 0;
+ if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) &&
+ (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
+ if (DUK_MEMCMP((const void *) p_cmp_start,
+ (const void *) DUK_HSTRING_GET_DATA(h_search),
+ (size_t) blen_search) == 0) {
+ result = 1;
+ }
+ }
+
+ duk_push_boolean(thr, result);
+ return 1;
+}
+#endif /* DUK_USE_ES6 */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) {
+ duk_hstring *h;
+ duk_hstring *h_search;
+ duk_int_t len;
+ duk_int_t pos;
+
+ h = duk_push_this_coercible_to_string(thr);
+ DUK_ASSERT(h != NULL);
+
+ h_search = duk__str_tostring_notregexp(thr, 0);
+ DUK_ASSERT(h_search != NULL);
+
+ len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
+ pos = duk_to_int_clamped(thr, 1, 0, len);
+ DUK_ASSERT(pos >= 0 && pos <= len);
+
+ pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/);
+ duk_push_boolean(thr, pos >= 0);
+ return 1;
+}
+#endif /* DUK_USE_ES6 */
+#endif /* DUK_USE_STRING_BUILTIN */
+/*
+ * Symbol built-in
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+
+/*
+ * Constructor
+ */
+
+DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
+ const duk_uint8_t *desc;
+ duk_size_t len;
+ duk_uint8_t *buf;
+ duk_uint8_t *p;
+ duk_int_t magic;
+
+ magic = duk_get_current_magic(thr);
+ if (duk_is_undefined(thr, 0) && (magic == 0)) {
+ /* Symbol() accepts undefined and empty string, but they are
+ * treated differently.
+ */
+ desc = NULL;
+ len = 0;
+ } else {
+ /* Symbol.for() coerces undefined to 'undefined' */
+ desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len);
+ }
+
+ /* Maximum symbol data length:
+ * +1 initial byte (0x80 or 0x81)
+ * +len description
+ * +1 0xff after description, before unique suffix
+ * +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest
+ * +1 0xff after unique suffix for symbols with undefined description
+ */
+ buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
+ p = buf + 1;
+ DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
+ DUK_MEMCPY((void *) p, (const void *) desc, len);
+ p += len;
+ if (magic == 0) {
+ /* Symbol(): create unique symbol. Use two 32-bit values
+ * to avoid dependency on 64-bit types and 64-bit integer
+ * formatting (at least for now).
+ */
+ if (++thr->heap->sym_counter[0] == 0) {
+ thr->heap->sym_counter[1]++;
+ }
+ p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx",
+ (unsigned long) thr->heap->sym_counter[1],
+ (unsigned long) thr->heap->sym_counter[0]);
+ if (desc == NULL) {
+ /* Special case for 'undefined' description, trailing
+ * 0xff distinguishes from empty string description,
+ * but needs minimal special case handling elsewhere.
+ */
+ *p++ = 0xff;
+ }
+ buf[0] = 0x81;
+ } else {
+ /* Symbol.for(): create a global symbol */
+ buf[0] = 0x80;
+ }
+
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
+ DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1)));
+ return 1;
+}
+
+DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) {
+ duk_tval *tv;
+ duk_tval tv_val;
+ duk_hobject *h_obj;
+ duk_hstring *h_str;
+
+ DUK_ASSERT(tv_arg != NULL);
+
+ /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */
+ /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */
+
+ tv = tv_arg;
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h_obj = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h_obj != NULL);
+ if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
+ if (!duk_hobject_get_internal_value(thr->heap, h_obj, &tv_val)) {
+ return NULL;
+ }
+ tv = &tv_val;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (!DUK_TVAL_IS_STRING(tv)) {
+ return NULL;
+ }
+ h_str = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h_str != NULL);
+
+ /* Here symbol is more expected than not. */
+ if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) {
+ return NULL;
+ }
+
+ return h_str;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) {
+ duk_hstring *h_str;
+
+ h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
+ if (h_str == NULL) {
+ return DUK_RET_TYPE_ERROR;
+ }
+
+ if (duk_get_current_magic(thr) == 0) {
+ /* .toString() */
+ duk_push_symbol_descriptive_string(thr, h_str);
+ } else {
+ /* .valueOf() */
+ duk_push_hstring(thr, h_str);
+ }
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) {
+ duk_hstring *h;
+ const duk_uint8_t *p;
+
+ /* Argument must be a symbol but not checked here. The initial byte
+ * check will catch non-symbol strings.
+ */
+ h = duk_require_hstring(thr, 0);
+ DUK_ASSERT(h != NULL);
+
+ p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ DUK_ASSERT(p != NULL);
+
+ /* Even for zero length strings there's at least one NUL byte so
+ * we can safely check the initial byte.
+ */
+ if (p[0] == 0x80) {
+ /* Global symbol, return its key (bytes just after the initial byte). */
+ duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1));
+ return 1;
+ } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) {
+ /* Local symbol or hidden symbol, return undefined. */
+ return 0;
+ }
+
+ /* Covers normal strings and unknown initial bytes. */
+ return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) {
+ duk_hstring *h_str;
+
+ h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
+ if (h_str == NULL) {
+ return DUK_RET_TYPE_ERROR;
+ }
+ duk_push_hstring(thr, h_str);
+ return 1;
+}
+
+#endif /* DUK_USE_SYMBOL_BUILTIN */
/*
* Thread builtins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
duk_hthread *new_thr;
duk_hobject *func;
- /* XXX: need a duk_require_func_or_lfunc_coerce() */
- if (!duk_is_callable(ctx, 0)) {
- return DUK_RET_TYPE_ERROR;
- }
- func = duk_require_hobject_or_lfunc_coerce(ctx, 0);
+ /* Check that the argument is callable; this is not 100% because we
+ * don't allow native functions to be a thread's initial function.
+ * Resume will reject such functions in any case.
+ */
+ /* XXX: need a duk_require_func_promote_lfunc() */
+ func = duk_require_hobject_promote_lfunc(thr, 0);
DUK_ASSERT(func != NULL);
+ duk_require_callable(thr, 0);
- duk_push_thread(ctx);
- new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(new_thr != NULL);
+ duk_push_thread(thr);
+ new_thr = (duk_hthread *) duk_known_hobject(thr, -1);
new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
/* push initial function call to new thread stack; this is
* picked up by resume().
*/
- duk_push_hobject((duk_context *) new_thr, func);
+ duk_push_hobject(new_thr, func);
return 1; /* return thread */
}
+#endif
/*
* Resume a thread.
@@ -35290,25 +40475,24 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
* Note: yield and resume handling is currently asymmetric.
*/
-DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hthread *thr_resume;
- duk_tval *tv;
- duk_hobject *func;
duk_hobject *caller_func;
- duk_small_int_t is_error;
+ duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
+ (duk_tval *) duk_get_tval(thr, 2)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
- thr_resume = duk_require_hthread(ctx, 0);
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
- duk_set_top(ctx, 2);
+ thr_resume = duk_require_hthread(thr, 0);
+ is_error = (duk_small_uint_t) duk_to_boolean(thr, 2);
+ duk_set_top(thr, 2);
/* [ thread value ] */
@@ -35320,12 +40504,14 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
goto state_error;
}
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
- DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
- caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
+ caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
+ if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
goto state_error;
}
@@ -35350,26 +40536,27 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
* tip-top shape (longjmp handler will assert for these).
*/
} else {
+ duk_hobject *h_fun;
+
DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
+ /* The initial function must be an Ecmascript function (but
+ * can be bound). We must make sure of that before we longjmp
+ * because an error in the RESUME handler call processing will
+ * not be handled very cleanly.
+ */
if ((thr_resume->callstack_top != 0) ||
(thr_resume->valstack_top - thr_resume->valstack != 1)) {
- goto state_invalid_initial;
- }
- tv = &thr_resume->valstack_top[-1];
- DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
- if (!DUK_TVAL_IS_OBJECT(tv)) {
- goto state_invalid_initial;
- }
- func = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(func != NULL);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- /* Note: cannot be a bound function either right now,
- * this would be easy to relax though.
- */
- goto state_invalid_initial;
+ goto state_error;
}
+ duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1));
+ duk_resolve_nonbound_function(thr);
+ h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */
+ if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
+ goto state_error;
+ }
+ duk_pop(thr);
}
/*
@@ -35382,24 +40569,24 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
- DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
+ DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in resumer's context */
}
#endif
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
} else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
} else {
DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
}
#endif
@@ -35412,22 +40599,19 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
- DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
+ DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
- return 0; /* never here */
-
- state_invalid_initial:
- DUK_ERROR_TYPE(thr, "invalid initial thread state/stack");
- return 0; /* never here */
+ DUK_UNREACHABLE();
+ /* Never here, fall through to error (from compiler point of view). */
state_error:
- DUK_ERROR_TYPE(thr, "invalid state");
- return 0; /* never here */
+ DUK_DCERROR_TYPE_INVALID_STATE(thr);
}
+#endif
/*
* Yield the current thread.
@@ -35444,20 +40628,20 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
* Note: yield and resume handling is currently asymmetric.
*/
-DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
duk_hobject *caller_func;
- duk_small_int_t is_error;
+ duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
- duk_set_top(ctx, 1);
+ is_error = (duk_small_uint_t) duk_to_boolean(thr, 1);
+ duk_set_top(thr, 1);
/* [ value ] */
@@ -35475,12 +40659,14 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
goto state_error;
}
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
- DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
- caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
+ caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
+ if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
goto state_error;
}
@@ -35502,18 +40688,18 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
- DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
+ DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in yielder's context */
}
#endif
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
+ (duk_tval *) duk_get_tval(thr, 0)));
} else {
DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
+ (duk_tval *) duk_get_tval(thr, 0)));
}
#endif
@@ -35529,43 +40715,43 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
- DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
+ DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
- return 0; /* never here */
+ DUK_UNREACHABLE();
+ /* Never here, fall through to error (from compiler point of view). */
state_error:
- DUK_ERROR_TYPE(thr, "invalid state");
- return 0; /* never here */
+ DUK_DCERROR_TYPE_INVALID_STATE(thr);
}
+#endif
-DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
- duk_push_current_thread(ctx);
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) {
+ duk_push_current_thread(thr);
return 1;
}
-#line 1 "duk_bi_thrower.c"
+#endif
/*
* Type error thrower, E5 Section 13.2.3.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_TYPE_ERROR;
+DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
-#line 1 "duk_debug_fixedbuffer.c"
/*
* Fixed buffer helper useful for debugging, requires no allocation
* which is critical for debugging.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
duk_size_t avail;
@@ -35609,7 +40795,7 @@ DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
}
} else {
/* normal */
- fb->offset += res;
+ fb->offset += (duk_size_t) res;
}
}
va_end(ap);
@@ -35627,255 +40813,6 @@ DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
}
#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debug_heap.c"
-/*
- * Debug dumping of duk_heap.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_DEBUG
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) {
- duk_size_t i;
- duk_size_t nchars;
- duk_size_t maxchars;
- duk_uint8_t *data;
-
- DUK_MEMZERO(buf, buf_size);
-
- maxchars = (duk_size_t) (buf_size - 1);
- data = DUK_HSTRING_GET_DATA(str);
- nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars);
- for (i = 0; i < nchars; i++) {
- duk_small_int_t c = (duk_small_int_t) data[i];
- if (c < 0x20 || c > 0x7e) {
- c = '.';
- }
- buf[i] = (char) c;
- }
-}
-#endif
-
-#if 0
-DUK_LOCAL const char *duk__get_heap_type_string(duk_heaphdr *hdr) {
- switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_STRING:
- return "string";
- case DUK_HTYPE_OBJECT:
- return "object";
- case DUK_HTYPE_BUFFER:
- return "buffer";
- default:
- return "???";
- }
-}
-#endif
-
-#if 0
-DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) {
- DUK_UNREF(obj);
- DUK_UNREF(index);
- DUK_UNREF(duk__get_heap_type_string);
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O",
- (long) index,
- (void *) obj,
- (const char *) duk__get_heap_type_string(obj),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
- (long) DUK_HEAPHDR_GET_REFCOUNT(obj),
- (duk_heaphdr *) obj));
-#else
- DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O",
- (long) index,
- (void *) obj,
- (const char *) duk__get_heap_type_string(obj),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
- (duk_heaphdr *) obj));
-#endif
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) {
- duk_int_t count;
- duk_heaphdr *curr;
-
- DUK_UNREF(heap);
- DUK_UNREF(name);
-
- count = 0;
- curr = root;
- while (curr) {
- count++;
- curr = DUK_HEAPHDR_GET_NEXT(curr);
- }
-
- DUK_D(DUK_DPRINT("%s, %ld objects", (const char *) name, (long) count));
-
- count = 0;
- curr = root;
- while (curr) {
- count++;
- duk__dump_indented(curr, count);
- curr = DUK_HEAPHDR_GET_NEXT(curr);
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_stringtable(duk_heap *heap) {
- duk_uint_fast32_t i;
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("stringtable %p, used %ld, size %ld, load %ld%%",
- (void *) heap->strtable,
- (long) heap->st_used,
- (long) heap->st_size,
- (long) (((double) heap->st_used) / ((double) heap->st_size) * 100.0)));
-
- for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
- duk_hstring *e = heap->strtable[i];
-
- if (!e) {
- DUK_D(DUK_DPRINT(" [%ld]: NULL", (long) i));
- } else if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
- DUK_D(DUK_DPRINT(" [%ld]: DELETED", (long) i));
- } else {
- duk__sanitize_snippet(buf, sizeof(buf), e);
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx, ref: %ld) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
- "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
- (long) i,
- (void *) e,
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
- (long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) e),
- (const char *) buf,
- (unsigned long) e->hash,
- (long) e->blen,
- (long) e->clen,
- (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
-#else
- DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
- "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
- (long) i,
- (void *) e,
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
- (const char *) buf,
- (long) e->hash,
- (long) e->blen,
- (long) e->clen,
- (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
-#endif
- }
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_strcache(duk_heap *heap) {
- duk_uint_fast32_t i;
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("stringcache"));
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = &heap->strcache[i];
- if (!c->h) {
- DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld, cidx=%ld, str=NULL",
- (long) i, (long) c->bidx, (long) c->cidx));
- } else {
- duk__sanitize_snippet(buf, sizeof(buf), c->h);
- DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld cidx=%ld str=%s",
- (long) i, (long) c->bidx, (long) c->cidx, (const char *) buf));
- }
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("=== heap %p ===", (void *) heap));
- DUK_D(DUK_DPRINT(" flags: 0x%08lx", (unsigned long) heap->flags));
-
- /* Note: there is no standard formatter for function pointers */
-#ifdef DUK_USE_GCC_PRAGMAS
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-pedantic"
-#endif
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->alloc_func, sizeof(heap->alloc_func));
- DUK_D(DUK_DPRINT(" alloc_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->realloc_func, sizeof(heap->realloc_func));
- DUK_D(DUK_DPRINT(" realloc_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->free_func, sizeof(heap->free_func));
- DUK_D(DUK_DPRINT(" free_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->fatal_func, sizeof(heap->fatal_func));
- DUK_D(DUK_DPRINT(" fatal_func: %s", (const char *) buf));
-#ifdef DUK_USE_GCC_PRAGMAS
-#pragma GCC diagnostic pop
-#endif
-
- DUK_D(DUK_DPRINT(" heap_udata: %p", (void *) heap->heap_udata));
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-#ifdef DUK_USE_VOLUNTARY_GC
- DUK_D(DUK_DPRINT(" mark-and-sweep trig counter: %ld", (long) heap->mark_and_sweep_trigger_counter));
-#endif
- DUK_D(DUK_DPRINT(" mark-and-sweep rec depth: %ld", (long) heap->mark_and_sweep_recursion_depth));
- DUK_D(DUK_DPRINT(" mark-and-sweep base flags: 0x%08lx", (unsigned long) heap->mark_and_sweep_base_flags));
-#endif
-
- DUK_D(DUK_DPRINT(" lj.jmpbuf_ptr: %p", (void *) heap->lj.jmpbuf_ptr));
- DUK_D(DUK_DPRINT(" lj.type: %ld", (long) heap->lj.type));
- DUK_D(DUK_DPRINT(" lj.value1: %!T", (duk_tval *) &heap->lj.value1));
- DUK_D(DUK_DPRINT(" lj.value2: %!T", (duk_tval *) &heap->lj.value2));
- DUK_D(DUK_DPRINT(" lj.iserror: %ld", (long) heap->lj.iserror));
-
- DUK_D(DUK_DPRINT(" handling_error: %ld", (long) heap->handling_error));
-
- DUK_D(DUK_DPRINT(" heap_thread: %!@O", (duk_heaphdr *) heap->heap_thread));
- DUK_D(DUK_DPRINT(" curr_thread: %!@O", (duk_heaphdr *) heap->curr_thread));
- DUK_D(DUK_DPRINT(" heap_object: %!@O", (duk_heaphdr *) heap->heap_object));
-
- DUK_D(DUK_DPRINT(" call_recursion_depth: %ld", (long) heap->call_recursion_depth));
- DUK_D(DUK_DPRINT(" call_recursion_limit: %ld", (long) heap->call_recursion_limit));
-
- DUK_D(DUK_DPRINT(" hash_seed: 0x%08lx", (unsigned long) heap->hash_seed));
- DUK_D(DUK_DPRINT(" rnd_state: 0x%08lx", (unsigned long) heap->rnd_state));
-
- duk__dump_strcache(heap);
-
- duk__dump_heaphdr_list(heap, heap->heap_allocated, "heap allocated");
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__dump_heaphdr_list(heap, heap->refzero_list, "refcounting refzero list");
-#endif
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk__dump_heaphdr_list(heap, heap->finalize_list, "mark-and-sweep finalize list");
-#endif
-
- duk__dump_stringtable(heap);
-
- /* heap->strs: not worth dumping */
-}
-#endif
-
-#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debug_vsnprintf.c"
/*
* Custom formatter for debug printing, allowing Duktape specific data
* structures (such as tagged values and heap objects) to be printed with
@@ -35928,12 +40865,12 @@ DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
* * Reference loops are detected using a loop stack.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
-#include <stdio.h>
-#include <stdarg.h>
+/* #include stdio.h -> already included */
+/* #include stdarg.h -> already included */
#include <string.h>
/* list of conversion specifiers that terminate a format tag;
@@ -35951,48 +40888,46 @@ DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
#define DUK__LOOP_STACK_DEPTH 256
/* must match bytecode defines now; build autogenerate? */
-DUK_LOCAL const char *duk__bc_optab[64] = {
- "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "MPUTOBJ", "MPUTOBJI", "MPUTARR", "MPUTARRI", "NEW",
- "NEWI", "REGEXP", "CSREG", "CSREGI", "GETVAR", "PUTVAR", "DECLVAR", "DELVAR", "CSVAR", "CSVARI",
- "CLOSURE", "GETPROP", "PUTPROP", "DELPROP", "CSPROP", "CSPROPI", "ADD", "SUB", "MUL", "DIV",
- "MOD", "BAND", "BOR", "BXOR", "BASL", "BLSR", "BASR", "EQ", "NEQ", "SEQ",
- "SNEQ", "GT", "GE", "LT", "LE", "IF", "JUMP", "RETURN", "CALL", "CALLI",
- "TRYCATCH", "EXTRA", "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
- "PREINCP", "PREDECP", "POSTINCP", "POSTDECP"
-};
-
-DUK_LOCAL const char *duk__bc_extraoptab[256] = {
- "NOP", "INVALID", "LDTHIS", "LDUNDEF", "LDNULL", "LDTRUE", "LDFALSE", "NEWOBJ", "NEWARR", "SETALEN",
- "TYPEOF", "TYPEOFID", "INITENUM", "NEXTENUM", "INITSET", "INITSETI", "INITGET", "INITGETI", "ENDTRY", "ENDCATCH",
- "ENDFIN", "THROW", "INVLHS", "UNM", "UNP", "DEBUGGER", "BREAK", "CONTINUE", "BNOT", "LNOT",
- "INSTOF", "IN", "LABEL", "ENDLABEL", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX"
+DUK_LOCAL const char * const duk__bc_optab[256] = {
+ "LDREG", "STREG", "JUMP", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF",
+ "LDNULL", "LDTRUE", "LDFALSE", "GETVAR", "BNOT", "LNOT", "UNM", "UNP",
+ "EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC",
+ "SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC",
+
+ "GT_RR", "GT_CR", "GT_RC", "GT_CC", "GE_RR", "GE_CR", "GE_RC", "GE_CC",
+ "LT_RR", "LT_CR", "LT_RC", "LT_CC", "LE_RR", "LE_CR", "LE_RC", "LE_CC",
+ "IFTRUE_R", "IFTRUE_C", "IFFALSE_R", "IFFALSE_C", "ADD_RR", "ADD_CR", "ADD_RC", "ADD_CC",
+ "SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC",
+
+ "DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC",
+ "EXP_RR", "EXP_CR", "EXP_RC", "EXP_CC", "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC",
+ "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC", "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC",
+ "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC", "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC",
+
+ "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC", "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC",
+ "IN_RR", "IN_CR", "IN_RC", "IN_CC", "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC",
+ "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC", "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC",
+ "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
+
+ "PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC",
+ "POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC",
+ "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC", "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC",
+ "CLOSURE", "TYPEOF", "TYPEOFID", "PUTVAR", "DELVAR", "RETREG", "RETUNDEF", "RETCONST",
+
+ "RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH",
+ "ENDFIN", "THROW", "INVLHS", "CSREG", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
+ "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7",
+ "CALL8", "CALL9", "CALL10", "CALL11", "CALL12", "CALL13", "CALL14", "CALL15",
+
+ "NEWOBJ", "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI",
+ "SETALEN", "INITENUM", "NEXTENUM", "NEWTARGET", "DEBUGGER", "NOP", "INVALID", "UNUSED207",
+ "GETPROPC_RR", "GETPROPC_CR", "GETPROPC_RC", "GETPROPC_CC", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
+ "UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223",
+
+ "UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231",
+ "UNUSED232", "UNUSED233", "UNUSED234", "UNUSED235", "UNUSED236", "UNUSED237", "UNUSED238", "UNUSED239",
+ "UNUSED240", "UNUSED241", "UNUSED242", "UNUSED243", "UNUSED244", "UNUSED245", "UNUSED246", "UNUSED247",
+ "UNUSED248", "UNUSED249", "UNUSED250", "UNUSED251", "UNUSED252", "UNUSED253", "UNUSED254", "UNUSED255"
};
typedef struct duk__dprint_state duk__dprint_state;
@@ -36047,7 +40982,7 @@ DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h)
duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
}
-#ifdef DUK_USE_REFERENCE_COUNTING /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
+#if defined(DUK_USE_REFERENCE_COUNTING) /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
if (st->heavy) {
duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
"reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
@@ -36095,7 +41030,7 @@ DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaph
duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
if (st->heavy) {
duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
(unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
@@ -36141,9 +41076,9 @@ DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_boo
p_end = p + DUK_HSTRING_GET_BYTELEN(h);
if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
- /* if property key begins with underscore, encode it with
+ /* If property key begins with underscore, encode it with
* forced quotes (e.g. "_Foo") to distinguish it from encoded
- * internal properties (e.g. \xffBar -> _Bar).
+ * internal properties (e.g. \x82Bar -> _Bar).
*/
quotes = 1;
}
@@ -36161,9 +41096,9 @@ DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_boo
duk_fb_sprintf(fb, "\\\"");
} else if (ch >= 0x20 && ch <= 0x7e) {
duk_fb_put_byte(fb, ch);
- } else if (ch == 0xff && !quotes) {
- /* encode \xffBar as _Bar if no quotes are applied, this is for
- * readable internal keys.
+ } else if (ch == 0x82 && !quotes) {
+ /* encode \x82Bar as _Bar if no quotes are
+ * applied, this is for readable internal keys.
*/
duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
} else {
@@ -36173,15 +41108,12 @@ DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_boo
if (quotes) {
duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
/* XXX: limit to quoted strings only, to save keys from being cluttered? */
duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
#endif
}
-#ifdef DUK__COMMA
-#undef DUK__COMMA
-#endif
#define DUK__COMMA() do { \
if (first) { \
first = 0; \
@@ -36217,15 +41149,20 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
}
if (st->depth >= st->depth_limit) {
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_fb_sprintf(fb, "%sobject/compiledfunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_fb_sprintf(fb, "%sobject/nativefunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
+ const char *subtype = "generic";
+
+ if (DUK_HOBJECT_IS_COMPFUNC(h)) {
+ subtype = "compfunc";
+ } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
+ subtype = "natfunc";
} else if (DUK_HOBJECT_IS_THREAD(h)) {
- duk_fb_sprintf(fb, "%sobject/thread %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- } else {
- duk_fb_sprintf(fb, "%sobject %p%s", (const char *) brace1, (void *) h, (const char *) brace2); /* may be NULL */
+ subtype = "thread";
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ subtype = "bufobj";
+ } else if (DUK_HOBJECT_IS_ARRAY(h)) {
+ subtype = "array";
}
+ duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2);
return;
}
@@ -36283,10 +41220,7 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
if (!key) {
continue;
}
- if (!st->internal &&
- DUK_HSTRING_GET_BYTELEN(key) > 0 &&
- DUK_HSTRING_GET_DATA(key)[0] == 0xff) {
- /* XXX: use DUK_HSTRING_FLAG_INTERNAL? */
+ if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) {
continue;
}
DUK__COMMA();
@@ -36306,101 +41240,75 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
}
}
if (st->internal) {
+ if (DUK_HOBJECT_IS_ARRAY(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__array:true");
+ }
if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
- } else {
- ;
}
- if (DUK_HOBJECT_HAS_BOUND(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__bound:true");
- } else {
- ;
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true");
}
- if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__compiledfunction:true");
- } else {
- ;
+ if (DUK_HOBJECT_HAS_COMPFUNC(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true");
}
- if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__nativefunction:true");
- } else {
- ;
+ if (DUK_HOBJECT_HAS_NATFUNC(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true");
}
- if (DUK_HOBJECT_HAS_THREAD(h)) {
+ if (DUK_HOBJECT_HAS_BUFOBJ(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true");
+ }
+ if (DUK_HOBJECT_IS_THREAD(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_STRICT(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
- } else {
- ;
+ }
+ if (DUK_HOBJECT_HAS_NOTAIL(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true");
}
if (DUK_HOBJECT_HAS_NEWENV(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
- } else {
- ;
}
if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
- } else {
- ;
}
- if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufferobj:true");
- } else {
- ;
+ if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true");
}
if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
- } else {
- ;
}
}
- if (st->internal && DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
+
+ if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) {
+ duk_harray *a = (duk_harray *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable);
+ } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) {
+ duk_hcompfunc *f = (duk_hcompfunc *) h;
DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
- duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
+ duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
+ DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f));
+ DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f));
DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
@@ -36408,42 +41316,67 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
#endif
DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
- duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
- } else if (st->internal && DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
+ duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
+ } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) {
+ duk_hnatfunc *f = (duk_hnatfunc *) h;
DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
- } else if (st->internal && DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
+ } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) {
+ duk_hdecenv *e = (duk_hdecenv *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld", (long) e->regbase_byteoff);
+ } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) {
+ duk_hobjenv *e = (duk_hobjenv *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) {
+ duk_hbufobj *b = (duk_hbufobj *) h;
DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:");
+ duk__print_hobject(st, (duk_hobject *) b->buf_prop);
DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
+#endif
+ } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__target:");
+ duk__print_hobject(st, p->target);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__handler:");
+ duk__print_hobject(st, p->handler);
} else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p", (void *) t->ptr_curr_pc);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p", (void *) t->heap);
DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
+ DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld", (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack));
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p", (void *) t->callstack_curr);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld", (long) t->callstack_top);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld", (long) t->callstack_preventcount);
DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p", (void *) t->compile_ctx);
+#if defined(DUK_USE_INTERRUPT_COUNTER)
+ DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld", (long) t->interrupt_counter);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld", (long) t->interrupt_init);
+#endif
+
/* XXX: print built-ins array? */
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
if (st->internal) {
DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
}
@@ -36493,8 +41426,6 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
}
}
-#undef DUK__COMMA
-
DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
duk_fixedbuffer *fb = st->fb;
duk_size_t i, n;
@@ -36527,7 +41458,7 @@ DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
#endif
@@ -36646,6 +41577,10 @@ DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
+ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ duk_fb_sprintf(fb, "%.18g_F", (double) DUK_TVAL_GET_NUMBER(tv));
+ break;
#endif
default: {
/* IEEE double is approximately 16 decimal digits; print a couple extra */
@@ -36664,21 +41599,15 @@ DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
duk_fixedbuffer *fb = st->fb;
duk_small_int_t op;
const char *op_name;
- const char *extraop_name;
op = (duk_small_int_t) DUK_DEC_OP(ins);
op_name = duk__bc_optab[op];
/* XXX: option to fix opcode length so it lines up nicely */
- if (op == DUK_OP_EXTRA) {
- extraop_name = duk__bc_extraoptab[DUK_DEC_A(ins)];
-
- duk_fb_sprintf(fb, "%s %ld, %ld",
- (const char *) extraop_name, (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
- } else if (op == DUK_OP_JUMP) {
- duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
- duk_int_t diff2 = diff1 + 1; /* from curr pc */
+ if (op == DUK_OP_JUMP) {
+ duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS); /* from next pc */
+ duk_int_t diff2 = diff1 + 1; /* from curr pc */
duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
(const char *) op_name, (long) diff1,
@@ -36745,7 +41674,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
if (ch == DUK_ASC_STAR) {
/* unsupported: would consume multiple args */
- goto error;
+ goto format_error;
} else if (ch == DUK_ASC_PERCENT) {
duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
break;
@@ -36797,7 +41726,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
fmtlen = (duk_size_t) (p - p_begfmt);
if (fmtlen >= sizeof(fmtbuf)) {
/* format is too large, abort */
- goto error;
+ goto format_error;
}
DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
@@ -36872,7 +41801,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
}
goto done;
- error:
+ format_error:
duk_fb_put_cstring(&fb, "FMTERR");
/* fall through */
@@ -36915,26 +41844,50 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u
}
/* Quite approximate but should be useful for little and big endian. */
-#ifdef DUK_USE_INTEGER_BE
+#if defined(DUK_USE_INTEGER_BE)
ch = fptr[i];
#else
ch = fptr[fptr_size - 1 - i];
#endif
- p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
+ p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx", (unsigned long) ch);
}
}
#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debugger.c"
+
+/* automatic undefs */
+#undef DUK__ALLOWED_STANDARD_SPECIFIERS
+#undef DUK__COMMA
+#undef DUK__DEEP_DEPTH_LIMIT
+#undef DUK__LOOP_STACK_DEPTH
+#undef DUK__MAX_FORMAT_TAG_LENGTH
/*
* Duktape debugger
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/*
+ * Assert helpers
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK__DBG_TPORT_ENTER() do { \
+ DUK_ASSERT(heap->dbg_calling_transport == 0); \
+ heap->dbg_calling_transport = 1; \
+ } while (0)
+#define DUK__DBG_TPORT_EXIT() do { \
+ DUK_ASSERT(heap->dbg_calling_transport == 1); \
+ heap->dbg_calling_transport = 0; \
+ } while (0)
+#else
+#define DUK__DBG_TPORT_ENTER() do {} while (0)
+#define DUK__DBG_TPORT_EXIT() do {} while (0)
+#endif
+
+/*
* Helper structs
*/
@@ -36994,14 +41947,14 @@ DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
/* heap->dbg_detached_cb: keep */
/* heap->dbg_udata: keep */
/* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
- heap->dbg_paused = 0;
heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
heap->dbg_have_next_byte = 0;
+ duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */
+ heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */
/* Ensure there are no stale active breakpoint pointers.
* Breakpoint list is currently kept - we could empty it
@@ -37016,6 +41969,13 @@ DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
duk_debug_detached_function detached_cb;
void *detached_udata;
+ duk_hthread *thr;
+
+ thr = heap->heap_thread;
+ if (thr == NULL) {
+ DUK_ASSERT(heap->dbg_detached_cb == NULL);
+ return;
+ }
/* Safe to call multiple times. */
@@ -37030,7 +41990,7 @@ DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
* inside the callback.
*/
DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
- detached_cb(detached_udata);
+ detached_cb(thr, detached_udata);
}
heap->dbg_detaching = 0;
@@ -37048,6 +42008,9 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
*/
DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
duk_heap *heap;
+
+ DUK_ASSERT(thr != NULL);
+
heap = thr->heap;
DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
heap->dbg_read_cb = NULL;
@@ -37060,11 +42023,40 @@ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
}
/*
+ * Pause handling
+ */
+
+DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) {
+ duk_uint_fast32_t line;
+
+ line = duk_debug_curr_line(thr);
+ if (line == 0) {
+ /* No line info for current function. */
+ duk_small_uint_t updated_flags;
+
+ updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE);
+ DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx",
+ (long) pause_flags, (long) updated_flags));
+ pause_flags = updated_flags;
+ }
+
+ heap->dbg_pause_flags = pause_flags;
+ heap->dbg_pause_act = thr->callstack_curr;
+ heap->dbg_pause_startline = (duk_uint32_t) line;
+ heap->dbg_state_dirty = 1;
+
+ DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld",
+ (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act,
+ (long) heap->dbg_pause_startline));
+}
+
+/*
* Debug connection peek and flush primitives
*/
DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
duk_heap *heap;
+ duk_bool_t ret;
DUK_ASSERT(thr != NULL);
heap = thr->heap;
@@ -37079,7 +42071,10 @@ DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
return 0;
}
- return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
+ DUK__DBG_TPORT_ENTER();
+ ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
+ DUK__DBG_TPORT_EXIT();
+ return ret;
}
DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
@@ -37098,7 +42093,9 @@ DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
return;
}
+ DUK__DBG_TPORT_ENTER();
heap->dbg_read_flush_cb(heap->dbg_udata);
+ DUK__DBG_TPORT_EXIT();
}
DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
@@ -37117,7 +42114,9 @@ DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
return;
}
+ DUK__DBG_TPORT_ENTER();
heap->dbg_write_flush_cb(heap->dbg_udata);
+ DUK__DBG_TPORT_EXIT();
}
/*
@@ -37195,7 +42194,10 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
left = 1;
#endif
+ DUK__DBG_TPORT_ENTER();
got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
+ DUK__DBG_TPORT_EXIT();
+
if (got == 0 || got > left) {
DUK_D(DUK_DPRINT("connection error during read, return zero data"));
duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
@@ -37230,7 +42232,7 @@ DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
(duk_uint32_t) buf[3];
}
-DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
+DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) {
return (duk_int32_t) duk__debug_read_uint32_raw(thr);
}
@@ -37266,25 +42268,23 @@ DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
}
DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t buf[31];
duk_uint8_t *p;
if (len <= sizeof(buf)) {
duk_debug_read_bytes(thr, buf, (duk_size_t) len);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) len);
} else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
+ p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
DUK_ASSERT(p != NULL);
duk_debug_read_bytes(thr, p, (duk_size_t) len);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safety relies on debug client, which is OK. */
}
- return duk_require_hstring(ctx, -1);
+ return duk_require_hstring(thr, -1);
}
DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t x;
duk_uint32_t len;
@@ -37307,19 +42307,18 @@ DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
fail:
DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
DUK__SET_CONN_BROKEN(thr, 1);
- duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
- return duk_require_hstring(ctx, -1);
+ duk_push_hstring_empty(thr); /* always push some string */
+ return duk_require_hstring(thr, -1);
}
DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t *p;
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
+ p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
DUK_ASSERT(p != NULL);
duk_debug_read_bytes(thr, p, (duk_size_t) len);
- return duk_require_hbuffer(ctx, -1);
+ return duk_require_hbuffer(thr, -1);
}
DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
@@ -37403,7 +42402,6 @@ DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
}
DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t x;
duk_uint_t t;
duk_uint32_t len;
@@ -37415,11 +42413,11 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
if (x >= 0xc0) {
t = (duk_uint_t) (x - 0xc0);
t = (t << 8) + duk_debug_read_byte(thr);
- duk_push_uint(ctx, (duk_uint_t) t);
+ duk_push_uint(thr, (duk_uint_t) t);
goto return_ptr;
}
if (x >= 0x80) {
- duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
+ duk_push_uint(thr, (duk_uint_t) (x - 0x80));
goto return_ptr;
}
if (x >= 0x60) {
@@ -37431,7 +42429,7 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
switch (x) {
case DUK_DBG_IB_INT4: {
duk_int32_t i = duk__debug_read_int32_raw(thr);
- duk_push_i32(ctx, i);
+ duk_push_i32(thr, i);
break;
}
case DUK_DBG_IB_STR4: {
@@ -37455,25 +42453,25 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
break;
}
case DUK_DBG_IB_UNDEFINED: {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
}
case DUK_DBG_IB_NULL: {
- duk_push_null(ctx);
+ duk_push_null(thr);
break;
}
case DUK_DBG_IB_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
}
case DUK_DBG_IB_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
}
case DUK_DBG_IB_NUMBER: {
duk_double_t d;
d = duk__debug_read_double_raw(thr);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
break;
}
case DUK_DBG_IB_OBJECT: {
@@ -37556,7 +42554,10 @@ DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *dat
#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
left = 1;
#endif
+ DUK__DBG_TPORT_ENTER();
got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
+ DUK__DBG_TPORT_EXIT();
+
if (got == 0 || got > left) {
duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
DUK_D(DUK_DPRINT("connection error during write"));
@@ -37682,8 +42683,7 @@ DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
}
DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
+ duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1));
}
DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
@@ -37871,7 +42871,7 @@ DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t e
DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
- duk_debug_write_int(thr, command);
+ duk_debug_write_int(thr, (duk_int32_t) command);
}
DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
@@ -37890,12 +42890,11 @@ DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
*/
DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_uint_fast32_t line;
duk_uint_fast32_t pc;
- act = duk_hthread_get_current_activation(thr); /* may be NULL */
+ act = thr->callstack_curr;
if (act == NULL) {
return 0;
}
@@ -37912,33 +42911,31 @@ DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
/* XXX: this should be optimized to be a raw query and avoid valstack
* operations if possible.
*/
- duk_push_tval(ctx, &act->tv_func);
- line = duk_hobject_pc2line_query(ctx, -1, pc);
- duk_pop(ctx);
+ duk_push_tval(thr, &act->tv_func);
+ line = duk_hobject_pc2line_query(thr, -1, pc);
+ duk_pop(thr);
return line;
}
DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
- duk_debug_write_int(thr, thr->heap->dbg_paused);
+ duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0));
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
- if (thr->callstack_top == 0) {
+ act = thr->callstack_curr;
+ if (act == NULL) {
duk_debug_write_undefined(thr);
duk_debug_write_undefined(thr);
duk_debug_write_int(thr, 0);
duk_debug_write_int(thr, 0);
} else {
- act = thr->callstack + thr->callstack_top - 1;
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_string(thr, -1, "fileName");
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_string(ctx, -2, "name");
+ duk_get_prop_string(thr, -2, "name");
duk__debug_write_hstring_safe_top(thr);
- duk_pop_3(ctx);
+ duk_pop_3(thr);
/* Report next pc/line to be executed. */
duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
@@ -37953,38 +42950,47 @@ DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
* NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
*/
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_uint32_t pc;
DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
- duk_debug_write_int(thr, fatal);
+ duk_debug_write_int(thr, (duk_int32_t) fatal);
/* Report thrown value to client coerced to string */
- duk_dup(ctx, -1);
+ duk_dup_top(thr);
duk__debug_write_hstring_safe_top(thr);
- duk_pop(ctx);
+ duk_pop(thr);
- if (duk_is_error(ctx, -1)) {
+ if (duk_is_error(thr, -1)) {
/* Error instance, use augmented error data directly */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER);
- duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER);
+ duk_debug_write_uint(thr, duk_get_uint(thr, -1));
+ duk_pop_2(thr);
} else {
- /* For anything other than an Error instance, we calculate the error
- * location directly from the current activation.
+ /* For anything other than an Error instance, we calculate the
+ * error location directly from the current activation if one
+ * exists.
*/
- act = thr->callstack + thr->callstack_top - 1;
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
- duk__debug_write_hstring_safe_top(thr);
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_string(thr, -1, "fileName");
+ duk__debug_write_hstring_safe_top(thr);
+ pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act);
+ duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc));
+ duk_pop_2(thr);
+ } else {
+ /* Can happen if duk_throw() is called on an empty
+ * callstack.
+ */
+ duk_debug_write_cstring(thr, "");
+ duk_debug_write_uint(thr, 0);
+ }
}
- duk_pop_2(ctx); /* shared pop */
duk_debug_write_eom(thr);
}
@@ -38009,7 +43015,7 @@ DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
return 0;
}
if (x >= 0x60) {
- duk_debug_skip_bytes(thr, x - 0x60);
+ duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60));
return 0;
}
switch(x) {
@@ -38077,6 +43083,34 @@ DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
}
}
+/* Read and validate a call stack index. If index is invalid, write out an
+ * error message and return zero.
+ */
+DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
+ duk_int32_t level;
+ level = duk_debug_read_int(thr);
+ if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
+ return 0; /* zero indicates failure */
+ }
+ return level;
+}
+
+/* Read a call stack index and lookup the corresponding duk_activation.
+ * If index is invalid, write out an error message and return NULL.
+ */
+DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) {
+ duk_activation *act;
+ duk_int32_t level;
+
+ level = duk_debug_read_int(thr);
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
+ }
+ return act;
+}
+
/*
* Simple commands
*/
@@ -38113,46 +43147,61 @@ DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap
DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
DUK_D(DUK_DPRINT("debug command Pause"));
-
- DUK_HEAP_SET_PAUSED(heap);
+ duk_debug_set_paused(heap);
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
+ duk_small_uint_t pause_flags;
+
DUK_D(DUK_DPRINT("debug command Resume"));
- DUK_HEAP_CLEAR_PAUSED(heap);
+ duk_debug_clear_paused(heap);
+
+ pause_flags = 0;
+#if 0 /* manual testing */
+ pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE;
+ pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR;
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+
+ duk__debug_set_pause_state(thr, heap, pause_flags);
+
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
- duk_small_uint_t step_type;
- duk_uint_fast32_t line;
+ duk_small_uint_t pause_flags;
DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
if (cmd == DUK_DBG_CMD_STEPINTO) {
- step_type = DUK_STEP_TYPE_INTO;
+ pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
+ DUK_PAUSE_FLAG_FUNC_ENTRY |
+ DUK_PAUSE_FLAG_FUNC_EXIT;
} else if (cmd == DUK_DBG_CMD_STEPOVER) {
- step_type = DUK_STEP_TYPE_OVER;
+ pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
+ DUK_PAUSE_FLAG_FUNC_EXIT;
} else {
DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
- step_type = DUK_STEP_TYPE_OUT;
+ pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT;
}
+#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+
+ /* If current activation doesn't have line information, line-based
+ * pause flags are automatically disabled. As a result, e.g.
+ * StepInto will then pause on (native) function entry or exit.
+ */
+ duk_debug_clear_paused(heap);
+ duk__debug_set_pause_state(thr, heap, pause_flags);
- line = duk_debug_curr_line(thr);
- if (line > 0) {
- heap->dbg_paused = 0;
- heap->dbg_step_type = step_type;
- heap->dbg_step_thread = thr;
- heap->dbg_step_csindex = thr->callstack_top - 1;
- heap->dbg_step_startline = line;
- heap->dbg_state_dirty = 1;
- } else {
- DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
- }
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
@@ -38205,46 +43254,27 @@ DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
+ duk_activation *act;
duk_hstring *str;
duk_bool_t rc;
- duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command GetVar"));
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
+ return;
+ }
str = duk_debug_read_hstring(thr); /* push to stack */
DUK_ASSERT(str != NULL);
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetVar"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- } else {
- level = -1;
- }
- if (thr->callstack_top > 0) {
- rc = duk_js_getvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- 0);
- } else {
- /* No activation, no variable access. Could also pretend
- * we're in the global program context and read stuff off
- * the global object.
- */
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
- rc = 0;
- }
+ rc = duk_js_getvar_activation(thr, act, str, 0);
duk_debug_write_reply(thr);
if (rc) {
duk_debug_write_int(thr, 1);
- DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
- duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
+ DUK_ASSERT(duk_get_tval(thr, -2) != NULL);
+ duk_debug_write_tval(thr, duk_get_tval(thr, -2));
} else {
duk_debug_write_int(thr, 0);
duk_debug_write_unused(thr);
@@ -38253,13 +43283,17 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
+ duk_activation *act;
duk_hstring *str;
duk_tval *tv;
- duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command PutVar"));
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
+ return;
+ }
str = duk_debug_read_hstring(thr); /* push to stack */
DUK_ASSERT(str != NULL);
tv = duk_debug_read_tval(thr);
@@ -38267,26 +43301,8 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
/* detached */
return;
}
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for PutVar"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- } else {
- level = -1;
- }
- if (thr->callstack_top > 0) {
- duk_js_putvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- tv,
- 0);
- } else {
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
- }
+ duk_js_putvar_activation(thr, act, str, tv, 0);
/* XXX: Current putvar implementation doesn't have a success flag,
* add one and send to debug client?
@@ -38296,23 +43312,17 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_hthread *curr_thr = thr;
duk_activation *curr_act;
duk_uint_fast32_t pc;
duk_uint_fast32_t line;
- duk_size_t i;
DUK_ASSERT(thr != NULL);
DUK_UNREF(heap);
duk_debug_write_reply(thr);
while (curr_thr != NULL) {
- i = curr_thr->callstack_top;
- while (i > 0) {
- i--;
- curr_act = curr_thr->callstack + i;
-
+ for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) {
/* PC/line semantics here are:
* - For callstack top we're conceptually between two
* opcodes and current PC indicates next line to
@@ -38326,19 +43336,19 @@ DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap
/* XXX: optimize to use direct reads, i.e. avoid
* value stack operations.
*/
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
+ duk_push_tval(thr, &curr_act->tv_func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
duk__debug_write_hstring_safe_top(thr);
pc = duk_hthread_get_act_curr_pc(thr, curr_act);
- if (i != curr_thr->callstack_top - 1 && pc > 0) {
+ if (curr_act != curr_thr->callstack_curr && pc > 0) {
pc--;
}
- line = duk_hobject_pc2line_query(ctx, -3, pc);
+ line = duk_hobject_pc2line_query(thr, -3, pc);
duk_debug_write_uint(thr, (duk_uint32_t) line);
duk_debug_write_uint(thr, (duk_uint32_t) pc);
- duk_pop_3(ctx);
+ duk_pop_3(thr);
}
curr_thr = curr_thr->resumer;
}
@@ -38349,30 +43359,17 @@ DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap
}
DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *curr_act;
- duk_int32_t level;
+ duk_activation *act;
duk_hstring *varname;
DUK_UNREF(heap);
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetLocals"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- duk_debug_write_reply(thr);
- } else {
- duk_debug_write_reply(thr);
- if (thr->callstack_top == 0) {
- goto callstack_empty;
- }
- level = -1;
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
+ return;
}
- curr_act = thr->callstack + thr->callstack_top + level;
+ duk_debug_write_reply(thr);
/* XXX: several nice-to-have improvements here:
* - Use direct reads avoiding value stack operations
@@ -38380,34 +43377,33 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
* - If side effects are possible, add error catching
*/
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP);
- if (duk_is_object(ctx, -1)) {
- duk_enum(ctx, -1, 0 /*enum_flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
- varname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(varname != NULL);
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VARMAP);
+ if (duk_is_object(thr, -1)) {
+ duk_enum(thr, -1, 0 /*enum_flags*/);
+ while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
+ varname = duk_known_hstring(thr, -1);
- duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
+ duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/);
/* [ ... func varmap enum key value this ] */
- duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
- duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
- duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
+ duk_debug_write_hstring(thr, duk_get_hstring(thr, -3));
+ duk_debug_write_tval(thr, duk_get_tval(thr, -2));
+ duk_pop_3(thr); /* -> [ ... func varmap enum ] */
}
} else {
DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
}
- callstack_empty:
duk_debug_write_eom(thr);
}
DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t call_flags;
duk_int_t call_ret;
duk_small_int_t eval_err;
+ duk_bool_t direct_eval;
duk_int32_t level;
+ duk_idx_t idx_func;
DUK_UNREF(heap);
@@ -38417,49 +43413,58 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
* activation. For now, use global object eval() function, with the eval
* considered a 'direct call to eval'.
*
- * Callstack level for debug commands only affects scope -- the callstack
+ * Callstack index for debug commands only affects scope -- the callstack
* as seen by, e.g. Duktape.act() will be the same regardless.
*/
- /* nargs == 2 so we can pass a callstack level to eval(). */
- duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
- duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
+ /* nargs == 2 so we can pass a callstack index to eval(). */
+ idx_func = duk_get_top(thr);
+ duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/);
+ duk_push_undefined(thr); /* 'this' binding shouldn't matter here */
- (void) duk_debug_read_hstring(thr);
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for Eval"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ /* Read callstack index, if non-null. */
+ if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) {
+ direct_eval = 0;
+ level = -1; /* Not needed, but silences warning. */
+ (void) duk_debug_read_byte(thr);
+ } else {
+ direct_eval = 1;
+ level = duk__debug_read_validate_csindex(thr);
+ if (level == 0) {
return;
}
}
- else {
- level = -1;
+
+ DUK_ASSERT(!direct_eval ||
+ (level < 0 && -level <= (duk_int32_t) thr->callstack_top));
+
+ (void) duk_debug_read_hstring(thr);
+ if (direct_eval) {
+ duk_push_int(thr, level - 1); /* compensate for eval() call */
}
- DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top);
- duk_push_int(ctx, level - 1); /* compensate for eval() call */
- /* [ ... eval "eval" eval_input level ] */
+ /* [ ... eval "eval" eval_input level? ] */
call_flags = 0;
- if (thr->callstack_top >= (duk_size_t) -level) {
+ if (direct_eval) {
duk_activation *act;
duk_hobject *fun;
- act = thr->callstack + thr->callstack_top + level;
- fun = DUK_ACT_GET_FUNC(act);
- if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
- /* Direct eval requires that there's a current
- * activation and it is an Ecmascript function.
- * When Eval is executed from e.g. cooperate API
- * call we'll need to do an indirect eval instead.
- */
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act != NULL) {
+ fun = DUK_ACT_GET_FUNC(act);
+ if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) {
+ /* Direct eval requires that there's a current
+ * activation and it is an Ecmascript function.
+ * When Eval is executed from e.g. cooperate API
+ * call we'll need to do an indirect eval instead.
+ */
+ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ }
}
}
- call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
+ call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -38470,15 +43475,15 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
* to traverse the error object.
*/
eval_err = 1;
- duk_safe_to_string(ctx, -1);
+ duk_safe_to_string(thr, -1);
}
/* [ ... result ] */
duk_debug_write_reply(thr);
duk_debug_write_int(thr, (duk_int32_t) eval_err);
- DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
- duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
+ DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
+ duk_debug_write_tval(thr, duk_get_tval(thr, -1));
duk_debug_write_eom(thr);
}
@@ -38494,12 +43499,11 @@ DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t old_top;
DUK_D(DUK_DPRINT("debug command AppRequest"));
- old_top = duk_get_top(ctx); /* save stack top */
+ old_top = duk_get_top(thr); /* save stack top */
if (heap->dbg_request_cb != NULL) {
duk_idx_t nrets;
@@ -38511,7 +43515,7 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
*/
while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
duk_tval *tv;
- if (!duk_check_stack(ctx, 1)) {
+ if (!duk_check_stack(thr, 1)) {
DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
goto fail;
}
@@ -38522,41 +43526,41 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
}
nvalues++;
}
- DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
+ DUK_ASSERT(duk_get_top(thr) == old_top + nvalues);
/* Request callback should push values for reply to client onto valstack */
DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
- nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
+ (long) nvalues, (long) old_top, (long) duk_get_top(thr)));
+ nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues);
DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
+ (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr)));
if (nrets >= 0) {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
- if (duk_get_top(ctx) < old_top + nrets) {
+ DUK_ASSERT(duk_get_top(thr) >= old_top + nrets);
+ if (duk_get_top(thr) < old_top + nrets) {
DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
"top=%ld < old_top=%ld + nrets=%ld; "
"this might mean it's unsafe to continue!",
- (long) duk_get_top(ctx), (long) old_top, (long) nrets));
+ (long) duk_get_top(thr), (long) old_top, (long) nrets));
goto fail;
}
/* Reply with tvals pushed by request callback */
duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
for (idx = top - nrets; idx < top; idx++) {
- duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
+ duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx));
}
duk_debug_write_eom(thr);
} else {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
- if (duk_get_top(ctx) < old_top + 1) {
+ DUK_ASSERT(duk_get_top(thr) >= old_top + 1);
+ if (duk_get_top(thr) < old_top + 1) {
DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
goto fail;
}
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1));
}
- duk_set_top(ctx, old_top); /* restore stack top */
+ duk_set_top(thr, old_top); /* restore stack top */
} else {
DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
@@ -38565,7 +43569,7 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
return;
fail:
- duk_set_top(ctx, old_top); /* restore stack top */
+ duk_set_top(thr, old_top); /* restore stack top */
DUK__SET_CONN_BROKEN(thr, 1);
}
@@ -38593,9 +43597,9 @@ DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_hea
case DUK_HTYPE_STRING: {
duk_hstring *h = (duk_hstring *) hdr;
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
duk_debug_write_hstring(thr, h);
break;
}
@@ -38662,89 +43666,36 @@ DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap)
}
}
-#if defined(DUK_USE_STRTAB_CHAIN)
-DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
- duk_uint_fast32_t i, j;
- duk_strtab_entry *e;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
-#else
- duk_hstring **lst;
-#endif
- duk_hstring *h;
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen > 0) {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- DUK_ASSERT(lst != NULL);
-
- for (j = 0; j < e->listlen; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
-#else
- h = lst[j];
-#endif
- if (h != NULL) {
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
- }
- }
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
-#else
- h = e->u.str;
-#endif
- if (h != NULL) {
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
- }
- }
- }
-}
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
+DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) {
duk_uint32_t i;
duk_hstring *h;
for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
#else
h = heap->strtable[i];
#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
+ while (h != NULL) {
+ duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
+ h = h->hdr.h_next;
}
-
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
}
}
-#endif /* DUK_USE_STRTAB_PROBE */
DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
DUK_D(DUK_DPRINT("debug command DumpHeap"));
duk_debug_write_reply(thr);
duk__debug_dump_heap_allocated(thr, heap);
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__debug_dump_strtab_chain(thr, heap);
-#endif
-#if defined(DUK_USE_STRTAB_PROBE)
- duk__debug_dump_strtab_probe(thr, heap);
-#endif
+ duk__debug_dump_strtab(thr, heap);
duk_debug_write_eom(thr);
}
#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
duk_activation *act;
- duk_hcompiledfunction *fun = NULL;
+ duk_hcompfunc *fun = NULL;
duk_size_t i, n;
duk_tval *tv;
duk_hobject **fn;
@@ -38764,7 +43715,7 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap)
}
if (DUK_TVAL_IS_OBJECT(tv)) {
/* tentative, checked later */
- fun = (duk_hcompiledfunction *) DUK_TVAL_GET_OBJECT(tv);
+ fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(fun != NULL);
} else if (DUK_TVAL_IS_NUMBER(tv)) {
level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
@@ -38775,38 +43726,37 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap)
}
if (fun == NULL) {
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetBytecode"));
- goto fail_level;
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ goto fail_index;
}
- act = thr->callstack + thr->callstack_top + level;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
+ fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
}
- if (fun == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)) {
+ if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) {
DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
goto fail_args;
}
- DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun));
+ DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun));
duk_debug_write_reply(thr);
- n = DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap, fun);
+ n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun);
duk_debug_write_int(thr, (duk_int32_t) n);
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, fun);
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun);
for (i = 0; i < n; i++) {
duk_debug_write_tval(thr, tv);
tv++;
}
- n = DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap, fun);
+ n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun);
duk_debug_write_int(thr, (duk_int32_t) n);
- fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, fun);
+ fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun);
for (i = 0; i < n; i++) {
duk_debug_write_hobject(thr, *fn);
fn++;
}
duk_debug_write_string(thr,
- (const char *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, fun),
- (duk_size_t) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap, fun));
+ (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun),
+ (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun));
duk_debug_write_eom(thr);
return;
@@ -38814,8 +43764,8 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap)
duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
return;
- fail_level:
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
+ fail_index:
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
return;
}
@@ -38847,7 +43797,8 @@ DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
#if 0
"arridx",
- "internal",
+ "symbol",
+ "hidden",
"reserved_word",
"strict_reserved_word",
"eval_or_arguments",
@@ -38858,7 +43809,8 @@ DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
#if 0
DUK_HSTRING_FLAG_ARRIDX,
- DUK_HSTRING_FLAG_INTERNAL,
+ DUK_HSTRING_FLAG_SYMBOL,
+ DUK_HSTRING_FLAG_HIDDEN,
DUK_HSTRING_FLAG_RESERVED_WORD,
DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
@@ -38869,45 +43821,47 @@ DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
"extensible",
"constructable",
- "bound",
- "compiledfunction",
- "nativefunction",
- "bufferobject",
- "thread",
+ "callable",
+ "boundfunc",
+ "compfunc",
+ "natfunc",
+ "bufobj",
+ "fastrefs",
"array_part",
"strict",
"notail",
"newenv",
"namebinding",
"createargs",
- "envrecclosed",
+ "have_finalizer",
"exotic_array",
"exotic_stringobj",
"exotic_arguments",
- "exotic_dukfunc",
- "exotic_proxyobj"
+ "exotic_proxyobj",
+ "special_call"
/* NULL not needed here */
};
DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
DUK_HOBJECT_FLAG_EXTENSIBLE,
DUK_HOBJECT_FLAG_CONSTRUCTABLE,
- DUK_HOBJECT_FLAG_BOUND,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION,
- DUK_HOBJECT_FLAG_NATIVEFUNCTION,
- DUK_HOBJECT_FLAG_BUFFEROBJECT,
- DUK_HOBJECT_FLAG_THREAD,
+ DUK_HOBJECT_FLAG_CALLABLE,
+ DUK_HOBJECT_FLAG_BOUNDFUNC,
+ DUK_HOBJECT_FLAG_COMPFUNC,
+ DUK_HOBJECT_FLAG_NATFUNC,
+ DUK_HOBJECT_FLAG_BUFOBJ,
+ DUK_HOBJECT_FLAG_FASTREFS,
DUK_HOBJECT_FLAG_ARRAY_PART,
DUK_HOBJECT_FLAG_STRICT,
DUK_HOBJECT_FLAG_NOTAIL,
DUK_HOBJECT_FLAG_NEWENV,
DUK_HOBJECT_FLAG_NAMEBINDING,
DUK_HOBJECT_FLAG_CREATEARGS,
- DUK_HOBJECT_FLAG_ENVRECCLOSED,
+ DUK_HOBJECT_FLAG_HAVE_FINALIZER,
DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
+ DUK_HOBJECT_FLAG_SPECIAL_CALL,
0 /* terminator */
};
DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
@@ -38950,7 +43904,7 @@ DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const *
for (;;) {
mask = *masks++;
- if (!mask) {
+ if (mask == 0) {
break;
}
key = *keys++;
@@ -38998,8 +43952,11 @@ DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap,
}
flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
- if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
- flags |= DUK_DBG_PROPFLAG_INTERNAL;
+ if (DUK_HSTRING_HAS_SYMBOL(h_key)) {
+ flags |= DUK_DBG_PROPFLAG_SYMBOL;
+ }
+ if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
+ flags |= DUK_DBG_PROPFLAG_HIDDEN;
}
duk_debug_write_uint(thr, flags);
duk_debug_write_hstring(thr, h_key);
@@ -39029,6 +43986,10 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
DUK_UNREF(heap);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1);
+
h = duk_debug_read_any_ptr(thr);
if (!h) {
duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
@@ -39067,9 +44028,9 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
duk__debug_getinfo_hstring_keys,
duk__debug_getinfo_hstring_masks,
DUK_HEAPHDR_GET_FLAGS_RAW(h));
- duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str));
- duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str));
- duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str));
+ duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str));
+ duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str));
+ duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str));
duk__debug_getinfo_flags_key(thr, "data");
duk_debug_write_hstring(thr, h_str);
break;
@@ -39102,14 +44063,21 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
- /* duk_hnativefunction specific fields. */
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
- duk_hnativefunction *h_fun;
- h_fun = (duk_hnativefunction *) h_obj;
+ if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
+ duk_harray *h_arr;
+ h_arr = (duk_harray *) h_obj;
+
+ duk__debug_getinfo_prop_uint(thr, "length", (duk_uint_t) h_arr->length);
+ duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable);
+ }
+
+ if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
+ duk_hnatfunc *h_fun;
+ h_fun = (duk_hnatfunc *) h_obj;
duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
- duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATIVEFUNCTION_NARGS_VARARGS);
+ duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS);
/* Native function pointer may be different from a void pointer,
* and we serialize it from memory directly now (no byte swapping etc).
*/
@@ -39117,22 +44085,53 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
}
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- duk_hcompiledfunction *h_fun;
+ if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
+ duk_hcompfunc *h_fun;
duk_hbuffer *h_buf;
- h_fun = (duk_hcompiledfunction *) h_obj;
+ duk_hobject *h_lexenv;
+ duk_hobject *h_varenv;
+ h_fun = (duk_hcompfunc *) h_obj;
duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
+
+ duk__debug_getinfo_flags_key(thr, "lex_env");
+ h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun);
+ if (h_lexenv != NULL) {
+ duk_debug_write_hobject(thr, h_lexenv);
+ } else {
+ duk_debug_write_null(thr);
+ }
+ duk__debug_getinfo_flags_key(thr, "var_env");
+ h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun);
+ if (h_varenv != NULL) {
+ duk_debug_write_hobject(thr, h_varenv);
+ } else {
+ duk_debug_write_null(thr);
+ }
+
duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
- h_buf = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun);
+ h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun);
if (h_buf != NULL) {
duk__debug_getinfo_flags_key(thr, "data");
duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
}
}
+ if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
+ duk_hboundfunc *h_bfun;
+ h_bfun = (duk_hboundfunc *) h_obj;
+
+ duk__debug_getinfo_flags_key(thr, "target");
+ duk_debug_write_tval(thr, &h_bfun->target);
+ duk__debug_getinfo_flags_key(thr, "this_binding");
+ duk_debug_write_tval(thr, &h_bfun->this_binding);
+ duk__debug_getinfo_flags_key(thr, "nargs");
+ duk_debug_write_int(thr, h_bfun->nargs);
+ /* h_bfun->args not exposed now */
+ }
+
if (DUK_HOBJECT_IS_THREAD(h_obj)) {
/* XXX: Currently no inspection of threads, e.g. value stack, call
* stack, catch stack, etc.
@@ -39142,20 +44141,42 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
DUK_UNREF(h_thr);
}
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) h_obj;
+ if (DUK_HOBJECT_IS_DECENV(h_obj)) {
+ duk_hdecenv *h_env;
+ h_env = (duk_hdecenv *) h_obj;
+
+ duk__debug_getinfo_flags_key(thr, "thread");
+ duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread));
+ duk__debug_getinfo_flags_key(thr, "varmap");
+ duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap));
+ duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase_byteoff);
+ }
+
+ if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
+ duk_hobjenv *h_env;
+ h_env = (duk_hobjenv *) h_obj;
+
+ duk__debug_getinfo_flags_key(thr, "target");
+ duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target));
+ duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this);
+ }
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ duk_hbufobj *h_bufobj;
+ h_bufobj = (duk_hbufobj *) h_obj;
duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
- duk__debug_getinfo_prop_bool(thr, "is_view", (duk_uint_t) h_bufobj->is_view);
+ duk__debug_getinfo_prop_bool(thr, "is_typedarray", (duk_uint_t) h_bufobj->is_typedarray);
if (h_bufobj->buf != NULL) {
duk__debug_getinfo_flags_key(thr, "buffer");
duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
break;
}
case DUK_HTYPE_BUFFER: {
@@ -39234,8 +44255,8 @@ DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_h
DUK_UNREF(heap);
h = duk_debug_read_any_ptr(thr);
- idx_start = duk_debug_read_int(thr);
- idx_end = duk_debug_read_int(thr);
+ idx_start = (duk_uint_t) duk_debug_read_int(thr);
+ idx_end = (duk_uint_t) duk_debug_read_int(thr);
if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
goto fail_args;
}
@@ -39276,7 +44297,6 @@ DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_h
* stack handling which is convenient.
*/
DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_heap *heap;
duk_uint8_t x;
duk_int32_t cmd;
@@ -39285,9 +44305,8 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
- DUK_UNREF(ctx);
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
x = duk_debug_read_byte(thr);
switch (x) {
@@ -39409,14 +44428,14 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
}
} /* switch initial byte */
- DUK_ASSERT(duk_get_top(ctx) >= entry_top);
- duk_set_top(ctx, entry_top);
+ DUK_ASSERT(duk_get_top(thr) >= entry_top);
+ duk_set_top(thr, entry_top);
duk__debug_skip_to_eom(thr);
return;
fail:
- DUK_ASSERT(duk_get_top(ctx) >= entry_top);
- duk_set_top(ctx, entry_top);
+ DUK_ASSERT(duk_get_top(thr) >= entry_top);
+ duk_set_top(thr, entry_top);
DUK__SET_CONN_BROKEN(thr, 1);
return;
}
@@ -39429,23 +44448,21 @@ DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
}
DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
- duk_context *ctx = (duk_context *) thr;
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
#endif
duk_bool_t retval = 0;
DUK_ASSERT(thr != NULL);
- DUK_UNREF(ctx);
DUK_ASSERT(thr->heap != NULL);
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
(long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
- DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(thr)));
/* thr->heap->dbg_detaching may be != 0 if a debugger write outside
* the message loop caused a transport error and detach1() to run.
@@ -39464,7 +44481,7 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
/* Process messages until we're no longer paused or we peek
* and see there's nothing to read right now.
*/
- DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(thr)));
DUK_ASSERT(thr->heap->dbg_processing == 1);
while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
@@ -39504,7 +44521,7 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
break;
}
- if (!thr->heap->dbg_paused || no_block) {
+ if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) {
if (!duk_debug_read_peek(thr)) {
/* Note: peek cannot currently trigger a detach
* so the dbg_detaching == 0 assert outside the
@@ -39535,11 +44552,11 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
duk_debug_read_flush(thr); /* this cannot initiate a detach */
DUK_ASSERT(thr->heap->dbg_detaching == 0);
- DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(thr)));
#if defined(DUK_USE_ASSERTIONS)
/* Easy to get wrong, so assert for it. */
- DUK_ASSERT(entry_top == duk_get_top(ctx));
+ DUK_ASSERT(entry_top == duk_get_top(thr));
#endif
return retval;
@@ -39557,17 +44574,18 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
duk_activation *act;
- duk_hcompiledfunction *fun;
+ duk_hcompfunc *fun;
duk_instr_t *old_pc = NULL;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
+ DUK_ASSERT(duk_debug_is_attached(thr->heap));
DUK_ASSERT(thr->heap->dbg_processing == 0);
+ DUK_ASSERT(!duk_debug_is_paused(thr->heap));
- DUK_HEAP_SET_PAUSED(thr->heap);
+ duk_debug_set_paused(thr->heap);
- act = duk_hthread_get_current_activation(thr);
+ act = thr->callstack_curr;
/* NOTE: act may be NULL if an error is thrown outside of any activation,
* which may happen in the case of, e.g. syntax errors.
@@ -39577,16 +44595,16 @@ DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev
if (act != NULL) {
duk_hthread_sync_currpc(thr);
old_pc = act->curr_pc;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
+ fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
/* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
* guaranteed to be a non-NULL Ecmascript function.
*/
DUK_ASSERT(act->curr_pc == NULL ||
- (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)));
+ (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)));
if (use_prev_pc &&
act->curr_pc != NULL &&
- act->curr_pc > DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun)) {
+ act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) {
act->curr_pc--;
}
}
@@ -39599,9 +44617,9 @@ DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev
*/
thr->heap->dbg_state_dirty = 1;
- while (thr->heap->dbg_paused) {
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
- DUK_ASSERT(thr->heap->dbg_processing);
+ while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
+ DUK_ASSERT(duk_debug_is_attached(thr->heap));
+ DUK_ASSERT(thr->heap->dbg_processing == 0);
duk_debug_process_messages(thr, 0 /*no_block*/);
}
@@ -39646,7 +44664,7 @@ DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstr
b->line = line;
DUK_HSTRING_INCREF(thr, filename);
- return heap->dbg_breakpoint_count - 1; /* index */
+ return (duk_small_int_t) (heap->dbg_breakpoint_count - 1); /* index */
}
DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
@@ -39663,7 +44681,7 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
+ DUK_ASSERT(duk_debug_is_attached(thr->heap));
DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
if (breakpoint_index >= heap->dbg_breakpoint_count) {
@@ -39692,14 +44710,64 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
return 1;
}
-#undef DUK__SET_CONN_BROKEN
+/*
+ * Misc state management
+ */
+
+DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) {
+ return (heap->dbg_read_cb != NULL);
+}
+
+DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) {
+ return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0);
+}
+
+DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) {
+ if (duk_debug_is_paused(heap)) {
+ DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring"));
+ } else {
+ DUK_HEAP_SET_DEBUGGER_PAUSED(heap);
+ heap->dbg_state_dirty = 1;
+ duk_debug_clear_pause_state(heap);
+ DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */
+ heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */
+ heap->ms_prevent_count++;
+ DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */
+ DUK_ASSERT(heap->heap_thread != NULL);
+ }
+}
+
+DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) {
+ if (duk_debug_is_paused(heap)) {
+ DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
+ heap->dbg_state_dirty = 1;
+ duk_debug_clear_pause_state(heap);
+ DUK_ASSERT(heap->ms_running == 1);
+ DUK_ASSERT(heap->ms_prevent_count > 0);
+ heap->ms_prevent_count--;
+ heap->ms_running = 0;
+ DUK_ASSERT(heap->heap_thread != NULL);
+ } else {
+ DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring"));
+ }
+}
+
+DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) {
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
+}
#else /* DUK_USE_DEBUGGER_SUPPORT */
/* No debugger support. */
#endif /* DUK_USE_DEBUGGER_SUPPORT */
-#line 1 "duk_error_augment.c"
+
+/* automatic undefs */
+#undef DUK__DBG_TPORT_ENTER
+#undef DUK__DBG_TPORT_EXIT
+#undef DUK__SET_CONN_BROKEN
/*
* Augmenting errors at their creation site and their throw site.
*
@@ -39723,7 +44791,7 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
* extensible. User error handlers have no limitations in this respect.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Helper for calling a user error handler.
@@ -39762,18 +44830,15 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv_hnd;
- duk_small_uint_t call_flags;
duk_int_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT_DISABLE(stridx_cb >= 0); /* unsigned */
- DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_STRIDX_VALID(stridx_cb);
- if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
- DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
+ if (thr->heap->augmenting_error) {
+ DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore"));
return;
}
@@ -39808,45 +44873,33 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
}
DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
(duk_tval *) tv_hnd));
- duk_push_tval(ctx, tv_hnd);
+ duk_push_tval(thr, tv_hnd);
/* [ ... errval errhandler ] */
- duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
- duk_push_undefined(ctx);
- duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
+ duk_insert(thr, -2); /* -> [ ... errhandler errval ] */
+ duk_push_undefined(thr);
+ duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */
/* [ ... errhandler undefined errval ] */
/*
- * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
- * recursion depth limit (and won't increase it either). This is
- * dangerous, but useful because it allows the error handler to run
- * even if the original error is caused by C recursion depth limit.
- *
- * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
- * duration of the error handler and cleared afterwards. This flag
- * prevents the error handler from running recursively. The flag is
- * heap level so that the flag properly controls even coroutines
- * launched by an error handler. Since the flag is heap level, it is
- * critical to restore it correctly.
+ * heap->augmenting_error prevents recursive re-entry and also causes
+ * call handling to use a larger (but not unbounded) call stack limit
+ * for the duration of error augmentation.
*
* We ignore errors now: a success return and an error value both
* replace the original error value. (This would be easy to change.)
*/
- DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
- DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
+ DUK_ASSERT(thr->heap->augmenting_error == 0);
+ thr->heap->augmenting_error = 1;
- call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
-
- rc = duk_handle_call_protected(thr,
- 1, /* num args */
- call_flags); /* call_flags */
+ rc = duk_pcall_method(thr, 1);
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
- DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
- DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
+ DUK_ASSERT(thr->heap->augmenting_error == 1);
+ thr->heap->augmenting_error = 0;
/* [ ... errval ] */
}
@@ -39857,16 +44910,17 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
*/
#if defined(DUK_USE_TRACEBACKS)
-DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t depth;
- duk_int_t i, i_min;
- duk_uarridx_t arr_idx;
+DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
+ duk_activation *act;
+ duk_int_t depth;
+ duk_int_t arr_size;
+ duk_tval *tv;
+ duk_hstring *s;
+ duk_uint32_t u32;
duk_double_t d;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
/* [ ... error ] */
@@ -39879,22 +44933,54 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
*/
DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_push_array(ctx); /* XXX: specify array size, as we know it */
- arr_idx = 0;
+ /* Preallocate array to correct size, so that we can just write out
+ * the _Tracedata values into the array part.
+ */
+ act = thr->callstack_curr;
+ depth = DUK_USE_TRACEBACK_DEPTH;
+ DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
+ if (depth > (duk_int_t) thr_callstack->callstack_top) {
+ depth = (duk_int_t) thr_callstack->callstack_top;
+ }
+ if (depth > 0) {
+ if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) {
+ DUK_ASSERT(act != NULL);
+ act = act->parent;
+ depth--;
+ }
+ }
+ arr_size = depth * 2;
+ if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
+ arr_size += 2;
+ }
+ if (c_filename) {
+ /* We need the C filename to be interned before getting the
+ * array part pointer to avoid any GC interference while the
+ * array part is populated.
+ */
+ duk_push_string(thr, c_filename);
+ arr_size += 2;
+ }
+
+ /* XXX: uninitialized would be OK */
+ DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size);
+ DUK_ASSERT(arr_size == 0 || tv != NULL);
/* Compiler SyntaxErrors (and other errors) come first, and are
* blamed by default (not flagged "noblame").
*/
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
- duk_push_hstring(ctx, thr->compile_ctx->h_filename);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ s = thr->compile_ctx->h_filename;
+ DUK_TVAL_SET_STRING(tv, s);
+ DUK_HSTRING_INCREF(thr, s);
+ tv++;
- duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); /* (flags<<32) + (line), flags = 0 */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */
+ DUK_TVAL_SET_U32(tv, u32);
+ tv++;
}
/* Filename/line from C macros (__FILE__, __LINE__) are added as an
@@ -39902,84 +44988,73 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
* the line and flags.
*/
- /* XXX: optimize: allocate an array part to the necessary size (upwards
- * estimate) and fill in the values directly into the array part; finally
- * update 'length'.
- */
-
- /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
- * has write-protected array index named properties. This was seen as DoubleErrors
- * in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier.
- * The best fix is to fill in the tracedata directly into the array part. There are
- * no side effect concerns if the array part is allocated directly and only INCREFs
- * happen after that.
- */
-
- /* [ ... error arr ] */
+ /* [ ... error c_filename? arr ] */
if (c_filename) {
- duk_push_string(ctx, c_filename);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
+ s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */
+ DUK_ASSERT(s != NULL);
+ DUK_TVAL_SET_STRING(tv, s);
+ DUK_HSTRING_INCREF(thr, s);
+ tv++;
- d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
+ d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
(duk_double_t) c_line;
- duk_push_number(ctx, d);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ DUK_TVAL_SET_DOUBLE(tv, d);
+ tv++;
}
- /* traceback depth doesn't take into account the filename/line
- * special handling above (intentional)
+ /* Traceback depth doesn't take into account the filename/line
+ * special handling above (intentional).
*/
- depth = DUK_USE_TRACEBACK_DEPTH;
- i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
- DUK_ASSERT(i_min >= 0);
-
- /* [ ... error arr ] */
-
- DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
- for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
+ for (; depth-- > 0; act = act->parent) {
duk_uint32_t pc;
-
- /*
- * Note: each API operation potentially resizes the callstack,
- * so be careful to re-lookup after every operation. Currently
- * these is no issue because we don't store a temporary 'act'
- * pointer at all. (This would be a non-issue if we operated
- * directly on the array part.)
- */
+ duk_tval *tv_src;
/* [... arr] */
- DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
+ DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */
+ DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */
/* Add function object. */
- duk_push_tval(ctx, &(thr_callstack->callstack + i)->tv_func);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ tv_src = &act->tv_func; /* object (function) or lightfunc */
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
+ DUK_TVAL_SET_TVAL(tv, tv_src);
+ DUK_TVAL_INCREF(thr, tv);
+ tv++;
/* Add a number containing: pc, activation flags.
*
* PC points to next instruction, find offending PC. Note that
* PC == 0 for native code.
*/
- pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
+ pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act);
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
- d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
- duk_push_number(ctx, d); /* -> [... arr num] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
+ d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
+ DUK_TVAL_SET_DOUBLE(tv, d);
+ tv++;
}
- /* XXX: set with duk_hobject_set_length() when tracedata is filled directly */
- duk_push_uint(ctx, (duk_uint_t) arr_idx);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_harray *a;
+ a = (duk_harray *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(a != NULL);
+ DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
+ DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
+ }
+#endif
+
+ /* [ ... error c_filename? arr ] */
+
+ if (c_filename) {
+ duk_remove_m2(thr);
+ }
/* [ ... error arr ] */
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
}
#endif /* DUK_USE_TRACEBACKS */
@@ -39987,16 +45062,14 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
* Add .fileName and .lineNumber to an error on the stack top.
*/
-#if !defined(DUK_USE_TRACEBACKS)
-DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx;
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS)
+DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
- ctx = (duk_context *) thr;
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
/*
@@ -40011,37 +45084,33 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
/* Compiler SyntaxError (or other error) gets the primary blame.
* Currently no flag to prevent blaming.
*/
- duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
- duk_push_hstring(ctx, thr->compile_ctx->h_filename);
- } else if (c_filename && !noblame_fileline) {
+ duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
+ duk_push_hstring(thr, thr->compile_ctx->h_filename);
+ } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) {
/* C call site gets blamed next, unless flagged not to do so.
* XXX: file/line is disabled in minimal builds, so disable this
* too when appropriate.
*/
- duk_push_int(ctx, c_line);
- duk_push_string(ctx, c_filename);
+ duk_push_int(thr, c_line);
+ duk_push_string(thr, c_filename);
} else {
/* Finally, blame the innermost callstack entry which has a
* .fileName property.
*/
duk_small_uint_t depth;
- duk_int_t i, i_min;
duk_uint32_t ecma_line;
-
- depth = DUK_USE_TRACEBACK_DEPTH;
- i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
- DUK_ASSERT(i_min >= 0);
+ duk_activation *act;
DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
- for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
- duk_activation *act;
+ depth = DUK_USE_TRACEBACK_DEPTH;
+ if (depth > thr_callstack->callstack_top) {
+ depth = thr_callstack->callstack_top;
+ }
+ for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) {
duk_hobject *func;
duk_uint32_t pc;
- DUK_UNREF(pc);
- act = thr_callstack->callstack + i;
- DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
-
+ DUK_ASSERT(act != NULL);
func = DUK_ACT_GET_FUNC(act);
if (func == NULL) {
/* Lightfunc, not blamed now. */
@@ -40052,17 +45121,18 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
* PC == 0 for native code.
*/
pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
+ DUK_UNREF(pc);
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
act = NULL; /* invalidated by pushes, so get out of the way */
- duk_push_hobject(ctx, func);
+ duk_push_hobject(thr, func);
/* [ ... error func ] */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- if (!duk_is_string(ctx, -1)) {
- duk_pop_2(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
+ if (!duk_is_string_notsymbol(thr, -1)) {
+ duk_pop_2(thr);
continue;
}
@@ -40070,17 +45140,17 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
ecma_line = 0;
#if defined(DUK_USE_PC2LINE)
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
+ if (DUK_HOBJECT_IS_COMPFUNC(func)) {
+ ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc);
} else {
/* Native function, no relevant lineNumber. */
}
#endif /* DUK_USE_PC2LINE */
- duk_push_u32(ctx, ecma_line);
+ duk_push_u32(thr, ecma_line);
/* [ ... error func fileName lineNumber ] */
- duk_replace(ctx, -3);
+ duk_replace(thr, -3);
/* [ ... error lineNumber fileName ] */
goto define_props;
@@ -40090,26 +45160,26 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
* .lineNumber (matches what we do with a _Tracedata based
* no-match lookup.
*/
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
}
define_props:
/* [ ... error lineNumber fileName ] */
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 2);
#endif
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
}
-#endif /* !DUK_USE_TRACEBACKS */
+#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
/*
* Add line number to a compiler error.
*/
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
- duk_context *ctx;
/* Append a "(line NNN)" to the "message" property of any error
* thrown during compilation. Usually compilation errors are
@@ -40119,27 +45189,27 @@ DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
/* [ ... error ] */
- ctx = (duk_context *) thr;
- DUK_ASSERT(duk_is_object(ctx, -1));
+ DUK_ASSERT(duk_is_object(thr, -1));
if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
return;
}
DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
- duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
- duk_concat(ctx, 2);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) {
+ duk_push_sprintf(thr, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
+ duk_concat(thr, 2);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
} else {
- duk_pop(ctx);
+ duk_pop(thr);
}
DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
}
+#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
/*
* Augment an error being created using Duktape specific properties
@@ -40147,19 +45217,17 @@ DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
+DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_hobject *obj, duk_small_uint_t flags) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
DUK_ASSERT(obj != NULL);
DUK_UNREF(obj); /* unreferenced w/o tracebacks */
- DUK_UNREF(ctx); /* unreferenced w/o asserts */
duk__add_compiler_error_line(thr);
@@ -40171,17 +45239,17 @@ DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *th
if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
} else {
- duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
+ duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags);
}
#else
/* Without tracebacks the concrete .fileName and .lineNumber need
* to be added directly.
*/
- duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
+ duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags);
#endif
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
+ DUK_ASSERT(duk_get_top(thr) == entry_top);
#endif
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
@@ -40195,22 +45263,18 @@ DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *th
* thr_callstack: thread which should be used for generating callstack etc.
* c_filename: C __FILE__ related to the error
* c_line: C __LINE__ related to the error
- * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
- * (needed because user code filename/line are reported but internal ones
- * are not)
- *
- * XXX: rename noblame_fileline to flags field; combine it to some existing
- * field (there are only a few call sites so this may not be worth it).
+ * flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE:
+ * if true, don't fileName/line as error source, otherwise use traceback
+ * (needed because user code filename/line are reported but internal ones
+ * are not)
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
duk_hobject *obj;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
/* [ ... error ] */
@@ -40226,7 +45290,7 @@ DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *th
* - error value is an extensible object
*/
- obj = duk_get_hobject(ctx, -1);
+ obj = duk_get_hobject(thr, -1);
if (!obj) {
DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
return;
@@ -40241,7 +45305,7 @@ DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *th
}
if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
- duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
+ duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags);
} else {
DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
}
@@ -40267,24 +45331,81 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
#endif /* DUK_USE_ERRTHROW */
}
#endif /* DUK_USE_AUGMENT_ERROR_THROW */
-#line 1 "duk_error_longjmp.c"
/*
* Do a longjmp call, calling the fatal error handler if no
* catchpoint exists.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
+ (void) duk_fatal(thr, "uncaught error");
+}
+#endif
+
+#if 0
+DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
+ const char *summary;
+ char buf[DUK_USE_FATAL_MAXLEN];
+
+ summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1);
+ DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
+ buf[sizeof(buf) - 1] = (char) 0;
+ (void) duk_fatal(thr, (const char *) buf);
+}
+#endif
+
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
+ const char *summary;
+ char buf[DUK_USE_FATAL_MAXLEN];
+
+ summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1);
+ DUK_ASSERT(summary != NULL);
+ DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
+ buf[sizeof(buf) - 1] = (char) 0;
+ (void) duk_fatal(thr, (const char *) buf);
+}
+#endif
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
(int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
&thr->heap->lj.value1, &thr->heap->lj.value2));
+ /* Prevent finalizer execution during error handling. All error
+ * handling sites will process pending finalizers once error handling
+ * is complete and we're ready for the side effects. Does not prevent
+ * refzero freeing or mark-and-sweep during error handling.
+ *
+ * NOTE: when we come here some calling code may have used DECREF
+ * NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call.
+ * We don't want to do it here because it would just check for
+ * pending finalizers and we prevent that explicitly. Instead,
+ * the error catcher will run the finalizers once error handling
+ * is complete.
+ */
+
+ DUK_ASSERT_LJSTATE_SET(thr->heap);
+
+ thr->heap->pf_prevent_count++;
+ DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
+
+#if defined(DUK_USE_ASSERTIONS)
+ /* XXX: set this immediately when longjmp state is set */
+ DUK_ASSERT(thr->heap->error_not_allowed == 0); /* Detect error within critical section. */
+ thr->heap->error_not_allowed = 1;
+#endif
+
+ DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count));
+
#if !defined(DUK_USE_CPP_EXCEPTIONS)
- /* If we don't have a jmpbuf_ptr, there is little we can do
- * except panic. The caller's expectation is that we never
+ /* If we don't have a jmpbuf_ptr, there is little we can do except
+ * cause a fatal error. The caller's expectation is that we never
* return.
*
* With C++ exceptions we now just propagate an uncaught error
@@ -40292,12 +45413,15 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
* a dummy jmpbuf for C++ exceptions now, this could be changed.
*/
if (!thr->heap->lj.jmpbuf_ptr) {
-
DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
(int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
&thr->heap->lj.value1, &thr->heap->lj.value2));
- duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
+#if defined(DUK_USE_PREFER_SIZE)
+ duk__uncaught_minimal(thr);
+#else
+ duk__uncaught_error_aware(thr);
+#endif
DUK_UNREACHABLE();
}
#endif /* DUK_USE_CPP_EXCEPTIONS */
@@ -40313,44 +45437,42 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_UNREACHABLE();
}
-#line 1 "duk_error_misc.c"
/*
* Error helpers
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Helper to walk the thread chain and see if there is an active error
* catcher. Protected calls or finally blocks aren't considered catching.
*/
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
- (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
- /*
- * XXX: As noted above, a protected API call won't be counted as a
- * catcher. This is usually convenient, e.g. in the case of a top-
- * level duk_pcall(), but may not always be desirable. Perhaps add an
- * argument to treat them as catchers?
+ /* As noted above, a protected API call won't be counted as a
+ * catcher. This is usually convenient, e.g. in the case of a top-
+ * level duk_pcall(), but may not always be desirable. Perhaps add
+ * an argument to treat them as catchers?
*/
- duk_size_t i;
+ duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- while (thr != NULL) {
- for (i = 0; i < thr->catchstack_top; i++) {
- duk_catcher *cat = thr->catchstack + i;
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- return 1; /* all we need to know */
+ for (; thr != NULL; thr = thr->resumer) {
+ for (act = thr->callstack_curr; act != NULL; act = act->parent) {
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
+ return 1; /* all we need to know */
+ }
}
}
- thr = thr->resumer;
}
return 0;
}
-#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
* Get prototype object for an integer error code.
@@ -40370,13 +45492,6 @@ DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_er
return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
case DUK_ERR_URI_ERROR:
return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
-
- /* XXX: more specific error classes? */
- case DUK_ERR_UNIMPLEMENTED_ERROR:
- case DUK_ERR_INTERNAL_ERROR:
- case DUK_ERR_ALLOC_ERROR:
- case DUK_ERR_ASSERTION_ERROR:
- case DUK_ERR_API_ERROR:
case DUK_ERR_ERROR:
default:
return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
@@ -40384,11 +45499,14 @@ DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_er
}
/*
- * Exposed helper for setting up heap longjmp state.
+ * Helper for debugger throw notify and pause-on-uncaught integration.
*/
-DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) {
#if defined(DUK_USE_DEBUGGER_SUPPORT)
+DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
+ duk_bool_t uncaught;
+ duk_tval *tv_obj;
+
/* If something is thrown with the debugger attached and nobody will
* catch it, execution is paused before the longjmp, turning over
* control to the debug client. This allows local state to be examined
@@ -40396,57 +45514,103 @@ DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t l
* message loop is active (e.g. for Eval).
*/
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+
/* XXX: Allow customizing the pause and notify behavior at runtime
* using debugger runtime flags. For now the behavior is fixed using
* config options.
*/
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) &&
- !thr->heap->dbg_processing &&
- lj_type == DUK_LJ_TYPE_THROW) {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t fatal;
- duk_hobject *h_obj;
- /* Don't intercept a DoubleError, we may have caused the initial double
- * fault and attempting to intercept it will cause us to be called
- * recursively and exhaust the C stack.
- */
- h_obj = duk_get_hobject(ctx, -1);
- if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
- DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
- goto skip_throw_intercept;
- }
+ if (!duk_debug_is_attached(thr->heap) ||
+ thr->heap->dbg_processing ||
+ thr->heap->lj.type != DUK_LJ_TYPE_THROW ||
+ thr->heap->creating_error) {
+ DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error"));
+ return;
+ }
+
+ /* Don't intercept a DoubleError, we may have caused the initial double
+ * fault and attempting to intercept it will cause us to be called
+ * recursively and exhaust the C stack. (This should no longer happen
+ * for the initial throw because DoubleError path doesn't do a debugger
+ * integration check, but it might happen for rethrows.)
+ */
+ tv_obj = &thr->heap->lj.value1;
+ if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
+ DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting"));
+ return;
+ }
+
+ uncaught = !duk__have_active_catcher(thr);
- DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
+ /* Debugger code expects the value at stack top. This also serves
+ * as a backup: we need to store/restore the longjmp state because
+ * when the debugger is paused Eval commands may be executed and
+ * they can arbitrarily clobber the longjmp state.
+ */
+ duk_push_tval(thr, tv_obj);
- fatal = !duk__have_active_catcher(thr);
+ /* Store and reset longjmp state. */
+ DUK_ASSERT_LJSTATE_SET(thr->heap);
+ DUK_TVAL_DECREF_NORZ(thr, tv_obj);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); /* Always for THROW type. */
+ DUK_TVAL_SET_UNDEFINED(tv_obj);
+ thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
- /* Report it to the debug client */
- duk_debug_send_throw(thr, fatal);
+ /* Report it to the debug client */
+ DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
+ duk_debug_send_throw(thr, uncaught);
#endif
-#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
- if (fatal) {
- DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
+ if (uncaught) {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error"));
+ duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
+ }
+ } else {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error"));
duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
}
-#endif
}
- skip_throw_intercept:
-#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
+ /* Restore longjmp state. */
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
+ thr->heap->lj.type = DUK_LJ_TYPE_THROW;
+ tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+ DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj);
+ DUK_TVAL_INCREF(thr, tv_obj);
+ DUK_ASSERT_LJSTATE_SET(thr->heap);
+
+ duk_pop(thr);
+}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
- thr->heap->lj.type = lj_type;
+/*
+ * Helpers for setting up heap longjmp state.
+ */
- DUK_ASSERT(thr->valstack_top > thr->valstack);
- DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */
+DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) {
+ duk_heap *heap;
- duk_pop((duk_context *) thr);
+ DUK_ASSERT(thr != NULL);
+ heap = thr->heap;
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(tv_val != NULL);
+
+ DUK_ASSERT_LJSTATE_UNSET(heap);
+
+ heap->lj.type = lj_type;
+ DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val);
+ DUK_TVAL_INCREF(thr, tv_val);
+
+ DUK_ASSERT_LJSTATE_SET(heap);
}
-#line 1 "duk_error_throw.c"
/*
* Create and throw an Ecmascript error object based on a code and a message.
*
@@ -40455,7 +45619,7 @@ DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t l
* executor.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Create and throw an error (originating from Duktape internally)
@@ -40465,19 +45629,16 @@ DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t l
*
* If an error occurs while we're dealing with the current error, we might
* enter an infinite recursion loop. This is prevented by detecting a
- * "double fault" through the heap->handling_error flag; the recursion
+ * "double fault" through the heap->creating_error flag; the recursion
* then stops at the second level.
*/
-#ifdef DUK_USE_VERBOSE_ERRORS
+#if defined(DUK_USE_VERBOSE_ERRORS)
DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
#else
DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
#endif
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t double_error = thr->heap->handling_error;
-
-#ifdef DUK_USE_VERBOSE_ERRORS
+#if defined(DUK_USE_VERBOSE_ERRORS)
DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
(long) code, (const char *) msg,
(const char *) filename, (long) line));
@@ -40486,20 +45647,12 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- thr->heap->handling_error = 1;
-
- if (!double_error) {
- /* Allow headroom for calls during error handling (see GH-191).
- * We allow space for 10 additional recursions, with one extra
- * for, e.g. a print() call at the deepest level.
- */
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
- }
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */
+ /* Even though nested call is possible because we throw an error when
+ * trying to create an error, the potential errors must happen before
+ * the longjmp state is configured.
+ */
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
/* Sync so that augmentation sees up-to-date activations, NULL
* thr->ptr_curr_pc so that it's not used if side effects occur
@@ -40509,69 +45662,89 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
/*
* Create and push an error object onto the top of stack.
+ * The error is potentially augmented before throwing.
+ *
* If a "double error" occurs, use a fixed error instance
* to avoid further trouble.
*/
- /* XXX: if attempt to push beyond allocated valstack, this double fault
- * handling fails miserably. We should really write the double error
- * directly to thr->heap->lj.value1 and avoid valstack use entirely.
- */
+ if (thr->heap->creating_error) {
+ duk_tval tv_val;
+ duk_hobject *h_err;
- if (double_error) {
- if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
- DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
- duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR);
+ thr->heap->creating_error = 0;
+
+ h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR];
+ if (h_err != NULL) {
+ DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance"));
+ DUK_TVAL_SET_OBJECT(&tv_val, h_err);
} else {
DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
- "-> push the error code as a number"));
- duk_push_int(ctx, (duk_int_t) code);
+ "-> use the error code as a number"));
+ DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code);
}
+
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val);
+
+ /* No augmentation to avoid any allocations or side effects. */
} else {
- /* Error object is augmented at its creation here. */
- duk_require_stack(ctx, 1);
- /* XXX: unnecessary '%s' formatting here, but cannot use
- * 'msg' as a format string directly.
+ /* Prevent infinite recursion. Extra call stack and C
+ * recursion headroom (see GH-191) is added for augmentation.
+ * That is now signalled by heap->augmenting error and taken
+ * into account in call handling without an explicit limit bump.
*/
-#ifdef DUK_USE_VERBOSE_ERRORS
- duk_push_error_object_raw(ctx,
+ thr->heap->creating_error = 1;
+
+ duk_require_stack(thr, 1);
+
+ /* XXX: usually unnecessary '%s' formatting here, but cannot
+ * use 'msg' as a format string directly.
+ */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
filename,
line,
"%s",
(const char *) msg);
#else
- duk_push_error_object_raw(ctx,
+ duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
NULL,
0,
NULL);
#endif
- }
-
- /*
- * Augment error (throw time), unless alloc/double error
- */
- if (double_error || code == DUK_ERR_ALLOC_ERROR) {
- DUK_D(DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble"));
- } else {
+ /* Note that an alloc error may happen during error augmentation.
+ * This may happen both when the original error is an alloc error
+ * and when it's something else. Because any error in augmentation
+ * must be handled correctly anyway, there's no special check for
+ * avoiding it for alloc errors (this differs from Duktape 1.x).
+ */
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
+
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
+ thr->heap->creating_error = 0;
+
+ /* Error is now created and we assume no errors can occur any
+ * more. Check for debugger Throw integration only when the
+ * error is complete. If we enter debugger message loop,
+ * creating_error must be 0 so that errors can be thrown in
+ * the paused state, e.g. in Eval commands.
+ */
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_err_check_debugger_integration(thr);
+#endif
}
/*
* Finally, longjmp
*/
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
-
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */
- thr->heap->handling_error = 0;
-
DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
(duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
@@ -40584,56 +45757,27 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
*/
DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
- duk_context *ctx = (duk_context *) thr;
- const char *msg;
- duk_errcode_t code;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(rc < 0);
- /* XXX: this generates quite large code - perhaps select the error
- * class based on the code and then just use the error 'name'?
- */
- /* XXX: shared strings */
-
- code = -rc;
-
- switch (rc) {
- case DUK_RET_UNIMPLEMENTED_ERROR: msg = "unimplemented"; break;
- case DUK_RET_UNSUPPORTED_ERROR: msg = "unsupported"; break;
- case DUK_RET_INTERNAL_ERROR: msg = "internal"; break;
- case DUK_RET_ALLOC_ERROR: msg = "alloc"; break;
- case DUK_RET_ASSERTION_ERROR: msg = "assertion"; break;
- case DUK_RET_API_ERROR: msg = "api"; break;
- case DUK_RET_UNCAUGHT_ERROR: msg = "uncaught"; break;
- case DUK_RET_ERROR: msg = "error"; break;
- case DUK_RET_EVAL_ERROR: msg = "eval"; break;
- case DUK_RET_RANGE_ERROR: msg = "range"; break;
- case DUK_RET_REFERENCE_ERROR: msg = "reference"; break;
- case DUK_RET_SYNTAX_ERROR: msg = "syntax"; break;
- case DUK_RET_TYPE_ERROR: msg = "type"; break;
- case DUK_RET_URI_ERROR: msg = "uri"; break;
- default: msg = "unknown"; break;
- }
-
- DUK_ASSERT(msg != NULL);
-
/*
* The __FILE__ and __LINE__ information is intentionally not used in the
* creation of the error object, as it isn't useful in the tracedata. The
* tracedata still contains the function which returned the negative return
* code, and having the file/line of this function isn't very useful.
+ *
+ * The error messages for DUK_RET_xxx shorthand are intentionally very
+ * minimal: they're only really useful for low memory targets.
*/
- duk_error_raw(ctx, code, NULL, 0, "%s error (rc %ld)", (const char *) msg, (long) rc);
+ duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
DUK_UNREACHABLE();
}
-#line 1 "duk_hbuffer_alloc.c"
/*
* duk_hbuffer allocation and freeing.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
* (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
@@ -40672,8 +45816,8 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk
}
res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
- goto error;
+ if (DUK_UNLIKELY(res == NULL)) {
+ goto alloc_error;
}
/* zero everything unless requested not to do so */
@@ -40704,14 +45848,14 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk
if (size > 0) {
DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
-#ifdef DUK_USE_ZERO_BUFFER_DATA
+#if defined(DUK_USE_ZERO_BUFFER_DATA)
ptr = DUK_ALLOC_ZEROED(heap, size);
#else
ptr = DUK_ALLOC(heap, size);
#endif
- if (!ptr) {
+ if (DUK_UNLIKELY(ptr == NULL)) {
/* Because size > 0, NULL check is correct */
- goto error;
+ goto alloc_error;
}
*out_bufdata = ptr;
@@ -40747,7 +45891,7 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk
DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
return res;
- error:
+ alloc_error:
DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
DUK_FREE(heap, res);
@@ -40761,19 +45905,12 @@ DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
DUK_UNREF(heap);
return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
}
-#line 1 "duk_hbuffer_ops.c"
/*
* duk_hbuffer operations such as resizing and inserting/appending data to
* a dynamic buffer.
- *
- * Append operations append to the end of the buffer and they are relatively
- * efficient: the buffer is grown with a "spare" part relative to the buffer
- * size to minimize reallocations. Insert operations need to move existing
- * data forward in the buffer with memmove() and are not very efficient.
- * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Resizing
@@ -40803,7 +45940,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
*/
res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
- if (res != NULL || new_size == 0) {
+ if (DUK_LIKELY(res != NULL || new_size == 0)) {
/* 'res' may be NULL if new allocation size is 0. */
DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
@@ -40821,7 +45958,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
if (new_size > prev_size) {
DUK_ASSERT(new_size - prev_size > 0);
-#ifdef DUK_USE_ZERO_BUFFER_DATA
+#if defined(DUK_USE_ZERO_BUFFER_DATA)
DUK_MEMZERO((void *) ((char *) res + prev_size),
(duk_size_t) (new_size - prev_size));
#endif
@@ -40830,7 +45967,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
} else {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ DUK_ERROR_ALLOC_FAILED(thr);
}
DUK_ASSERT(res != NULL || new_size == 0);
@@ -40844,11 +45981,10 @@ DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf)
duk_hbuffer_resize(thr, buf, 0);
}
-/* include removed: duk_internal.h */
-#line 2 "duk_hbufferobject_misc.c"
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len) {
+DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) {
duk_uint_t buf_size;
duk_uint_t buf_avail;
@@ -40865,20 +46001,11 @@ DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_
return buf_avail >= len ? len : buf_avail;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#line 1 "duk_heap_alloc.c"
/*
* duk_heap allocation and freeing.
*/
-/* include removed: duk_internal.h */
-
-/* Constants for built-in string data depacking. */
-#define DUK__BITPACK_LETTER_LIMIT 26
-#define DUK__BITPACK_UNDERSCORE 26
-#define DUK__BITPACK_FF 27
-#define DUK__BITPACK_SWITCH1 29
-#define DUK__BITPACK_SWITCH 30
-#define DUK__BITPACK_SEVENBIT 31
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_ROM_STRINGS)
/* Fixed seed value used with ROM strings. */
@@ -40894,38 +46021,63 @@ DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_
* been already dealt with.
*/
-DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) {
+DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(h != NULL);
DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
+ if (DUK_HOBJECT_IS_COMPFUNC(h)) {
+ duk_hcompfunc *f = (duk_hcompfunc *) h;
DUK_UNREF(f);
/* Currently nothing to free; 'data' is a heap object */
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
+ } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
+ duk_hnatfunc *f = (duk_hnatfunc *) h;
DUK_UNREF(f);
/* Currently nothing to free */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
+
DUK_FREE(heap, t->valstack);
- DUK_FREE(heap, t->callstack);
- DUK_FREE(heap, t->catchstack);
+
/* Don't free h->resumer because it exists in the heap.
* Callstack entries also contain function pointers which
- * are not freed for the same reason.
+ * are not freed for the same reason. They are decref
+ * finalized and the targets are freed if necessary based
+ * on their refcount (or reachability).
*/
+ for (act = t->callstack_curr; act != NULL;) {
+ duk_activation *act_next;
+ duk_catcher *cat;
+
+ for (cat = act->cat; cat != NULL;) {
+ duk_catcher *cat_next;
+
+ cat_next = cat->parent;
+ DUK_FREE(heap, (void *) cat);
+ cat = cat_next;
+ }
+
+ act_next = act->parent;
+ DUK_FREE(heap, (void *) act);
+ act = act_next;
+ }
/* XXX: with 'caller' property the callstack would need
* to be unwound to update the 'caller' properties of
* functions in the callstack.
*/
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+
+ DUK_FREE(heap, f->args);
}
+
+ DUK_FREE(heap, (void *) h);
}
-DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
+DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(h != NULL);
@@ -40934,9 +46086,10 @@ DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
}
+ DUK_FREE(heap, (void *) h);
}
-DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
+DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(h != NULL);
@@ -40950,6 +46103,7 @@ DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
}
#endif
+ DUK_FREE(heap, (void *) h);
}
DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
@@ -40958,21 +46112,18 @@ DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
- switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
+ switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
case DUK_HTYPE_STRING:
- duk_free_hstring_inner(heap, (duk_hstring *) hdr);
+ duk_free_hstring(heap, (duk_hstring *) hdr);
break;
case DUK_HTYPE_OBJECT:
- duk_free_hobject_inner(heap, (duk_hobject *) hdr);
- break;
- case DUK_HTYPE_BUFFER:
- duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
+ duk_free_hobject(heap, (duk_hobject *) hdr);
break;
default:
- DUK_UNREACHABLE();
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER);
+ duk_free_hbuffer(heap, (duk_hbuffer *) hdr);
}
- DUK_FREE(heap, hdr);
}
/*
@@ -40988,6 +46139,63 @@ DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
* after this call.
*/
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) {
+ duk_activation *act;
+ duk_activation *act_next;
+ duk_size_t count_act = 0;
+
+ for (act = heap->activation_free; act != NULL;) {
+ act_next = act->parent;
+ DUK_FREE(heap, (void *) act);
+ act = act_next;
+#if defined(DUK_USE_DEBUG)
+ count_act++;
+#endif
+ }
+ heap->activation_free = NULL; /* needed when called from mark-and-sweep */
+ return count_act;
+}
+#endif /* DUK_USE_CACHE_ACTIVATION */
+
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) {
+ duk_catcher *cat;
+ duk_catcher *cat_next;
+ duk_size_t count_cat = 0;
+
+ for (cat = heap->catcher_free; cat != NULL;) {
+ cat_next = cat->parent;
+ DUK_FREE(heap, (void *) cat);
+ cat = cat_next;
+#if defined(DUK_USE_DEBUG)
+ count_cat++;
+#endif
+ }
+ heap->catcher_free = NULL; /* needed when called from mark-and-sweep */
+
+ return count_cat;
+}
+#endif /* DUK_USE_CACHE_CATCHER */
+
+DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) {
+ duk_size_t count_act = 0;
+ duk_size_t count_cat = 0;
+
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ count_act = duk__heap_free_activation_freelist(heap);
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ count_cat = duk__heap_free_catcher_freelist(heap);
+#endif
+ DUK_UNREF(heap);
+ DUK_UNREF(count_act);
+ DUK_UNREF(count_cat);
+
+ DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries",
+ (long) count_act, (long) count_cat));
+}
+
DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -41006,24 +46214,8 @@ DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
}
}
-#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-
- curr = heap->refzero_list;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
- (duk_heaphdr *) curr));
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- duk_heap_free_heaphdr_raw(heap, curr);
- curr = next;
- }
-}
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
-DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) {
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -41036,15 +46228,15 @@ DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
curr = next;
}
}
-#endif
+#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
/* strings are only tracked by stringtable */
- duk_heap_free_strtab(heap);
+ duk_heap_strtable_free(heap);
}
+#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
- duk_hthread *thr;
duk_heaphdr *curr;
duk_uint_t round_no;
duk_size_t count_all;
@@ -41052,27 +46244,31 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
duk_size_t curr_limit;
DUK_ASSERT(heap != NULL);
- DUK_ASSERT(heap->heap_thread != NULL);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
-#endif
+ DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */
- /* XXX: here again finalizer thread is the heap_thread which needs
- * to be coordinated with finalizer thread fixes.
- */
- thr = heap->heap_thread;
- DUK_ASSERT(thr != NULL);
+ if (heap->heap_thread == NULL) {
+ /* May happen when heap allocation fails right off. There
+ * cannot be any finalizable objects in this case.
+ */
+ DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects"));
+ return;
+ }
- /* Prevent mark-and-sweep for the pending finalizers, also prevents
- * refzero handling from moving objects away from the heap_allocated
- * list. (The flag meaning is slightly abused here.)
+ /* Prevent finalize_list processing and mark-and-sweep entirely.
+ * Setting ms_running = 1 also prevents refzero handling from moving
+ * objects away from the heap_allocated list (the flag name is a bit
+ * misleading here).
*/
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
+ DUK_ASSERT(heap->pf_prevent_count == 0);
+ heap->pf_prevent_count = 1;
+ DUK_ASSERT(heap->ms_running == 0);
+ heap->ms_running = 1;
+ DUK_ASSERT(heap->ms_prevent_count == 0);
+ heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */
curr_limit = 0; /* suppress warning, not used */
for (round_no = 0; ; round_no++) {
@@ -41081,18 +46277,17 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
count_finalized = 0;
while (curr) {
count_all++;
- if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
+ if (DUK_HEAPHDR_IS_OBJECT(curr)) {
/* Only objects in heap_allocated may have finalizers. Check that
* the object itself has a _Finalizer property (own or inherited)
* so that we don't execute finalizers for e.g. Proxy objects.
*/
- DUK_ASSERT(thr != NULL);
DUK_ASSERT(curr != NULL);
- if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
+ if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) {
if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
+ duk_heap_run_finalizer(heap, (duk_hobject *) curr);
count_finalized++;
}
}
@@ -41133,15 +46328,18 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
}
}
- DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
+ DUK_ASSERT(heap->ms_running == 1);
+ heap->ms_running = 0;
+ DUK_ASSERT(heap->pf_prevent_count == 1);
+ heap->pf_prevent_count = 0;
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
#if defined(DUK_USE_DEBUG)
- duk_heap_dump_strtab(heap);
+ duk_heap_strtable_dump(heap);
#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT)
@@ -41155,50 +46353,67 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
#endif
/* Execute finalizers before freeing the heap, even for reachable
- * objects, and regardless of whether or not mark-and-sweep is
- * enabled. This gives finalizers the chance to free any native
+ * objects. This gives finalizers the chance to free any native
* resources like file handles, allocations made outside Duktape,
* etc. This is quite tricky to get right, so that all finalizer
* guarantees are honored.
*
- * XXX: this perhaps requires an execution time limit.
- */
- DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* Run mark-and-sweep a few times just in case (unreachable object
+ * Run mark-and-sweep a few times just in case (unreachable object
* finalizers run already here). The last round must rescue objects
* from the previous round without running any more finalizers. This
* ensures rescued objects get their FINALIZED flag cleared so that
* their finalizer is called once more in forced finalization to
* satisfy finalizer guarantees. However, we don't want to run any
- * more finalizer because that'd required one more loop, and so on.
+ * more finalizers because that'd required one more loop, and so on.
+ *
+ * XXX: this perhaps requires an execution time limit.
*/
+ DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
+ DUK_ASSERT(heap->pf_skip_finalizers == 0);
DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
duk_heap_mark_and_sweep(heap, 0);
DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
duk_heap_mark_and_sweep(heap, 0);
DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
- duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
+ heap->pf_skip_finalizers = 1;
+ duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */
+
+ /* There are never objects in refzero_list at this point, or at any
+ * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1
+ * refzero_list processing is side effect free, so it is always
+ * processed to completion by a DECREF initially triggering a zero
+ * refcount.
+ */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */
+#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */
#endif
- DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects"));
+ DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */
duk__free_run_finalizers(heap);
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
* are on the heap allocated list.
*/
- DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
+ DUK_D(DUK_DPRINT("freeing temporary freelists"));
+ duk_heap_free_freelists(heap);
+
+ DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap));
duk__free_allocated(heap);
#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
- duk__free_refzero_list(heap);
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
- duk__free_markandsweep_finalize_list(heap);
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap));
+ duk__free_finalize_list(heap);
#endif
DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
@@ -41221,29 +46436,36 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
duk_small_uint_t i;
#endif
+ DUK_UNREF(heap);
+
/* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
* so nothing to initialize for strs[].
*/
#if defined(DUK_USE_ASSERTIONS)
- for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
- duk_uint32_t hash;
+ for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) {
const duk_hstring *h;
- h = duk_rom_strings[i];
- DUK_ASSERT(h != NULL);
- hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
- DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
- (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
- DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
+ duk_uint32_t hash;
+
+ h = duk_rom_strings_lookup[i];
+ while (h != NULL) {
+ hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+ DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx",
+ (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
+ DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
+
+ h = (const duk_hstring *) h->hdr.h_next;
+ }
}
#endif
return 1;
}
#else /* DUK_USE_ROM_STRINGS */
+
DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
duk_bitdecoder_ctx bd_ctx;
duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
- duk_small_uint_t i, j;
+ duk_small_uint_t i;
DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
bd->data = (const duk_uint8_t *) duk_strings_data;
@@ -41251,49 +46473,19 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
- duk_hstring *h;
duk_small_uint_t len;
- duk_small_uint_t mode;
- duk_small_uint_t t;
+ duk_hstring *h;
- len = duk_bd_decode(bd, 5);
- mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
- for (j = 0; j < len; j++) {
- t = duk_bd_decode(bd, 5);
- if (t < DUK__BITPACK_LETTER_LIMIT) {
- t = t + DUK_ASC_UC_A + mode;
- } else if (t == DUK__BITPACK_UNDERSCORE) {
- t = DUK_ASC_UNDERSCORE;
- } else if (t == DUK__BITPACK_FF) {
- /* Internal keys are prefixed with 0xFF in the stringtable
- * (which makes them invalid UTF-8 on purpose).
- */
- t = 0xff;
- } else if (t == DUK__BITPACK_SWITCH1) {
- t = duk_bd_decode(bd, 5);
- DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
- DUK_ASSERT(t <= 25);
- t = t + DUK_ASC_UC_A + (mode ^ 32);
- } else if (t == DUK__BITPACK_SWITCH) {
- mode = mode ^ 32;
- t = duk_bd_decode(bd, 5);
- DUK_ASSERT_DISABLE(t >= 0);
- DUK_ASSERT(t <= 25);
- t = t + DUK_ASC_UC_A + mode;
- } else if (t == DUK__BITPACK_SEVENBIT) {
- t = duk_bd_decode(bd, 7);
- }
- tmp[j] = (duk_uint8_t) t;
- }
+ len = duk_bd_decode_bitpacked_string(bd, tmp);
/* No need to length check string: it will never exceed even
* the 16-bit length maximum.
*/
DUK_ASSERT(len <= 0xffffUL);
DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
- h = duk_heap_string_intern(heap, tmp, len);
+ h = duk_heap_strtable_intern(heap, tmp, len);
if (!h) {
- goto error;
+ goto failed;
}
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
@@ -41328,7 +46520,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
return 1;
- error:
+ failed:
return 0;
}
#endif /* DUK_USE_ROM_STRINGS */
@@ -41336,12 +46528,11 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
duk_hthread *thr;
- DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
- thr = duk_hthread_alloc(heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_THREAD |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
- if (!thr) {
+ DUK_D(DUK_DPRINT("heap init: alloc heap thread"));
+ thr = duk_hthread_alloc_unchecked(heap,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
+ if (thr == NULL) {
DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
return 0;
}
@@ -41361,6 +46552,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
/* 'thr' is now reachable */
+ DUK_D(DUK_DPRINT("heap init: init heap thread stacks"));
if (!duk_hthread_init_stacks(heap, thr)) {
return 0;
}
@@ -41368,8 +46560,8 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
/* XXX: this may now fail, and is not handled correctly */
duk_hthread_create_builtin_objects(thr);
- /* default prototype (Note: 'thr' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
+ /* default prototype */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
return 1;
}
@@ -41476,9 +46668,16 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_hstring);
DUK__DUMPSZ(duk_hstring_external);
DUK__DUMPSZ(duk_hobject);
- DUK__DUMPSZ(duk_hcompiledfunction);
- DUK__DUMPSZ(duk_hnativefunction);
+ DUK__DUMPSZ(duk_harray);
+ DUK__DUMPSZ(duk_hcompfunc);
+ DUK__DUMPSZ(duk_hnatfunc);
+ DUK__DUMPSZ(duk_hdecenv);
+ DUK__DUMPSZ(duk_hobjenv);
DUK__DUMPSZ(duk_hthread);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ DUK__DUMPSZ(duk_hbufobj);
+#endif
+ DUK__DUMPSZ(duk_hproxy);
DUK__DUMPSZ(duk_hbuffer);
DUK__DUMPSZ(duk_hbuffer_fixed);
DUK__DUMPSZ(duk_hbuffer_dynamic);
@@ -41487,9 +46686,6 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_propvalue);
DUK__DUMPSZ(duk_propdesc);
DUK__DUMPSZ(duk_heap);
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK__DUMPSZ(duk_strtab_entry);
-#endif
DUK__DUMPSZ(duk_activation);
DUK__DUMPSZ(duk_catcher);
DUK__DUMPSZ(duk_strcache);
@@ -41552,11 +46748,6 @@ DUK_LOCAL void duk__dump_type_limits(void) {
DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
}
-#undef DUK__DUMPSZ
-#undef DUK__DUMPLM_SIGNED_RAW
-#undef DUK__DUMPLM_UNSIGNED_RAW
-#undef DUK__DUMPLM_SIGNED
-#undef DUK__DUMPLM_UNSIGNED
DUK_LOCAL void duk__dump_misc_options(void) {
DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
@@ -41564,6 +46755,7 @@ DUK_LOCAL void duk__dump_misc_options(void) {
DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
+ DUK_D(DUK_DPRINT("debug level: %ld", (long) DUK_USE_DEBUG_LEVEL));
#if defined(DUK_USE_PACKED_TVAL)
DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
#else
@@ -41602,13 +46794,21 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
void *heap_udata,
duk_fatal_function fatal_func) {
duk_heap *res = NULL;
-
- /* Silence a few global unused warnings here. */
- DUK_UNREF(duk_str_unsupported);
+ duk_uint32_t st_initsize;
DUK_D(DUK_DPRINT("allocate heap"));
/*
+ * Random config sanity asserts
+ */
+
+ DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64);
+
+ DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0);
+ DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0);
+ DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */
+
+ /*
* Debug dump type sizes
*/
@@ -41619,15 +46819,37 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#endif
/*
- * If selftests enabled, run them as early as possible
+ * If selftests enabled, run them as early as possible.
*/
+
#if defined(DUK_USE_SELF_TESTS)
- DUK_D(DUK_DPRINT("running self tests"));
- duk_selftest_run_tests();
+ DUK_D(DUK_DPRINT("run self tests"));
+ if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) {
+ fatal_func(heap_udata, "self test(s) failed");
+ }
DUK_D(DUK_DPRINT("self tests passed"));
#endif
/*
+ * Important assert-like checks that should be enabled even
+ * when assertions are otherwise not enabled.
+ */
+
+#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
+ /* Can't check sizeof() using preprocessor so explicit check.
+ * This will be optimized away in practice; unfortunately a
+ * warning is generated on some compilers as a result.
+ */
+#if defined(DUK_USE_PACKED_TVAL)
+ if (sizeof(duk_tval) != 8) {
+#else
+ if (sizeof(duk_tval) != 16) {
+#endif
+ fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option");
+ }
+#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
+
+ /*
* Computed values (e.g. INFINITY)
*/
@@ -41662,9 +46884,13 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Use a raw call, all macros expect the heap to be initialized
*/
+#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1)
+ goto failed;
+#endif
+ DUK_D(DUK_DPRINT("alloc duk_heap object"));
res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
if (!res) {
- goto error;
+ goto failed;
}
/*
@@ -41672,6 +46898,9 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
*/
DUK_MEMZERO(res, sizeof(*res));
+#if defined(DUK_USE_ASSERTIONS)
+ res->heap_initializing = 1;
+#endif
/* explicit NULL inits */
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
@@ -41679,22 +46908,26 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->heap_allocated = NULL;
#if defined(DUK_USE_REFERENCE_COUNTING)
res->refzero_list = NULL;
- res->refzero_list_tail = NULL;
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
+#if defined(DUK_USE_FINALIZER_SUPPORT)
res->finalize_list = NULL;
+#if defined(DUK_USE_ASSERTIONS)
+ res->currently_finalizing = NULL;
+#endif
+#endif
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ res->activation_free = NULL;
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ res->catcher_free = NULL;
#endif
res->heap_thread = NULL;
res->curr_thread = NULL;
res->heap_object = NULL;
-#if defined(DUK_USE_STRTAB_CHAIN)
- /* nothing to NULL */
-#elif defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16 = (duk_uint16_t *) NULL;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ res->strtable16 = NULL;
#else
- res->strtable = (duk_hstring **) NULL;
-#endif
+ res->strtable = NULL;
#endif
#if defined(DUK_USE_ROM_STRINGS)
/* no res->strs[] */
@@ -41718,7 +46951,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->dbg_write_flush_cb = NULL;
res->dbg_request_cb = NULL;
res->dbg_udata = NULL;
- res->dbg_step_thread = NULL;
+ res->dbg_pause_act = NULL;
#endif
#endif /* DUK_USE_EXPLICIT_NULL_INIT */
@@ -41728,20 +46961,28 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->heap_udata = heap_udata;
res->fatal_func = fatal_func;
-#if defined(DUK_USE_HEAPPTR16)
- /* XXX: zero assumption */
- res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
- res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
-#endif
+ /* XXX: for now there's a pointer packing zero assumption, i.e.
+ * NULL <=> compressed pointer 0. If this is removed, may need
+ * to precompute e.g. null16 here.
+ */
+
+ /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */
- /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
+ /* Prevent mark-and-sweep and finalizer execution until heap is completely
+ * initialized.
+ */
+ DUK_ASSERT(res->ms_prevent_count == 0);
+ DUK_ASSERT(res->pf_prevent_count == 0);
+ res->ms_prevent_count = 1;
+ res->pf_prevent_count = 1;
+ DUK_ASSERT(res->ms_running == 0);
res->call_recursion_depth = 0;
res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
/* XXX: use the pointer as a seed for now: mix in time at least */
- /* The casts through duk_intr_pt is to avoid the following GCC warning:
+ /* The casts through duk_intptr_t is to avoid the following GCC warning:
*
* warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
*
@@ -41753,7 +46994,6 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
#else /* DUK_USE_ROM_STRINGS */
res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
- res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
#if !defined(DUK_USE_STRHASH_DENSE)
res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
#endif
@@ -41763,71 +47003,49 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->lj.jmpbuf_ptr = NULL;
#endif
DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
-
+ DUK_ASSERT(res->lj.iserror == 0);
DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
-#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
-#error initial heap stringtable size is defined incorrectly
-#endif
+ DUK_ASSERT_LJSTATE_UNSET(res);
/*
* Init stringtable: fixed variant
*/
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- {
- duk_small_uint_t i;
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable[i].u.str16 = res->heapptr_null16;
+ st_initsize = DUK_USE_STRTAB_MINSIZE;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize);
+ if (res->strtable16 == NULL) {
+ goto failed;
+ }
#else
- res->strtable[i].u.str = NULL;
-#endif
- }
+ res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize);
+ if (res->strtable == NULL) {
+ goto failed;
}
-#endif /* DUK_USE_EXPLICIT_NULL_INIT */
-#endif /* DUK_USE_STRTAB_CHAIN */
-
- /*
- * Init stringtable: probe variant
- */
+#endif
+ res->st_size = st_initsize;
+ res->st_mask = st_initsize - 1;
+#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
+ DUK_ASSERT(res->st_count == 0);
+#endif
-#if defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
- if (!res->strtable16) {
- goto error;
- }
-#else /* DUK_USE_HEAPPTR16 */
- res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
- if (!res->strtable) {
- goto error;
- }
-#endif /* DUK_USE_HEAPPTR16 */
- res->st_size = DUK_STRTAB_INITIAL_SIZE;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ /* zero assumption */
+ DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize);
+#else
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
duk_small_uint_t i;
- DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
- for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16[i] = res->heapptr_null16;
-#else
+ for (i = 0; i < st_initsize; i++) {
res->strtable[i] = NULL;
-#endif
}
}
-#else /* DUK_USE_EXPLICIT_NULL_INIT */
-#if defined(DUK_USE_HEAPPTR16)
- DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
#else
- DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
-#endif
+ DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize);
#endif /* DUK_USE_EXPLICIT_NULL_INIT */
-#endif /* DUK_USE_STRTAB_PROBE */
+#endif /* DUK_USE_STRTAB_PTRCOMP */
/*
* Init stringcache
@@ -41852,63 +47070,585 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Init built-in strings
*/
- DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
+#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2)
+ goto failed;
+#endif
+ DUK_D(DUK_DPRINT("heap init: initialize heap strings"));
if (!duk__init_heap_strings(res)) {
- goto error;
+ goto failed;
}
/*
* Init the heap thread
*/
- DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
+#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3)
+ goto failed;
+#endif
+ DUK_D(DUK_DPRINT("heap init: initialize heap thread"));
if (!duk__init_heap_thread(res)) {
- goto error;
+ goto failed;
}
/*
* Init the heap object
*/
- DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
+#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4)
+ goto failed;
+#endif
+ DUK_D(DUK_DPRINT("heap init: initialize heap object"));
DUK_ASSERT(res->heap_thread != NULL);
- res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
- if (!res->heap_object) {
- goto error;
+ res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
+ if (res->heap_object == NULL) {
+ goto failed;
}
DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
/*
- * All done
+ * Odds and ends depending on the heap thread
+ */
+
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
+#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
+ res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread);
+ duk_util_tinyrandom_prepare_seed(res->heap_thread);
+#else
+ res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread);
+ DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */
+#if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */
+ res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678);
+ res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678);
+#endif
+ duk_util_tinyrandom_prepare_seed(res->heap_thread);
+ /* Mix in heap pointer: this ensures that if two Duktape heaps are
+ * created on the same millisecond, they get a different PRNG
+ * sequence (unless e.g. virtual memory addresses cause also the
+ * heap object pointer to be the same).
+ */
+ {
+ duk_uint64_t tmp_u64;
+ tmp_u64 = 0;
+ DUK_MEMCPY((void *) &tmp_u64,
+ (const void *) &res,
+ (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *)));
+ res->rnd_state[1] ^= tmp_u64;
+ }
+ do {
+ duk_small_uint_t i;
+ for (i = 0; i < 10; i++) {
+ /* Throw away a few initial random numbers just in
+ * case. Probably unnecessary due to SplitMix64
+ * preparation.
+ */
+ (void) duk_util_tinyrandom_get_double(res->heap_thread);
+ }
+ } while (0);
+#endif
+#endif
+
+ /*
+ * Allow finalizer and mark-and-sweep processing.
+ */
+
+ DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing"));
+ DUK_ASSERT(res->ms_prevent_count == 1);
+ DUK_ASSERT(res->pf_prevent_count == 1);
+ res->ms_prevent_count = 0;
+ res->pf_prevent_count = 0;
+ DUK_ASSERT(res->ms_running == 0);
+#if defined(DUK_USE_ASSERTIONS)
+ res->heap_initializing = 0;
+#endif
+
+ /*
+ * All done.
*/
DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
return res;
- error:
+ failed:
DUK_D(DUK_DPRINT("heap allocation failed"));
- if (res) {
- /* assumes that allocated pointers and alloc funcs are valid
- * if res exists
+ if (res != NULL) {
+ /* Assumes that allocated pointers and alloc funcs are valid
+ * if res exists.
*/
+ DUK_ASSERT(res->ms_prevent_count == 1);
+ DUK_ASSERT(res->pf_prevent_count == 1);
+ DUK_ASSERT(res->ms_running == 0);
+ if (res->heap_thread != NULL) {
+ res->ms_prevent_count = 0;
+ res->pf_prevent_count = 0;
+ }
+#if defined(DUK_USE_ASSERTIONS)
+ res->heap_initializing = 0;
+#endif
+
DUK_ASSERT(res->alloc_func != NULL);
DUK_ASSERT(res->realloc_func != NULL);
DUK_ASSERT(res->free_func != NULL);
duk_heap_free(res);
}
+
return NULL;
}
-#undef DUK__BITPACK_LETTER_LIMIT
-#undef DUK__BITPACK_UNDERSCORE
-#undef DUK__BITPACK_FF
-#undef DUK__BITPACK_SWITCH1
-#undef DUK__BITPACK_SWITCH
-#undef DUK__BITPACK_SEVENBIT
+/* automatic undefs */
+#undef DUK__DUMPLM_SIGNED
+#undef DUK__DUMPLM_SIGNED_RAW
+#undef DUK__DUMPLM_UNSIGNED
+#undef DUK__DUMPLM_UNSIGNED_RAW
+#undef DUK__DUMPSZ
#undef DUK__FIXED_HASH_SEED
-#line 1 "duk_heap_hashstring.c"
+/*
+ * Finalizer handling.
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+
+/*
+ * Fake torture finalizer.
+ */
+
+#if defined(DUK_USE_FINALIZER_TORTURE)
+DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) {
+ DUK_DD(DUK_DDPRINT("fake global torture finalizer executed"));
+
+ /* Require a lot of stack to force a value stack grow/shrink. */
+ duk_require_stack(thr, 100000);
+
+ /* Force a reallocation with pointer change for value stack
+ * to maximize side effects.
+ */
+ duk_hthread_valstack_torture_realloc(thr);
+
+ /* Inner function call, error throw. */
+ duk_eval_string_noresult(thr,
+ "(function dummy() {\n"
+ " dummy.prototype = null; /* break reference loop */\n"
+ " try {\n"
+ " throw 'fake-finalizer-dummy-error';\n"
+ " } catch (e) {\n"
+ " void e;\n"
+ " }\n"
+ "})()");
+
+ /* The above creates garbage (e.g. a function instance). Because
+ * the function/prototype reference loop is broken, it gets collected
+ * immediately by DECREF. If Function.prototype has a _Finalizer
+ * property (happens in some test cases), the garbage gets queued to
+ * finalize_list. This still won't cause an infinite loop because
+ * the torture finalizer is called once per finalize_list run and
+ * the garbage gets handled in the same run. (If the garbage needs
+ * mark-and-sweep collection, an infinite loop might ensue.)
+ */
+ return 0;
+}
+
+DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) {
+ DUK_ASSERT(thr != NULL);
+
+ /* Avoid fake finalization when callstack limit is near. Otherwise
+ * a callstack limit error will be created, then refzero'ed. The
+ * +5 headroom is conservative.
+ */
+ if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit ||
+ thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) {
+ DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size"));
+ return;
+ }
+
+ /* Run fake finalizer. Avoid creating unnecessary garbage. */
+ duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/);
+ (void) duk_pcall(thr, 0 /*nargs*/);
+ duk_pop(thr);
+}
+#endif /* DUK_USE_FINALIZER_TORTURE */
+
+/*
+ * Process the finalize_list to completion.
+ *
+ * An object may be placed on finalize_list by either refcounting or
+ * mark-and-sweep. The refcount of objects placed by refcounting will be
+ * zero; the refcount of objects placed by mark-and-sweep is > 0. In both
+ * cases the refcount is bumped by 1 artificially so that a REFZERO event
+ * can never happen while an object is waiting for finalization. Without
+ * this bump a REFZERO could now happen because user code may call
+ * duk_push_heapptr() and then pop a value even when it's on finalize_list.
+ *
+ * List processing assumes refcounts are kept up-to-date at all times, so
+ * that once the finalizer returns, a zero refcount is a reliable reason to
+ * free the object immediately rather than place it back to the heap. This
+ * is the case because we run outside of refzero_list processing so that
+ * DECREF cascades are handled fully inline.
+ *
+ * For mark-and-sweep queued objects (had_zero_refcount false) the object
+ * may be freed immediately if its refcount is zero after the finalizer call
+ * (i.e. finalizer removed the reference loop for the object). If not, the
+ * next mark-and-sweep will collect the object unless it has become reachable
+ * (i.e. rescued) by that time and its refcount hasn't fallen to zero before
+ * that. Mark-and-sweep detects these objects because their FINALIZED flag
+ * is set.
+ *
+ * There's an inherent limitation for mark-and-sweep finalizer rescuing: an
+ * object won't get refinalized if (1) it's rescued, but (2) becomes
+ * unreachable before mark-and-sweep has had time to notice it. The next
+ * mark-and-sweep round simply doesn't have any information of whether the
+ * object has been unreachable the whole time or not (the only way to get
+ * that information would be a mark-and-sweep pass for *every finalized
+ * object*). This is awkward for the application because the mark-and-sweep
+ * round is not generally visible or under full application control.
+ *
+ * For refcount queued objects (had_zero_refcount true) the object is either
+ * immediately freed or rescued, and waiting for a mark-and-sweep round is not
+ * necessary (or desirable); FINALIZED is cleared when a rescued object is
+ * queued back to heap_allocated. The object is eligible for finalization
+ * again (either via refcounting or mark-and-sweep) immediately after being
+ * rescued. If a refcount finalized object is placed into an unreachable
+ * reference loop by its finalizer, it will get collected by mark-and-sweep
+ * and currently the finalizer will execute again.
+ *
+ * There's a special case where:
+ *
+ * - Mark-and-sweep queues an object to finalize_list for finalization.
+ * - The finalizer is executed, FINALIZED is set, and object is queued
+ * back to heap_allocated, waiting for a new mark-and-sweep round.
+ * - The object's refcount drops to zero before mark-and-sweep has a
+ * chance to run another round and make a rescue/free decision.
+ *
+ * This is now handled by refzero code: if an object has a finalizer but
+ * FINALIZED is already set, the object is freed without finalizer processing.
+ * The outcome is the same as if mark-and-sweep was executed at that point;
+ * mark-and-sweep would also free the object without another finalizer run.
+ * This could also be changed so that the refzero-triggered finalizer *IS*
+ * executed: being refzero collected implies someone has operated on the
+ * object so it hasn't been totally unreachable the whole time. This would
+ * risk a finalizer loop however.
+ */
+
+DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
+ duk_heaphdr *curr;
+#if defined(DUK_USE_DEBUG)
+ duk_size_t count = 0;
+#endif
+
+ DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p", (void *) heap));
+
+ if (heap->pf_prevent_count != 0) {
+ DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0"));
+ return;
+ }
+
+ /* Heap alloc prevents mark-and-sweep before heap_thread is ready. */
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(heap->heap_thread->valstack != NULL);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL);
+#endif
+
+ DUK_ASSERT(heap->pf_prevent_count == 0);
+ heap->pf_prevent_count = 1;
+
+ /* Mark-and-sweep no longer needs to be prevented when running
+ * finalizers: mark-and-sweep skips any rescue decisions if there
+ * are any objects in finalize_list when mark-and-sweep is entered.
+ * This protects finalized objects from incorrect rescue decisions
+ * caused by finalize_list being a reachability root and only
+ * partially processed. Freeing decisions are not postponed.
+ */
+
+ /* When finalizer torture is enabled, make a fake finalizer call with
+ * maximum side effects regardless of whether finalize_list is empty.
+ */
+#if defined(DUK_USE_FINALIZER_TORTURE)
+ duk__run_global_torture_finalizer(heap->heap_thread);
+#endif
+
+ /* Process finalize_list until it becomes empty. There's currently no
+ * protection against a finalizer always creating more garbage.
+ */
+ while ((curr = heap->finalize_list) != NULL) {
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_bool_t queue_back;
+#endif
+
+ DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO", (void *) curr, curr));
+
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* Only objects have finalizers. */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); /* All objects on finalize_list will have this flag (except object being finalized right now). */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); /* Queueing code ensures. */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* ROM objects never get freed (or finalized). */
+
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(heap->currently_finalizing == NULL);
+ heap->currently_finalizing = curr;
+#endif
+
+ /* Clear FINALIZABLE for object being finalized, so that
+ * duk_push_heapptr() can properly ignore the object.
+ */
+ DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+
+ if (DUK_LIKELY(!heap->pf_skip_finalizers)) {
+ /* Run the finalizer, duk_heap_run_finalizer() sets
+ * and checks for FINALIZED to prevent the finalizer
+ * from executing multiple times per finalization cycle.
+ * (This safeguard shouldn't be actually needed anymore).
+ */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_bool_t had_zero_refcount;
+#endif
+
+ /* The object's refcount is >0 throughout so it won't be
+ * refzero processed prematurely.
+ */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
+ had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1); /* Preincremented on finalize_list insert. */
+#endif
+
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
+ duk_heap_run_finalizer(heap, (duk_hobject *) curr); /* must never longjmp */
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
+ /* XXX: assert that object is still in finalize_list
+ * when duk_push_heapptr() allows automatic rescue.
+ */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld", (long) DUK_HEAPHDR_GET_REFCOUNT(curr)));
+ if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) { /* Only artificial bump in refcount? */
+#if defined(DUK_USE_DEBUG)
+ if (had_zero_refcount) {
+ DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)"));
+ } else {
+ DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)"));
+ }
+#endif
+ queue_back = 0;
+ } else
+#endif
+ {
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ queue_back = 1;
+ if (had_zero_refcount) {
+ /* When finalization is triggered
+ * by refzero and we queue the object
+ * back, clear FINALIZED right away
+ * so that the object can be refinalized
+ * immediately if necessary.
+ */
+ DUK_HEAPHDR_CLEAR_FINALIZED(curr);
+ }
+#endif
+ }
+ } else {
+ /* Used during heap destruction: don't actually run finalizers
+ * because we're heading into forced finalization. Instead,
+ * queue finalizable objects back to the heap_allocated list.
+ */
+ DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ queue_back = 1;
+#endif
+ }
+
+ /* Dequeue object from finalize_list. Note that 'curr' may no
+ * longer be finalize_list head because new objects may have
+ * been queued to the list. As a result we can't optimize for
+ * the single-linked heap case and must scan the list for
+ * removal, typically the scan is very short however.
+ */
+ DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr);
+
+ /* Queue back to heap_allocated or free immediately. */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ if (queue_back) {
+ /* FINALIZED is only cleared if object originally
+ * queued for finalization by refcounting. For
+ * mark-and-sweep FINALIZED is left set, so that
+ * next mark-and-sweep round can make a rescue/free
+ * decision.
+ */
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
+ DUK_HEAPHDR_PREDEC_REFCOUNT(curr); /* Remove artificial refcount bump. */
+ DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+ DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
+ } else {
+ /* No need to remove the refcount bump here. */
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
+ DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O", curr));
+ duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
+ duk_free_hobject(heap, (duk_hobject *) curr);
+ DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p", (void *) curr));
+ }
+#else /* DUK_USE_REFERENCE_COUNTING */
+ DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+ DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+#if defined(DUK_USE_DEBUG)
+ count++;
+#endif
+
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(heap->currently_finalizing != NULL);
+ heap->currently_finalizing = NULL;
+#endif
+ }
+
+ /* finalize_list will always be processed completely. */
+ DUK_ASSERT(heap->finalize_list == NULL);
+
+#if 0
+ /* While NORZ macros are used above, this is unnecessary because the
+ * only pending side effects are now finalizers, and finalize_list is
+ * empty.
+ */
+ DUK_REFZERO_CHECK_SLOW(heap->heap_thread);
+#endif
+
+ /* Prevent count may be bumped while finalizers run, but should always
+ * be reliably unbumped by the time we get here.
+ */
+ DUK_ASSERT(heap->pf_prevent_count == 1);
+ heap->pf_prevent_count = 0;
+
+#if defined(DUK_USE_DEBUG)
+ DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called", (long) count));
+#endif
+}
+
+/*
+ * Run an duk_hobject finalizer. Must never throw an uncaught error
+ * (but may throw caught errors).
+ *
+ * There is no return value. Any return value or error thrown by
+ * the finalizer is ignored (although errors are debug logged).
+ *
+ * Notes:
+ *
+ * - The finalizer thread 'top' assertions are there because it is
+ * critical that strict stack policy is observed (i.e. no cruft
+ * left on the finalizer stack).
+ */
+
+DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) {
+ DUK_ASSERT(thr != NULL);
+ DUK_UNREF(udata);
+
+ DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
+
+ /* [... obj] */
+
+ /* _Finalizer property is read without checking if the value is
+ * callable or even exists. This is intentional, and handled
+ * by throwing an error which is caught by the safe call wrapper.
+ *
+ * XXX: Finalizer lookup should traverse the prototype chain (to allow
+ * inherited finalizers) but should not invoke accessors or proxy object
+ * behavior. At the moment this lookup will invoke proxy behavior, so
+ * caller must ensure that this function is not called if the target is
+ * a Proxy.
+ */
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
+ duk_dup_m2(thr);
+ duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
+ DUK_DDD(DUK_DDDPRINT("calling finalizer"));
+ duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
+ DUK_DDD(DUK_DDDPRINT("finalizer returned successfully"));
+ return 0;
+
+ /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
+ * so we don't need to pop stuff here. There is no return value;
+ * caller determines rescued status based on object refcount.
+ */
+}
+
+DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
+ duk_hthread *thr;
+ duk_ret_t rc;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_idx_t entry_top;
+#endif
+
+ DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p", (void *) obj));
+
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ thr = heap->heap_thread;
+ DUK_ASSERT(obj != NULL);
+ DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1);
+
+#if defined(DUK_USE_ASSERTIONS)
+ entry_top = duk_get_top(thr);
+#endif
+ /*
+ * Get and call the finalizer. All of this must be wrapped
+ * in a protected call, because even getting the finalizer
+ * may trigger an error (getter may throw one, for instance).
+ */
+
+ /* ROM objects could inherit a finalizer, but they are never deemed
+ * unreachable by mark-and-sweep, and their refcount never falls to 0.
+ */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
+
+ /* Duktape 2.1: finalize_list never contains objects with FINALIZED
+ * set, so no need to check here.
+ */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj));
+#if 0
+ if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
+ DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
+ return;
+ }
+#endif
+ DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_HOBJECT_IS_PROXY(obj)) {
+ /* This may happen if duk_set_finalizer() or Duktape.fin() is
+ * called for a Proxy object. In such cases the fast finalizer
+ * flag will be set on the Proxy, not the target, and neither
+ * will be finalized.
+ */
+ DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call"));
+ return;
+ }
+#endif /* DUK_USE_ES6_PROXY */
+
+ duk_push_hobject(thr, obj); /* this also increases refcount by one */
+ rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
+ DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */
+
+ if (rc != DUK_EXEC_SUCCESS) {
+ /* Note: we ask for one return value from duk_safe_call to get this
+ * error debugging here.
+ */
+ DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
+ (void *) obj, (duk_tval *) duk_get_tval(thr, -1)));
+ }
+ duk_pop_2(thr); /* -> [...] */
+
+ DUK_ASSERT_TOP(thr, entry_top);
+}
+
+#else /* DUK_USE_FINALIZER_SUPPORT */
+
+/* nothing */
+
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* String hash computation (interning).
*
@@ -41924,11 +47664,11 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* with real world inputs). Unless the hash is cryptographic, it's always
* possible to craft inputs with maximal hash collisions.
*
- * NOTE: The hash algorithms must match src/dukutil.py:duk_heap_hashstring()
+ * NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring()
* for ROM string support!
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_STRHASH_DENSE)
/* Constants for duk_hashstring(). */
@@ -41991,10 +47731,6 @@ DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t
#endif
return hash;
}
-
-#undef DUK__STRHASH_SHORTSTRING
-#undef DUK__STRHASH_MEDIUMSTRING
-#undef DUK__STRHASH_BLOCKSIZE
#else /* DUK_USE_STRHASH_DENSE */
DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
duk_uint32_t hash;
@@ -42029,35 +47765,24 @@ DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t
return hash;
}
#endif /* DUK_USE_STRHASH_DENSE */
-#line 1 "duk_heap_markandsweep.c"
+
+/* automatic undefs */
+#undef DUK__STRHASH_BLOCKSIZE
+#undef DUK__STRHASH_MEDIUMSTRING
+#undef DUK__STRHASH_SHORTSTRING
/*
* Mark-and-sweep garbage collection.
*/
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
+/* #include duk_internal.h -> already included */
DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
+DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h);
DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
+DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count);
/*
- * Misc
- */
-
-/* Select a thread for mark-and-sweep use.
- *
- * XXX: This needs to change later.
- */
-DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
- if (heap->curr_thread) {
- return heap->curr_thread;
- }
- return heap->heap_thread; /* may be NULL, too */
-}
-
-/*
- * Marking functions for heap types: mark children recursively
+ * Marking functions for heap types: mark children recursively.
*/
DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
@@ -42081,10 +47806,10 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
- if (!key) {
+ if (key == NULL) {
continue;
}
- duk__mark_heaphdr(heap, (duk_heaphdr *) key);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key);
if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
@@ -42097,112 +47822,165 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
}
- /* hash part is a 'weak reference' and does not contribute */
+ /* Hash part is a 'weak reference' and does not contribute. */
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
+ /* Fast path for objects which don't have a subclass struct, or have a
+ * subclass struct but nothing that needs marking in the subclass struct.
+ */
+ if (DUK_HOBJECT_HAS_FASTREFS(h)) {
+ DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
+ return;
+ }
+ DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
+
+ /* XXX: reorg, more common first */
+ if (DUK_HOBJECT_IS_COMPFUNC(h)) {
+ duk_hcompfunc *f = (duk_hcompfunc *) h;
duk_tval *tv, *tv_end;
duk_hobject **fn, **fn_end;
+ DUK_ASSERT_HCOMPFUNC_VALID(f);
+
/* 'data' is reachable through every compiled function which
* contains a reference.
*/
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));
+ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f));
+ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
+ duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
- if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) {
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
+ if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) {
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
+ tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
while (tv < tv_end) {
duk__mark_tval(heap, tv);
tv++;
}
- fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
- fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
+ fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
+ fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
while (fn < fn_end) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn);
fn++;
}
} else {
/* May happen in some out-of-memory corner cases. */
- DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking"));
- }
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK_UNREF(f);
- /* nothing to mark */
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
+ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking"));
+ }
+ } else if (DUK_HOBJECT_IS_DECENV(h)) {
+ duk_hdecenv *e = (duk_hdecenv *) h;
+ DUK_ASSERT_HDECENV_VALID(e);
+ duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread);
+ duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap);
+ } else if (DUK_HOBJECT_IS_OBJENV(h)) {
+ duk_hobjenv *e = (duk_hobjenv *) h;
+ DUK_ASSERT_HOBJENV_VALID(e);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ duk_hbufobj *b = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(b);
duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
+ duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+ DUK_ASSERT_HBOUNDFUNC_VALID(f);
+ duk__mark_tval(heap, &f->target);
+ duk__mark_tval(heap, &f->this_binding);
+ duk__mark_tvals(heap, f->args, f->nargs);
+#if defined(DUK_USE_ES6_PROXY)
+ } else if (DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK_ASSERT_HPROXY_VALID(p);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler);
+#endif /* DUK_USE_ES6_PROXY */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
duk_tval *tv;
+ DUK_ASSERT_HTHREAD_VALID(t);
+
tv = t->valstack;
while (tv < t->valstack_top) {
duk__mark_tval(heap, tv);
tv++;
}
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
+ for (act = t->callstack_curr; act != NULL; act = act->parent) {
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
#endif
- }
-
#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ }
#endif
+ }
duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
- /* XXX: duk_small_uint_t would be enough for this loop */
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
}
+ } else {
+ /* We may come here if the object should have a FASTREFS flag
+ * but it's missing for some reason. Assert for never getting
+ * here; however, other than performance, this is harmless.
+ */
+ DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
+ DUK_ASSERT(0);
}
}
-/* recursion tracking happens here only */
+/* Mark any duk_heaphdr type. Recursion tracking happens only here. */
DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
(void *) h,
(h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
- if (!h) {
+
+ /* XXX: add non-null variant? */
+ if (h == NULL) {
return;
}
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
- return;
+
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h));
+
+#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
+ if (!DUK_HEAPHDR_HAS_READONLY(h)) {
+ h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */
}
#endif
if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
return;
}
+#if defined(DUK_USE_ROM_OBJECTS)
+ /* READONLY objects always have REACHABLE set, so the check above
+ * will prevent READONLY objects from being marked here.
+ */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h));
+#endif
+
DUK_HEAPHDR_SET_REACHABLE(h);
- if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
- /* log this with a normal debug level because this should be relatively rare */
+ if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
DUK_HEAPHDR_SET_TEMPROOT(h);
return;
}
- heap->mark_and_sweep_recursion_depth++;
+ heap->ms_recursion_depth++;
+ DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */
- switch ((int) DUK_HEAPHDR_GET_TYPE(h)) {
+ switch (DUK_HEAPHDR_GET_TYPE(h)) {
case DUK_HTYPE_STRING:
duk__mark_hstring(heap, (duk_hstring *) h);
break;
@@ -42217,19 +47995,45 @@ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
DUK_UNREACHABLE();
}
- heap->mark_and_sweep_recursion_depth--;
+ DUK_ASSERT(heap->ms_recursion_depth > 0);
+ heap->ms_recursion_depth--;
}
DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
- if (!tv) {
+ if (tv == NULL) {
return;
}
if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
+ duk_heaphdr *h;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ duk__mark_heaphdr_nonnull(heap, h);
}
}
+DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) {
+ DUK_ASSERT(count == 0 || tv != NULL);
+
+ while (count-- > 0) {
+ if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
+ duk_heaphdr *h;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ duk__mark_heaphdr_nonnull(heap, h);
+ }
+ tv++;
+ }
+}
+
+/* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */
+DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) {
+ /* For now, just call the generic handler. Change when call sites
+ * are changed too.
+ */
+ duk__mark_heaphdr(heap, h);
+}
+
/*
* Mark the heap.
*/
@@ -42258,69 +48062,43 @@ DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
}
/*
- * Mark refzero_list objects.
- *
- * Objects on the refzero_list have no inbound references. They might have
- * outbound references to objects that we might free, which would invalidate
- * any references held by the refzero objects. A refzero object might also
- * be rescued by refcount finalization. Refzero objects are treated as
- * reachability roots to ensure they (or anything they point to) are not
- * freed in mark-and-sweep.
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
-
- hdr = heap->refzero_list;
- while (hdr) {
- duk__mark_heaphdr(heap, hdr);
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif
-
-/*
* Mark unreachable, finalizable objects.
*
- * Such objects will be moved aside and their finalizers run later. They have
- * to be treated as reachability roots for their properties etc to remain
- * allocated. This marking is only done for unreachable values which would
- * be swept later (refzero_list is thus excluded).
+ * Such objects will be moved aside and their finalizers run later. They
+ * have to be treated as reachability roots for their properties etc to
+ * remain allocated. This marking is only done for unreachable values which
+ * would be swept later.
*
* Objects are first marked FINALIZABLE and only then marked as reachability
* roots; otherwise circular references might be handled inconsistently.
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
- duk_hthread *thr;
duk_heaphdr *hdr;
duk_size_t count_finalizable = 0;
DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
hdr = heap->heap_allocated;
- while (hdr) {
- /* A finalizer is looked up from the object and up its prototype chain
- * (which allows inherited finalizers). A prototype loop must not cause
- * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
- * prototype loop silently and indicate that the property doesn't exist.
+ while (hdr != NULL) {
+ /* A finalizer is looked up from the object and up its
+ * prototype chain (which allows inherited finalizers).
+ * The finalizer is checked for using a duk_hobject flag
+ * which is kept in sync with the presence and callability
+ * of a _Finalizer hidden symbol.
*/
if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
- DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
+ DUK_HEAPHDR_IS_OBJECT(hdr) &&
!DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
- duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
-
+ DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) {
/* heaphdr:
* - is not reachable
* - is an object
- * - is not a finalized object
+ * - is not a finalized object waiting for rescue/keep decision
* - has a finalizer
*/
@@ -42330,7 +48108,7 @@ DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
(void *) hdr));
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
DUK_HEAPHDR_SET_FINALIZABLE(hdr);
- count_finalizable ++;
+ count_finalizable++;
}
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
@@ -42344,9 +48122,9 @@ DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
(long) count_finalizable));
hdr = heap->heap_allocated;
- while (hdr) {
+ while (hdr != NULL) {
if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
- duk__mark_heaphdr(heap, hdr);
+ duk__mark_heaphdr_nonnull(heap, hdr);
}
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
@@ -42354,56 +48132,63 @@ DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
/* Caller will finish the marking process if we hit a recursion limit. */
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Mark objects on finalize_list.
- *
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
duk_heaphdr *hdr;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk_size_t count_finalize_list = 0;
#endif
DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
hdr = heap->finalize_list;
- while (hdr) {
- duk__mark_heaphdr(heap, hdr);
+ while (hdr != NULL) {
+ duk__mark_heaphdr_nonnull(heap, hdr);
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
count_finalize_list++;
#endif
}
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
if (count_finalize_list > 0) {
DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
(long) count_finalize_list));
}
#endif
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Fallback marking handler if recursion limit is reached.
*
- * Iterates 'temproots' until recursion limit is no longer hit. Note
- * that temproots may reside either in heap allocated list or the
- * refzero work list. This is a slow scan, but guarantees that we
- * finish with a bounded C stack.
+ * Iterates 'temproots' until recursion limit is no longer hit. Temproots
+ * can be in heap_allocated or finalize_list; refzero_list is now always
+ * empty for mark-and-sweep. A temproot may occur in finalize_list now if
+ * there are objects on the finalize_list and user code creates a reference
+ * from an object in heap_allocated to the object in finalize_list (which is
+ * now allowed), and it happened to coincide with the recursion depth limit.
+ *
+ * This is a slow scan, but guarantees that we finish with a bounded C stack.
*
- * Note that nodes may have been marked as temproots before this
- * scan begun, OR they may have been marked during the scan (as
- * we process nodes recursively also during the scan). This is
- * intended behavior.
+ * Note that nodes may have been marked as temproots before this scan begun,
+ * OR they may have been marked during the scan (as we process nodes
+ * recursively also during the scan). This is intended behavior.
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
#else
DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
#endif
+ DUK_ASSERT(hdr != NULL);
+
if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
return;
@@ -42411,17 +48196,20 @@ DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
- DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
- duk__mark_heaphdr(heap, hdr);
+ DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */
+#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
+ hdr->h_assert_refcount--; /* Same node visited twice. */
+#endif
+ duk__mark_heaphdr_nonnull(heap, hdr);
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
(*count)++;
#endif
}
DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
duk_heaphdr *hdr;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk_size_t count;
#endif
@@ -42430,14 +48218,14 @@ DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
count = 0;
#endif
DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
hdr = heap->heap_allocated;
while (hdr) {
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk__handle_temproot(heap, hdr, &count);
#else
duk__handle_temproot(heap, hdr);
@@ -42445,20 +48233,19 @@ DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
- /* must also check refzero_list */
-#ifdef DUK_USE_REFERENCE_COUNTING
- hdr = heap->refzero_list;
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ hdr = heap->finalize_list;
while (hdr) {
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk__handle_temproot(heap, hdr, &count);
#else
duk__handle_temproot(heap, hdr);
#endif
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
-#endif /* DUK_USE_REFERENCE_COUNTING */
+#endif
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
#endif
}
@@ -42473,16 +48260,13 @@ DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
* identically to duk__sweep_heap().
*/
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
- duk_hthread *thr;
duk_heaphdr *hdr;
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
- DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
- (void *) heap, (void *) thr));
+ DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap));
hdr = heap->heap_allocated;
while (hdr) {
@@ -42498,37 +48282,21 @@ DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
*/
DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
- duk_heaphdr_refcount_finalize(thr, hdr);
- }
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-/*
- * Clear (reachable) flags of refzero work list.
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap));
+ /* Finalize using heap->heap_thread; DECREF has a
+ * suppress check for mark-and-sweep which is based
+ * on heap->ms_running.
+ */
+ duk_heaphdr_refcount_finalize_norz(heap, hdr);
+ }
- hdr = heap->refzero_list;
- while (hdr) {
- DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
}
#endif /* DUK_USE_REFERENCE_COUNTING */
/*
- * Clear (reachable) flags of finalize_list
+ * Clear (reachable) flags of finalize_list.
*
* We could mostly do in the sweep phase when we move objects from the
* heap into the finalize_list. However, if a finalizer run is skipped
@@ -42538,6 +48306,7 @@ DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
* here. (This now overlaps with the sweep handling in a harmless way.)
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
duk_heaphdr *hdr;
@@ -42546,218 +48315,110 @@ DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
hdr = heap->finalize_list;
while (hdr) {
DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \
+ (heap->currently_finalizing == hdr));
+#endif
+ /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */
DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
- * Sweep stringtable
+ * Sweep stringtable.
*/
-#if defined(DUK_USE_STRTAB_CHAIN)
-
-/* XXX: skip count_free w/o debug? */
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) {
- duk_uint16_t h16 = *slot;
+DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) {
duk_hstring *h;
- duk_uint16_t null16 = heap->heapptr_null16;
-
- if (h16 == null16) {
- /* nop */
- return;
- }
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16);
- DUK_ASSERT(h != NULL);
-
- if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- (*count_keep)++;
- } else {
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
-#endif
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- *slot = null16;
-
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- (*count_free)++;
- }
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) {
- duk_hstring *h = *slot;
-
- if (h == NULL) {
- /* nop */
- return;
- }
-
- if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- (*count_keep)++;
- } else {
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
-#endif
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- *slot = NULL;
-
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- (*count_free)++;
- }
-}
-#endif /* DUK_USE_HEAPPTR16 */
-
-DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) {
- duk_strtab_entry *e;
- duk_uint_fast32_t i;
+ duk_hstring *prev;
+ duk_uint32_t i;
+#if defined(DUK_USE_DEBUG)
duk_size_t count_free = 0;
- duk_size_t count_keep = 0;
- duk_size_t j, n;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
-#else
- duk_hstring **lst;
#endif
+ duk_size_t count_keep = 0;
DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
- /* Non-zero refcounts should not happen for unreachable strings,
- * because we refcount finalize all unreachable objects which
- * should have decreased unreachable string refcounts to zero
- * (even for cycles).
- */
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen == 0) {
-#if defined(DUK_USE_HEAPPTR16)
- duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free);
-#else
- duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free);
-#endif
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- for (j = 0, n = e->listlen; j < n; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ if (heap->strtable16 == NULL) {
#else
- duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free);
+ if (heap->strtable == NULL) {
#endif
- }
- }
+ goto done;
}
- DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
- (long) count_free, (long) count_keep));
- *out_count_keep = count_keep;
-}
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) {
- duk_hstring *h;
- duk_uint_fast32_t i;
-#ifdef DUK_USE_DEBUG
- duk_size_t count_free = 0;
-#endif
- duk_size_t count_keep = 0;
-
- DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
-
for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
#else
h = heap->strtable[i];
#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
- } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- count_keep++;
- continue;
- }
+ prev = NULL;
+ while (h != NULL) {
+ duk_hstring *next;
+ next = h->hdr.h_next;
-#ifdef DUK_USE_DEBUG
- count_free++;
+ if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
+ DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
+ count_keep++;
+ prev = h;
+ } else {
+#if defined(DUK_USE_DEBUG)
+ count_free++;
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
- /* Non-zero refcounts should not happen for unreachable strings,
- * because we refcount finalize all unreachable objects which
- * should have decreased unreachable string refcounts to zero
- * (even for cycles).
- */
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
+ /* Non-zero refcounts should not happen for unreachable strings,
+ * because we refcount finalize all unreachable objects which
+ * should have decreased unreachable string refcounts to zero
+ * (even for cycles).
+ */
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
#endif
- DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
+ /* Deal with weak references first. */
+ duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
+ /* Remove the string from the string table. */
+ duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev);
- /* remove the string (mark DELETED), could also call
- * duk_heap_string_remove() but that would be slow and
- * pointless because we already know the slot.
- */
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16[i] = heap->heapptr_deleted16;
-#else
- heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
-#endif
+ /* Free inner references (these exist e.g. when external
+ * strings are enabled) and the struct itself.
+ */
+ duk_free_hstring(heap, (duk_hstring *) h);
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, (duk_hstring *) h);
+ /* Don't update 'prev'; it should be last string kept. */
+ }
- /* finally free the struct itself */
- DUK_FREE(heap, h);
+ h = next;
+ }
}
-#ifdef DUK_USE_DEBUG
+ done:
+#if defined(DUK_USE_DEBUG)
DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
(long) count_free, (long) count_keep));
#endif
*out_count_keep = count_keep;
}
-#endif /* DUK_USE_STRTAB_PROBE */
/*
- * Sweep heap
+ * Sweep heap.
*/
-DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
+DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) {
duk_heaphdr *prev; /* last element that was left in the heap */
duk_heaphdr *curr;
duk_heaphdr *next;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk_size_t count_free = 0;
duk_size_t count_finalize = 0;
duk_size_t count_rescue = 0;
#endif
duk_size_t count_keep = 0;
- DUK_UNREF(flags);
DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
prev = NULL;
@@ -42772,67 +48433,64 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
/*
- * Reachable object, keep
+ * Reachable object:
+ * - If FINALIZABLE -> actually unreachable (but marked
+ * artificially reachable), queue to finalize_list.
+ * - If !FINALIZABLE but FINALIZED -> rescued after
+ * finalizer execution.
+ * - Otherwise just a normal, reachable object.
+ *
+ * Objects which are kept are queued to heap_allocated
+ * tail (we're essentially filtering heap_allocated in
+ * practice).
*/
- DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
-
- if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
- /*
- * If object has been marked finalizable, move it to the
- * "to be finalized" work list. It will be collected on
- * the next mark-and-sweep if it is still unreachable
- * after running the finalizer.
- */
-
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) {
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
- DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
+ DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr));
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
- if (heap->finalize_list) {
- DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
- }
- DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */
#endif
- DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
- DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
- heap->finalize_list = curr;
-#ifdef DUK_USE_DEBUG
+ DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr);
+#if defined(DUK_USE_DEBUG)
count_finalize++;
#endif
- } else {
- /*
- * Object will be kept; queue object back to heap_allocated (to tail)
- */
-
- if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
- /*
- * Object's finalizer was executed on last round, and
- * object has been happily rescued.
- */
-
+ }
+ else
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+ {
+ if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) {
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
- DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
-#ifdef DUK_USE_DEBUG
- count_rescue++;
+
+ if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) {
+ DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr));
+ count_keep++;
+ } else {
+ DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr));
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ DUK_HEAPHDR_CLEAR_FINALIZED(curr);
+#endif
+#if defined(DUK_USE_DEBUG)
+ count_rescue++;
#endif
+ }
} else {
- /*
- * Plain, boring reachable object.
- */
- DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
+ DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr));
count_keep++;
}
- if (!heap->heap_allocated) {
- heap->heap_allocated = curr;
- }
- if (prev) {
+ if (prev != NULL) {
+ DUK_ASSERT(heap->heap_allocated != NULL);
DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
+ } else {
+ DUK_ASSERT(heap->heap_allocated == NULL);
+ heap->heap_allocated = curr;
}
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
+#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
DUK_HEAPHDR_SET_PREV(heap, curr, prev);
#endif
DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
@@ -42840,22 +48498,36 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
prev = curr;
}
- DUK_HEAPHDR_CLEAR_REACHABLE(curr);
- DUK_HEAPHDR_CLEAR_FINALIZED(curr);
- DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+ /*
+ * Shrink check for value stacks here. We're inside
+ * ms_prevent_count protection which prevents recursive
+ * mark-and-sweep and refzero finalizers, so there are
+ * no side effects that would affect the heap lists.
+ */
+ if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) {
+ duk_hthread *thr_curr = (duk_hthread *) curr;
+ DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O", curr));
+ duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/);
+ }
+ DUK_HEAPHDR_CLEAR_REACHABLE(curr);
+ /* Keep FINALIZED if set, used if rescue decisions are postponed. */
+ /* Keep FINALIZABLE for objects on finalize_list. */
DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
-
- curr = next;
} else {
/*
- * Unreachable object, free
+ * Unreachable object:
+ * - If FINALIZED, object was finalized but not
+ * rescued. This doesn't affect freeing.
+ * - Otherwise normal unreachable object.
+ *
+ * There's no guard preventing a FINALIZED object
+ * from being freed while finalizers execute: the
+ * artificial finalize_list reachability roots can't
+ * cause an incorrect free decision (but can cause
+ * an incorrect rescue decision).
*/
- DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
-
#if defined(DUK_USE_REFERENCE_COUNTING)
/* Non-zero refcounts should not happen because we refcount
* finalize all unreachable objects which should cancel out
@@ -42865,35 +48537,41 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
#endif
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
+#if defined(DUK_USE_DEBUG)
if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
- DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
+ DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr));
+ } else {
+ DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr));
}
+#endif
+
/* Note: object cannot be a finalizable unreachable object, as
* they have been marked temporarily reachable for this round,
* and are handled above.
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
count_free++;
#endif
- /* weak refs should be handled here, but no weak refs for
+ /* Weak refs should be handled here, but no weak refs for
* any non-string objects exist right now.
*/
- /* free object and all auxiliary (non-heap) allocs */
+ /* Free object and all auxiliary (non-heap) allocs. */
duk_heap_free_heaphdr_raw(heap, curr);
-
- curr = next;
}
+
+ curr = next;
}
- if (prev) {
+
+ if (prev != NULL) {
DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
}
DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
(long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
#endif
@@ -42901,90 +48579,28 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
}
/*
- * Run (object) finalizers in the "to be finalized" work list.
- */
-
-DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-#ifdef DUK_USE_DEBUG
- duk_size_t count = 0;
-#endif
- duk_hthread *thr;
-
- DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
-
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
-
- curr = heap->finalize_list;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
-
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
-
- if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
- /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
- * Next mark-and-sweep will collect the object unless it has
- * become reachable (i.e. rescued). FINALIZED prevents the
- * finalizer from being executed again before that.
- */
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
- } else {
- /* Used during heap destruction: don't actually run finalizers
- * because we're heading into forced finalization. Instead,
- * queue finalizable objects back to the heap_allocated list.
- */
- DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- }
-
- /* queue back to heap_allocated */
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
-
- curr = next;
-#ifdef DUK_USE_DEBUG
- count++;
-#endif
- }
-
- /* finalize_list will always be processed completely */
- heap->finalize_list = NULL;
-
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
-#endif
-}
-
-/*
* Object compaction.
*
* Compaction is assumed to never throw an error.
*/
-DUK_LOCAL int duk__protected_compact_object(duk_context *ctx) {
- /* XXX: for threads, compact value stack, call stack, catch stack? */
+DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) {
+ duk_hobject *obj;
+ /* XXX: for threads, compact stacks? */
- duk_hobject *obj = duk_get_hobject(ctx, -1);
- DUK_ASSERT(obj != NULL);
- duk_hobject_compact_props((duk_hthread *) ctx, obj);
+ DUK_UNREF(udata);
+ obj = duk_known_hobject(thr, -1);
+ duk_hobject_compact_props(thr, obj);
return 0;
}
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) {
#else
DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
#endif
duk_heaphdr *curr;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk_size_t old_size, new_size;
#endif
duk_hobject *obj;
@@ -43000,31 +48616,31 @@ DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_he
}
obj = (duk_hobject *) curr;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
DUK_HOBJECT_GET_ASIZE(obj),
DUK_HOBJECT_GET_HSIZE(obj));
#endif
DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
- duk_push_hobject((duk_context *) thr, obj);
+ duk_push_hobject(thr, obj);
/* XXX: disable error handlers for duration of compaction? */
- duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0);
+ duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0);
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
DUK_HOBJECT_GET_ASIZE(obj),
DUK_HOBJECT_GET_HSIZE(obj));
#endif
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
(*p_count_compact)++;
(*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
#endif
next:
curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
(*p_count_check)++;
#endif
}
@@ -43032,33 +48648,32 @@ DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_he
DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
/* XXX: which lists should participate? to be finalized? */
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
duk_size_t count_check = 0;
duk_size_t count_compact = 0;
duk_size_t count_bytes_saved = 0;
#endif
- duk_hthread *thr;
DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
-#ifdef DUK_USE_DEBUG
- duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
- duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
+#if defined(DUK_USE_DEBUG)
+ duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
#endif
#else
- duk__compact_object_list(heap, thr, heap->heap_allocated);
- duk__compact_object_list(heap, thr, heap->finalize_list);
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__compact_object_list(heap, thr, heap->refzero_list);
+ duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated);
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list);
#endif
#endif
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
+#endif
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
(long) count_check, (long) count_compact, (long) count_bytes_saved));
#endif
@@ -43068,7 +48683,7 @@ DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
* Assertion helpers.
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
duk_heaphdr *hdr;
@@ -43081,165 +48696,246 @@ DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
-#ifdef DUK_USE_REFERENCE_COUNTING
- hdr = heap->refzero_list;
- while (hdr) {
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-#endif /* DUK_USE_REFERENCE_COUNTING */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
+#endif
}
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
duk_heaphdr *hdr = heap->heap_allocated;
while (hdr) {
+ /* Cannot really assert much w.r.t. refcounts now. */
+
if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
/* An object may be in heap_allocated list with a zero
* refcount if it has just been finalized and is waiting
* to be collected by the next cycle.
+ * (This doesn't currently happen however.)
*/
} else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
/* An object may be in heap_allocated list with a zero
- * refcount also if it is a temporary object created by
- * a finalizer; because finalization now runs inside
- * mark-and-sweep, such objects will not be queued to
- * refzero_list and will thus appear here with refcount
- * zero.
+ * refcount also if it is a temporary object created
+ * during debugger paused state. It will get collected
+ * by mark-and-sweep based on its reachability status
+ * (presumably not reachable because refcount is 0).
*/
-#if 0 /* this case can no longer occur because refcount is unsigned */
- } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
- DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O",
- (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0),
- (void *) hdr, (duk_heaphdr *) hdr));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
-#endif
}
+ DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0); /* Unsigned. */
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
}
-#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_USE_ASSERTIONS */
-/*
- * Finalizer torture. Do one fake finalizer call which causes side effects
- * similar to one or more finalizers on actual objects.
- */
+DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) {
+ duk_heaphdr *curr;
+ duk_uint32_t i;
-#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
-DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) {
- DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed"));
+ for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ curr->h_assert_refcount = 0;
+ }
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ curr->h_assert_refcount = 0;
+ }
+#endif
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ curr->h_assert_refcount = 0;
+ }
+#endif
- /* Require a lot of stack to force a value stack grow/shrink.
- * Recursive mark-and-sweep is prevented by allocation macros
- * so this won't trigger another mark-and-sweep.
+ for (i = 0; i < heap->st_size; i++) {
+ duk_hstring *h;
+
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
+#else
+ h = heap->strtable[i];
+#endif
+ while (h != NULL) {
+ ((duk_heaphdr *) h)->h_assert_refcount = 0;
+ h = h->hdr.h_next;
+ }
+ }
+}
+
+DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) {
+ duk_bool_t count_ok;
+
+ /* The refcount check only makes sense for reachable objects on
+ * heap_allocated or string table, after the sweep phase. Prior to
+ * sweep phase refcounts will include references that are not visible
+ * via reachability roots.
+ *
+ * Because we're called after the sweep phase, all heap objects on
+ * heap_allocated are reachable. REACHABLE flags have already been
+ * cleared so we can't check them.
*/
- duk_require_stack(ctx, 100000);
- /* XXX: do something to force a callstack grow/shrink, perhaps
- * just a manual forced resize or a forced relocating realloc?
+ /* ROM objects have intentionally incorrect refcount (1), but we won't
+ * check them.
*/
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
- return 0;
+ count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount);
+ if (!count_ok) {
+ DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO",
+ (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr),
+ (long) hdr->h_assert_refcount, hdr));
+ DUK_ASSERT(0);
+ }
}
-DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
- duk_context *ctx;
- duk_int_t rc;
+DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) {
+ duk_heaphdr *curr;
+ duk_uint32_t i;
- DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
+ for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ duk__check_refcount_heaphdr(curr);
+ }
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ duk__check_refcount_heaphdr(curr);
+ }
+#endif
- /* Avoid fake finalization when callstack limit has been reached.
- * Otherwise a callstack limit error will be created, then refzero'ed.
- */
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
- thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
- DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer"));
- return;
+ for (i = 0; i < heap->st_size; i++) {
+ duk_hstring *h;
+
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
+#else
+ h = heap->strtable[i];
+#endif
+ while (h != NULL) {
+ duk__check_refcount_heaphdr((duk_heaphdr *) h);
+ h = h->hdr.h_next;
+ }
}
+}
+#endif /* DUK_USE_REFERENCE_COUNTING */
+#endif /* DUK_USE_ASSERTIONS */
- /* Run fake finalizer. Avoid creating unnecessary garbage. */
- duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/);
- rc = duk_pcall(ctx, 0 /*nargs*/);
- DUK_UNREF(rc); /* ignored */
- duk_pop(ctx);
+/*
+ * Stats dump.
+ */
+
+#if defined(DUK_USE_DEBUG)
+DUK_LOCAL void duk__dump_stats(duk_heap *heap) {
+ DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld",
+ (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt,
+ (long) heap->stats_exec_throw));
+ DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld",
+ (long) heap->stats_call_all, (long) heap->stats_call_tailcall,
+ (long) heap->stats_call_ecmatoecma));
+ DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld",
+ (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow,
+ (long) heap->stats_safecall_throw));
+ DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld",
+ (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count,
+ (long) heap->stats_ms_emergency_count));
+ DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, resize_check=%ld, resize_grow=%ld, resize_shrink=%ld",
+ (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss,
+ (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow,
+ (long) heap->stats_strtab_resize_shrink));
+ DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld",
+ (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array));
+ DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld",
+ (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit,
+ (long) heap->stats_getownpropdesc_miss));
+ DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld",
+ (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit,
+ (long) heap->stats_getpropdesc_miss));
+ DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
+ "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, "
+ "proxy=%ld, arguments=%ld",
+ (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx,
+ (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx,
+ (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx,
+ (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy,
+ (long) heap->stats_getprop_arguments));
+ DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
+ "bufferidx=%ld, proxy=%ld",
+ (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx,
+ (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx,
+ (long) heap->stats_putprop_proxy));
+ DUK_D(DUK_DPRINT("stats getvar: all=%ld",
+ (long) heap->stats_getvar_all));
+ DUK_D(DUK_DPRINT("stats putvar: all=%ld",
+ (long) heap->stats_putvar_all));
}
-#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
+#endif /* DUK_USE_DEBUG */
/*
* Main mark-and-sweep function.
*
* 'flags' represents the features requested by the caller. The current
- * heap->mark_and_sweep_base_flags is ORed automatically into the flags;
- * the base flags mask typically prevents certain mark-and-sweep operations
- * to avoid trouble.
+ * heap->ms_base_flags is ORed automatically into the flags; the base flags
+ * mask typically prevents certain mark-and-sweep operation to avoid trouble.
*/
-DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
- duk_hthread *thr;
+DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
duk_size_t count_keep_obj;
duk_size_t count_keep_str;
-#ifdef DUK_USE_VOLUNTARY_GC
+#if defined(DUK_USE_VOLUNTARY_GC)
duk_size_t tmp;
#endif
- /* XXX: thread selection for mark-and-sweep is currently a hack.
- * If we don't have a thread, the entire mark-and-sweep is now
- * skipped (although we could just skip finalizations).
- */
+ DUK_STATS_INC(heap, stats_ms_try_count);
+#if defined(DUK_USE_DEBUG)
+ if (flags & DUK_MS_FLAG_EMERGENCY) {
+ DUK_STATS_INC(heap, stats_ms_emergency_count);
+ }
+#endif
- /* If thr != NULL, the thr may still be in the middle of
- * initialization.
- * XXX: Improve the thread viability test.
+ /* If debugger is paused, garbage collection is disabled by default.
+ * This is achieved by bumping ms_prevent_count when becoming paused.
*/
- thr = duk__get_temp_hthread(heap);
- if (thr == NULL) {
- DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
+ DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0);
- /* reset voluntary gc trigger count */
-#ifdef DUK_USE_VOLUNTARY_GC
- heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
-#endif
- return 0; /* OK */
+ /* Prevention/recursion check as soon as possible because we may
+ * be called a number of times when voluntary mark-and-sweep is
+ * pending.
+ */
+ if (heap->ms_prevent_count != 0) {
+ DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep"));
+ DUK_STATS_INC(heap, stats_ms_skip_count);
+ return;
}
+ DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */
- /* If debugger is paused, garbage collection is disabled by default. */
- /* XXX: will need a force flag if garbage collection is triggered
- * explicitly during paused state.
+ /* Heap_thread is used during mark-and-sweep for refcount finalization
+ * (it's also used for finalizer execution once mark-and-sweep is
+ * complete). Heap allocation code ensures heap_thread is set and
+ * properly initialized before setting ms_prevent_count to 0.
*/
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_PAUSED(heap)) {
- /* Checking this here rather that in memory alloc primitives
- * reduces checking code there but means a failed allocation
- * will go through a few retries before giving up. That's
- * fine because this only happens during debugging.
- */
- DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
- return 0;
- }
-#endif
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(heap->heap_thread->valstack != NULL);
DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
- (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
+ (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags)));
- flags |= heap->mark_and_sweep_base_flags;
+ flags |= heap->ms_base_flags;
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ if (heap->finalize_list != NULL) {
+ flags |= DUK_MS_FLAG_POSTPONE_RESCUE;
+ }
+#endif
/*
* Assertions before
*/
-#ifdef DUK_USE_ASSERTIONS
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(heap->ms_prevent_count == 0);
+ DUK_ASSERT(heap->ms_running == 0);
+ DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap));
DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
- DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
+ DUK_ASSERT(heap->ms_recursion_depth == 0);
duk__assert_heaphdr_flags(heap);
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Note: heap->refzero_free_running may be true; a refcount
* finalizer may trigger a mark-and-sweep.
*/
duk__assert_valid_refcounts(heap);
@@ -43250,7 +48946,19 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
* Begin
*/
- DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
+ DUK_ASSERT(heap->ms_prevent_count == 0);
+ DUK_ASSERT(heap->ms_running == 0);
+ heap->ms_prevent_count = 1;
+ heap->ms_running = 1;
+
+ /*
+ * Free activation/catcher freelists on every mark-and-sweep for now.
+ * This is an initial rough draft; ideally we'd keep count of the
+ * freelist size and free only excess entries.
+ */
+
+ DUK_D(DUK_DPRINT("freeing temporary freelists"));
+ duk_heap_free_freelists(heap);
/*
* Mark roots, hoping that recursion limit is not normally hit.
@@ -43268,15 +48976,20 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
* previous run had finalizer skip flag.
*/
- duk__mark_roots_heap(heap); /* main reachability roots */
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
+#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
+ duk__clear_assert_refcounts(heap);
+#endif
+ duk__mark_roots_heap(heap); /* Mark main reachability roots. */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
#endif
- duk__mark_temproots_by_heap_scan(heap); /* temproots */
+ duk__mark_temproots_by_heap_scan(heap); /* Temproots. */
- duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
- duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
- duk__mark_temproots_by_heap_scan(heap); /* temproots */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */
+ duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */
+#endif
+ duk__mark_temproots_by_heap_scan(heap); /* Temproots. */
/*
* Sweep garbage and remove marking flags, and move objects with
@@ -43294,21 +49007,20 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
/* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
duk__finalize_refcounts(heap);
#endif
duk__sweep_heap(heap, flags, &count_keep_obj);
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__sweep_stringtable_chain(heap, &count_keep_str);
-#elif defined(DUK_USE_STRTAB_PROBE)
- duk__sweep_stringtable_probe(heap, &count_keep_str);
-#else
-#error internal error, invalid strtab options
+ duk__sweep_stringtable(heap, &count_keep_str);
+#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
+ duk__check_assert_refcounts(heap);
#endif
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__clear_refzero_list_flags(heap);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
duk__clear_finalize_list_flags(heap);
+#endif
/*
* Object compaction (emergency only).
@@ -43335,92 +49047,39 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
/*
* String table resize check.
*
- * Note: this may silently (and safely) fail if GC is caused by an
- * allocation call in stringtable resize_hash(). Resize_hash()
- * will prevent a recursive call to itself by setting the
- * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
+ * This is mainly useful in emergency GC: if the string table load
+ * factor is really low for some reason, we can shrink the string
+ * table to a smaller size and free some memory in the process.
+ * Only execute in emergency GC. String table has internal flags
+ * to protect against recursive resizing if this mark-and-sweep pass
+ * was triggered by a string table resize.
*/
- /* XXX: stringtable emergency compaction? */
-
- /* XXX: remove this feature entirely? it would only matter for
- * emergency GC. Disable for lowest memory builds.
- */
-#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
- if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
- DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
- duk_heap_force_strtab_resize(heap);
- } else {
- DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
- }
-#endif
-
- /*
- * Finalize objects in the finalization work list. Finalized
- * objects are queued back to heap_allocated with FINALIZED set.
- *
- * Since finalizers may cause arbitrary side effects, they are
- * prevented during string table and object property allocation
- * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
- * heap->mark_and_sweep_base_flags. In this case the objects
- * remain in the finalization work list after mark-and-sweep
- * exits and they may be finalized on the next pass.
- *
- * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
- * protection (no mark-and-sweep may be triggered by the
- * finalizers). As a side effect:
- *
- * 1) an out-of-memory error inside a finalizer will not
- * cause a mark-and-sweep and may cause the finalizer
- * to fail unnecessarily
- *
- * 2) any temporary objects whose refcount decreases to zero
- * during finalization will not be put into refzero_list;
- * they can only be collected by another mark-and-sweep
- *
- * This is not optimal, but since the sweep for this phase has
- * already happened, this is probably good enough for now.
- */
-
-#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
- /* Cannot simulate individual finalizers because finalize_list only
- * contains objects with actual finalizers. But simulate side effects
- * from finalization by doing a bogus function call and resizing the
- * stacks.
- */
- if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
- DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
- } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
- DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
- } else {
- DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
- duk__markandsweep_torture_finalizer(thr);
- }
-#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
-
- if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
- DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
- } else {
- duk__run_object_finalizers(heap, flags);
+ if (flags & DUK_MS_FLAG_EMERGENCY) {
+ DUK_D(DUK_DPRINT("stringtable resize check in emergency gc"));
+ duk_heap_strtable_force_resize(heap);
}
/*
* Finish
*/
- DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
+ DUK_ASSERT(heap->ms_prevent_count == 1);
+ heap->ms_prevent_count = 0;
+ DUK_ASSERT(heap->ms_running == 1);
+ heap->ms_running = 0;
/*
* Assertions after
*/
-#ifdef DUK_USE_ASSERTIONS
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(heap->ms_prevent_count == 0);
DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
- DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
+ DUK_ASSERT(heap->ms_recursion_depth == 0);
duk__assert_heaphdr_flags(heap);
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Note: heap->refzero_free_running may be true; a refcount
* finalizer may trigger a mark-and-sweep.
*/
duk__assert_valid_refcounts(heap);
@@ -43431,74 +49090,99 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
* Reset trigger counter
*/
-#ifdef DUK_USE_VOLUNTARY_GC
+#if defined(DUK_USE_VOLUNTARY_GC)
tmp = (count_keep_obj + count_keep_str) / 256;
- heap->mark_and_sweep_trigger_counter = (duk_int_t) (
+ heap->ms_trigger_counter = (duk_int_t) (
(tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
- (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
+ (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter));
#else
DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
(long) count_keep_obj, (long) count_keep_str));
#endif
- return 0; /* OK */
-}
+ /*
+ * Stats dump
+ */
-#else /* DUK_USE_MARK_AND_SWEEP */
+#if defined(DUK_USE_DEBUG)
+ duk__dump_stats(heap);
+#endif
-/* no mark-and-sweep gc */
+ /*
+ * Finalize objects in the finalization work list. Finalized
+ * objects are queued back to heap_allocated with FINALIZED set.
+ *
+ * Since finalizers may cause arbitrary side effects, they are
+ * prevented e.g. during string table and object property allocation
+ * resizing using heap->pf_prevent_count. In this case the objects
+ * remain in the finalization work list after mark-and-sweep exits
+ * and they may be finalized on the next pass or any DECREF checking
+ * for finalize_list.
+ *
+ * As of Duktape 2.1 finalization happens outside mark-and-sweep
+ * protection. Mark-and-sweep is allowed while the finalize_list
+ * is being processed, but no rescue decisions are done while the
+ * process is on-going. This avoids incorrect rescue decisions
+ * if an object is considered reachable (and thus rescued) because
+ * of a reference via finalize_list (which is considered a reachability
+ * root). When finalize_list is being processed, reachable objects
+ * with FINALIZED set will just keep their FINALIZED flag for later
+ * mark-and-sweep processing.
+ *
+ * This could also be handled (a bit better) by having a more refined
+ * notion of reachability for rescue/free decisions.
+ *
+ * XXX: avoid finalizer execution when doing emergency GC?
+ */
-#endif /* DUK_USE_MARK_AND_SWEEP */
-#line 1 "duk_heap_memory.c"
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ /* Attempt to process finalize_list, pf_prevent_count check
+ * is inside the target.
+ */
+ duk_heap_process_finalize_list(heap);
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+}
/*
* Memory allocation handling.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
- * Helpers
- *
- * The fast path checks are done within a macro to ensure "inlining"
- * while the slow path actions use a helper (which won't typically be
- * inlined in size optimized builds).
+ * Voluntary GC check
*/
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
-#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \
- (heap)->mark_and_sweep_trigger_counter--; \
- if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
- duk__run_voluntary_gc(heap); \
- } \
- } while (0)
-
-DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) {
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
- } else {
- duk_small_uint_t flags;
- duk_bool_t rc;
+#if defined(DUK_USE_VOLUNTARY_GC)
+DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) {
+ if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
+#if defined(DUK_USE_DEBUG)
+ if (heap->ms_prevent_count == 0) {
+ DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
+ } else {
+ DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now"));
+ }
+#endif
- DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
- flags = 0;
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
+ /* Prevention checks in the call target handle cases where
+ * voluntary GC is not allowed. The voluntary GC trigger
+ * counter is only rewritten if mark-and-sweep actually runs.
+ */
+ duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/);
}
}
+#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { duk__check_voluntary_gc((heap)); } while (0)
#else
#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */
-#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
+#endif /* DUK_USE_VOLUNTARY_GC */
/*
* Allocate memory with garbage collection
*/
-#ifdef DUK_USE_MARK_AND_SWEEP
DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
void *res;
- duk_bool_t rc;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
@@ -43514,9 +49198,11 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
* First attempt
*/
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+#if defined(DUK_USE_GC_TORTURE)
+ /* Simulate alloc failure on every alloc, except when mark-and-sweep
+ * is running.
+ */
+ if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
res = NULL;
DUK_UNREF(res);
@@ -43524,26 +49210,32 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
}
#endif
res = heap->alloc_func(heap->heap_udata, size);
- if (res || size == 0) {
- /* for zero size allocations NULL is allowed */
+ if (DUK_LIKELY(res || size == 0)) {
+ /* For zero size allocations NULL is allowed. */
return res;
}
-#ifdef DUK_USE_GC_TORTURE
+#if defined(DUK_USE_GC_TORTURE)
skip_attempt:
#endif
DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
+#if 0
/*
* Avoid a GC if GC is already running. This can happen at a late
* stage in a GC when we try to e.g. resize the stringtable
* or compact objects.
+ *
+ * NOTE: explicit handling isn't actually be needed: if the GC is
+ * not allowed, duk_heap_mark_and_sweep() will reject it for every
+ * attempt in the loop below, resulting in a NULL same as here.
*/
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+ if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
return NULL;
}
+#endif
/*
* Retry with several GC attempts. Initial attempts are made without
@@ -43559,8 +49251,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
flags |= DUK_MS_FLAG_EMERGENCY;
}
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
+ duk_heap_mark_and_sweep(heap, flags);
res = heap->alloc_func(heap->heap_udata, size);
if (res) {
@@ -43573,18 +49264,6 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
return NULL;
}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/*
- * Compared to a direct macro expansion this wrapper saves a few
- * instructions because no heap dereferencing is required.
- */
-DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT_DISABLE(size >= 0);
-
- return heap->alloc_func(heap->heap_udata, size);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
void *res;
@@ -43593,21 +49272,43 @@ DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
DUK_ASSERT_DISABLE(size >= 0);
res = DUK_ALLOC(heap, size);
- if (res) {
+ if (DUK_LIKELY(res != NULL)) {
/* assume memset with zero size is OK */
DUK_MEMZERO(res, size);
}
return res;
}
+DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) {
+ void *res;
+
+ DUK_ASSERT(thr != NULL);
+ res = duk_heap_mem_alloc(thr->heap, size);
+ if (DUK_LIKELY(res != NULL || size == 0)) {
+ return res;
+ }
+ DUK_ERROR_ALLOC_FAILED(thr);
+ return NULL;
+}
+
+DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) {
+ void *res;
+
+ DUK_ASSERT(thr != NULL);
+ res = duk_heap_mem_alloc_zeroed(thr->heap, size);
+ if (DUK_LIKELY(res != NULL || size == 0)) {
+ return res;
+ }
+ DUK_ERROR_ALLOC_FAILED(thr);
+ return NULL;
+}
+
/*
* Reallocate memory with garbage collection
*/
-#ifdef DUK_USE_MARK_AND_SWEEP
DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
void *res;
- duk_bool_t rc;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
@@ -43624,9 +49325,11 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
* First attempt
*/
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+#if defined(DUK_USE_GC_TORTURE)
+ /* Simulate alloc failure on every realloc, except when mark-and-sweep
+ * is running.
+ */
+ if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
res = NULL;
DUK_UNREF(res);
@@ -43634,24 +49337,26 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
}
#endif
res = heap->realloc_func(heap->heap_udata, ptr, newsize);
- if (res || newsize == 0) {
- /* for zero size allocations NULL is allowed */
+ if (DUK_LIKELY(res || newsize == 0)) {
+ /* For zero size allocations NULL is allowed. */
return res;
}
-#ifdef DUK_USE_GC_TORTURE
+#if defined(DUK_USE_GC_TORTURE)
skip_attempt:
#endif
DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
+#if 0
/*
* Avoid a GC if GC is already running. See duk_heap_mem_alloc().
*/
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+ if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
return NULL;
}
+#endif
/*
* Retry with several GC attempts. Initial attempts are made without
@@ -43667,8 +49372,7 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
flags |= DUK_MS_FLAG_EMERGENCY;
}
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
+ duk_heap_mark_and_sweep(heap, flags);
res = heap->realloc_func(heap->heap_udata, ptr, newsize);
if (res || newsize == 0) {
@@ -43681,16 +49385,6 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
return NULL;
}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
- DUK_ASSERT_DISABLE(newsize >= 0);
-
- return heap->realloc_func(heap->heap_udata, ptr, newsize);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
/*
* Reallocate memory with garbage collection, using a callback to provide
@@ -43698,10 +49392,8 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
* (e.g. finalizers) might change the original pointer.
*/
-#ifdef DUK_USE_MARK_AND_SWEEP
DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
void *res;
- duk_bool_t rc;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
@@ -43717,9 +49409,11 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
* First attempt
*/
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+#if defined(DUK_USE_GC_TORTURE)
+ /* Simulate alloc failure on every realloc, except when mark-and-sweep
+ * is running.
+ */
+ if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
res = NULL;
DUK_UNREF(res);
@@ -43727,24 +49421,26 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
}
#endif
res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
- if (res || newsize == 0) {
- /* for zero size allocations NULL is allowed */
+ if (DUK_LIKELY(res || newsize == 0)) {
+ /* For zero size allocations NULL is allowed. */
return res;
}
-#ifdef DUK_USE_GC_TORTURE
+#if defined(DUK_USE_GC_TORTURE)
skip_attempt:
#endif
DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
+#if 0
/*
* Avoid a GC if GC is already running. See duk_heap_mem_alloc().
*/
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
+ if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
return NULL;
}
+#endif
/*
* Retry with several GC attempts. Initial attempts are made without
@@ -43755,12 +49451,12 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
duk_small_uint_t flags;
-#ifdef DUK_USE_ASSERTIONS
- void *ptr_pre; /* ptr before mark-and-sweep */
+#if defined(DUK_USE_DEBUG)
+ void *ptr_pre;
void *ptr_post;
#endif
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_DEBUG)
ptr_pre = cb(heap, ud);
#endif
flags = 0;
@@ -43768,13 +49464,11 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
flags |= DUK_MS_FLAG_EMERGENCY;
}
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
-#ifdef DUK_USE_ASSERTIONS
+ duk_heap_mark_and_sweep(heap, flags);
+#if defined(DUK_USE_DEBUG)
ptr_post = cb(heap, ud);
if (ptr_pre != ptr_post) {
- /* useful for debugging */
- DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
+ DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p",
(void *) ptr_pre, (void *) ptr_post));
}
#endif
@@ -43794,18 +49488,11 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
return NULL;
}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
- return heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
/*
* Free memory
*/
-#ifdef DUK_USE_MARK_AND_SWEEP
DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
DUK_ASSERT(heap != NULL);
/* ptr may be NULL */
@@ -43815,74 +49502,162 @@ DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
*/
heap->free_func(heap->heap_udata, ptr);
- /* Count free operations toward triggering a GC but never actually trigger
- * a GC from a free. Otherwise code which frees internal structures would
- * need to put in NULLs at every turn to ensure the object is always in
- * consistent state for a mark-and-sweep.
+ /* Never perform a GC (even voluntary) in a memory free, otherwise
+ * all call sites doing frees would need to deal with the side effects.
+ * No need to update voluntary GC counter either.
*/
-#ifdef DUK_USE_VOLUNTARY_GC
- heap->mark_and_sweep_trigger_counter--;
-#endif
}
-#else
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
- /* Note: must behave like a no-op with NULL and any pointer
- * returned from malloc/realloc with zero size.
- */
- heap->free_func(heap->heap_udata, ptr);
-}
-#endif
-#line 1 "duk_heap_misc.c"
+/* automatic undefs */
+#undef DUK__VOLUNTARY_PERIODIC_GC
/*
* Support functions for duk_heap.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
+ duk_heaphdr *root;
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
-/* arbitrary remove only works with double linked heap, and is only required by
- * reference counting so far.
- */
-DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
- if (DUK_HEAPHDR_GET_PREV(heap, hdr)) {
- DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr));
+ root = heap->heap_allocated;
+#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
+ if (root != NULL) {
+ DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
+ DUK_HEAPHDR_SET_PREV(heap, root, hdr);
+ }
+ DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
+#endif
+ DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
+ DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
+ DUK_ASSERT_HEAPHDR_LINKS(heap, root);
+ heap->heap_allocated = hdr;
+}
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
+ duk_heaphdr *prev;
+ duk_heaphdr *next;
+
+ /* Strings are in string table. */
+ DUK_ASSERT(hdr != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
+
+ /* Target 'hdr' must be in heap_allocated (not e.g. finalize_list).
+ * If not, heap lists will become corrupted so assert early for it.
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_heaphdr *tmp;
+ for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) {
+ if (tmp == hdr) {
+ break;
+ }
+ }
+ DUK_ASSERT(tmp == hdr);
+ }
+#endif
+
+ /* Read/write only once to minimize pointer compression calls. */
+ prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
+ next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
+
+ if (prev != NULL) {
+ DUK_ASSERT(heap->heap_allocated != hdr);
+ DUK_HEAPHDR_SET_NEXT(heap, prev, next);
} else {
- heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr);
+ DUK_ASSERT(heap->heap_allocated == hdr);
+ heap->heap_allocated = next;
}
- if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) {
- DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr));
+ if (next != NULL) {
+ DUK_HEAPHDR_SET_PREV(heap, next, prev);
} else {
;
}
-
- /* The prev/next pointers of the removed duk_heaphdr are left as garbage.
- * It's up to the caller to ensure they're written before inserting the
- * object back.
- */
}
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
+ duk_heaphdr *root;
+
+ root = heap->finalize_list;
+#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
+ DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
+ if (root != NULL) {
+ DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
+ DUK_HEAPHDR_SET_PREV(heap, root, hdr);
+ }
#endif
+ DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
+ DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
+ DUK_ASSERT_HEAPHDR_LINKS(heap, root);
+ heap->finalize_list = hdr;
+}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
-DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
+#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
+ duk_heaphdr *next;
+ duk_heaphdr *prev;
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
- if (heap->heap_allocated) {
- DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL);
- DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr);
+ next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
+ prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
+ if (next != NULL) {
+ DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr);
+ DUK_HEAPHDR_SET_PREV(heap, next, prev);
+ }
+ if (prev == NULL) {
+ DUK_ASSERT(hdr == heap->finalize_list);
+ heap->finalize_list = next;
+ } else {
+ DUK_ASSERT(hdr != heap->finalize_list);
+ DUK_HEAPHDR_SET_NEXT(heap, prev, next);
+ }
+#else
+ duk_heaphdr *next;
+ duk_heaphdr *curr;
+
+ /* Random removal is expensive: we need to locate the previous element
+ * because we don't have a 'prev' pointer.
+ */
+ curr = heap->finalize_list;
+ if (curr == hdr) {
+ heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr);
+ } else {
+ DUK_ASSERT(hdr != heap->finalize_list);
+ for (;;) {
+ DUK_ASSERT(curr != NULL); /* Caller responsibility. */
+
+ next = DUK_HEAPHDR_GET_NEXT(heap, curr);
+ if (next == hdr) {
+ next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
+ DUK_HEAPHDR_SET_NEXT(heap, curr, next);
+ break;
+ }
+ }
}
- DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
#endif
- DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated);
- heap->heap_allocated = hdr;
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+#if defined(DUK_USE_ASSERTIONS)
+DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) {
+ duk_heaphdr *curr;
+ DUK_ASSERT(heap != NULL);
+
+ for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
+ if (curr == ptr) {
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif /* DUK_USE_ASSERTIONS */
-#ifdef DUK_USE_INTERRUPT_COUNTER
+#if defined(DUK_USE_INTERRUPT_COUNTER)
DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
duk_hthread *curr_thr;
@@ -43916,50 +49691,23 @@ DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
heap->curr_thread = new_thr; /* may be NULL */
}
#endif /* DUK_USE_INTERRUPT_COUNTER */
-#line 1 "duk_heap_refcount.c"
/*
* Reference counting implementation.
+ *
+ * INCREF/DECREF, finalization and freeing of objects whose refcount reaches
+ * zero (refzero). These operations are very performance sensitive, so
+ * various small tricks are used in an attempt to maximize speed.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
-#ifndef DUK_USE_DOUBLE_LINKED_HEAP
+#if !defined(DUK_USE_DOUBLE_LINKED_HEAP)
#error internal error, reference counting requires a double linked heap
#endif
/*
- * Misc
- */
-
-DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
- /* tail insert: don't disturb head in case refzero is running */
-
- if (heap->refzero_list != NULL) {
- duk_heaphdr *hdr_prev;
-
- hdr_prev = heap->refzero_list_tail;
- DUK_ASSERT(hdr_prev != NULL);
- DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL);
-
- DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
- DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev);
- DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev);
- heap->refzero_list_tail = hdr;
- } else {
- DUK_ASSERT(heap->refzero_list_tail == NULL);
- DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
- DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
- heap->refzero_list = hdr;
- heap->refzero_list_tail = hdr;
- }
-}
-
-/*
* Heap object refcount finalization.
*
* When an object is about to be freed, all other objects it refers to must
@@ -43967,447 +49715,654 @@ DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
* allocations (mark-and-sweep shares these helpers), it just manipulates
* the refcounts.
*
- * Note that any of the decref's may cause a refcount to drop to zero, BUT
- * it will not be processed inline; instead, because refzero is already
- * running, the objects will just be queued to refzero list and processed
- * later. This eliminates C recursion.
+ * Note that any of the DECREFs may cause a refcount to drop to zero. If so,
+ * the object won't be refzero processed inline, but will just be queued to
+ * refzero_list and processed by an earlier caller working on refzero_list,
+ * eliminating C recursion from even long refzero cascades. If refzero
+ * finalization is triggered by mark-and-sweep, refzero conditions are ignored
+ * (objects are not even queued to refzero_list) because mark-and-sweep deals
+ * with them; refcounts are still updated so that they remain in sync with
+ * actual references.
*/
-DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
+DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) {
+ DUK_ASSERT(count == 0 || tv != NULL);
+
+ while (count-- > 0) {
+ DUK_TVAL_DECREF_NORZ(thr, tv);
+ tv++;
+ }
+}
+
+DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) {
+ duk_hthread *thr;
duk_uint_fast32_t i;
+ duk_uint_fast32_t n;
+ duk_propvalue *p_val;
+ duk_tval *p_tv;
+ duk_hstring **p_key;
+ duk_uint8_t *p_flag;
+ duk_hobject *h_proto;
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(h);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
- /* XXX: better to get base and walk forwards? */
+ thr = heap->heap_thread;
+ DUK_ASSERT(thr != NULL);
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
- duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
- if (!key) {
+ p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h);
+ p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h);
+ p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h);
+ n = DUK_HOBJECT_GET_ENEXT(h);
+ while (n-- > 0) {
+ duk_hstring *key;
+
+ key = p_key[n];
+ if (DUK_UNLIKELY(key == NULL)) {
continue;
}
- duk_heaphdr_decref(thr, (duk_heaphdr *) key);
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i));
+ DUK_HSTRING_DECREF_NORZ(thr, key);
+ if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) {
+ duk_hobject *h_getset;
+ h_getset = p_val[n].a.get;
+ DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
+ h_getset = p_val[n].a.set;
+ DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
} else {
- duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
+ duk_tval *tv_val;
+ tv_val = &p_val[n].v;
+ DUK_TVAL_DECREF_NORZ(thr, tv_val);
}
}
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
- duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i));
+ p_tv = DUK_HOBJECT_A_GET_BASE(heap, h);
+ n = DUK_HOBJECT_GET_ASIZE(h);
+ while (n-- > 0) {
+ duk_tval *tv_val;
+ tv_val = p_tv + n;
+ DUK_TVAL_DECREF_NORZ(thr, tv_val);
}
- /* hash part is a 'weak reference' and does not contribute */
+ /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */
+
+ h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h);
+ DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto));
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto);
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));
+ /* XXX: Object subclass tests are quite awkward at present, ideally
+ * we should be able to switch-case here with a dense index (subtype
+ * number or something). For now, fast path plain objects and arrays
+ * and bit test the rest individually.
+ */
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
+ if (DUK_HOBJECT_HAS_FASTREFS(h)) {
+ /* Plain object or array, nothing more to do. While a
+ * duk_harray has additional fields, none of them need
+ * DECREF updates.
+ */
+ DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
+ return;
+ }
+ DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
+
+ /* Slow path: special object, start bit checks from most likely. */
+
+ /* XXX: reorg, more common first */
+ if (DUK_HOBJECT_IS_COMPFUNC(h)) {
+ duk_hcompfunc *f = (duk_hcompfunc *) h;
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
- if (DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL) {
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
+ DUK_ASSERT_HCOMPFUNC_VALID(f);
+
+ if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) {
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
+ tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
while (tv < tv_end) {
- duk_tval_decref(thr, tv);
+ DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
+ funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
+ funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
while (funcs < funcs_end) {
- duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
+ duk_hobject *h_func;
+ h_func = *funcs;
+ DUK_ASSERT(h_func != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func));
+ DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func);
funcs++;
}
} else {
/* May happen in some out-of-memory corner cases. */
- DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping decref"));
- }
-
- duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK_UNREF(f);
- /* nothing to finalize */
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
- if (b->buf) {
- duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf);
- }
+ DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref"));
+ }
+
+ DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
+ DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
+ DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f));
+ } else if (DUK_HOBJECT_IS_DECENV(h)) {
+ duk_hdecenv *e = (duk_hdecenv *) h;
+ DUK_ASSERT_HDECENV_VALID(e);
+ DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap);
+ } else if (DUK_HOBJECT_IS_OBJENV(h)) {
+ duk_hobjenv *e = (duk_hobjenv *) h;
+ DUK_ASSERT_HOBJENV_VALID(e);
+ DUK_ASSERT(e->target != NULL); /* Required for object environments. */
+ DUK_HOBJECT_DECREF_NORZ(thr, e->target);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ duk_hbufobj *b = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(b);
+ DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+ DUK_ASSERT_HBOUNDFUNC_VALID(f);
+ DUK_TVAL_DECREF_NORZ(thr, &f->target);
+ DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
+ duk__decref_tvals_norz(thr, f->args, f->nargs);
+#if defined(DUK_USE_ES6_PROXY)
+ } else if (DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK_ASSERT_HPROXY_VALID(p);
+ DUK_HOBJECT_DECREF_NORZ(thr, p->target);
+ DUK_HOBJECT_DECREF_NORZ(thr, p->handler);
+#endif /* DUK_USE_ES6_PROXY */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
duk_tval *tv;
+ DUK_ASSERT_HTHREAD_VALID(t);
+
tv = t->valstack;
while (tv < t->valstack_top) {
- duk_tval_decref(thr, tv);
+ DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env);
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env);
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
+ for (act = t->callstack_curr; act != NULL; act = act->parent) {
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
#endif
- }
-
#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ }
#endif
-
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
}
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
- }
-}
-DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
- DUK_ASSERT(hdr);
+ for (i = 0; i < DUK_NUM_BUILTINS; i++) {
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
+ }
- switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_OBJECT:
- duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
- break;
- case DUK_HTYPE_BUFFER:
- /* nothing to finalize */
- break;
- case DUK_HTYPE_STRING:
- /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */
- default:
- DUK_UNREACHABLE();
+ DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer);
+ } else {
+ /* We may come here if the object should have a FASTREFS flag
+ * but it's missing for some reason. Assert for never getting
+ * here; however, other than performance, this is harmless.
+ */
+ DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
+ DUK_ASSERT(0);
}
}
-#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
-DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
- DUK_UNREF(ctx);
- DUK_D(DUK_DPRINT("fake refcount torture finalizer executed"));
-#if 0
- DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0)));
-#endif
- /* Require a lot of stack to force a value stack grow/shrink. */
- duk_require_stack(ctx, 100000);
-
- /* XXX: do something to force a callstack grow/shrink, perhaps
- * just a manual forced resize?
- */
- return 0;
-}
-
-DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx;
- duk_int_t rc;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) {
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(hdr != NULL);
- /* Avoid fake finalization for the duk__refcount_fake_finalizer function
- * itself, otherwise we're in infinite recursion.
- */
- if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
- if (((duk_hnativefunction *) obj)->func == duk__refcount_fake_finalizer) {
- DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself"));
- return;
- }
+ if (DUK_HEAPHDR_IS_OBJECT(hdr)) {
+ duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr);
}
- /* Avoid fake finalization when callstack limit has been reached.
- * Otherwise a callstack limit error will be created, then refzero'ed,
- * and we're in an infinite loop.
- */
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
- thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
- DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer"));
- return;
- }
-
- /* Run fake finalizer. Avoid creating new refzero queue entries
- * so that we are not forced into a forever loop.
- */
- duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/);
- duk_push_hobject(ctx, obj);
- rc = duk_pcall(ctx, 1);
- DUK_UNREF(rc); /* ignored */
- duk_pop(ctx);
+ /* DUK_HTYPE_BUFFER: nothing to finalize */
+ /* DUK_HTYPE_STRING: nothing to finalize */
}
-#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
/*
- * Refcount memory freeing loop.
+ * Refzero processing for duk_hobject: queue a refzero'ed object to either
+ * finalize_list or refzero_list and process the relevent list(s) if
+ * necessary.
+ *
+ * Refzero_list is single linked, with only 'prev' pointers set and valid.
+ * All 'next' pointers are intentionally left as garbage. This doesn't
+ * matter because refzero_list is processed to completion before any other
+ * code (like mark-and-sweep) might walk the list.
+ *
+ * In more detail:
+ *
+ * - On first insert refzero_list is NULL and the new object becomes the
+ * first and only element on the list; duk__refcount_free_pending() is
+ * called and it starts processing the list from the initial element,
+ * i.e. the list tail.
*
- * Frees objects in the refzero_pending list until the list becomes
- * empty. When an object is freed, its references get decref'd and
- * may cause further objects to be queued for freeing.
+ * - As each object is refcount finalized, new objects may be queued to
+ * refzero_list head. Their 'next' pointers are left as garbage, but
+ * 'prev' points are set correctly, with the element at refzero_list
+ * having a NULL 'prev' pointer. The fact that refzero_list is non-NULL
+ * is used to reject (1) recursive duk__refcount_free_pending() and
+ * (2) finalize_list processing calls.
+ *
+ * - When we're done with the current object, read its 'prev' pointer and
+ * free the object. If 'prev' is NULL, we've reached head of list and are
+ * done: set refzero_list to NULL and process pending finalizers. Otherwise
+ * continue processing the list.
+ *
+ * A refzero cascade is free of side effects because it only involves
+ * queueing more objects and freeing memory; finalizer execution is blocked
+ * in the code path queueing objects to finalize_list. As a result the
+ * initial refzero call (which triggers duk__refcount_free_pending()) must
+ * check finalize_list so that finalizers are executed snappily.
+ *
+ * If finalize_list processing starts first, refzero may occur while we're
+ * processing finalizers. That's fine: that particular refzero cascade is
+ * handled to completion without side effects. Once the cascade is complete,
+ * we'll run pending finalizers but notice that we're already doing that and
+ * return.
*
* This could be expanded to allow incremental freeing: just bail out
- * early and resume at a future alloc/decref/refzero.
+ * early and resume at a future alloc/decref/refzero. However, if that
+ * were done, the list structure would need to be kept consistent at all
+ * times, mark-and-sweep would need to handle refzero_list, etc.
*/
-DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
- duk_heaphdr *h1, *h2;
- duk_heap *heap;
+DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) {
+ duk_heaphdr *curr;
+#if defined(DUK_USE_DEBUG)
duk_int_t count = 0;
+#endif
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- heap = thr->heap;
DUK_ASSERT(heap != NULL);
- /*
- * Detect recursive invocation
- */
+ curr = heap->refzero_list;
+ DUK_ASSERT(curr != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL); /* We're called on initial insert only. */
+ /* curr->next is GARBAGE. */
- if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
- DUK_DDD(DUK_DDDPRINT("refzero free running, skip run"));
- return;
- }
+ do {
+ duk_heaphdr *prev;
- /*
- * Churn refzero_list until empty
- */
+ DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr));
- DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
- while (heap->refzero_list) {
- duk_hobject *obj;
- duk_bool_t rescued = 0;
+#if defined(DUK_USE_DEBUG)
+ count++;
+#endif
- /*
- * Pick an object from the head (don't remove yet).
+ DUK_ASSERT(curr != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
+ /* FINALIZED may be set; don't care about flags here. */
+
+ /* Refcount finalize 'curr'. Refzero_list must be non-NULL
+ * here to prevent recursive entry to duk__refcount_free_pending().
*/
+ DUK_ASSERT(heap->refzero_list != NULL);
+ duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
- h1 = heap->refzero_list;
- obj = (duk_hobject *) h1;
- DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1));
- DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL);
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
+ prev = DUK_HEAPHDR_GET_PREV(heap, curr);
+ DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \
+ (prev != NULL && heap->refzero_list != curr));
+ /* prev->next is intentionally not updated and is garbage. */
-#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
- /* Torture option to shake out finalizer side effect issues:
- * make a bogus function call for every finalizable object,
- * essentially simulating the case where everything has a
- * finalizer.
- */
- DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer"));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
- duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */
- DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
- DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
-#endif
+ duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */
- /*
- * Finalizer check.
- *
- * Note: running a finalizer may have arbitrary side effects, e.g.
- * queue more objects on refzero_list (tail), or even trigger a
- * mark-and-sweep.
- *
- * Note: quick reject check should match vast majority of
- * objects and must be safe (not throw any errors, ever).
- */
+ curr = prev;
+ } while (curr != NULL);
- /* An object may have FINALIZED here if it was finalized by mark-and-sweep
- * on a previous run and refcount then decreased to zero. We won't run the
- * finalizer again here.
- */
+ heap->refzero_list = NULL;
- /* A finalizer is looked up from the object and up its prototype chain
- * (which allows inherited finalizers).
- */
- if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
- DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
+ DUK_DD(DUK_DDPRINT("refzero processed %ld objects", (long) count));
+}
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
+DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) {
+ duk_heaphdr *hdr;
+ duk_heaphdr *root;
- duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(obj != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT);
- DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
- DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
+ hdr = (duk_heaphdr *) obj;
- if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) {
- DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued"));
- rescued = 1;
- } else {
- DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
- }
- }
+ /* Refzero'd objects must be in heap_allocated. They can't be in
+ * finalize_list because all objects on finalize_list have an
+ * artificial +1 refcount bump.
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj));
+#endif
- /* Refzero head is still the same. This is the case even if finalizer
- * inserted more refzero objects; they are inserted to the tail.
- */
- DUK_ASSERT(h1 == heap->refzero_list);
+ DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr);
- /*
- * Remove the object from the refzero list. This cannot be done
- * before a possible finalizer has been executed; the finalizer
- * may trigger a mark-and-sweep, and mark-and-sweep must be able
- * to traverse a complete refzero_list.
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ /* This finalizer check MUST BE side effect free. It should also be
+ * as fast as possible because it's applied to every object freed.
+ */
+ if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) {
+ /* Special case: FINALIZED may be set if mark-and-sweep queued
+ * object for finalization, the finalizer was executed (and
+ * FINALIZED set), mark-and-sweep hasn't yet processed the
+ * object again, but its refcount drops to zero. Free without
+ * running the finalizer again.
*/
-
- h2 = DUK_HEAPHDR_GET_NEXT(heap, h1);
- if (h2) {
- DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */
- heap->refzero_list = h2;
+ if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
+ DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free"));
} else {
- heap->refzero_list = NULL;
- heap->refzero_list_tail = NULL;
+ /* Set FINALIZABLE flag so that all objects on finalize_list
+ * will have it set and are thus detectable based on the
+ * flag alone.
+ */
+ DUK_HEAPHDR_SET_FINALIZABLE(hdr);
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Bump refcount on finalize_list insert so that a
+ * refzero can never occur when an object is waiting
+ * for its finalizer call. Refzero might otherwise
+ * now happen because we allow duk_push_heapptr() for
+ * objects pending finalization.
+ */
+ DUK_HEAPHDR_PREINC_REFCOUNT(hdr);
+#endif
+ DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr);
+
+ /* Process finalizers unless skipping is explicitly
+ * requested (NORZ) or refzero_list is being processed
+ * (avoids side effects during a refzero cascade).
+ * If refzero_list is processed, the initial refzero
+ * call will run pending finalizers when refzero_list
+ * is done.
+ */
+ if (!skip_free_pending && heap->refzero_list == NULL) {
+ duk_heap_process_finalize_list(heap);
+ }
+ return;
}
+ }
+#endif /* DUK_USE_FINALIZER_SUPPORT */
- /*
- * Rescue or free.
- */
-
- if (rescued) {
- /* yes -> move back to heap allocated */
- DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
- DUK_HEAPHDR_CLEAR_FINALIZED(h1);
- h2 = heap->heap_allocated;
- DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
- if (h2) {
- DUK_HEAPHDR_SET_PREV(heap, h2, h1);
- }
- DUK_HEAPHDR_SET_NEXT(heap, h1, h2);
- DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
- DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
- heap->heap_allocated = h1;
- } else {
- /* no -> decref members, then free */
- duk__refcount_finalize_hobject(thr, obj);
- duk_heap_free_heaphdr_raw(heap, h1);
+ /* No need to finalize, free object via refzero_list. */
+
+ root = heap->refzero_list;
+
+ DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
+ /* 'next' is left as GARBAGE. */
+ heap->refzero_list = hdr;
+
+ if (root == NULL) {
+ /* Object is now queued. Refzero_list was NULL so
+ * no-one is currently processing it; do it here.
+ * With refzero processing just doing a cascade of
+ * free calls, we can process it directly even when
+ * NORZ macros are used: there are no side effects.
+ */
+ duk__refcount_free_pending(heap);
+ DUK_ASSERT(heap->refzero_list == NULL);
+
+ /* Process finalizers only after the entire cascade
+ * is finished. In most cases there's nothing to
+ * finalize, so fast path check to avoid a call.
+ */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) {
+ duk_heap_process_finalize_list(heap);
}
+#endif
+ } else {
+ DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
+ DUK_HEAPHDR_SET_PREV(heap, root, hdr);
- count++;
+ /* Object is now queued. Because refzero_list was
+ * non-NULL, it's already being processed by someone
+ * in the C call stack, so we're done.
+ */
}
- DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
+}
- DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count));
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
- /*
- * Once the whole refzero cascade has been freed, check for
- * a voluntary mark-and-sweep.
- */
+ if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
+ duk_heap_process_finalize_list(thr->heap);
+ }
+}
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
- /* 'count' is more or less comparable to normal trigger counter update
- * which happens in memory block (re)allocation.
- */
- heap->mark_and_sweep_trigger_counter -= count;
- if (heap->mark_and_sweep_trigger_counter <= 0) {
- duk_bool_t rc;
- duk_small_uint_t flags = 0; /* not emergency */
- DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep"));
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
- DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc));
+DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
+
+ if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
+ duk_heap_process_finalize_list(thr->heap);
}
-#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
+}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+/*
+ * Refzero processing for duk_hstring.
+ */
+
+DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) {
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(str != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING);
+
+ duk_heap_strcache_string_remove(heap, str);
+ duk_heap_strtable_unlink(heap, str);
+ duk_free_hstring(heap, str);
+}
+
+/*
+ * Refzero processing for duk_hbuffer.
+ */
+
+DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) {
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->heap_thread != NULL);
+ DUK_ASSERT(buf != NULL);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER);
+
+ DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf);
+ duk_free_hbuffer(heap, buf);
}
/*
* Incref and decref functions.
*
* Decref may trigger immediate refzero handling, which may free and finalize
- * an arbitrary number of objects.
- *
- */
+ * an arbitrary number of objects (a "DECREF cascade").
+ *
+ * Refzero handling is skipped entirely if (1) mark-and-sweep is running or
+ * (2) execution is paused in the debugger. The objects are left in the heap,
+ * and will be freed by mark-and-sweep or eventual heap destruction.
+ *
+ * This is necessary during mark-and-sweep because refcounts are also updated
+ * during the sweep phase (otherwise objects referenced by a swept object
+ * would have incorrect refcounts) which then calls here. This could be
+ * avoided by using separate decref macros in mark-and-sweep; however,
+ * mark-and-sweep also calls finalizers which would use the ordinary decref
+ * macros anyway.
+ *
+ * We can't process refzeros (= free objects) when the debugger is running
+ * as the debugger might make an object unreachable but still continue
+ * inspecting it (or even cause it to be pushed back). So we must rely on
+ * mark-and-sweep to collect them.
+ *
+ * The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction
+ * when running finalizers for remaining objects: the flag prevents objects
+ * from being moved around in heap linked lists while that's being done.
+ *
+ * The suppress condition is important to performance.
+ */
+
+#define DUK__RZ_SUPPRESS_ASSERT1() do { \
+ DUK_ASSERT(thr != NULL); \
+ DUK_ASSERT(thr->heap != NULL); \
+ /* When mark-and-sweep runs, heap_thread must exist. */ \
+ DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \
+ /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \
+ * This could be used to e.g. suppress check against 'thr' directly (and \
+ * knowing it would be heap_thread); not really used now. \
+ */ \
+ DUK_ASSERT(thr->heap->ms_running == 0 || thr == thr->heap->heap_thread); \
+ /* We may be called when the heap is initializing and we process \
+ * refzeros normally, but mark-and-sweep and finalizers are prevented \
+ * if that's the case. \
+ */ \
+ DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \
+ DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \
+ } while (0)
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+#define DUK__RZ_SUPPRESS_ASSERT2() do { \
+ /* When debugger is paused, ms_running is set. */ \
+ DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \
+ } while (0)
+#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
+#else
+#define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0)
+#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
+#define DUK__RZ_SUPPRESS_CHECK() do { \
+ DUK__RZ_SUPPRESS_ASSERT1(); \
+ DUK__RZ_SUPPRESS_ASSERT2(); \
+ if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \
+ DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \
+ return; \
+ } \
+ } while (0)
+
+#define DUK__RZ_STRING() do { \
+ duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \
+ } while (0)
+#define DUK__RZ_BUFFER() do { \
+ duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \
+ } while (0)
+#define DUK__RZ_OBJECT() do { \
+ duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \
+ } while (0)
+
+/* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */
+#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+#define DUK__RZ_INLINE DUK_ALWAYS_INLINE
+#else
+#define DUK__RZ_INLINE /*nop*/
+#endif
+
+DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) {
duk_heap *heap;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
+ heap = thr->heap;
+ DUK__RZ_SUPPRESS_CHECK();
+ DUK__RZ_STRING();
+}
+
+DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) {
+ duk_heap *heap;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(h != NULL);
heap = thr->heap;
- DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
- /*
- * Refzero handling is skipped entirely if (1) mark-and-sweep is
- * running or (2) execution is paused in the debugger. The objects
- * are left in the heap, and will be freed by mark-and-sweep or
- * eventual heap destruction.
- *
- * This is necessary during mark-and-sweep because refcounts are also
- * updated during the sweep phase (otherwise objects referenced by a
- * swept object would have incorrect refcounts) which then calls here.
- * This could be avoided by using separate decref macros in
- * mark-and-sweep; however, mark-and-sweep also calls finalizers which
- * would use the ordinary decref macros anyway and still call this
- * function.
- *
- * This check must be enabled also when mark-and-sweep support has been
- * disabled: the flag is also used in heap destruction when running
- * finalizers for remaining objects, and the flag prevents objects from
- * being moved around in heap linked lists.
- */
+ DUK__RZ_SUPPRESS_CHECK();
+ DUK__RZ_BUFFER();
+}
- /* XXX: ideally this would be just one flag (maybe a derived one) so
- * that a single bit test is sufficient to check the condition.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))) {
-#else
- if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) {
-#endif
- DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h));
- return;
- }
+DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) {
+ duk_heap *heap;
- switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(h != NULL);
+ heap = thr->heap;
+
+ DUK__RZ_SUPPRESS_CHECK();
+ DUK__RZ_OBJECT();
+}
+
+DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) {
+ duk_heap *heap;
+ duk_small_uint_t htype;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(h != NULL);
+ heap = thr->heap;
+
+ htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h);
+ DUK__RZ_SUPPRESS_CHECK();
+
+ switch (htype) {
case DUK_HTYPE_STRING:
- /*
- * Strings have no internal references but do have "weak"
- * references in the string cache. Also note that strings
- * are not on the heap_allocated list like other heap
- * elements.
+ /* Strings have no internal references but do have "weak"
+ * references in the string cache. Also note that strings
+ * are not on the heap_allocated list like other heap
+ * elements.
*/
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- duk_heap_string_remove(heap, (duk_hstring *) h);
- duk_heap_free_heaphdr_raw(heap, h);
+ DUK__RZ_STRING();
break;
case DUK_HTYPE_OBJECT:
- /*
- * Objects have internal references. Must finalize through
- * the "refzero" work list.
+ /* Objects have internal references. Must finalize through
+ * the "refzero" work list.
*/
- duk_heap_remove_any_from_heap_allocated(heap, h);
- duk__queue_refzero(heap, h);
- duk__refzero_free_pending(thr);
+ DUK__RZ_OBJECT();
break;
- case DUK_HTYPE_BUFFER:
- /*
- * Buffers have no internal references. However, a dynamic
- * buffer has a separate allocation for the buffer. This is
- * freed by duk_heap_free_heaphdr_raw().
+ default:
+ /* Buffers have no internal references. However, a dynamic
+ * buffer has a separate allocation for the buffer. This is
+ * freed by duk_heap_free_heaphdr_raw().
*/
- duk_heap_remove_any_from_heap_allocated(heap, h);
- duk_heap_free_heaphdr_raw(heap, h);
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER);
+ DUK__RZ_BUFFER();
break;
-
- default:
- DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h)));
- DUK_UNREACHABLE();
}
}
+DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
+ duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/);
+}
+
+DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) {
+ duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/);
+}
+
+DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) {
+ duk__hstring_refzero_helper(thr, h);
+}
+
+DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) {
+ duk__hbuffer_refzero_helper(thr, h);
+}
+
+DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) {
+ duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/);
+}
+
+DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) {
+ duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/);
+}
+
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
DUK_ASSERT(tv != NULL);
@@ -44418,24 +50373,9 @@ DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(h->h_refcount >= 0);
DUK_HEAPHDR_PREINC_REFCOUNT(h);
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0); /* No wrapping. */
}
}
-#endif
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_tval_incref_allownull(duk_tval *tv) {
- if (tv == NULL) {
- return;
- }
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(h->h_refcount >= 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
- }
-}
-#endif
DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
DUK_ASSERT(thr != NULL);
@@ -44445,93 +50385,154 @@ DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
+#if 0
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
+ return;
+ }
+ duk_heaphdr_refzero(thr, h);
+#else
duk_heaphdr_decref(thr, h);
+#endif
}
}
-#if 0 /* unused */
-DUK_INTERNAL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv) {
+DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) {
DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(tv != NULL);
- if (tv == NULL) {
- return;
- }
if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- duk_heaphdr_decref(thr, h);
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
+#if 0
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
+ return;
+ }
+ duk_heaphdr_refzero_norz(thr, h);
+#else
+ duk_heaphdr_decref_norz(thr, h);
+#endif
}
}
+#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
+
+#define DUK__DECREF_ASSERTS() do { \
+ DUK_ASSERT(thr != NULL); \
+ DUK_ASSERT(thr->heap != NULL); \
+ DUK_ASSERT(h != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \
+ } while (0)
+#if defined(DUK_USE_ROM_OBJECTS)
+#define DUK__INCREF_SHARED() do { \
+ if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
+ return; \
+ } \
+ DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
+ } while (0)
+#define DUK__DECREF_SHARED() do { \
+ if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
+ return; \
+ } \
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
+ return; \
+ } \
+ } while (0)
+#else
+#define DUK__INCREF_SHARED() do { \
+ DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
+ } while (0)
+#define DUK__DECREF_SHARED() do { \
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
+ return; \
+ } \
+ } while (0)
#endif
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+/* This will in practice be inlined because it's just an INC instructions
+ * and a bit test + INC when ROM objects are enabled.
+ */
DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
+ DUK__INCREF_SHARED();
}
-#endif
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_heaphdr_incref_allownull(duk_heaphdr *h) {
- if (h == NULL) {
- return;
- }
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
-
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
-}
-#endif
DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- return;
- }
-#endif
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
- return;
- }
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
duk_heaphdr_refzero(thr, h);
-}
-
-DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- if (h == NULL) {
- return;
- }
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
+ /* Forced mark-and-sweep when GC torture enabled; this could happen
+ * on any DECREF (but not DECREF_NORZ).
+ */
+ DUK_GC_TORTURE(thr->heap);
+}
+DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_heaphdr_refzero_norz(thr, h);
+}
+#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- return;
- }
-#endif
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
- return;
- }
- duk_heaphdr_refzero(thr, h);
+#if 0 /* Not needed. */
+DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hstring_refzero(thr, h);
}
+DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hstring_refzero_norz(thr, h);
+}
+DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hbuffer_refzero(thr, h);
+}
+DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hbuffer_refzero_norz(thr, h);
+}
+DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hobject_refzero(thr, h);
+}
+DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
+ DUK__DECREF_ASSERTS();
+ DUK__DECREF_SHARED();
+ duk_hobject_refzero_norz(thr, h);
+}
+#endif
-#else
+#else /* DUK_USE_REFERENCE_COUNTING */
/* no refcounting */
#endif /* DUK_USE_REFERENCE_COUNTING */
-#line 1 "duk_heap_stringcache.c"
+
+/* automatic undefs */
+#undef DUK__DECREF_ASSERTS
+#undef DUK__DECREF_SHARED
+#undef DUK__INCREF_SHARED
+#undef DUK__RZ_BUFFER
+#undef DUK__RZ_INLINE
+#undef DUK__RZ_OBJECT
+#undef DUK__RZ_STRING
+#undef DUK__RZ_SUPPRESS_ASSERT1
+#undef DUK__RZ_SUPPRESS_ASSERT2
+#undef DUK__RZ_SUPPRESS_CHECK
+#undef DUK__RZ_SUPPRESS_COND
/*
* String cache.
*
@@ -44541,7 +50542,7 @@ DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h)
* strings in (extended) UTF-8.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Delete references to given hstring from the heap string cache.
@@ -44618,6 +50619,10 @@ DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk
*
* Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
* Better typing might be to use duk_size_t.
+ *
+ * Caller should ensure 'char_offset' is within the string bounds [0,charlen]
+ * (endpoint is inclusive). If this is not the case, no memory unsafe
+ * behavior will happen but an error will be thrown.
*/
DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
@@ -44627,20 +50632,27 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
duk_small_int_t i;
duk_bool_t use_cache;
duk_uint_fast32_t dist_start, dist_end, dist_sce;
+ duk_uint_fast32_t char_length;
const duk_uint8_t *p_start;
const duk_uint8_t *p_end;
const duk_uint8_t *p_found;
- if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
- goto error;
- }
-
/*
* For ASCII strings, the answer is simple.
*/
- if (DUK_HSTRING_IS_ASCII(h)) {
- /* clen == blen -> pure ascii */
+ if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
+ return char_offset;
+ }
+
+ char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h);
+ DUK_ASSERT(char_offset <= char_length);
+
+ if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
+ /* Must recheck because the 'is ascii' flag may be set
+ * lazily. Alternatively, we could just compare charlen
+ * to bytelen.
+ */
return char_offset;
}
@@ -44662,10 +50674,10 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
heap = thr->heap;
sce = NULL;
- use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
+ use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
if (use_cache) {
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
@@ -44693,7 +50705,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
dist_start = char_offset;
- dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
+ dist_end = char_length - char_offset;
dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
@@ -44766,12 +50778,12 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
scan_done:
- if (!p_found) {
+ if (DUK_UNLIKELY(p_found == NULL)) {
/* Scan error: this shouldn't normally happen; it could happen if
* string is not valid UTF-8 data, and clen/blen are not consistent
* with the scanning algorithm.
*/
- goto error;
+ goto scan_error;
}
DUK_ASSERT(p_found >= p_start);
@@ -44814,7 +50826,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
/* 'sce' points to the wrong entry here, but is no longer used */
}
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
@@ -44826,65 +50838,176 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
return byte_offset;
- error:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ scan_error:
+ DUK_ERROR_INTERNAL(thr);
return 0;
}
-#line 1 "duk_heap_stringtable.c"
/*
- * Heap stringtable handling, string interning.
+ * Heap string table handling, string interning.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#if defined(DUK_USE_STRTAB_PROBE)
-#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size))
-#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash))
-#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap))
+/* Resize checks not needed if minsize == maxsize, typical for low memory
+ * targets.
+ */
+#define DUK__STRTAB_RESIZE_CHECK
+#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE)
+#undef DUK__STRTAB_RESIZE_CHECK
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
-#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \
- (heap)->mark_and_sweep_base_flags |= \
- DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \
- } while (0)
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr))
+#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val))
+#define DUK__GET_STRTABLE(heap) ((heap)->strtable16)
+#else
+#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr)
+#define DUK__HEAPPTR_DEC16(heap,val) (val)
+#define DUK__GET_STRTABLE(heap) ((heap)->strtable)
#endif
+#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
+
+/*
+ * Debug dump stringtable.
+ */
+
+#if defined(DUK_USE_DEBUG)
+DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *strtable;
+#else
+ duk_hstring **strtable;
+#endif
+ duk_uint32_t i;
+ duk_hstring *h;
+ duk_size_t count_total = 0;
+ duk_size_t count_chain;
+ duk_size_t count_chain_min = DUK_SIZE_MAX;
+ duk_size_t count_chain_max = 0;
+ duk_size_t count_len[8]; /* chain lengths from 0 to 7 */
+
+ if (heap == NULL) {
+ DUK_D(DUK_DPRINT("string table, heap=NULL"));
+ return;
+ }
+
+ strtable = DUK__GET_STRTABLE(heap);
+ if (strtable == NULL) {
+ DUK_D(DUK_DPRINT("string table, strtab=NULL"));
+ return;
+ }
+
+ DUK_MEMZERO((void *) count_len, sizeof(count_len));
+ for (i = 0; i < heap->st_size; i++) {
+ h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
+ count_chain = 0;
+ while (h != NULL) {
+ count_chain++;
+ h = h->hdr.h_next;
+ }
+ if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) {
+ count_len[count_chain]++;
+ }
+ count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max);
+ count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min);
+ count_total += count_chain;
+ }
+
+ DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: "
+ "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...",
+ (void *) heap->strtable, (unsigned long) count_total,
+ (unsigned long) count_chain_min, (unsigned long) count_chain_max,
+ (double) count_total / (double) heap->st_size,
+ (unsigned long) count_len[0], (unsigned long) count_len[1],
+ (unsigned long) count_len[2], (unsigned long) count_len[3],
+ (unsigned long) count_len[4], (unsigned long) count_len[5],
+ (unsigned long) count_len[6], (unsigned long) count_len[7]));
+}
+#endif /* DUK_USE_DEBUG */
+
/*
- * Create a hstring and insert into the heap. The created object
- * is directly garbage collectable with reference count zero.
+ * Assertion helper to ensure strtable is populated correctly.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *strtable;
+#else
+ duk_hstring **strtable;
+#endif
+ duk_uint32_t i;
+ duk_hstring *h;
+ duk_size_t count = 0;
+
+ DUK_ASSERT(heap != NULL);
+
+ strtable = DUK__GET_STRTABLE(heap);
+ if (strtable != NULL) {
+ DUK_ASSERT(heap->st_size != 0);
+ DUK_ASSERT(heap->st_mask == heap->st_size - 1);
+
+ for (i = 0; i < heap->st_size; i++) {
+ h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
+ while (h != NULL) {
+ DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
+ count++;
+ h = h->hdr.h_next;
+ }
+ }
+ } else {
+ DUK_ASSERT(heap->st_size == 0);
+ DUK_ASSERT(heap->st_mask == 0);
+ }
+
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+ DUK_ASSERT(count == (duk_size_t) heap->st_count);
+#endif
+}
+#endif /* DUK_USE_ASSERTIONS */
+
+/*
+ * Allocate and initialize a duk_hstring.
+ *
+ * Returns a NULL if allocation or initialization fails for some reason.
*
- * The caller must place the interned string into the stringtable
- * immediately (without chance of a longjmp); otherwise the string
- * is lost.
+ * The string won't be inserted into the string table and isn't tracked in
+ * any way (link pointers will be NULL). The caller must place the string
+ * into the string table without any risk of a longjmp, otherwise the string
+ * is leaked.
*/
-DUK_LOCAL
-duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
- const duk_uint8_t *str,
- duk_uint32_t blen,
- duk_uint32_t strhash,
- const duk_uint8_t *extdata) {
- duk_hstring *res = NULL;
- duk_uint8_t *data;
- duk_size_t alloc_size;
+DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
+ const duk_uint8_t *str,
+ duk_uint32_t blen,
+ duk_uint32_t strhash,
+ const duk_uint8_t *extdata) {
+ duk_hstring *res;
+ const duk_uint8_t *data;
+#if !defined(DUK_USE_HSTRING_ARRIDX)
duk_uarridx_t dummy;
- duk_uint32_t clen;
+#endif
+
+ DUK_ASSERT(heap != NULL);
+ DUK_UNREF(extdata);
#if defined(DUK_USE_STRLEN16)
/* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
if (blen > 0xffffUL) {
DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
- return NULL;
+ goto alloc_error;
}
#endif
+ /* XXX: Memzeroing the allocated structure is not really necessary
+ * because we could just initialize all fields explicitly (almost
+ * all fields are initialized explicitly anyway).
+ */
+#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
if (extdata) {
- alloc_size = (duk_size_t) sizeof(duk_hstring_external);
- res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
+ res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external));
+ if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
DUK_MEMZERO(res, sizeof(duk_hstring_external));
@@ -44893,12 +51016,18 @@ duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
#endif
DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
+ DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */
+ data = extdata;
((duk_hstring_external *) res)->extdata = extdata;
- } else {
+ } else
+#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */
+ {
+ duk_uint8_t *data_tmp;
+
/* NUL terminate for convenient C access */
- alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1);
- res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
+ DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */
+ res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1);
+ if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
DUK_MEMZERO(res, sizeof(duk_hstring));
@@ -44907,1112 +51036,801 @@ duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
#endif
DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
- data = (duk_uint8_t *) (res + 1);
- DUK_MEMCPY(data, str, blen);
- data[blen] = (duk_uint8_t) 0;
+ data_tmp = (duk_uint8_t *) (res + 1);
+ DUK_MEMCPY(data_tmp, str, blen);
+ data_tmp[blen] = (duk_uint8_t) 0;
+ data = (const duk_uint8_t *) data_tmp;
}
+ DUK_HSTRING_SET_BYTELEN(res, blen);
+ DUK_HSTRING_SET_HASH(res, strhash);
+
DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
- if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
+#if defined(DUK_USE_HSTRING_ARRIDX)
+ res->arridx = duk_js_to_arrayindex_string(data, blen);
+ if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) {
+#else
+ dummy = duk_js_to_arrayindex_string(data, blen);
+ if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) {
+#endif
+ /* Array index strings cannot be symbol strings,
+ * and they're always pure ASCII so blen == clen.
+ */
DUK_HSTRING_SET_ARRIDX(res);
- }
-
- /* All strings beginning with 0xff are treated as "internal",
- * even strings interned by the user. This allows user code to
- * create internal properties too, and makes behavior consistent
- * in case user code happens to use a string also used by Duktape
- * (such as string has already been interned and has the 'internal'
- * flag set).
- */
- DUK_ASSERT(!DUK_HSTRING_HAS_INTERNAL(res));
- if (blen > 0 && str[0] == (duk_uint8_t) 0xff) {
- DUK_HSTRING_SET_INTERNAL(res);
- }
+ DUK_HSTRING_SET_ASCII(res);
+ DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen);
+ } else {
+ /* Because 'data' is NUL-terminated, we don't need a
+ * blen > 0 check here. For NUL (0x00) the symbol
+ * checks will be false.
+ */
+ if (DUK_UNLIKELY(data[0] >= 0x80U)) {
+ if (data[0] <= 0x81) {
+ DUK_HSTRING_SET_SYMBOL(res);
+ } else if (data[0] == 0x82U || data[0] == 0xffU) {
+ DUK_HSTRING_SET_HIDDEN(res);
+ DUK_HSTRING_SET_SYMBOL(res);
+ }
+ }
- DUK_HSTRING_SET_HASH(res, strhash);
- DUK_HSTRING_SET_BYTELEN(res, blen);
+ /* Using an explicit 'ASCII' flag has larger footprint (one call site
+ * only) but is quite useful for the case when there's no explicit
+ * 'clen' in duk_hstring.
+ *
+ * The flag is set lazily for RAM strings.
+ */
+ DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
- clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);
- DUK_ASSERT(clen <= blen);
-#if defined(DUK_USE_HSTRING_CLEN)
- DUK_HSTRING_SET_CHARLEN(res, clen);
+#if defined(DUK_USE_HSTRING_LAZY_CLEN)
+ /* Charlen initialized to 0, updated on-the-fly. */
+#else
+ duk_hstring_init_charlen(res); /* Also sets ASCII flag. */
#endif
-
- /* Using an explicit 'ASCII' flag has larger footprint (one call site
- * only) but is quite useful for the case when there's no explicit
- * 'clen' in duk_hstring.
- */
- DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
- if (clen == blen) {
- DUK_HSTRING_SET_ASCII(res);
}
- DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld",
+ DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld",
(unsigned long) DUK_HSTRING_GET_HASH(res),
(long) DUK_HSTRING_GET_BYTELEN(res),
- (long) DUK_HSTRING_GET_CHARLEN(res),
(long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
(long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
+ DUK_ASSERT(res != NULL);
return res;
alloc_error:
- DUK_FREE(heap, res);
return NULL;
}
/*
- * String table algorithm: fixed size string table with array chaining
- *
- * The top level string table has a fixed size, with each slot holding
- * either NULL, string pointer, or pointer to a separately allocated
- * string pointer list.
- *
- * This is good for low memory environments using a pool allocator: the
- * top level allocation has a fixed size and the pointer lists have quite
- * small allocation size, which further matches the typical pool sizes
- * needed by objects, strings, property tables, etc.
+ * Grow strtable allocation in-place.
*/
-#if defined(DUK_USE_STRTAB_CHAIN)
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) {
+ duk_uint32_t new_st_size;
+ duk_uint32_t old_st_size;
+ duk_uint32_t i;
+ duk_hstring *h;
+ duk_hstring *next;
+ duk_hstring *prev;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *new_ptr;
+ duk_uint16_t *new_ptr_high;
+#else
+ duk_hstring **new_ptr;
+ duk_hstring **new_ptr_high;
+#endif
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_uint16_t *new_lst;
- duk_size_t i, n;
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
+ DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
+ DUK_ASSERT(heap->st_resizing == 1);
+ DUK_ASSERT(heap->st_size >= 2);
+ DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
+ DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
+ DUK_STATS_INC(heap, stats_strtab_resize_grow);
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 == null16) {
- e->u.str16 = h16;
- } else {
- /* Now two entries in the same slot, alloc list */
- lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
- if (lst == NULL) {
- return 1; /* fail */
- }
- lst[0] = e->u.str16;
- lst[1] = h16;
- e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
- e->listlen = 2;
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == null16) {
- lst[i] = h16;
- return 0;
- }
- }
+ new_st_size = heap->st_size << 1U;
+ DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */
- if (e->listlen + 1 == 0) {
- /* Overflow, relevant mainly when listlen is 16 bits. */
- return 1; /* fail */
- }
+ /* Reallocate the strtable first and then work in-place to rehash
+ * strings. We don't need an indirect allocation here: even if GC
+ * is triggered to satisfy the allocation, recursive strtable resize
+ * is prevented by flags. This is also why we don't need to use
+ * DUK_REALLOC_INDIRECT().
+ */
- new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
- if (new_lst == NULL) {
- return 1; /* fail */
- }
- new_lst[e->listlen++] = h16;
- e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
+#else
+ new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
+#endif
+ if (DUK_UNLIKELY(new_ptr == NULL)) {
+ /* If realloc fails we can continue normally: the string table
+ * won't "fill up" although chains will gradually get longer.
+ * When string insertions continue, we'll quite soon try again
+ * with no special handling.
+ */
+ DUK_D(DUK_DPRINT("string table grow failed, ignoring"));
+ return;
}
- return 0;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_hstring **new_lst;
- duk_size_t i, n;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str == NULL) {
- e->u.str = h;
- } else {
- /* Now two entries in the same slot, alloc list */
- lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
- if (lst == NULL) {
- return 1; /* fail */
- }
- lst[0] = e->u.str;
- lst[1] = h;
- e->u.strlist = lst;
- e->listlen = 2;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == NULL) {
- lst[i] = h;
- return 0;
- }
- }
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ heap->strtable16 = new_ptr;
+#else
+ heap->strtable = new_ptr;
+#endif
- if (e->listlen + 1 == 0) {
- /* Overflow, relevant mainly when listlen is 16 bits. */
- return 1; /* fail */
- }
+ /* Rehash a single bucket into two separate ones. When we grow
+ * by x2 the highest 'new' bit determines whether a string remains
+ * in its old position (bit is 0) or goes to a new one (bit is 1).
+ */
- new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
- if (new_lst == NULL) {
- return 1; /* fail */
- }
- new_lst[e->listlen++] = h;
- e->u.strlist = new_lst;
- }
- return 0;
-}
-#endif /* DUK_USE_HEAPPTR16 */
+ old_st_size = heap->st_size;
+ new_ptr_high = new_ptr + old_st_size;
+ for (i = 0; i < old_st_size; i++) {
+ duk_hstring *new_root;
+ duk_hstring *new_root_high;
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_size_t i, n;
- duk_uint16_t null16 = heap->heapptr_null16;
+ h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]);
+ new_root = h;
+ new_root_high = NULL;
- DUK_ASSERT(heap != NULL);
+ prev = NULL;
+ while (h != NULL) {
+ duk_uint32_t mask;
- slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
+ DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
+ next = h->hdr.h_next;
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 != null16) {
- duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
- DUK_ASSERT(h != NULL);
- if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
- return h;
- }
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] != null16) {
- duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
- DUK_ASSERT(h != NULL);
- if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
- return h;
+ /* Example: if previous size was 256, previous mask is 0xFF
+ * and size is 0x100 which corresponds to the new bit that
+ * comes into play.
+ */
+ DUK_ASSERT(heap->st_mask == old_st_size - 1);
+ mask = old_st_size;
+ if (DUK_HSTRING_GET_HASH(h) & mask) {
+ if (prev != NULL) {
+ prev->hdr.h_next = h->hdr.h_next;
+ } else {
+ DUK_ASSERT(h == new_root);
+ new_root = h->hdr.h_next;
}
- }
- }
- }
-
- return NULL;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_size_t i, n;
-
- DUK_ASSERT(heap != NULL);
-
- slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str != NULL &&
- DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
- return e->u.str;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] != NULL &&
- DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
- return lst[i];
+ h->hdr.h_next = new_root_high;
+ new_root_high = h;
+ } else {
+ prev = h;
}
+ h = next;
}
+
+ new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root);
+ new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high);
}
- return NULL;
-}
-#endif /* DUK_USE_HEAPPTR16 */
+ heap->st_size = new_st_size;
+ heap->st_mask = new_st_size - 1;
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_size_t i, n;
- duk_uint16_t h16;
- duk_uint16_t null16 = heap->heapptr_null16;
+#if defined(DUK_USE_ASSERTIONS)
+ duk__strtable_assert_checks(heap);
+#endif
+}
+#endif /* DUK__STRTAB_RESIZE_CHECK */
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
+/*
+ * Shrink strtable allocation in-place.
+ */
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) {
+ duk_uint32_t new_st_size;
+ duk_uint32_t i;
+ duk_hstring *h;
+ duk_hstring *other;
+ duk_hstring *root;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *old_ptr;
+ duk_uint16_t *old_ptr_high;
+ duk_uint16_t *new_ptr;
+#else
+ duk_hstring **old_ptr;
+ duk_hstring **old_ptr_high;
+ duk_hstring **new_ptr;
+#endif
- DUK_ASSERT(h != NULL);
- h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
+ DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 == h16) {
- e->u.str16 = null16;
- return;
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == h16) {
- lst[i] = null16;
- return;
- }
- }
- }
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(heap->st_resizing == 1);
+ DUK_ASSERT(heap->st_size >= 2);
+ DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
+ DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
- DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
- DUK_UNREACHABLE();
- return;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_size_t i, n;
+ DUK_STATS_INC(heap, stats_strtab_resize_shrink);
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
+ new_st_size = heap->st_size >> 1U;
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
+ /* Combine two buckets into a single one. When we shrink, one hash
+ * bit (highest) disappears.
+ */
+ old_ptr = DUK__GET_STRTABLE(heap);
+ old_ptr_high = old_ptr + new_st_size;
+ for (i = 0; i < new_st_size; i++) {
+ h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]);
+ other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]);
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- DUK_ASSERT(h != NULL);
- if (e->u.str == h) {
- e->u.str = NULL;
- return;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- DUK_ASSERT(h != NULL);
- if (lst[i] == h) {
- lst[i] = NULL;
- return;
+ if (h == NULL) {
+ /* First chain is empty, so use second one as is. */
+ root = other;
+ } else {
+ /* Find end of first chain, and link in the second. */
+ root = h;
+ while (h->hdr.h_next != NULL) {
+ h = h->hdr.h_next;
}
+ h->hdr.h_next = other;
}
- }
-
- DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
- DUK_UNREACHABLE();
- return;
-}
-#endif /* DUK_USE_HEAPPTR16 */
-#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
- duk_strtab_entry *e;
- duk_small_uint_t i;
- duk_size_t j, n, used;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
- duk_uint16_t null16 = heap->heapptr_null16;
-#else
- duk_hstring **lst;
-#endif
+ old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root);
+ }
- DUK_ASSERT(heap != NULL);
+ heap->st_size = new_st_size;
+ heap->st_mask = new_st_size - 1;
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
+ /* The strtable is now consistent and we can realloc safely. Even
+ * if side effects cause string interning or removal the strtable
+ * updates are safe. Recursive resize has been prevented by caller.
+ * This is also why we don't need to use DUK_REALLOC_INDIRECT().
+ *
+ * We assume a realloc() to a smaller size is guaranteed to succeed.
+ * It would be relatively straightforward to handle the error by
+ * essentially performing a "grow" step to recover.
+ */
- if (e->listlen == 0) {
-#if defined(DUK_USE_HEAPPTR16)
- DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0)));
-#else
- DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0)));
-#endif
- } else {
- used = 0;
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
+ DUK_ASSERT(new_ptr != NULL);
+ heap->strtable16 = new_ptr;
#else
- lst = e->u.strlist;
+ new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
+ DUK_ASSERT(new_ptr != NULL);
+ heap->strtable = new_ptr;
#endif
- DUK_ASSERT(lst != NULL);
- for (j = 0, n = e->listlen; j < n; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- if (lst[j] != null16) {
-#else
- if (lst[j] != NULL) {
+
+#if defined(DUK_USE_ASSERTIONS)
+ duk__strtable_assert_checks(heap);
#endif
- used++;
- }
- }
- DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen));
- }
- }
}
-#endif /* DUK_USE_DEBUG */
-
-#endif /* DUK_USE_STRTAB_CHAIN */
+#endif /* DUK__STRTAB_RESIZE_CHECK */
/*
- * String table algorithm: closed hashing with a probe sequence
- *
- * This is the default algorithm and works fine for environments with
- * minimal memory constraints.
+ * Grow/shrink check.
*/
-#if defined(DUK_USE_STRTAB_PROBE)
-
-/* Count actually used (non-NULL, non-DELETED) entries. */
-DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) {
- duk_int_t res = 0;
- duk_uint_fast32_t i, n;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t deleted16 = heap->heapptr_deleted16;
-#endif
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) {
+ duk_uint32_t load_factor; /* fixed point */
- n = (duk_uint_fast32_t) heap->st_size;
- for (i = 0; i < n; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) {
+ DUK_ASSERT(heap != NULL);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ DUK_ASSERT(heap->strtable16 != NULL);
#else
- if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) {
+ DUK_ASSERT(heap->strtable != NULL);
#endif
- res++;
- }
+
+ DUK_STATS_INC(heap, stats_strtab_resize_check);
+
+ /* Prevent recursive resizing. */
+ if (DUK_UNLIKELY(heap->st_resizing != 0U)) {
+ DUK_D(DUK_DPRINT("prevent recursive strtable resize"));
+ return;
}
- return res;
-}
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
-#else
-DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t deleted16 = heap->heapptr_deleted16;
-#endif
+ heap->st_resizing = 1;
- DUK_ASSERT(size > 0);
+ DUK_ASSERT(heap->st_size >= 16U);
+ DUK_ASSERT((heap->st_size >> 4U) >= 1);
+ load_factor = heap->st_count / (heap->st_size >> 4U);
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h));
- for (;;) {
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t e16 = entries16[i];
-#else
- duk_hstring *e = entries[i];
-#endif
+ DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)",
+ (unsigned long) heap->st_size, (unsigned long) heap->st_count,
+ (unsigned long) load_factor,
+ (double) heap->st_count / (double) heap->st_size));
-#if defined(DUK_USE_HEAPPTR16)
- /* XXX: could check for e16 == 0 because NULL is guaranteed to
- * encode to zero.
- */
- if (e16 == null16) {
-#else
- if (e == NULL) {
-#endif
- DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#else
- entries[i] = h;
-#endif
- (*p_used)++;
- break;
-#if defined(DUK_USE_HEAPPTR16)
- } else if (e16 == deleted16) {
-#else
- } else if (e == DUK__DELETED_MARKER(heap)) {
+ if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) {
+ if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) {
+ DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size"));
+ } else {
+ DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
+#if defined(DUK_USE_DEBUG)
+ duk_heap_strtable_dump(heap);
#endif
- /* st_used remains the same, DELETED is counted as used */
- DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#else
- entries[i] = h;
+ duk__strtable_grow_inplace(heap);
+ }
+ } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) {
+ if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) {
+ DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size"));
+ } else {
+ DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
+#if defined(DUK_USE_DEBUG)
+ duk_heap_strtable_dump(heap);
#endif
- break;
+ duk__strtable_shrink_inplace(heap);
}
- DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i));
- i = (i + step) % size;
-
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
+ } else {
+ DUK_DD(DUK_DDPRINT("no need for strtable resize"));
}
+
+ heap->st_resizing = 0;
}
+#endif /* DUK__STRTAB_RESIZE_CHECK */
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
-#else
-DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
+/*
+ * Torture grow/shrink: unconditionally grow and shrink back.
+ */
- DUK_ASSERT(size > 0);
+#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
+DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) {
+ duk_uint32_t old_st_size;
- i = DUK__HASH_INITIAL(strhash, size);
- step = DUK__HASH_PROBE_STEP(strhash);
- for (;;) {
- duk_hstring *e;
-#if defined(DUK_USE_HEAPPTR16)
- e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]);
-#else
- e = entries[i];
-#endif
+ DUK_ASSERT(heap != NULL);
- if (!e) {
- return NULL;
- }
- if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
- if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
- DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
- (long) i, (long) step, (long) size));
- return e;
- }
- }
- DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)",
- (long) i, (long) step, (long) size));
- i = (i + step) % size;
+ old_st_size = heap->st_size;
+ if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) {
+ return;
+ }
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
+ heap->st_resizing = 1;
+ duk__strtable_grow_inplace(heap);
+ if (heap->st_size > old_st_size) {
+ duk__strtable_shrink_inplace(heap);
}
- DUK_UNREACHABLE();
+ heap->st_resizing = 0;
}
+#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
-#else
-DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
- duk_uint32_t hash;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#endif
-
- DUK_ASSERT(size > 0);
-
- hash = DUK_HSTRING_GET_HASH(h);
- i = DUK__HASH_INITIAL(hash, size);
- step = DUK__HASH_PROBE_STEP(hash);
- for (;;) {
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t e16 = entries16[i];
-#else
- duk_hstring *e = entries[i];
-#endif
+/*
+ * Raw intern; string already checked not to be present.
+ */
-#if defined(DUK_USE_HEAPPTR16)
- if (e16 == null16) {
-#else
- if (!e) {
-#endif
- DUK_UNREACHABLE();
- break;
- }
-#if defined(DUK_USE_HEAPPTR16)
- if (e16 == h16) {
-#else
- if (e == h) {
-#endif
- /* st_used remains the same, DELETED is counted as used */
- DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = heap->heapptr_deleted16;
+DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
+ duk_hstring *res;
+ const duk_uint8_t *extdata;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *slot;
#else
- entries[i] = DUK__DELETED_MARKER(heap);
+ duk_hstring **slot;
#endif
- break;
- }
- DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
- i = (i + step) % size;
+ DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf",
+ (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash,
+ (unsigned long) heap->st_size, (unsigned long) heap->st_count,
+ (double) heap->st_count / (double) heap->st_size));
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
- }
-}
+ DUK_ASSERT(heap != NULL);
-DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
-#if defined(DUK_USE_DEBUG)
- duk_uint32_t old_used = heap->st_used;
-#endif
- duk_uint32_t old_size = heap->st_size;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *old_entries = heap->strtable16;
- duk_uint16_t *new_entries = NULL;
-#else
- duk_hstring **old_entries = heap->strtable;
- duk_hstring **new_entries = NULL;
-#endif
- duk_uint32_t new_used = 0;
- duk_uint32_t i;
+ /* Prevent any side effects on the string table and the caller provided
+ * str/blen arguments while interning is in progress. For example, if
+ * the caller provided str/blen from a dynamic buffer, a finalizer
+ * might resize or modify that dynamic buffer, invalidating the call
+ * arguments.
+ *
+ * While finalizers must be prevented, mark-and-sweep itself is fine.
+ * Recursive string table resize is prevented explicitly here.
+ */
-#if defined(DUK_USE_DEBUG)
- DUK_UNREF(old_used); /* unused with some debug level combinations */
-#endif
+ heap->pf_prevent_count++;
+ DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */
-#ifdef DUK_USE_DDDPRINT
- DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
- (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
- (long) (((double) old_used) / ((double) old_size) * 100.0),
- (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
- (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
+#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
+ duk__strtable_resize_torture(heap);
#endif
- DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */
- DUK_ASSERT(old_entries);
-
- /*
- * The attempt to allocate may cause a GC. Such a GC must not attempt to resize
- * the stringtable (though it can be swept); finalizer execution and object
- * compaction must also be postponed to avoid the pressure to add strings to the
- * string table. Call site must prevent these.
+ /* String table grow/shrink check. Because of chaining (and no
+ * accumulation issues as with hash probe chains and DELETED
+ * markers) there's never a mandatory need to resize right now.
+ * Check for the resize only periodically, based on st_count
+ * bit pattern. Because string table removal doesn't do a shrink
+ * check, we do that also here.
+ *
+ * Do the resize and possible grow/shrink before the new duk_hstring
+ * has been allocated. Otherwise we may trigger a GC when the result
+ * duk_hstring is not yet strongly referenced.
*/
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE);
- DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS);
- DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION);
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+ if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) {
+ duk__strtable_resize_check(heap);
+ }
#endif
-#if defined(DUK_USE_HEAPPTR16)
- new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
+ /* External string check (low memory optimization). */
+
+#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
+ extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
#else
- new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
+ extdata = (const duk_uint8_t *) NULL;
#endif
- if (!new_entries) {
- goto resize_error;
- }
+ /* Allocate and initialize string, not yet linked. This may cause a
+ * GC which may cause other strings to be interned and inserted into
+ * the string table before we insert our string. Finalizer execution
+ * is disabled intentionally to avoid a finalizer from e.g. resizing
+ * a buffer used as a data area for 'str'.
+ */
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- for (i = 0; i < new_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- new_entries[i] = heap->heapptr_null16;
-#else
- new_entries[i] = NULL;
-#endif
- }
-#else
-#if defined(DUK_USE_HEAPPTR16)
- /* Relies on NULL encoding to zero. */
- DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
-#else
- DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
-#endif
-#endif
+ res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata);
+
+ /* Allow side effects again: GC must be avoided until duk_hstring
+ * result (if successful) has been INCREF'd.
+ */
+ DUK_ASSERT(heap->pf_prevent_count > 0);
+ heap->pf_prevent_count--;
- /* Because new_size > duk__count_used_probe(heap), guaranteed to work */
- for (i = 0; i < old_size; i++) {
- duk_hstring *e;
+ /* Alloc error handling. */
-#if defined(DUK_USE_HEAPPTR16)
- e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
-#else
- e = old_entries[i];
-#endif
- if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
- continue;
+ if (DUK_UNLIKELY(res == NULL)) {
+#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
+ if (extdata != NULL) {
+ DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata);
}
- /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
- duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
+#endif
+ return NULL;
}
-#ifdef DUK_USE_DDPRINT
- DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
- (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
- (long) (((double) old_used) / ((double) old_size) * 100.0),
- (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
- (long) (((double) new_used) / ((double) new_size) * 100.0)));
-#endif
+ /* Insert into string table. */
-#if defined(DUK_USE_HEAPPTR16)
- DUK_FREE(heap, heap->strtable16);
- heap->strtable16 = new_entries;
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ slot = heap->strtable16 + (strhash & heap->st_mask);
#else
- DUK_FREE(heap, heap->strtable);
- heap->strtable = new_entries;
+ slot = heap->strtable + (strhash & heap->st_mask);
#endif
- heap->st_size = new_size;
- heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */
-
- return 0; /* OK */
-
- resize_error:
- DUK_FREE(heap, new_entries);
- return 1; /* FAIL */
-}
-
-DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
- duk_uint32_t new_size;
- duk_bool_t ret;
+ DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */
+ res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot);
+ *slot = DUK__HEAPPTR_ENC16(heap, res);
- new_size = (duk_uint32_t) duk__count_used_probe(heap);
- if (new_size >= 0x80000000UL) {
- new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
- } else {
- new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
- new_size = duk_util_get_hash_prime(new_size);
- }
- DUK_ASSERT(new_size > 0);
+ /* Update string count only for successful inserts. */
- /* rehash even if old and new sizes are the same to get rid of
- * DELETED entries.
- */
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+ heap->st_count++;
+#endif
- ret = duk__resize_strtab_raw_probe(heap, new_size);
+ /* The duk_hstring is in the string table but is not yet strongly
+ * reachable. Calling code MUST NOT make any allocations or other
+ * side effects before the duk_hstring has been INCREF'd and made
+ * reachable.
+ */
- return ret;
+ return res;
}
-DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) {
- duk_uint32_t new_free;
- duk_uint32_t tmp1;
- duk_uint32_t tmp2;
+/*
+ * Intern a string from str/blen, returning either an existing duk_hstring
+ * or adding a new one into the string table. The input string does -not-
+ * need to be NUL terminated.
+ *
+ * The input 'str' argument may point to a Duktape managed data area such as
+ * the data area of a dynamic buffer. It's crucial to avoid any side effects
+ * that might affect the data area (e.g. resize the dynamic buffer, or write
+ * to the buffer) before the string is fully interned.
+ */
- DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */
- new_free = heap->st_size - new_used; /* unsigned intentionally */
+#if defined(DUK_USE_ROM_STRINGS)
+DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) {
+ duk_size_t lookup_hash;
+ duk_hstring *curr;
- /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */
- /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */
+ DUK_ASSERT(heap != NULL);
+ DUK_UNREF(heap);
- tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
- tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
+ lookup_hash = (blen << 4);
+ if (blen > 0) {
+ lookup_hash += str[0];
+ }
+ lookup_hash &= 0xff;
- if (new_free <= tmp1 || new_used <= tmp2) {
- /* load factor too low or high, count actually used entries and resize */
- return duk__resize_strtab_probe(heap);
- } else {
- return 0; /* OK */
+ curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]);
+ while (curr != NULL) {
+ if (strhash == DUK_HSTRING_GET_HASH(curr) &&
+ blen == DUK_HSTRING_GET_BYTELEN(curr) &&
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
+ DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
+ curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr)));
+ return curr;
+ }
+ curr = curr->hdr.h_next;
}
+
+ return NULL;
}
+#endif /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
- duk_uint32_t i;
+DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
+ duk_uint32_t strhash;
duk_hstring *h;
- DUK_ASSERT(heap != NULL);
-#if defined(DUK_USE_HEAPPTR16)
- DUK_ASSERT(heap->strtable16 != NULL);
-#else
- DUK_ASSERT(heap->strtable != NULL);
-#endif
- DUK_UNREF(h);
+ DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen));
- for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
-#else
- h = heap->strtable[i];
-#endif
-
- DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h));
- }
-}
-#endif /* DUK_USE_DEBUG */
+ /* Preliminaries. */
-#endif /* DUK_USE_STRTAB_PROBE */
-
-/*
- * Raw intern and lookup
- */
-
-DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_hstring *res;
- const duk_uint8_t *extdata;
-#if defined(DUK_USE_MARK_AND_SWEEP)
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(blen == 0 || str != NULL);
+ DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */
+ strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
- /* Prevent any side effects on the string table and the caller provided
- * str/blen arguments while interning is in progress. For example, if
- * the caller provided str/blen from a dynamic buffer, a finalizer might
- * resize that dynamic buffer, invalidating the call arguments.
- */
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
- prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
- DUK__PREVENT_MS_SIDE_EFFECTS(heap);
-#endif
+ /* String table lookup. */
-#if defined(DUK_USE_STRTAB_PROBE)
- if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) {
- goto failed;
- }
+ DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
+ DUK_ASSERT(heap->st_size > 0);
+ DUK_ASSERT(heap->st_size == heap->st_mask + 1);
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]);
+#else
+ h = heap->strtable[strhash & heap->st_mask];
#endif
-
- /* For manual testing only. */
-#if 0
- {
- duk_size_t i;
- DUK_PRINTF("INTERN: \"");
- for (i = 0; i < blen; i++) {
- duk_uint8_t x = str[i];
- if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') {
- DUK_PRINTF("%c", (int) x); /* char: use int cast */
- } else {
- DUK_PRINTF("\\x%02lx", (long) x);
- }
+ while (h != NULL) {
+ if (DUK_HSTRING_GET_HASH(h) == strhash &&
+ DUK_HSTRING_GET_BYTELEN(h) == blen &&
+ DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
+ /* Found existing entry. */
+ DUK_STATS_INC(heap, stats_strtab_intern_hit);
+ return h;
}
- DUK_PRINTF("\"\n");
+ h = h->hdr.h_next;
}
-#endif
-#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
- extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
-#else
- extdata = (const duk_uint8_t *) NULL;
-#endif
- res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata);
- if (!res) {
- goto failed;
- }
+ /* ROM table lookup. Because this lookup is slower, do it only after
+ * RAM lookup. This works because no ROM string is ever interned into
+ * the RAM string table.
+ */
-#if defined(DUK_USE_STRTAB_CHAIN)
- if (duk__insert_hstring_chain(heap, res)) {
- /* failed */
- DUK_FREE(heap, res);
- goto failed;
+#if defined(DUK_USE_ROM_STRINGS)
+ h = duk__strtab_romstring_lookup(heap, str, blen, strhash);
+ if (h != NULL) {
+ DUK_STATS_INC(heap, stats_strtab_intern_hit);
+ return h;
}
-#elif defined(DUK_USE_STRTAB_PROBE)
- /* guaranteed to succeed */
- duk__insert_hstring_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
#endif
- heap->st_size,
- &heap->st_used,
- res);
-#else
-#error internal error, invalid strtab options
-#endif
-
- /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
- * Caller should increase refcount and make the hstring reachable before any
- * operations which require allocation (and possible gc).
- */
- done:
-#if defined(DUK_USE_MARK_AND_SWEEP)
- heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
- return res;
+ /* Not found in string table; insert. */
- failed:
- res = NULL;
- goto done;
+ DUK_STATS_INC(heap, stats_strtab_intern_miss);
+ h = duk__strtable_do_intern(heap, str, blen, strhash);
+ return h; /* may be NULL */
}
-DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
- duk_hstring *res;
+/*
+ * Intern a string from u32.
+ */
- DUK_ASSERT(out_strhash);
+/* XXX: Could arrange some special handling because we know that the result
+ * will have an arridx flag and an ASCII flag, won't need a clen check, etc.
+ */
- *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
+DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) {
+ duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN];
+ duk_uint8_t *p;
-#if defined(DUK_USE_ROM_STRINGS)
- {
- duk_small_uint_t i;
- /* XXX: This is VERY inefficient now, and should be e.g. a
- * binary search or perfect hash, to be fixed.
- */
- for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) {
- duk_hstring *romstr;
- romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]);
- if (blen == DUK_HSTRING_GET_BYTELEN(romstr) &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) {
- DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
- romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr)));
- DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr));
- *out_strhash = DUK_HSTRING_GET_HASH(romstr);
- return romstr;
- }
- }
- }
-#endif /* DUK_USE_ROM_STRINGS */
+ DUK_ASSERT(heap != NULL);
-#if defined(DUK_USE_STRTAB_CHAIN)
- res = duk__find_matching_string_chain(heap, str, blen, *out_strhash);
-#elif defined(DUK_USE_STRTAB_PROBE)
- res = duk__find_matching_string_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
-#endif
- heap->st_size,
- str,
- blen,
- *out_strhash);
-#else
-#error internal error, invalid strtab options
-#endif
+ /* This is smaller and faster than a %lu sprintf. */
+ p = buf + sizeof(buf);
+ do {
+ p--;
+ *p = duk_lc_digits[val % 10];
+ val = val / 10;
+ } while (val != 0); /* For val == 0, emit exactly one '0'. */
+ DUK_ASSERT(p >= buf);
- return res;
+ return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p));
}
/*
- * Exposed calls
+ * Checked convenience variants.
+ *
+ * XXX: Because the main use case is for the checked variants, make them the
+ * main functionality and provide a safe variant separately (it is only needed
+ * during heap init). The problem with that is that longjmp state and error
+ * creation must already be possible to throw.
*/
-#if 0 /*unused*/
-DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
- duk_uint32_t strhash; /* dummy */
- return duk__do_lookup(heap, str, blen, &strhash);
-}
-#endif
-
-DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
+DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
duk_hstring *res;
- duk_uint32_t strhash;
-
- /* caller is responsible for ensuring this */
- DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
- res = duk__do_lookup(heap, str, blen, &strhash);
- if (res) {
- return res;
- }
-
- res = duk__do_intern(heap, str, blen, strhash);
- return res; /* may be NULL */
-}
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT(blen == 0 || str != NULL);
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
- duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ res = duk_heap_strtable_intern(thr->heap, str, blen);
+ if (DUK_UNLIKELY(res == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
return res;
}
-#if 0 /*unused*/
-DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
- char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
- DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
- buf[sizeof(buf) - 1] = (char) 0;
- DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
- return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
-}
-#endif
+DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
+ duk_hstring *res;
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
- char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
- DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
- buf[sizeof(buf) - 1] = (char) 0;
- DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
- return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
-}
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
- duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ res = duk_heap_strtable_intern_u32(thr->heap, val);
+ if (DUK_UNLIKELY(res == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
return res;
}
-/* find and remove string from stringtable; caller must free the string itself */
-#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
- DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h));
+/*
+ * Remove (unlink) a string from the string table.
+ *
+ * Just unlinks the duk_hstring, leaving link pointers as garbage.
+ * Caller must free the string itself.
+ */
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__remove_matching_hstring_chain(heap, h);
-#elif defined(DUK_USE_STRTAB_PROBE)
- duk__remove_matching_hstring_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
-#endif
- heap->st_size,
- h);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+/* Unlink without a 'prev' pointer. */
+DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *slot;
#else
-#error internal error, invalid strtab options
-#endif
-}
+ duk_hstring **slot;
#endif
+ duk_hstring *other;
+ duk_hstring *prev;
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
-DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) {
- duk_small_uint_t prev_mark_and_sweep_base_flags;
- /* Force a resize so that DELETED entries are eliminated.
- * Another option would be duk__recheck_strtab_size_probe();
- * but since that happens on every intern anyway, this whole
- * check can now be disabled.
- */
+ DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx",
+ (void *) heap, (void *) h,
+ (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
+ (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
- DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
- prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
- DUK__PREVENT_MS_SIDE_EFFECTS(heap);
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(h != NULL);
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK_UNREF(heap);
-#elif defined(DUK_USE_STRTAB_PROBE)
- (void) duk__resize_strtab_probe(heap);
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+ DUK_ASSERT(heap->st_count > 0);
+ heap->st_count--;
#endif
- heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-}
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
+#else
+ slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
#endif
+ other = DUK__HEAPPTR_DEC16(heap, *slot);
+ DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */
-#if defined(DUK_USE_STRTAB_CHAIN)
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
- /* Free strings in the stringtable and any allocations needed
- * by the stringtable itself.
+ prev = NULL;
+ while (other != h) {
+ prev = other;
+ other = other->hdr.h_next;
+ DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */
+ }
+ if (prev != NULL) {
+ /* Middle of list. */
+ prev->hdr.h_next = h->hdr.h_next;
+ } else {
+ /* Head of list. */
+ *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
+ }
+
+ /* There's no resize check on a string free. The next string
+ * intern will do one.
*/
- duk_uint_fast32_t i, j;
- duk_strtab_entry *e;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
- duk_uint16_t null16 = heap->heapptr_null16;
-#else
- duk_hstring **lst;
-#endif
- duk_hstring *h;
+}
+#endif /* DUK_USE_REFERENCE_COUNTING */
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen > 0) {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
+/* Unlink with a 'prev' pointer. */
+DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *slot;
#else
- lst = e->u.strlist;
+ duk_hstring **slot;
#endif
- DUK_ASSERT(lst != NULL);
- for (j = 0; j < e->listlen; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
- lst[j] = null16;
-#else
- h = lst[j];
- lst[j] = NULL;
-#endif
- /* strings may have inner refs (extdata) in some cases */
- if (h != NULL) {
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- }
- }
-#if defined(DUK_USE_HEAPPTR16)
- e->u.strlist16 = null16;
-#else
- e->u.strlist = NULL;
+ DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx",
+ (void *) heap, (void *) prev, (void *) h,
+ (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
+ (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
+
+ DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(prev == NULL || prev->hdr.h_next == h);
+
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+ DUK_ASSERT(heap->st_count > 0);
+ heap->st_count--;
#endif
- DUK_FREE(heap, lst);
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
- e->u.str16 = null16;
+
+ if (prev != NULL) {
+ /* Middle of list. */
+ prev->hdr.h_next = h->hdr.h_next;
+ } else {
+ /* Head of list. */
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
#else
- h = e->u.str;
- e->u.str = NULL;
+ slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
#endif
- if (h != NULL) {
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- }
- }
- e->listlen = 0;
+ DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h);
+ *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
}
}
-#endif /* DUK_USE_STRTAB_CHAIN */
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
- duk_uint_fast32_t i;
- duk_hstring *h;
+/*
+ * Force string table resize check in mark-and-sweep.
+ */
-#if defined(DUK_USE_HEAPPTR16)
- if (heap->strtable16) {
+DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) {
+ /* Does only one grow/shrink step if needed. The heap->st_resizing
+ * flag protects against recursive resizing.
+ */
+
+ DUK_ASSERT(heap != NULL);
+ DUK_UNREF(heap);
+
+#if defined(DUK__STRTAB_RESIZE_CHECK)
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ if (heap->strtable16 != NULL) {
#else
- if (heap->strtable) {
+ if (heap->strtable != NULL) {
#endif
- for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
-#else
- h = heap->strtable[i];
+ duk__strtable_resize_check(heap);
+ }
#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
- }
- DUK_ASSERT(h != NULL);
+}
- /* strings may have inner refs (extdata) in some cases */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
-#if 0 /* not strictly necessary */
- heap->strtable[i] = NULL;
-#endif
- }
-#if defined(DUK_USE_HEAPPTR16)
- DUK_FREE(heap, heap->strtable16);
+/*
+ * Free strings in the string table and the string table itself.
+ */
+
+DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ duk_uint16_t *strtable;
+ duk_uint16_t *st;
#else
- DUK_FREE(heap, heap->strtable);
+ duk_hstring **strtable;
+ duk_hstring **st;
#endif
-#if 0 /* not strictly necessary */
- heap->strtable = NULL;
+ duk_hstring *h;
+
+ DUK_ASSERT(heap != NULL);
+
+#if defined(DUK_USE_ASSERTIONS)
+ duk__strtable_assert_checks(heap);
#endif
+
+ /* Strtable can be NULL if heap init fails. However, in that case
+ * heap->st_size is 0, so strtable == strtable_end and we skip the
+ * loop without a special check.
+ */
+ strtable = DUK__GET_STRTABLE(heap);
+ st = strtable + heap->st_size;
+ DUK_ASSERT(strtable != NULL || heap->st_size == 0);
+
+ while (strtable != st) {
+ --st;
+ h = DUK__HEAPPTR_DEC16(heap, *st);
+ while (h) {
+ duk_hstring *h_next;
+ h_next = h->hdr.h_next;
+
+ /* Strings may have inner refs (extdata) in some cases. */
+ duk_free_hstring(heap, h);
+
+ h = h_next;
+ }
}
+
+ DUK_FREE(heap, strtable);
}
-#endif /* DUK_USE_STRTAB_PROBE */
-/* Undefine local defines */
-#undef DUK__HASH_INITIAL
-#undef DUK__HASH_PROBE_STEP
-#undef DUK__DELETED_MARKER
-#line 1 "duk_hobject_alloc.c"
+/* automatic undefs */
+#undef DUK__GET_STRTABLE
+#undef DUK__HEAPPTR_DEC16
+#undef DUK__HEAPPTR_ENC16
+#undef DUK__STRTAB_U32_MAX_STRLEN
/*
* Hobject allocation.
*
@@ -46021,19 +51839,29 @@ DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
* in "heap allocated" list and has a refcount of zero, so caller must careful.
*/
-/* include removed: duk_internal.h */
+/* XXX: In most cases there's no need for plain allocation without pushing
+ * to the value stack. Maybe rework contract?
+ */
-DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
-#endif
+/* #include duk_internal.h -> already included */
- /* XXX: macro? sets both heaphdr and object flags */
- obj->hdr.h_flags = hobject_flags;
- DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */
+/*
+ * Helpers.
+ */
+DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) {
+ DUK_ASSERT(obj != NULL);
+ /* Zeroed by caller. */
+
+ obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT;
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT); /* Assume zero shift. */
+
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL);
+ DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
+#endif
#if defined(DUK_USE_HEAPPTR16)
- /* Zero encoded pointer is required to match NULL */
+ /* Zero encoded pointer is required to match NULL. */
DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
@@ -46042,14 +51870,22 @@ DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint
DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
- /*
- * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
- * with this properly. This is intentional: empty objects consume a minimum
- * amount of memory. Further, an initial allocation might fail and cause
- * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
+ /* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
+ * with this properly. This is intentional: empty objects consume a minimum
+ * amount of memory. Further, an initial allocation might fail and cause
+ * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
*/
}
+DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) {
+ void *res;
+
+ res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size);
+ DUK_ASSERT(res != NULL);
+ duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res);
+ return res;
+}
+
/*
* Allocate an duk_hobject.
*
@@ -46061,153 +51897,212 @@ DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint
* count before invoking any operation that might require memory allocation.
*/
-DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
+DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
duk_hobject *res;
DUK_ASSERT(heap != NULL);
/* different memory layout, alloc size, and init */
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
+ DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
+ DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
+ DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0);
- res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
- if (!res) {
+ res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject));
+ if (DUK_UNLIKELY(res == NULL)) {
return NULL;
}
- DUK_MEMZERO(res, sizeof(duk_hobject));
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
- duk__init_object_parts(heap, res, hobject_flags);
+ duk__init_object_parts(heap, hobject_flags, res);
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
return res;
}
-DUK_INTERNAL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hcompiledfunction *res;
+DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hobject *res;
- res = (duk_hcompiledfunction *) DUK_ALLOC(heap, sizeof(duk_hcompiledfunction));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hcompiledfunction));
+ res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject));
+ return res;
+}
- duk__init_object_parts(heap, &res->obj, hobject_flags);
+DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hcompfunc *res;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
-#ifdef DUK_USE_HEAPPTR16
+ res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+#if defined(DUK_USE_HEAPPTR16)
/* NULL pointer is required to encode to zero, so memset is enough. */
#else
res->data = NULL;
res->funcs = NULL;
res->bytecode = NULL;
#endif
+ res->lex_env = NULL;
+ res->var_env = NULL;
#endif
return res;
}
-DUK_INTERNAL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hnativefunction *res;
-
- res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hnativefunction));
-
- duk__init_object_parts(heap, &res->obj, hobject_flags);
+DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hnatfunc *res;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+ res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->func = NULL;
#endif
return res;
}
-DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hbufferobject *res;
+DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
+ duk_hboundfunc *res;
- res = (duk_hbufferobject *) DUK_ALLOC(heap, sizeof(duk_hbufferobject));
+ res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc));
if (!res) {
return NULL;
}
- DUK_MEMZERO(res, sizeof(duk_hbufferobject));
+ DUK_MEMZERO(res, sizeof(duk_hboundfunc));
- duk__init_object_parts(heap, &res->obj, hobject_flags);
+ duk__init_object_parts(heap, hobject_flags, &res->obj);
+
+ DUK_TVAL_SET_UNDEFINED(&res->target);
+ DUK_TVAL_SET_UNDEFINED(&res->this_binding);
+
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ res->args = NULL;
+#endif
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+ return res;
+}
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hbufobj *res;
+
+ res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->buf = NULL;
+ res->buf_prop = NULL;
#endif
- DUK_ASSERT_HBUFFEROBJECT_VALID(res);
+ DUK_ASSERT_HBUFOBJ_VALID(res);
return res;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/*
- * Allocate a new thread.
+/* Allocate a new thread.
*
- * Leaves the built-ins array uninitialized. The caller must either
- * initialize a new global context or share existing built-ins from
- * another thread.
+ * Leaves the built-ins array uninitialized. The caller must either
+ * initialize a new global context or share existing built-ins from
+ * another thread.
*/
-
-DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
+DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
duk_hthread *res;
res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
- if (!res) {
+ if (DUK_UNLIKELY(res == NULL)) {
return NULL;
}
DUK_MEMZERO(res, sizeof(duk_hthread));
- duk__init_object_parts(heap, &res->obj, hobject_flags);
+ duk__init_object_parts(heap, hobject_flags, &res->obj);
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->ptr_curr_pc = NULL;
res->heap = NULL;
res->valstack = NULL;
res->valstack_end = NULL;
+ res->valstack_alloc_end = NULL;
res->valstack_bottom = NULL;
res->valstack_top = NULL;
- res->callstack = NULL;
- res->catchstack = NULL;
+ res->callstack_curr = NULL;
res->resumer = NULL;
res->compile_ctx = NULL,
-#ifdef DUK_USE_HEAPPTR16
+#if defined(DUK_USE_HEAPPTR16)
res->strs16 = NULL;
#else
res->strs = NULL;
#endif
{
- int i;
+ duk_small_uint_t i;
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
res->builtins[i] = NULL;
}
}
#endif
- /* when nothing is running, API calls are in non-strict mode */
+ /* When nothing is running, API calls are in non-strict mode. */
DUK_ASSERT(res->strict == 0);
res->heap = heap;
- res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
- res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
- res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
+ /* XXX: Any reason not to merge duk_hthread_alloc.c here? */
return res;
}
-#if 0 /* unused now */
-DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) {
- duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hthread *res;
+
+ res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags);
+ if (res == NULL) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
return res;
}
+
+DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_harray *res;
+
+ res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray));
+
+ DUK_ASSERT(res->length == 0);
+
+ return res;
+}
+
+DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hdecenv *res;
+
+ res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ res->thread = NULL;
+ res->varmap = NULL;
#endif
-#line 1 "duk_hobject_enum.c"
+
+ DUK_ASSERT(res->thread == NULL);
+ DUK_ASSERT(res->varmap == NULL);
+ DUK_ASSERT(res->regbase_byteoff == 0);
+
+ return res;
+}
+
+DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hobjenv *res;
+
+ res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ res->target = NULL;
+#endif
+
+ DUK_ASSERT(res->target == NULL);
+
+ return res;
+}
+
+DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hproxy *res;
+
+ res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy));
+
+ /* Leave ->target and ->handler uninitialized, as caller will always
+ * explicitly initialize them before any side effects are possible.
+ */
+
+ return res;
+}
/*
- * Hobject enumeration support.
+ * Object enumeration support.
*
* Creates an internal enumeration state object to be used e.g. with for-in
* enumeration. The state object contains a snapshot of target object keys
@@ -46225,145 +52120,154 @@ DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t
* enumerator object is memory inefficient especially for iterating arrays.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* XXX: identify enumeration target with an object index (not top of stack) */
-/* must match exactly the number of internal properties inserted to enumerator */
+/* First enumerated key index in enumerator object, must match exactly the
+ * number of control properties inserted to the enumerator.
+ */
#define DUK__ENUM_START_INDEX 2
-DUK_LOCAL const duk_uint16_t duk__bufferobject_virtual_props[] = {
- DUK_STRIDX_LENGTH,
- DUK_STRIDX_BYTE_LENGTH,
- DUK_STRIDX_BYTE_OFFSET,
- DUK_STRIDX_BYTES_PER_ELEMENT
-};
+/* Current implementation suffices for ES2015 for now because there's no symbol
+ * sorting, so commented out for now.
+ */
/*
- * Helper to sort array index keys. The keys are in the enumeration object
- * entry part, starting from DUK__ENUM_START_INDEX, and the entry part is dense.
- *
- * We use insertion sort because it is simple (leading to compact code,)
- * works nicely in-place, and minimizes operations if data is already sorted
- * or nearly sorted (which is a very common case here). It also minimizes
- * the use of element comparisons in general. This is nice because element
- * comparisons here involve re-parsing the string keys into numbers each
- * time, which is naturally very expensive.
- *
- * Note that the entry part values are all "true", e.g.
+ * Helper to sort enumeration keys using a callback for pairwise duk_hstring
+ * comparisons. The keys are in the enumeration object entry part, starting
+ * from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values
+ * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true,
+ * so it suffices to just switch keys without switching values.
*
- * "1" -> true, "3" -> true, "2" -> true
+ * ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
+ * (1) array indices in ascending order,
+ * (2) non-array-index keys in insertion order, and
+ * (3) symbols in insertion order.
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
*
- * so it suffices to only work in the key part without exchanging any keys,
- * simplifying the sort.
+ * This rule is applied to "own properties" at each inheritance level;
+ * non-duplicate parent keys always follow child keys. For example,
+ * an inherited array index will enumerate -after- a symbol in the
+ * child.
*
+ * Insertion sort is used because (1) it's simple and compact, (2) works
+ * in-place, (3) minimizes operations if data is already nearly sorted,
+ * (4) doesn't reorder elements considered equal.
* http://en.wikipedia.org/wiki/Insertion_sort
- *
- * (Compiles to about 160 bytes now as a stand-alone function.)
*/
-DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
+/* Sort key, must hold array indices, "not array index" marker, and one more
+ * higher value for symbols.
+ */
+#if !defined(DUK_USE_SYMBOL_BUILTIN)
+typedef duk_uint32_t duk__sort_key_t;
+#elif defined(DUK_USE_64BIT_OPS)
+typedef duk_uint64_t duk__sort_key_t;
+#else
+typedef duk_double_t duk__sort_key_t;
+#endif
+
+/* Get sort key for a duk_hstring. */
+DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) {
+ duk__sort_key_t val;
+
+ /* For array indices [0,0xfffffffe] use the array index as is.
+ * For strings, use 0xffffffff, the marker 'arridx' already in
+ * duk_hstring. For symbols, any value above 0xffffffff works,
+ * as long as it is the same for all symbols; currently just add
+ * the masked flag field into the arridx temporary.
+ */
+ DUK_ASSERT(x != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX);
+
+ val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x);
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL);
+#endif
+
+ return (duk__sort_key_t) val;
+}
+
+/* Insert element 'b' after element 'a'? */
+DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) {
+ duk__sort_key_t val_a;
+
+ DUK_ASSERT(a != NULL);
+ DUK_ASSERT(b != NULL);
+ DUK_UNREF(b); /* Not actually needed now, val_b suffices. */
+
+ val_a = duk__hstring_sort_key(a);
+
+ if (val_a > val_b) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk_int_fast32_t idx_start, duk_int_fast32_t idx_end) {
duk_hstring **keys;
- duk_hstring **p_curr, **p_insert, **p_end;
- duk_hstring *h_curr;
- duk_uarridx_t val_highest, val_curr, val_insert;
+ duk_int_fast32_t idx;
DUK_ASSERT(h_obj != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h_obj) >= 2); /* control props */
+ DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
+ DUK_ASSERT(idx_end >= idx_start);
DUK_UNREF(thr);
- if (DUK_HOBJECT_GET_ENEXT(h_obj) <= 1 + DUK__ENUM_START_INDEX) {
- return;
+ if (idx_end <= idx_start + 1) {
+ return; /* Zero or one element(s). */
}
keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
- p_end = keys + DUK_HOBJECT_GET_ENEXT(h_obj);
- keys += DUK__ENUM_START_INDEX;
-
- DUK_DDD(DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
- (void *) keys, (void *) p_end));
-#ifdef DUK_USE_DDDPRINT
- {
- duk_uint_fast32_t i;
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
- DUK_DDD(DUK_DDDPRINT("initial: %ld %p -> %!O",
- (long) i,
- (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
- (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
- }
- }
-#endif
+ for (idx = idx_start + 1; idx < idx_end; idx++) {
+ duk_hstring *h_curr;
+ duk_int_fast32_t idx_insert;
+ duk__sort_key_t val_curr;
- val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
- for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
- DUK_ASSERT(*p_curr != NULL);
- val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
+ h_curr = keys[idx];
+ DUK_ASSERT(h_curr != NULL);
- if (val_curr >= val_highest) {
- DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
- "already in correct order, next",
- (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
- val_highest = val_curr;
- continue;
- }
-
- DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
- "needs to be inserted",
- (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
-
- /* Needs to be inserted; scan backwards, since we optimize
- * for the case where elements are nearly in order.
+ /* Scan backwards for insertion place. This works very well
+ * when the elements are nearly in order which is the common
+ * (and optimized for) case.
*/
- p_insert = p_curr - 1;
- for (;;) {
- val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
- if (val_insert < val_curr) {
- DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> insert after this",
- (void *) p_insert, (long) val_insert, (long) val_curr));
- p_insert++;
- break;
- }
- if (p_insert == keys) {
- DUK_DDD(DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning", (void *) p_insert));
+ val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */
+ for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
+ duk_hstring *h_insert;
+ h_insert = keys[idx_insert];
+ DUK_ASSERT(h_insert != NULL);
+
+ if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
break;
}
- DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> search backwards",
- (void *) p_insert, (long) val_insert, (long) val_curr));
- p_insert--;
}
-
- DUK_DDD(DUK_DDDPRINT("final p_insert=%p", (void *) p_insert));
+ /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++
+ * brings us back to idx_start.
+ */
+ idx_insert++;
+ DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx);
/* .-- p_insert .-- p_curr
* v v
* | ... | insert | ... | curr
*/
- h_curr = *p_curr;
- DUK_DDD(DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%ld, h_curr=%p",
- (void *) (p_insert + 1), (void *) p_insert,
- (long) (p_curr - p_insert), (void *) h_curr));
-
- DUK_MEMMOVE((void *) (p_insert + 1),
- (const void *) p_insert,
- (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
- *p_insert = h_curr;
- /* keep val_highest */
- }
-
-#ifdef DUK_USE_DDDPRINT
- {
- duk_uint_fast32_t i;
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
- DUK_DDD(DUK_DDDPRINT("final: %ld %p -> %!O",
- (long) i,
- (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
- (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
+ /* This could also done when the keys are in order, i.e.
+ * idx_insert == idx. The result would be an unnecessary
+ * memmove() but we use an explicit check because the keys
+ * are very often in order already.
+ */
+ if (idx != idx_insert) {
+ DUK_MEMMOVE((void *) (keys + idx_insert + 1),
+ (const void *) (keys + idx_insert),
+ ((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
+ keys[idx_insert] = h_curr;
}
}
-#endif
}
/*
@@ -46375,8 +52279,20 @@ DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
* scan would be needed to eliminate duplicates found in the prototype chain.
*/
-DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) {
+ /* 'k' may be unreachable on entry so must push without any
+ * potential for GC.
+ */
+ duk_push_hstring(thr, k);
+ duk_push_true(thr);
+ duk_put_prop(thr, -3);
+}
+
+DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
+ duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+}
+
+DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *enum_target;
duk_hobject *curr;
duk_hobject *res;
@@ -46386,18 +52302,15 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
duk_hobject *h_trap_result;
#endif
duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
+ duk_uint_fast32_t sort_start_index;
- DUK_ASSERT(ctx != NULL);
-
- DUK_DDD(DUK_DDDPRINT("create enumerator, stack top: %ld", (long) duk_get_top(ctx)));
+ DUK_ASSERT(thr != NULL);
- enum_target = duk_require_hobject(ctx, -1);
+ enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
- duk_push_object_internal(ctx);
- res = duk_require_hobject(ctx, -1);
-
- DUK_DDD(DUK_DDDPRINT("created internal object"));
+ duk_push_bare_object(thr);
+ res = duk_known_hobject(thr, -1);
/* [enum_target res] */
@@ -46406,12 +52319,12 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
* enumeration result comes from a proxy trap as there is no
* real object to check against.
*/
- duk_push_hobject(ctx, enum_target);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET);
+ duk_push_hobject(thr, enum_target);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET);
/* Initialize index so that we skip internal control keys. */
- duk_push_int(ctx, DUK__ENUM_START_INDEX);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
+ duk_push_int(thr, DUK__ENUM_START_INDEX);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
/*
* Proxy object handling
@@ -46421,62 +52334,61 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
goto skip_proxy;
}
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- enum_target,
+ if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
}
+ /* XXX: share code with Object.keys() Proxy handling */
+
+ /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate"
+ * has been obsoleted and "ownKeys" is used instead.
+ */
DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ENUMERATE)) {
+ duk_push_hobject(thr, h_proxy_handler);
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* No need to replace the 'enum_target' value in stack, only the
* enum_target reference. This also ensures that the original
* enum target is reachable, which keeps the proxy and the proxy
* target reachable. We do need to replace the internal _Target.
*/
- DUK_DDD(DUK_DDDPRINT("no enumerate trap, enumerate proxy target instead"));
+ DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead"));
DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
enum_target = h_proxy_target;
- duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_INT_TARGET);
+ duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET);
- duk_pop_2(ctx); /* -> [ ... enum_target res ] */
+ duk_pop_2(thr); /* -> [ ... enum_target res ] */
goto skip_proxy;
}
/* [ ... enum_target res handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
+ duk_insert(thr, -2);
+ duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
+ duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
+ h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
- /* Copy trap result keys into the enumerator object. */
- len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
+ duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
+ /* -> [ ... enum_target res trap_result keys_array ] */
+
+ /* Copy cleaned up trap result keys into the enumerator object. */
+ /* XXX: result is a dense array; could make use of that. */
+ DUK_ASSERT(duk_is_array(thr, -1));
+ len = (duk_uint_fast32_t) duk_get_length(thr, -1);
for (i = 0; i < len; i++) {
- /* XXX: not sure what the correct semantic details are here,
- * e.g. handling of missing values (gaps), handling of non-array
- * trap results, etc.
- *
- * For keys, we simply skip non-string keys which seems to be
- * consistent with how e.g. Object.keys() will process proxy trap
- * results (ES6, Section 19.1.2.14).
- */
- if (duk_get_prop_index(ctx, -1, i) && duk_is_string(ctx, -1)) {
- /* [ ... enum_target res trap_result val ] */
- duk_push_true(ctx);
- /* [ ... enum_target res trap_result val true ] */
- duk_put_prop(ctx, -4);
- } else {
- duk_pop(ctx);
- }
+ (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i);
+ DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */
+ /* [ ... enum_target res trap_result keys_array val ] */
+ duk_push_true(thr);
+ /* [ ... enum_target res trap_result keys_array val true ] */
+ duk_put_prop(thr, -5);
}
- /* [ ... enum_target res trap_result ] */
- duk_pop(ctx);
- duk_remove(ctx, -2);
+ /* [ ... enum_target res trap_result keys_array ] */
+ duk_pop_2(thr);
+ duk_remove_m2(thr);
/* [ ... res ] */
@@ -46493,17 +52405,45 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
#endif /* DUK_USE_ES6_PROXY */
curr = enum_target;
+ sort_start_index = DUK__ENUM_START_INDEX;
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX);
while (curr) {
+ duk_uint_fast32_t sort_end_index;
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_bool_t need_sort = 0;
+#endif
+
+ /* Enumeration proceeds by inheritance level. Virtual
+ * properties need to be handled specially, followed by
+ * array part, and finally entry part.
+ *
+ * If there are array index keys in the entry part or any
+ * other risk of the ES2015 [[OwnPropertyKeys]] order being
+ * violated, need_sort is set and an explicit ES2015 sort is
+ * done for the inheritance level.
+ */
+
+ /* XXX: inheriting from proxy */
+
/*
* Virtual properties.
*
* String and buffer indices are virtual and always enumerable,
* 'length' is virtual and non-enumerable. Array and arguments
* object props have special behavior but are concrete.
+ *
+ * String and buffer objects don't have an array part so as long
+ * as virtual array index keys are enumerated first, we don't
+ * need to set need_sort.
*/
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) ||
- DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr)) {
+#else
+ if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
+#endif
+ duk_bool_t have_length = 1;
+
/* String and buffer enumeration behavior is identical now,
* so use shared handler.
*/
@@ -46512,15 +52452,20 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
- } else {
- duk_hbufferobject *h_bufobj;
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT(curr));
- h_bufobj = (duk_hbufferobject *) curr;
- if (h_bufobj == NULL) {
- /* Neutered buffer, zero length seems
- * like good behavior here.
+ }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ else {
+ duk_hbufobj *h_bufobj;
+ DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr));
+ h_bufobj = (duk_hbufobj *) curr;
+
+ if (h_bufobj == NULL || !h_bufobj->is_typedarray) {
+ /* Zero length seems like a good behavior for neutered buffers.
+ * ArrayBuffer (non-view) and DataView don't have index properties
+ * or .length property.
*/
len = 0;
+ have_length = 0;
} else {
/* There's intentionally no check for
* current underlying buffer length.
@@ -46528,17 +52473,18 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
for (i = 0; i < len; i++) {
duk_hstring *k;
- k = duk_heap_string_intern_u32_checked(thr, i);
+ /* This is a bit fragile: the string is not
+ * reachable until it is pushed by the helper.
+ */
+ k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);
DUK_ASSERT(k);
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
@@ -46548,38 +52494,13 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
* properties are requested.
*/
- if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk_uint_fast32_t n;
-
- if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
- n = sizeof(duk__bufferobject_virtual_props) / sizeof(duk_uint16_t);
- } else {
- DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr));
- DUK_ASSERT(duk__bufferobject_virtual_props[0] == DUK_STRIDX_LENGTH);
- n = 1; /* only 'length' */
- }
-
- for (i = 0; i < n; i++) {
- duk_push_hstring_stridx(ctx, duk__bufferobject_virtual_props[i]);
- duk_push_true(ctx);
- duk_put_prop(ctx, -3);
- }
-
- }
- } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
- if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- duk_push_true(ctx);
- duk_put_prop(ctx, -3);
+ if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
+ duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
}
}
/*
* Array part
- *
- * Note: ordering between array and entry part must match 'abandon array'
- * behavior in duk_hobject_props.c: key order after an array is abandoned
- * must be the same.
*/
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
@@ -46590,18 +52511,21 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (DUK_TVAL_IS_UNUSED(tv)) {
continue;
}
- k = duk_heap_string_intern_u32_checked(thr, i);
+ k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */
DUK_ASSERT(k);
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
-
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
+ if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
+ /* Array .length comes after numeric indices. */
+ if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
+ duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
+ }
+ }
+
/*
* Entries part
*/
@@ -46613,31 +52537,80 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (!k) {
continue;
}
- if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i) &&
- !(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
+ if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) &&
+ !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) {
continue;
}
- if (DUK_HSTRING_HAS_INTERNAL(k) &&
- !(enum_flags & DUK_ENUM_INCLUDE_INTERNAL)) {
- continue;
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
+ if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) &&
+ DUK_HSTRING_HAS_HIDDEN(k)) {
+ continue;
+ }
+ if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
+ continue;
+ }
+#if !defined(DUK_USE_PREFER_SIZE)
+ need_sort = 1;
+#endif
+ } else {
+ DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */
+ if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
+ continue;
+ }
}
- if ((enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) &&
- (DUK_HSTRING_GET_ARRIDX_SLOW(k) == DUK_HSTRING_NO_ARRAY_INDEX)) {
- continue;
+ if (DUK_HSTRING_HAS_ARRIDX(k)) {
+ /* This in currently only possible if the
+ * object has no array part: the array part
+ * is exhaustive when it is present.
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
+ need_sort = 1;
+#endif
+ } else {
+ if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) {
+ continue;
+ }
}
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
-
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
+ /* Sort enumerated keys according to ES2015 requirements for
+ * the "inheritance level" just processed. This is far from
+ * optimal, ES2015 semantics could be achieved more efficiently
+ * by handling array index string keys (and symbol keys)
+ * specially above in effect doing the sort inline.
+ *
+ * Skip the sort if array index sorting is requested because
+ * we must consider all keys, also inherited, so an explicit
+ * sort is done for the whole result after we're done with the
+ * prototype chain.
+ *
+ * Also skip the sort if need_sort == 0, i.e. we know for
+ * certain that the enumerated order is already correct.
+ */
+ sort_end_index = DUK_HOBJECT_GET_ENEXT(res);
+
+ if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
+#else
+ if (need_sort) {
+ DUK_DDD(DUK_DDDPRINT("need to sort"));
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
+ } else {
+ DUK_DDD(DUK_DDDPRINT("no need to sort"));
+ }
+#endif
+ }
+
+ sort_start_index = sort_end_index;
+
if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
break;
}
@@ -46647,33 +52620,22 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* [enum_target res] */
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
/* [res] */
- if ((enum_flags & (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) ==
- (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) {
- /*
- * Some E5/E5.1 algorithms require that array indices are iterated
- * in a strictly ascending order. This is the case for e.g.
- * Array.prototype.forEach() and JSON.stringify() PropertyList
- * handling.
- *
- * To ensure this property for arrays with an array part (and
- * arbitrary objects too, since e.g. forEach() can be applied
- * to an array), the caller can request that we sort the keys
- * here.
- */
-
- /* XXX: avoid this at least when enum_target is an Array, it has an
- * array part, and no ancestor properties were included? Not worth
- * it for JSON, but maybe worth it for forEach().
+ if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) {
+ /* Some E5/E5.1 algorithms require that array indices are iterated
+ * in a strictly ascending order. This is the case for e.g.
+ * Array.prototype.forEach() and JSON.stringify() PropertyList
+ * handling. The caller can request an explicit sort in these
+ * cases.
*/
- /* XXX: may need a 'length' filter for forEach()
+ /* Sort to ES2015 order which works for pure array incides but
+ * also for mixed keys.
*/
- DUK_DDD(DUK_DDDPRINT("sort array indices by caller request"));
- duk__sort_array_indices(thr, res);
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res));
}
#if defined(DUK_USE_ES6_PROXY)
@@ -46682,7 +52644,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* compact; no need to seal because object is internal */
duk_hobject_compact_props(thr, res);
- DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
}
/*
@@ -46693,24 +52655,23 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
*
* Returns zero without pushing anything on the stack otherwise.
*/
-DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) {
duk_hobject *e;
duk_hobject *enum_target;
duk_hstring *res = NULL;
duk_uint_fast32_t idx;
duk_bool_t check_existence;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
/* [... enum] */
- e = duk_require_hobject(ctx, -1);
+ e = duk_require_hobject(thr, -1);
/* XXX use get tval ptr, more efficient */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_NEXT);
- idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT);
+ idx = (duk_uint_fast32_t) duk_require_uint(thr, -1);
+ duk_pop(thr);
DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
/* Enumeration keys are checked against the enumeration target (to see
@@ -46718,18 +52679,18 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
* be the proxy, and checking key existence against the proxy is not
* required (or sensible, as the keys may be fully virtual).
*/
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
- enum_target = duk_require_hobject(ctx, -1);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET);
+ enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
#if defined(DUK_USE_ES6_PROXY)
- check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
+ check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target));
#else
check_existence = 1;
#endif
- duk_pop(ctx); /* still reachable */
+ duk_pop(thr); /* still reachable */
DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
- (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1)));
/* no array part */
for (;;) {
@@ -46761,25 +52722,25 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
- duk_push_u32(ctx, (duk_uint32_t) idx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
+ duk_push_u32(thr, (duk_uint32_t) idx);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
/* [... enum] */
if (res) {
- duk_push_hstring(ctx, res);
+ duk_push_hstring(thr, res);
if (get_value) {
- duk_push_hobject(ctx, enum_target);
- duk_dup(ctx, -2); /* -> [... enum key enum_target key] */
- duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
- duk_remove(ctx, -2); /* -> [... enum key val] */
- duk_remove(ctx, -3); /* -> [... key val] */
+ duk_push_hobject(thr, enum_target);
+ duk_dup_m2(thr); /* -> [... enum key enum_target key] */
+ duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */
+ duk_remove_m2(thr); /* -> [... enum key val] */
+ duk_remove(thr, -3); /* -> [... key val] */
} else {
- duk_remove(ctx, -2); /* -> [... key] */
+ duk_remove_m2(thr); /* -> [... key] */
}
return 1;
} else {
- duk_pop(ctx); /* -> [...] */
+ duk_pop(thr); /* -> [...] */
return 0;
}
}
@@ -46789,166 +52750,64 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
* described in E5 Section 15.2.3.14.
*/
-DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *e;
- duk_uint_fast32_t i;
- duk_uint_fast32_t idx;
+ duk_hstring **keys;
+ duk_tval *tv;
+ duk_uint_fast32_t count;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
- DUK_UNREF(thr);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(duk_get_hobject(thr, -1) != NULL);
/* Create a temporary enumerator to get the (non-duplicated) key list;
* the enumerator state is initialized without being needed, but that
* has little impact.
*/
- duk_hobject_enumerator_create(ctx, enum_flags);
- duk_push_array(ctx);
+ duk_hobject_enumerator_create(thr, enum_flags);
+ e = duk_known_hobject(thr, -1);
/* [enum_target enum res] */
- e = duk_require_hobject(ctx, -2);
- DUK_ASSERT(e != NULL);
+ /* Create dense result array to exact size. */
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
+ count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
- idx = 0;
- for (i = DUK__ENUM_START_INDEX; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(e); i++) {
+ /* XXX: uninit would be OK */
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);
+ DUK_ASSERT(count == 0 || tv != NULL);
+
+ /* Fill result array, no side effects. */
+
+ keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e);
+ keys += DUK__ENUM_START_INDEX;
+
+ while (count-- > 0) {
duk_hstring *k;
- k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, i);
- DUK_ASSERT(k); /* enumerator must have no keys deleted */
+ k = *keys++;
+ DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */
- /* [enum_target enum res] */
- duk_push_hstring(ctx, k);
- duk_put_prop_index(ctx, -2, idx);
- idx++;
+ DUK_TVAL_SET_STRING(tv, k);
+ tv++;
+ DUK_HSTRING_INCREF(thr, k);
}
/* [enum_target enum res] */
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
/* [enum_target res] */
return 1; /* return 1 to allow callers to tail call */
}
-#line 1 "duk_hobject_finalizer.c"
-/*
- * Run an duk_hobject finalizer. Used for both reference counting
- * and mark-and-sweep algorithms. Must never throw an error.
- *
- * There is no return value. Any return value or error thrown by
- * the finalizer is ignored (although errors are debug logged).
- *
- * Notes:
- *
- * - The thread used for calling the finalizer is the same as the
- * 'thr' argument. This may need to change later.
- *
- * - The finalizer thread 'top' assertions are there because it is
- * critical that strict stack policy is observed (i.e. no cruft
- * left on the finalizer stack).
- */
-
-/* include removed: duk_internal.h */
-
-DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
-
- /* [... obj] */
-
- /* XXX: Finalizer lookup should traverse the prototype chain (to allow
- * inherited finalizers) but should not invoke accessors or proxy object
- * behavior. At the moment this lookup will invoke proxy behavior, so
- * caller must ensure that this function is not called if the target is
- * a Proxy.
- */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
- return 0;
- }
- duk_dup(ctx, -2);
- duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
- DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
- duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
- DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
- return 0;
-
- /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
- * so we don't need to pop stuff here. There is no return value;
- * caller determines rescued status based on object refcount.
- */
-}
-
-DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_ret_t rc;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top;
-#endif
-
- DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, 1);
-
-#ifdef DUK_USE_ASSERTIONS
- entry_top = duk_get_top(ctx);
-#endif
- /*
- * Get and call the finalizer. All of this must be wrapped
- * in a protected call, because even getting the finalizer
- * may trigger an error (getter may throw one, for instance).
- */
-
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
- if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
- DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
- return;
- }
- DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
- /* This shouldn't happen; call sites should avoid looking up
- * _Finalizer "through" a Proxy, but ignore if we come here
- * with a Proxy to avoid finalizer re-entry.
- */
- DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
- return;
- }
- /* XXX: use a NULL error handler for the finalizer call? */
-
- DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
- duk_push_hobject(ctx, obj); /* this also increases refcount by one */
- rc = duk_safe_call(ctx, duk__finalize_helper, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
- DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
-
- if (rc != DUK_EXEC_SUCCESS) {
- /* Note: we ask for one return value from duk_safe_call to get this
- * error debugging here.
- */
- DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
- (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
- }
- duk_pop_2(ctx); /* -> [...] */
-
- DUK_ASSERT_TOP(ctx, entry_top);
-}
-#line 1 "duk_hobject_misc.c"
+/* automatic undefs */
+#undef DUK__ENUM_START_INDEX
/*
* Misc support functions
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
duk_uint_t sanity;
@@ -46982,7 +52841,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, d
}
DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
duk_hobject *tmp;
DUK_ASSERT(h);
@@ -46996,7 +52855,6 @@ DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
#endif
}
-#line 1 "duk_hobject_pc2line.c"
/*
* Helpers for creating and querying pc2line debug data, which
* converts a bytecode program counter to a source line number.
@@ -47006,13 +52864,12 @@ DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject
* doc/function-objects.rst
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_PC2LINE)
/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
- duk_context *ctx = (duk_context *) thr;
duk_hbuffer_dynamic *h_buf;
duk_bitencoder_ctx be_ctx_alloc;
duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
@@ -47026,16 +52883,11 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
- /* XXX: add proper spare handling to dynamic buffer, to minimize
- * reallocs; currently there is no spare at all.
- */
-
num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
- duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
- h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_buf != NULL);
+ duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset);
+ h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
@@ -47087,17 +52939,17 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
duk_be_encode(be_ctx, 0, 1);
} else if (diff_line >= 1 && diff_line <= 4) {
/* 1 0 <2 bits> */
- duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4);
} else if (diff_line >= -0x80 && diff_line <= 0x7f) {
/* 1 1 0 <8 bits> */
DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
- duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11);
} else {
/* 1 1 1 <32 bits>
* Encode in two parts to avoid bitencode 24-bit limitation
*/
- duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
- duk_be_encode(be_ctx, next_line & 0xffffU, 16);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19);
+ duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16);
}
curr_line = next_line;
@@ -47114,11 +52966,11 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
new_size = (duk_size_t) curr_offset;
duk_hbuffer_resize(thr, h_buf, new_size);
- (void) duk_to_fixed_buffer(ctx, -1, NULL);
+ (void) duk_to_fixed_buffer(thr, -1, NULL);
DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
(long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
}
/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
@@ -47150,7 +53002,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
- goto error;
+ goto pc2line_error;
}
hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
@@ -47159,7 +53011,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
/* Note: pc is unsigned and cannot be negative */
DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
(long) pc, (long) pc_limit));
- goto error;
+ goto pc2line_error;
}
curr_line = hdr[1 + hdr_index * 2];
@@ -47167,7 +53019,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
(long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
- goto error;
+ goto pc2line_error;
}
/*
@@ -47218,12 +53070,12 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
return curr_line;
- error:
+ pc2line_error:
DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
return 0;
}
-DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
+DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) {
duk_hbuffer_fixed *pc2line;
duk_uint_fast32_t line;
@@ -47233,23 +53085,22 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
* future work in debugger.rst).
*/
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
- pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
+ duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
+ pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(thr, -1);
if (pc2line != NULL) {
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
- line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
+ line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
} else {
line = 0;
}
- duk_pop(ctx);
+ duk_pop(thr);
return line;
}
#endif /* DUK_USE_PC2LINE */
-#line 1 "duk_hobject_props.c"
/*
- * Hobject property set/get functionality.
+ * duk_hobject property access functionality.
*
* This is very central functionality for size, performance, and compliance.
* It is also rather intricate; see hobject-algorithms.rst for discussion on
@@ -47281,7 +53132,8 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
*
* - The order of operations for a DECREF matters. When DECREF is executed,
* the entire object graph must be consistent; note that a refzero may
- * lead to a mark-and-sweep through a refcount finalizer.
+ * lead to a mark-and-sweep through a refcount finalizer. Use NORZ macros
+ * and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard.
*/
/*
@@ -47289,11 +53141,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
* might be more appropriate.
*/
-/*
- * XXX: duk_uint_fast32_t should probably be used in many places here.
- */
-
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Local defines
@@ -47301,21 +53149,17 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
-/* hash probe sequence */
-#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
-#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash))
-
-/* marker values for hash part */
+/* Marker values for hash part. */
#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
-/* valstack space that suffices for all local calls, including recursion
- * of other than Duktape calls (getters etc)
+/* Valstack space that suffices for all local calls, excluding any recursion
+ * into Ecmascript or Duktape/C calls (Proxy, getters, etc).
*/
#define DUK__VALSTACK_SPACE 10
-/* valstack space allocated especially for proxy lookup which does a
- * recursive property lookup
+/* Valstack space allocated especially for proxy lookup which does a
+ * recursive property lookup.
*/
#define DUK__VALSTACK_PROXY_LOOKUP 20
@@ -47332,7 +53176,6 @@ DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hob
DUK_LOCAL_DECL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
DUK_LOCAL_DECL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags);
-DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc);
/*
* Misc helpers
@@ -47375,7 +53218,7 @@ DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
t = DUK_TVAL_GET_FASTINT(tv);
- if ((t & ~0xffffffffULL) != 0) {
+ if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) {
/* Catches >0x100000000 and negative values. */
return DUK__NO_ARRAY_INDEX;
}
@@ -47387,20 +53230,41 @@ DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
}
#endif /* DUK_USE_FASTINT */
-/* Push an arbitrary duk_tval to the stack, coerce it to string, and return
- * both a duk_hstring pointer and an array index (or DUK__NO_ARRAY_INDEX).
+/* Convert a duk_tval on the value stack (in a trusted index we don't validate)
+ * to a string or symbol using ES2015 ToPropertyKey():
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey.
+ *
+ * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX
+ * if not).
*/
-DUK_LOCAL duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_tval *tv, duk_hstring **out_h) {
+DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) {
duk_uint32_t arr_idx;
duk_hstring *h;
+ duk_tval *tv_dst;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv != NULL);
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(out_h != NULL);
-
- duk_push_tval(ctx, tv);
- duk_to_string(ctx, -1);
- h = duk_get_hstring(ctx, -1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx));
+ DUK_ASSERT(idx < 0);
+
+ /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just
+ * ToString()) involves a ToPrimitive(), a symbol check, and finally
+ * a ToString(). Figure out the best way to have a good fast path
+ * but still be compliant and share code.
+ */
+
+ tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx); /* intentionally unvalidated */
+ if (DUK_TVAL_IS_STRING(tv_dst)) {
+ /* Most important path: strings and plain symbols are used as
+ * is. For symbols the array index check below is unnecessary
+ * (they're never valid array indices) but checking that the
+ * string is a symbol would make the plain string path slower
+ * unnecessarily.
+ */
+ h = DUK_TVAL_GET_STRING(tv_dst);
+ } else {
+ h = duk_to_property_key_hstring(thr, idx);
+ }
DUK_ASSERT(h != NULL);
*out_h = h;
@@ -47408,11 +53272,27 @@ DUK_LOCAL duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_t
return arr_idx;
}
-/* String is an own (virtual) property of a lightfunc. */
-DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
+DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) {
+ duk_push_tval(thr, tv_key); /* XXX: could use an unsafe push here */
+ return duk__to_property_key(thr, -1, out_h);
+}
+
+/* String is an own (virtual) property of a plain buffer. */
+DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) {
DUK_UNREF(thr);
- return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_NAME(thr));
+
+ /* Virtual index properties. Checking explicitly for
+ * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary
+ * because DUK__NO_ARRAY_INDEXi is always larger than
+ * maximum allowed buffer size.
+ */
+ DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf));
+ if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) {
+ return 1;
+ }
+
+ /* Other virtual properties. */
+ return (key == DUK_HTHREAD_STRING_LENGTH(thr));
}
/*
@@ -47424,14 +53304,26 @@ DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring
DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
- if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
+ if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
duk_uint32_t res;
+ duk_uint32_t tmp;
- /* result: hash_prime(floor(1.2 * e_size)) */
- res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
-
- /* if fails, e_size will be zero = not an issue, except performance-wise */
- DUK_ASSERT(res == 0 || res > e_size);
+ /* Hash size should be 2^N where N is chosen so that 2^N is
+ * larger than e_size. Extra shifting is used to ensure hash
+ * is relatively sparse.
+ */
+ tmp = e_size;
+ res = 2; /* Result will be 2 ** (N + 1). */
+ while (tmp >= 0x40) {
+ tmp >>= 6;
+ res <<= 6;
+ }
+ while (tmp != 0) {
+ tmp >>= 1;
+ res <<= 1;
+ }
+ DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */
+ DUK_ASSERT(res > e_size);
return res;
} else {
return 0;
@@ -47445,7 +53337,7 @@ DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
- res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
+ res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR;
DUK_ASSERT(res >= 1); /* important for callers */
return res;
}
@@ -47456,7 +53348,7 @@ DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
- res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
+ res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR;
DUK_ASSERT(res >= 1); /* important for callers */
return res;
}
@@ -47509,8 +53401,8 @@ DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint
* for out_min_size as intended.
*/
- *out_used = used;
- *out_min_size = highest_idx + 1; /* 0 if no used entries */
+ *out_used = (duk_uint32_t) used;
+ *out_min_size = (duk_uint32_t) (highest_idx + 1); /* 0 if no used entries */
}
/* Check array density and indicate whether or not the array part should be abandoned. */
@@ -47531,7 +53423,7 @@ DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_u
* of the check, but may confuse debugging.
*/
- return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
+ return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3));
}
/* Fast check for extending array: check whether or not a slow density check is required. */
@@ -47557,7 +53449,7 @@ DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx
* arr_idx > limit'' * ((old_size + 7) / 8)
*/
- return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
+ return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
}
/*
@@ -47565,13 +53457,9 @@ DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx
*/
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
- duk_tval *tv_target;
- duk_tval *tv_handler;
- duk_hobject *h_target;
- duk_hobject *h_handler;
+DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
+ duk_hproxy *h_proxy;
- DUK_ASSERT(thr != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(out_target != NULL);
DUK_ASSERT(out_handler != NULL);
@@ -47579,31 +53467,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *o
/* Caller doesn't need to check exotic proxy behavior (but does so for
* some fast paths).
*/
- if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) {
return 0;
}
+ h_proxy = (duk_hproxy *) obj;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
- tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
- if (!tv_handler) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
- h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
- DUK_ASSERT(h_handler != NULL);
- *out_handler = h_handler;
- tv_handler = NULL; /* avoid issues with relocation */
-
- tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
- if (!tv_target) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
- h_target = DUK_TVAL_GET_OBJECT(tv_target);
- DUK_ASSERT(h_target != NULL);
- *out_target = h_target;
- tv_target = NULL; /* avoid issues with relocation */
+ DUK_ASSERT(h_proxy->handler != NULL);
+ DUK_ASSERT(h_proxy->target != NULL);
+ *out_handler = h_proxy->handler;
+ *out_target = h_proxy->target;
return 1;
}
@@ -47613,25 +53486,21 @@ DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *o
* If a Proxy is revoked, an error is thrown.
*/
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- DUK_ASSERT(thr != NULL);
+DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) {
DUK_ASSERT(obj != NULL);
/* Resolve Proxy targets until Proxy chain ends. No explicit check for
- * a Proxy loop: user code cannot create such a loop without tweaking
- * internal properties directly.
+ * a Proxy loop: user code cannot create such a loop (it would only be
+ * possible by editing duk_hproxy references directly).
*/
- while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
- DUK_ASSERT(h_target != NULL);
- obj = h_target;
- } else {
- break;
- }
+ while (DUK_HOBJECT_IS_PROXY(obj)) {
+ duk_hproxy *h_proxy;
+
+ h_proxy = (duk_hproxy *) obj;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
+ obj = h_proxy->target;
+ DUK_ASSERT(obj != NULL);
}
DUK_ASSERT(obj != NULL);
@@ -47641,7 +53510,6 @@ DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk
#if defined(DUK_USE_ES6_PROXY)
DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h_handler;
DUK_ASSERT(thr != NULL);
@@ -47649,7 +53517,7 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
DUK_ASSERT(tv_key != NULL);
DUK_ASSERT(out_target != NULL);
- if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
+ if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) {
return 0;
}
DUK_ASSERT(*out_target != NULL);
@@ -47668,8 +53536,12 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
if (DUK_TVAL_IS_STRING(tv_key)) {
duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
DUK_ASSERT(h_key != NULL);
- if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
- DUK_DDD(DUK_DDDPRINT("internal key, skip proxy handler and apply to target"));
+ if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
+ /* Symbol accesses must go through proxy lookup in ES2015.
+ * Hidden symbols behave like Duktape 1.x internal keys
+ * and currently won't.
+ */
+ DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target"));
return 0;
}
}
@@ -47687,16 +53559,16 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
/* XXX: C recursion limit if proxies are allowed as handler/target values */
- duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
- duk_push_hobject(ctx, h_handler);
- if (duk_get_prop_stridx(ctx, -1, stridx_trap)) {
+ duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP);
+ duk_push_hobject(thr, h_handler);
+ if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) {
/* -> [ ... handler trap ] */
- duk_insert(ctx, -2); /* -> [ ... trap handler ] */
+ duk_insert(thr, -2); /* -> [ ... trap handler ] */
/* stack prepped for func call: [ ... trap handler ] */
return 1;
} else {
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return 0;
}
}
@@ -47705,46 +53577,39 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
/*
* Reallocate property allocation, moving properties to the new allocation.
*
- * Includes key compaction, rehashing, and can also optionally abandoning
+ * Includes key compaction, rehashing, and can also optionally abandon
* the array part, 'migrating' array entries into the beginning of the
- * new entry part. Arguments are not validated here, so e.g. new_h_size
- * MUST be a valid prime.
+ * new entry part.
*
* There is no support for in-place reallocation or just compacting keys
* without resizing the property allocation. This is intentional to keep
- * code size minimal.
+ * code size minimal, but would be useful future work.
*
* The implementation is relatively straightforward, except for the array
* abandonment process. Array abandonment requires that new string keys
* are interned, which may trigger GC. All keys interned so far must be
- * reachable for GC at all times; valstack is used for that now.
+ * reachable for GC at all times and correctly refcounted for; valstack is
+ * used for that now.
*
* Also, a GC triggered during this reallocation process must not interfere
- * with the object being resized. This is currently controlled by using
- * heap->mark_and_sweep_base_flags to indicate that no finalizers will be
- * executed (as they can affect ANY object) and no objects are compacted
- * (it would suffice to protect this particular object only, though).
- *
- * Note: a non-checked variant would be nice but is a bit tricky to
- * implement for the array abandonment process. It's easy for
- * everything else.
+ * with the object being resized. This is currently controlled by preventing
+ * finalizers (as they may affect ANY object) and object compaction in
+ * mark-and-sweep. It would suffice to protect only this particular object
+ * from compaction, however. DECREF refzero cascades are side effect free
+ * and OK.
*
* Note: because we need to potentially resize the valstack (as part
* of abandoning the array part), any tval pointers to the valstack
* will become invalid after this call.
*/
-DUK_LOCAL
-void duk__realloc_props(duk_hthread *thr,
- duk_hobject *obj,
- duk_uint32_t new_e_size,
- duk_uint32_t new_a_size,
- duk_uint32_t new_h_size,
- duk_bool_t abandon_array) {
- duk_context *ctx = (duk_context *) thr;
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
+DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size,
+ duk_uint32_t new_a_size,
+ duk_uint32_t new_h_size,
+ duk_bool_t abandon_array) {
+ duk_small_uint_t prev_ms_base_flags;
duk_uint32_t new_alloc_size;
duk_uint32_t new_e_size_adjusted;
duk_uint8_t *new_p;
@@ -47755,9 +53620,12 @@ void duk__realloc_props(duk_hthread *thr,
duk_uint32_t *new_h;
duk_uint32_t new_e_next;
duk_uint_fast32_t i;
+ duk_size_t array_copy_size;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_bool_t prev_error_not_allowed;
+#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
@@ -47767,11 +53635,13 @@ void duk__realloc_props(duk_hthread *thr,
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_object_realloc_props);
+
/*
* Pre resize assertions.
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
/* XXX: pre-checks (such as no duplicate keys) */
#endif
@@ -47791,7 +53661,8 @@ void duk__realloc_props(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
new_e_size_adjusted = new_e_size;
#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
- new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
+ new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) &
+ (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U));
DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
(long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
DUK_ASSERT(new_e_size_adjusted >= new_e_size);
@@ -47824,60 +53695,61 @@ void duk__realloc_props(duk_hthread *thr,
/*
* Property count check. This is the only point where we ensure that
* we don't get more (allocated) property space that we can handle.
- * There aren't hard limits as such, but some algorithms fail (e.g.
- * finding next higher prime, selecting hash part size) if we get too
- * close to the 4G property limit.
+ * There aren't hard limits as such, but some algorithms may fail
+ * if we get too close to the 4G property limit.
*
* Since this works based on allocation size (not actually used size),
* the limit is a bit approximate but good enough in practice.
*/
if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ DUK_ERROR_ALLOC_FAILED(thr);
}
/*
* Compute new alloc size and alloc new area.
*
- * The new area is allocated as a dynamic buffer and placed into the
- * valstack for reachability. The actual buffer is then detached at
- * the end.
- *
- * Note: heap_mark_and_sweep_base_flags are altered here to ensure
- * no-one touches this object while we're resizing and rehashing it.
- * The flags must be reset on every exit path after it. Finalizers
- * and compaction is prevented currently for all objects while it
- * would be enough to restrict it only for the current object.
+ * The new area is not tracked in the heap at all, so it's critical
+ * we get to free/keep it in a controlled manner.
*/
-#ifdef DUK_USE_MARK_AND_SWEEP
- prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
- thr->heap->mark_and_sweep_base_flags |=
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */
+#if defined(DUK_USE_ASSERTIONS)
+ /* Whole path must be error throw free, but we may be called from
+ * within error handling so can't assert for error_not_allowed == 0.
+ */
+ prev_error_not_allowed = thr->heap->error_not_allowed;
+ thr->heap->error_not_allowed = 1;
#endif
+ prev_ms_base_flags = thr->heap->ms_base_flags;
+ thr->heap->ms_base_flags |=
+ DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */
+ thr->heap->pf_prevent_count++; /* Avoid finalizers. */
+ DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
if (new_alloc_size == 0) {
- /* for zero size, don't push anything on valstack */
DUK_ASSERT(new_e_size_adjusted == 0);
DUK_ASSERT(new_a_size == 0);
DUK_ASSERT(new_h_size == 0);
new_p = NULL;
} else {
- /* This may trigger mark-and-sweep with arbitrary side effects,
- * including an attempted resize of the object we're resizing,
- * executing a finalizer which may add or remove properties of
- * the object we're resizing etc.
+ /* Alloc may trigger mark-and-sweep but no compaction, and
+ * cannot throw.
*/
-
- /* Note: buffer is dynamic so that we can 'steal' the actual
- * allocation later.
- */
-
- new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */
- DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */
+#if 0 /* XXX: inject test */
+ if (1) {
+ new_p = NULL;
+ goto alloc_failed;
+ }
+#endif
+ new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size);
+ if (new_p == NULL) {
+ /* NULL always indicates alloc failure because
+ * new_alloc_size > 0.
+ */
+ goto alloc_failed;
+ }
}
/* Set up pointers to the new property area: this is hidden behind a macro
@@ -47898,30 +53770,32 @@ void duk__realloc_props(duk_hthread *thr,
(void *) new_a, (void *) new_h));
/*
- * Migrate array to start of entries if requested.
+ * Migrate array part to start of entries if requested.
*
* Note: from an enumeration perspective the order of entry keys matters.
* Array keys should appear wherever they appeared before the array abandon
- * operation.
+ * operation. (This no longer matters much because keys are ES2015 sorted.)
*/
if (abandon_array) {
- /*
- * Note: assuming new_a_size == 0, and that entry part contains
- * no conflicting keys, refcounts do not need to be adjusted for
- * the values, as they remain exactly the same.
+ /* Assuming new_a_size == 0, and that entry part contains
+ * no conflicting keys, refcounts do not need to be adjusted for
+ * the values, as they remain exactly the same.
*
- * The keys, however, need to be interned, incref'd, and be
- * reachable for GC. Any intern attempt may trigger a GC and
- * claim any non-reachable strings, so every key must be reachable
- * at all times.
+ * The keys, however, need to be interned, incref'd, and be
+ * reachable for GC. Any intern attempt may trigger a GC and
+ * claim any non-reachable strings, so every key must be reachable
+ * at all times. Refcounts must be correct to satisfy refcount
+ * assertions.
*
- * A longjmp must not occur here, as the new_p allocation would
- * be freed without these keys being decref'd, hence the messy
- * decref handling if intern fails.
+ * A longjmp must not occur here, as the new_p allocation would
+ * leak. Refcounts would come out correctly as the interned
+ * strings are valstack tracked.
*/
DUK_ASSERT(new_a_size == 0);
+ DUK_STATS_INC(thr->heap, stats_object_abandon_array);
+
for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
duk_tval *tv1;
duk_tval *tv2;
@@ -47947,20 +53821,29 @@ void duk__realloc_props(duk_hthread *thr,
* must be careful.
*/
- /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
- if (!duk_check_stack(ctx, 1)) {
+#if 0 /* XXX: inject test */
+ if (1) {
+ goto abandon_error;
+ }
+#endif
+ /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which
+ * is generous.
+ */
+ if (!duk_check_stack(thr, 1)) {
goto abandon_error;
}
DUK_ASSERT_VALSTACK_SPACE(thr, 1);
- key = duk_heap_string_intern_u32(thr->heap, i);
- if (!key) {
+ key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i);
+ if (key == NULL) {
goto abandon_error;
}
- duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
+ duk_push_hstring(thr, key); /* keep key reachable for GC etc; guaranteed not to fail */
- /* key is now reachable in the valstack */
+ /* Key is now reachable in the valstack, don't INCREF
+ * the new allocation yet (we'll steal the refcounts
+ * from the value stack once all keys are done).
+ */
- DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */
new_e_k[new_e_next] = key;
tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
DUK_TVAL_SET_TVAL(tv2, tv1);
@@ -47974,8 +53857,9 @@ void duk__realloc_props(duk_hthread *thr,
*/
}
+ /* Steal refcounts from value stack. */
DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
- duk_pop_n(ctx, new_e_next);
+ duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next);
}
/*
@@ -47988,7 +53872,7 @@ void duk__realloc_props(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
- if (!key) {
+ if (key == NULL) {
continue;
}
@@ -48003,53 +53887,46 @@ void duk__realloc_props(duk_hthread *thr,
/* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
/*
- * Copy array elements to new array part.
+ * Copy array elements to new array part. If the new array part is
+ * larger, initialize the unused entries as UNUSED because they are
+ * GC reachable.
*/
- if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
- /* copy existing entries as is */
- DUK_ASSERT(new_p != NULL && new_a != NULL);
- if (DUK_HOBJECT_GET_ASIZE(obj) > 0) {
- /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
- * the 'new_a' pointer will be invalid which is not allowed even
- * when copy size is zero.
- */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
- DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj));
- }
-
- /* fill new entries with -unused- (required, gc reachable) */
- for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
- duk_tval *tv = &new_a[i];
- DUK_TVAL_SET_UNUSED(tv);
- }
- } else {
-#ifdef DUK_USE_ASSERTIONS
- /* caller must have decref'd values above new_a_size (if that is necessary) */
- if (!abandon_array) {
- for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
- duk_tval *tv;
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
-
- /* current assertion is quite strong: decref's and set to unused */
- DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
- }
+#if defined(DUK_USE_ASSERTIONS)
+ /* Caller must have decref'd values above new_a_size (if that is necessary). */
+ if (!abandon_array) {
+ for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
+ duk_tval *tv;
+ tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
+ DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
}
+ }
#endif
- if (new_a_size > 0) {
- /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
- * the 'new_a' pointer will be invalid which is not allowed even
- * when copy size is zero.
- */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(new_a_size > 0);
- DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size);
- }
+ if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
+ array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj);
+ } else {
+ array_copy_size = sizeof(duk_tval) * new_a_size;
+ }
+ if (array_copy_size > 0) {
+ /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
+ * the 'new_a' pointer will be invalid which is not allowed even
+ * when copy size is zero.
+ */
+ DUK_ASSERT(new_a != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
+ DUK_MEMCPY((void *) new_a,
+ (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
+ array_copy_size);
+ }
+ for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
+ duk_tval *tv = &new_a[i];
+ DUK_TVAL_SET_UNUSED(tv);
}
/*
- * Rebuild the hash part always from scratch (guaranteed to finish).
+ * Rebuild the hash part always from scratch (guaranteed to finish
+ * as long as caller gave consistent parameters).
*
* Any resize of hash part requires rehashing. In addition, by rehashing
* get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
@@ -48057,39 +53934,41 @@ void duk__realloc_props(duk_hthread *thr,
*/
#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (DUK_UNLIKELY(new_h_size > 0)) {
+ if (new_h_size == 0) {
+ DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
+ } else {
+ duk_uint32_t mask;
+
DUK_ASSERT(new_h != NULL);
/* fill new_h with u32 0xff = UNUSED */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
DUK_ASSERT(new_h_size > 0);
DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
+
+ mask = new_h_size - 1;
for (i = 0; i < new_e_next; i++) {
duk_hstring *key = new_e_k[i];
duk_uint32_t j, step;
DUK_ASSERT(key != NULL);
- j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
+ j = DUK_HSTRING_GET_HASH(key) & mask;
+ step = 1; /* Cache friendly but clustering prone. */
for (;;) {
DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
if (new_h[j] == DUK__HASH_UNUSED) {
DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
- new_h[j] = i;
+ new_h[j] = (duk_uint32_t) i;
break;
}
DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
- j = (j + step) % new_h_size;
+ j = (j + step) & mask;
- /* guaranteed to finish */
- DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));
+ /* Guaranteed to finish (hash is larger than #props). */
}
}
- } else {
- DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
}
#endif /* DUK_USE_HOBJECT_HASH_PART */
@@ -48121,75 +54000,114 @@ void duk__realloc_props(duk_hthread *thr,
* All done, switch properties ('p') allocation to new one.
*/
- DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
+ DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
- if (new_p) {
- /*
- * Detach actual buffer from dynamic buffer in valstack, and
- * pop it from the stack.
- *
- * XXX: the buffer object is certainly not reachable at this point,
- * so it would be nice to free it forcibly even with only
- * mark-and-sweep enabled. Not a big issue though.
- */
- (void) duk_steal_buffer(ctx, -1, NULL);
- duk_pop(ctx);
- } else {
- DUK_ASSERT(new_alloc_size == 0);
- /* no need to pop, nothing was pushed */
- }
-
- /* clear array part flag only after switching */
+ /* Clear array part flag only after switching. */
if (abandon_array) {
DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
}
DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
-#ifdef DUK_USE_MARK_AND_SWEEP
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
+ DUK_ASSERT(thr->heap->pf_prevent_count > 0);
+ thr->heap->pf_prevent_count--;
+ thr->heap->ms_base_flags = prev_ms_base_flags;
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(thr->heap->error_not_allowed == 1);
+ thr->heap->error_not_allowed = prev_error_not_allowed;
#endif
/*
* Post resize assertions.
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
/* XXX: post-checks (such as no duplicate keys) */
#endif
return;
/*
- * Abandon array failed, need to decref keys already inserted
- * into the beginning of new_e_k before unwinding valstack.
+ * Abandon array failed. We don't need to DECREF anything
+ * because the references in the new allocation are not
+ * INCREF'd until abandon is complete. The string interned
+ * keys are on the value stack and are handled normally by
+ * unwind.
*/
abandon_error:
- DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys"));
- i = new_e_next;
- while (i > 0) {
- i--;
- DUK_ASSERT(new_e_k != NULL);
- DUK_ASSERT(new_e_k[i] != NULL);
- DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */
- }
+ alloc_failed:
+ DUK_D(DUK_DPRINT("object property table resize failed"));
+
+ DUK_FREE_CHECKED(thr, new_p); /* OK for NULL. */
-#ifdef DUK_USE_MARK_AND_SWEEP
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
+ thr->heap->pf_prevent_count--;
+ thr->heap->ms_base_flags = prev_ms_base_flags;
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(thr->heap->error_not_allowed == 1);
+ thr->heap->error_not_allowed = prev_error_not_allowed;
#endif
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ DUK_ERROR_ALLOC_FAILED(thr);
}
/*
* Helpers to resize properties allocation on specific needs.
*/
+DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size) {
+ duk_uint32_t old_e_size;
+ duk_uint32_t new_a_size;
+ duk_uint32_t new_h_size;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(obj != NULL);
+
+ old_e_size = DUK_HOBJECT_GET_ESIZE(obj);
+ if (old_e_size > new_e_size) {
+ new_e_size = old_e_size;
+ }
+#if defined(DUK_USE_HOBJECT_HASH_PART)
+ new_h_size = duk__get_default_h_size(new_e_size);
+#else
+ new_h_size = 0;
+#endif
+ new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
+
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+}
+
+#if 0 /*unused */
+DUK_INTERNAL void duk_hobject_resize_arraypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_a_size) {
+ duk_uint32_t old_a_size;
+ duk_uint32_t new_e_size;
+ duk_uint32_t new_h_size;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(obj != NULL);
+
+ if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
+ return;
+ }
+ old_a_size = DUK_HOBJECT_GET_ASIZE(obj);
+ if (old_a_size > new_a_size) {
+ new_a_size = old_a_size;
+ }
+ new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
+ new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
+
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+}
+#endif
+
/* Grow entry part allocation for one additional entry. */
DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
duk_uint32_t old_e_used; /* actually used, non-NULL entries */
@@ -48217,7 +54135,7 @@ DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject
new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
}
/* Grow array part for a new highest array index. */
@@ -48237,7 +54155,7 @@ DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj
new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
}
/* Abandon array part, moving array entries into entries part.
@@ -48280,7 +54198,7 @@ DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
(void *) obj, (long) e_used, (long) a_used, (long) a_size,
(long) new_e_size, (long) new_a_size, (long) new_h_size));
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
}
/*
@@ -48333,7 +54251,7 @@ DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj)
}
#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
+ if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
h_size = duk__get_default_h_size(e_size);
} else {
h_size = 0;
@@ -48345,7 +54263,7 @@ DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj)
DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
(long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
- duk__realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
+ duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
}
/*
@@ -48358,7 +54276,7 @@ DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj)
* but there is no hash part, h_idx is set to -1.
*/
-DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
+DUK_INTERNAL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
DUK_ASSERT(e_idx != NULL);
@@ -48381,9 +54299,9 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
n = DUK_HOBJECT_GET_ENEXT(obj);
for (i = 0; i < n; i++) {
if (h_keys_base[i] == key) {
- *e_idx = i;
+ *e_idx = (duk_int_t) i;
*h_idx = -1;
- return;
+ return 1;
}
}
}
@@ -48394,13 +54312,15 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
duk_uint32_t n;
duk_uint32_t i, step;
duk_uint32_t *h_base;
+ duk_uint32_t mask;
DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
n = DUK_HOBJECT_GET_HSIZE(obj);
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
+ mask = n - 1;
+ i = DUK_HSTRING_GET_HASH(key) & mask;
+ step = 1; /* Cache friendly but clustering prone. */
for (;;) {
duk_uint32_t t;
@@ -48421,24 +54341,22 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
(long) i, (long) t, (void *) key));
- *e_idx = t;
- *h_idx = i;
- return;
+ *e_idx = (duk_int_t) t;
+ *h_idx = (duk_int_t) i;
+ return 1;
}
DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
(long) i, (long) t));
}
- i = (i + step) % n;
+ i = (i + step) & mask;
- /* guaranteed to finish, as hash is never full */
- DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));
+ /* Guaranteed to finish (hash is larger than #props). */
}
}
#endif /* DUK_USE_HOBJECT_HASH_PART */
- /* not found */
- *e_idx = -1;
- *h_idx = -1;
+ /* Not found, leave e_idx and h_idx unset. */
+ return 0;
}
/* For internal use: get non-accessor entry value */
@@ -48450,16 +54368,17 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap,
DUK_ASSERT(key != NULL);
DUK_UNREF(heap);
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- return NULL;
+ if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
+ if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
+ return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
+ }
}
+ return NULL;
}
/* For internal use: get non-accessor entry value and attributes */
-DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs) {
+DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) {
duk_int_t e_idx;
duk_int_t h_idx;
@@ -48468,14 +54387,15 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_he
DUK_ASSERT(out_attrs != NULL);
DUK_UNREF(heap);
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- *out_attrs = 0;
- return NULL;
+ if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
+ if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
+ *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
+ return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
+ }
}
+ /* If not found, out_attrs is left unset. */
+ return NULL;
}
/* For internal use: get array part value */
@@ -48504,7 +54424,7 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *
* the entry value refcount. A decref for the previous value is not necessary.
*/
-DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
+DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
duk_uint32_t idx;
DUK_ASSERT(thr != NULL);
@@ -48512,7 +54432,7 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
DUK_ASSERT(key != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
/* key must not already exist in entry part */
{
duk_uint_fast32_t i;
@@ -48536,18 +54456,19 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
#if defined(DUK_USE_HOBJECT_HASH_PART)
if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
- duk_uint32_t n;
+ duk_uint32_t n, mask;
duk_uint32_t i, step;
duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
n = DUK_HOBJECT_GET_HSIZE(obj);
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
+ mask = n - 1;
+ i = DUK_HSTRING_GET_HASH(key) & mask;
+ step = 1; /* Cache friendly but clustering prone. */
for (;;) {
duk_uint32_t t = h_base[i];
if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
+ DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld",
(long) i, (long) idx));
DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
@@ -48556,11 +54477,10 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
h_base[i] = idx;
break;
}
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
- i = (i + step) % n;
+ DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld", (long) i));
+ i = (i + step) & mask;
- /* guaranteed to find an empty slot */
- DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj)));
+ /* Guaranteed to finish (hash is larger than #props). */
}
}
#endif /* DUK_USE_HOBJECT_HASH_PART */
@@ -48572,7 +54492,7 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
DUK_ASSERT_DISABLE(idx >= 0);
DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
- return idx;
+ return (duk_int_t) idx;
}
/*
@@ -48590,9 +54510,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobje
DUK_ASSERT(obj != NULL);
DUK_ASSERT(tv_out != NULL);
- /* always in entry part, no need to look up parents etc */
- duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
- if (e_idx >= 0) {
+ /* Always in entry part, no need to look up parents etc. */
+ if (duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
return 1;
@@ -48616,6 +54536,7 @@ DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap,
duk_hstring *h;
DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
h = DUK_TVAL_GET_STRING(&tv);
+ /* No explicit check for string vs. symbol, accept both. */
return h;
}
@@ -48642,7 +54563,6 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
duk_propdesc *temp_desc,
duk_hobject **out_map,
duk_hobject **out_varenv) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_bool_t rc;
@@ -48659,9 +54579,9 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
return 0;
}
- map = duk_require_hobject(ctx, -1);
+ map = duk_require_hobject(thr, -1);
DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
+ duk_pop_unsafe(thr); /* map is reachable through obj */
if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
@@ -48670,16 +54590,16 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
/* [... varname] */
DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_ASSERT(duk_is_string(thr, -1)); /* guaranteed when building arguments */
/* get varenv for varname (callee's declarative lexical environment) */
rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
- varenv = duk_require_hobject(ctx, -1);
+ varenv = duk_require_hobject(thr, -1);
DUK_ASSERT(varenv != NULL);
- duk_pop(ctx); /* varenv remains reachable through 'obj' */
+ duk_pop_unsafe(thr); /* varenv remains reachable through 'obj' */
DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
@@ -48694,7 +54614,6 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
* Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
*/
DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_hstring *varname;
@@ -48708,9 +54627,9 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
/* [... varname] */
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
+ duk_pop_unsafe(thr); /* varname is still reachable */
DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
"key=%!O, varname=%!O",
@@ -48721,7 +54640,7 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
/* [... value this_binding] */
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
/* leave result on stack top */
return 1;
@@ -48732,7 +54651,6 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
* Assumes stack top contains 'put' value (which is NOT popped).
*/
DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_hstring *varname;
@@ -48746,15 +54664,15 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
/* [... put_value varname] */
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
+ duk_pop_unsafe(thr); /* varname is still reachable */
DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
"key=%!O, varname=%!O, value=%!T",
(duk_heaphdr *) key,
(duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, -1)));
+ (duk_tval *) duk_require_tval(thr, -1)));
/* [... put_value] */
@@ -48766,7 +54684,7 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
* the property write call.
*/
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
+ duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag);
/* [... put_value] */
}
@@ -48776,7 +54694,6 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
* variable/argument itself (where the map points) is not deleted.
*/
DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
@@ -48786,9 +54703,9 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
return;
}
- map = duk_require_hobject(ctx, -1);
+ map = duk_require_hobject(thr, -1);
DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
+ duk_pop_unsafe(thr); /* map is reachable through obj */
DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
(duk_heaphdr *) key));
@@ -48840,7 +54757,6 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
*/
DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv;
DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
@@ -48849,7 +54765,6 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
(long) flags, (long) arr_idx,
(duk_heaphdr *) obj, (duk_heaphdr *) key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(obj != NULL);
@@ -48857,51 +54772,39 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
DUK_ASSERT(out_desc != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- /* XXX: optimize this filling behavior later */
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_count);
+
+ /* Each code path returning 1 (= found) must fill in all the output
+ * descriptor fields. We don't do it beforehand because it'd be
+ * unnecessary work if the property isn't found and would happen
+ * multiple times for an inheritance chain.
+ */
+ DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc));
+#if 0
out_desc->flags = 0;
out_desc->get = NULL;
out_desc->set = NULL;
out_desc->e_idx = -1;
out_desc->h_idx = -1;
out_desc->a_idx = -1;
+#endif
/*
- * Array part
- */
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
- if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- DUK_DDD(DUK_DDDPRINT("-> found in array part"));
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
- }
- /* implicit attributes */
- out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_CONFIGURABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE;
- out_desc->a_idx = arr_idx;
- goto prop_found;
- }
- }
- /* assume array part is comprehensive (contains all array indexed elements
- * or none of them); hence no need to check the entries part here.
- */
- DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
- "should be there if present)"));
- goto prop_not_found_concrete;
- }
-
- /*
- * Entries part
+ * Try entries part first because it's the common case.
+ *
+ * Array part lookups are usually handled by the array fast path, and
+ * are not usually inherited. Array and entry parts never contain the
+ * same keys so the entry part vs. array part order doesn't matter.
*/
- duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
- if (out_desc->e_idx >= 0) {
+ if (duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) {
duk_int_t e_idx = out_desc->e_idx;
+ DUK_ASSERT(out_desc->e_idx >= 0);
+ out_desc->a_idx = -1;
out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
- if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) {
DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
@@ -48909,29 +54812,89 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
/* a dummy undefined value is pushed to make valstack
* behavior uniform for caller
*/
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
} else {
DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
}
}
goto prop_found;
}
/*
- * Not found as a concrete property, check whether a String object
- * virtual property matches.
+ * Try array part.
+ */
+
+ if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
+ if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
+ tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
+ if (!DUK_TVAL_IS_UNUSED(tv)) {
+ DUK_DDD(DUK_DDDPRINT("-> found in array part"));
+ if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
+ duk_push_tval(thr, tv);
+ }
+ /* implicit attributes */
+ out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
+ DUK_PROPDESC_FLAG_CONFIGURABLE |
+ DUK_PROPDESC_FLAG_ENUMERABLE;
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = (duk_int_t) arr_idx; /* XXX: limit 2G due to being signed */
+ goto prop_found;
+ }
+ }
+ }
+
+ DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property"));
+
+ /*
+ * Not found as a concrete property, check for virtual properties.
*/
- prop_not_found_concrete:
+ if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) {
+ /* Quick skip. */
+ goto prop_not_found;
+ }
+
+ if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
+ duk_harray *a;
+
+ DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld",
+ (duk_heaphdr *) key, (long) arr_idx));
+
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
+ DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
+ if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
+ duk_push_uint(thr, (duk_uint_t) a->length);
+ }
+ out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
+ if (DUK_HARRAY_LENGTH_WRITABLE(a)) {
+ out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
+ }
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
+
+ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
+ goto prop_found_noexotic; /* cannot be arguments exotic */
+ }
+ } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
(duk_heaphdr *) key, (long) arr_idx));
+ /* XXX: charlen; avoid multiple lookups? */
+
if (arr_idx != DUK__NO_ARRAY_INDEX) {
duk_hstring *h_val;
@@ -48942,14 +54905,19 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_hstring(ctx, h_val);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ duk_push_hstring(thr, h_val);
+ duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
}
out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
DUK_PROPDESC_FLAG_VIRTUAL;
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
} else {
/* index is above internal string length -> property is fully normal */
DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
@@ -48962,24 +54930,31 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
DUK_ASSERT(h_val != NULL);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
+ duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
}
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
- duk_hbufferobject *h_bufobj;
+ }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ else if (DUK_HOBJECT_IS_BUFOBJ(obj)) {
+ duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
- h_bufobj = (duk_hbufferobject *) obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- DUK_DDD(DUK_DDDPRINT("bufferobject property get for key: %!O, arr_idx: %ld",
+ h_bufobj = (duk_hbufobj *) obj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld",
(duk_heaphdr *) key, (long) arr_idx));
- if (arr_idx != DUK__NO_ARRAY_INDEX) {
+ if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
DUK_DDD(DUK_DDDPRINT("array index exists"));
/* Careful with wrapping: arr_idx upshift may easily wrap, whereas
@@ -48987,83 +54962,59 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
duk_uint8_t *data;
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
+ if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
} else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
+ DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
+ duk_push_uint(thr, 0);
}
}
out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
DUK_PROPDESC_FLAG_VIRTUAL;
+ if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
+ /* ArrayBuffer indices are non-standard and are
+ * non-enumerable to avoid their serialization.
+ */
+ out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
+ }
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
+ goto prop_found_noexotic; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
} else {
/* index is above internal buffer length -> property is fully normal */
DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
}
- } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
+ } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
/* Length in elements: take into account shift, but
* intentionally don't check the underlying buffer here.
*/
- duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
- /* If neutered must return 0; length is zeroed during
- * neutering.
- */
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, h_bufobj->length);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
- /* If neutered must return 0; offset is zeroed during
- * neutering.
- */
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, h_bufobj->offset);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, 1 << h_bufobj->shift);
+ duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift);
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- }
- } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
- DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
- (duk_heaphdr *) key, (long) arr_idx));
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
-
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
- duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Array properties have exotic behavior but they are concrete,
* so no special handling here.
@@ -49074,14 +55025,16 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
/*
- * Not found as concrete or virtual
+ * Not found as concrete or virtual.
*/
+ prop_not_found:
DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss);
return 0;
/*
- * Found
+ * Found.
*
* Arguments object has exotic post-processing, see E5 Section 10.6,
* description of [[GetOwnProperty]] variant for arguments.
@@ -49091,15 +55044,15 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
/* Notes:
- * - only numbered indices are relevant, so arr_idx fast reject is good
+ * - Only numbered indices are relevant, so arr_idx fast reject is good
* (this is valid unless there are more than 4**32-1 arguments).
- * - since variable lookup has no side effects, this can be skipped if
+ * - Since variable lookup has no side effects, this can be skipped if
* DUK_GETDESC_FLAG_PUSH_VALUE is not set.
*/
- if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
- arr_idx != DUK__NO_ARRAY_INDEX &&
- (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
+ arr_idx != DUK__NO_ARRAY_INDEX &&
+ (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) {
duk_propdesc temp_desc;
/* Magically bound variable cannot be an accessor. However,
@@ -49112,15 +55065,20 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
/* replaces top of stack with new value if necessary */
DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
+ /* This can perform a variable lookup but only into a declarative
+ * environment which has no side effects.
+ */
if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [... old_result result] -> [... result] */
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
}
+ prop_found_noexotic:
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit);
return 1;
}
@@ -49165,6 +55123,8 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
DUK_ASSERT(out_desc != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_count);
+
arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
@@ -49179,11 +55139,12 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
do {
if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
/* stack contains value (if requested), 'out_desc' is set */
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_hit);
return 1;
}
/* not found in 'curr', next in prototype chain; impose max depth */
- if (sanity-- == 0) {
+ if (DUK_UNLIKELY(sanity-- == 0)) {
if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
/* treat like property not found */
break;
@@ -49192,12 +55153,13 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
}
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
+ } while (curr != NULL);
/* out_desc is left untouched (possibly garbage), caller must use return
* value to determine whether out_desc can be looked up
*/
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_miss);
return 0;
}
@@ -49221,6 +55183,7 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
* standard Array objects.
*/
+#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
duk_tval *tv;
duk_uint32_t idx;
@@ -49230,8 +55193,8 @@ DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, d
if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
- !DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
- !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ !DUK_HOBJECT_IS_BUFOBJ(obj) &&
+ !DUK_HOBJECT_IS_PROXY(obj))) {
/* Must have array part and no conflicting exotic behaviors.
* Doesn't need to have array special behavior, e.g. Arguments
* object has array part.
@@ -49283,8 +55246,9 @@ DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, d
return NULL;
}
-DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val, duk_propdesc *temp_desc) {
+DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
duk_tval *tv;
+ duk_harray *a;
duk_uint32_t idx;
duk_uint32_t old_len, new_len;
@@ -49295,6 +55259,9 @@ DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr,
}
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_key)) {
idx = duk__tval_fastint_to_arr_idx(tv_key);
@@ -49318,24 +55285,22 @@ DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr,
DUK_ASSERT(idx != 0xffffffffUL);
DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
- old_len = duk__get_old_array_length(thr, obj, temp_desc);
+ old_len = a->length;
if (idx >= old_len) {
DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
"(arr_idx=%ld, old_len=%ld)",
(long) idx, (long) old_len));
- if (!(temp_desc->flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
- return 0; /* not reachable */
+ if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
+ /* The correct behavior here is either a silent error
+ * or a TypeError, depending on strictness. Fall back
+ * to the slow path to handle the situation.
+ */
+ return 0;
}
new_len = idx + 1;
- /* No resize has occurred so temp_desc->e_idx is still OK */
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- DUK_TVAL_SET_FASTINT_U32(tv, new_len); /* no need for decref/incref because value is a number */
- } else {
- ;
+ ((duk_harray *) obj)->length = new_len;
}
tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
@@ -49344,25 +55309,27 @@ DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
return 1;
}
+#endif /* DUK_USE_ARRAY_PROP_FASTPATH */
/*
- * Fast path for bufferobject getprop/putprop
+ * Fast path for bufobj getprop/putprop
*/
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
- duk_context *ctx;
duk_uint32_t idx;
- duk_hbufferobject *h_bufobj;
+ duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
duk_uint8_t *data;
- ctx = (duk_context *) thr;
-
- if (!DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
+ if (!DUK_HOBJECT_IS_BUFOBJ(obj)) {
+ return 0;
+ }
+ h_bufobj = (duk_hbufobj *) obj;
+ if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
return 0;
}
- h_bufobj = (duk_hbufferobject *) obj;
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_key)) {
@@ -49377,7 +55344,7 @@ DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
/* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
* is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside bufferobject length.
+ * because 0xffffffffUL will never be inside bufobj length.
*/
/* Careful with wrapping (left shifting idx would be unsafe). */
@@ -49387,36 +55354,39 @@ DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
+ if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
} else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
+ DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
+ duk_push_uint(thr, 0);
}
return 1;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
- duk_context *ctx;
duk_uint32_t idx;
- duk_hbufferobject *h_bufobj;
+ duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
duk_uint8_t *data;
- ctx = (duk_context *) thr;
-
- if (!(DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
+ if (!(DUK_HOBJECT_IS_BUFOBJ(obj) &&
DUK_TVAL_IS_NUMBER(tv_val))) {
return 0;
}
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufferobjects now */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufobjs now */
+
+ h_bufobj = (duk_hbufobj *) obj;
+ if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
+ return 0;
+ }
- h_bufobj = (duk_hbufferobject *) obj;
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_key)) {
idx = duk__tval_fastint_to_arr_idx(tv_key);
@@ -49430,7 +55400,7 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
/* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
* is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside bufferobject length.
+ * because 0xffffffffUL will never be inside bufobj length.
*/
/* Careful with wrapping (left shifting idx would be unsafe). */
@@ -49440,31 +55410,31 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
/* Value is required to be a number in the fast path so there
* are no side effects in write coercion.
*/
- duk_push_tval(ctx, tv_val);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_push_tval(thr, tv_val);
+ DUK_ASSERT(duk_is_number(thr, -1));
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
+ if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
} else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
+ DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
return 1;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
* GETPROP: Ecmascript property read.
*/
DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_obj_copy;
duk_tval tv_key_copy;
duk_hobject *curr = NULL;
@@ -49477,7 +55447,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
(void *) thr, (void *) tv_obj, (void *) tv_key,
(duk_tval *) tv_obj, (duk_tval *) tv_key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(tv_obj != NULL);
@@ -49485,6 +55454,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_getprop_all);
+
/*
* Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
* them being invalidated by a valstack resize.
@@ -49512,7 +55483,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
}
@@ -49527,6 +55498,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
duk_int_t pop_count;
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ /* Symbols (ES2015 or hidden) don't have virtual properties. */
+ DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype"));
+ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
+ break;
+ }
+
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_key)) {
arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
@@ -49539,23 +55517,24 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_hstring(ctx, h);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ duk_pop_n_unsafe(thr, pop_count);
+ duk_push_hstring(thr, h);
+ duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ DUK_STATS_INC(thr->heap, stats_getprop_stringidx);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
"after coercion -> return char)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -49563,72 +55542,85 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
+ duk_pop_unsafe(thr); /* [key] -> [] */
+ duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
+ DUK_STATS_INC(thr->heap, stats_getprop_stringlen);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
"return string length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
+
DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
goto lookup; /* avoid double coercion */
}
case DUK_TAG_OBJECT: {
+#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
duk_tval *tmp;
+#endif
curr = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(curr != NULL);
+ /* XXX: array .length fast path (important in e.g. loops)? */
+
+#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
if (tmp) {
- duk_push_tval(ctx, tmp);
+ duk_push_tval(thr, tmp);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
"fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_STATS_INC(thr->heap, stats_getprop_arrayidx);
return 1;
}
+#endif
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
/* Read value pushed on stack. */
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufferobject "
+ DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj "
"fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx);
return 1;
}
+#endif
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) {
duk_hobject *h_target;
if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
/* -> [ ... trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 3 /*nargs*/);
+ DUK_STATS_INC(thr->heap, stats_getprop_proxy);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
+ duk_call_method(thr, 3 /*nargs*/);
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
- duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
+ duk_tval *tv_hook = duk_require_tval(thr, -3); /* value from hook */
+ duk_tval *tv_targ = duk_require_tval(thr, -1); /* value from target */
duk_bool_t datadesc_reject;
duk_bool_t accdesc_reject;
@@ -49651,9 +55643,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
} else {
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
return 1; /* return value */
}
@@ -49664,18 +55656,19 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
#endif /* DUK_USE_ES6_PROXY */
if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
+ DUK_STATS_INC(thr->heap, stats_getprop_arguments);
if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
"key matches magically bound property -> skip standard "
"Get with replacement value)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* no need for 'caller' post-check, because 'key' must be an array index */
- duk_remove(ctx, -2); /* [key result] -> [result] */
+ duk_remove_m2(thr); /* [key result] -> [result] */
return 1;
}
@@ -49709,22 +55702,22 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
-
+ duk_pop_n_unsafe(thr, pop_count);
+ duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
+ DUK_STATS_INC(thr->heap, stats_getprop_bufferidx);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
"after coercion -> return byte as number)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -49732,42 +55725,26 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
- if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
+ duk_pop_unsafe(thr); /* [key] -> [] */
+ duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
+ DUK_STATS_INC(thr->heap, stats_getprop_bufferlen);
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' or 'byteLength' "
+ DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' "
"after coercion -> return buffer length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, 0); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'byteOffset' after coercion -> "
- "return 0 for consistency with Buffer objects)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, 1); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'BYTES_PER_ELEMENT' after coercion -> "
- "return 1 for consistency with Buffer objects)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
- DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
- curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
+ DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
+ curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
goto lookup; /* avoid double coercion */
}
@@ -49778,25 +55755,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
}
case DUK_TAG_LIGHTFUNC: {
- duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
-
- /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- duk_pop(ctx);
- duk_push_int(ctx, lf_len);
- return 1;
- } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
- duk_pop(ctx);
- duk_push_lightfunc_name(ctx, tv_obj);
- return 1;
- }
-
+ /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */
DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
+ curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
+ break;
}
#if defined(DUK_USE_FASTINT)
@@ -49814,9 +55776,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* key coercion (unless already coerced above) */
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
-
/*
* Property lookup
*/
@@ -49836,14 +55797,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* accessor with defined getter */
DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
- duk_pop(ctx); /* [key undefined] -> [key] */
- duk_push_hobject(ctx, desc.get);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
-#ifdef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
- duk_dup(ctx, -3);
- duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
+ duk_pop_unsafe(thr); /* [key undefined] -> [key] */
+ duk_push_hobject(thr, desc.get);
+ duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
+#if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT)
+ duk_dup_m3(thr);
+ duk_call_method(thr, 1); /* [key getter this key] -> [key retval] */
#else
- duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
+ duk_call_method(thr, 0); /* [key getter this] -> [key retval] */
#endif
} else {
/* [key value] or [key undefined] */
@@ -49854,7 +55815,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* if accessor without getter, return value is undefined */
DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
- duk_is_undefined(ctx, -1));
+ duk_is_undefined(thr, -1));
/* Note: for an accessor without getter, falling through to
* check for "caller" exotic behavior is unnecessary as
@@ -49869,19 +55830,19 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* XXX: option to pretend property doesn't exist if sanity limit is
* hit might be useful.
*/
- if (sanity-- == 0) {
+ if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
+ } while (curr != NULL);
/*
* Not found
*/
- duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
+ duk_to_undefined(thr, -1); /* [key] -> [undefined] (default value) */
- DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(thr, -1)));
return 0;
/*
@@ -49933,9 +55894,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
* only refers to the value being a "strict mode Function
* object" which is ambiguous.
*/
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(orig));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig));
- h = duk_get_hobject(ctx, -1); /* NULL if not an object */
+ h = duk_get_hobject(thr, -1); /* NULL if not an object */
if (h &&
DUK_HOBJECT_IS_FUNCTION(h) &&
DUK_HOBJECT_HAS_STRICT(h)) {
@@ -49946,9 +55907,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
}
#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
- duk_remove(ctx, -2); /* [key result] -> [result] */
+ duk_remove_m2(thr); /* [key result] -> [result] */
- DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -49960,7 +55921,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_key_copy;
duk_hobject *obj;
duk_hstring *key;
@@ -49987,7 +55947,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
*
* However, lightfuncs need to behave like fully fledged objects
* here to be maximally transparent, so we need to handle them
- * here.
+ * here. Same goes for plain buffers which behave like ArrayBuffers.
*/
/* XXX: Refactor key coercion so that it's only called once. It can't
@@ -49999,21 +55959,23 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
obj = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(obj != NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- /* FOUND */
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
+ } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
+ if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) {
rc = 1;
goto pop_and_return;
}
+ obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
- /* If not found, resume existence check from Function.prototype.
+ /* If not found, resume existence check from %NativeFunctionPrototype%.
* We can just substitute the value in this case; nothing will
* need the original base value (as would be the case with e.g.
* setters/getters.
*/
- obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
} else {
/* Note: unconditional throw */
DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
@@ -50027,7 +55989,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_UNREF(arr_idx);
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
@@ -50039,10 +56001,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
/* [ ... key trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_call_method(thr, 2 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
if (!tmp_bool) {
/* Target object must be checked for a conflicting
* non-configurable property.
@@ -50065,7 +56027,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
}
}
- duk_pop_2(ctx); /* [ key trap_result ] -> [] */
+ duk_pop_2_unsafe(thr); /* [ key trap_result ] -> [] */
return tmp_bool;
}
@@ -50079,7 +56041,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
/* fall through */
pop_and_return:
- duk_pop(ctx); /* [ key ] -> [] */
+ duk_pop_unsafe(thr); /* [ key ] -> [] */
return rc;
}
@@ -50116,70 +56078,57 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *o
* Used by duk_hobject_putprop().
*/
-DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc) {
- duk_bool_t rc;
- duk_tval *tv;
+/* Coerce a new .length candidate to a number and check that it's a valid
+ * .length.
+ */
+DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) {
duk_uint32_t res;
+ duk_double_t d;
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* This function is only called for objects with array exotic behavior.
- * The [[DefineOwnProperty]] algorithm for arrays requires that
- * 'length' can never have a value outside the unsigned 32-bit range,
- * attempt to write such a value is a RangeError. Here we can thus
- * assert for this. When Duktape internals go around the official
- * property write interface (doesn't happen often) this assumption is
- * easy to accidentally break, so such code must be written carefully.
- * See test-bi-array-push-maxlen.js.
- */
-
- rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, temp_desc, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0); /* arrays MUST have a 'length' property */
- DUK_ASSERT(temp_desc->e_idx >= 0);
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* array 'length' is always a number, as we coerce it */
- DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) >= 0.0);
- DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (double) 0xffffffffUL);
- DUK_ASSERT((duk_double_t) (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv) == DUK_TVAL_GET_NUMBER(tv));
+#if !defined(DUK_USE_PREFER_SIZE)
#if defined(DUK_USE_FASTINT)
- /* Downgrade checks are not made everywhere, so 'length' is not always
- * a fastint (it is a number though). This can be removed once length
- * is always guaranteed to be a fastint.
+ /* When fastints are enabled, the most interesting case is assigning
+ * a fastint to .length (e.g. arr.length = 0).
*/
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv) || DUK_TVAL_IS_DOUBLE(tv));
if (DUK_TVAL_IS_FASTINT(tv)) {
- res = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv);
- } else {
- res = (duk_uint32_t) DUK_TVAL_GET_DOUBLE(tv);
+ /* Very common case. */
+ duk_int64_t fi;
+ fi = DUK_TVAL_GET_FASTINT(tv);
+ if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) {
+ goto fail_range;
+ }
+ return (duk_uint32_t) fi;
+ }
+#else /* DUK_USE_FASTINT */
+ /* When fastints are not enabled, the most interesting case is any
+ * number.
+ */
+ if (DUK_TVAL_IS_DOUBLE(tv)) {
+ d = DUK_TVAL_GET_NUMBER(tv);
}
-#else
- res = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
#endif /* DUK_USE_FASTINT */
+ else
+#endif /* !DUK_USE_PREFER_SIZE */
+ {
+ /* In all other cases, and when doing a size optimized build,
+ * fall back to the comprehensive handler.
+ */
+ d = duk_js_tonumber(thr, tv);
+ }
- return res;
-}
-
-DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint32_t res;
- duk_double_t d;
-
- /* Input value should be on stack top and will be coerced and
- * popped. Refuse to update an Array's 'length' to a value
- * outside the 32-bit range. Negative zero is accepted as zero.
+ /* Refuse to update an Array's 'length' to a value outside the
+ * 32-bit range. Negative zero is accepted as zero.
*/
-
- /* XXX: fastint */
-
- d = duk_to_number(ctx, -1);
res = (duk_uint32_t) d;
if ((duk_double_t) res != d) {
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
+ goto fail_range;
}
- duk_pop(ctx);
+
return res;
+
+ fail_range:
+ DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
+ return 0; /* unreachable */
}
/* Delete elements required by a smaller length, taking into account
@@ -50227,6 +56176,9 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
DUK_ASSERT(out_result_len != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
+
if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
/*
* All defined array-indexed properties are in the array part
@@ -50255,7 +56207,7 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
return 1;
} else {
/*
- * Entries part is a bit more complex
+ * Entries part is a bit more complex.
*/
/* Stage 1: find highest preventing non-configurable entry (if any).
@@ -50374,40 +56326,41 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
/* XXX: is valstack top best place for argument? */
DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_propdesc desc;
+ duk_harray *a;
duk_uint32_t old_len;
duk_uint32_t new_len;
duk_uint32_t result_len;
- duk_tval *tv;
duk_bool_t rc;
DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
"new val: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- DUK_ASSERT(duk_is_valid_index(ctx, -1));
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+
+ DUK_ASSERT(duk_is_valid_index(thr, -1));
/*
* Get old and new length
*/
- old_len = duk__get_old_array_length(thr, obj, &desc);
- duk_dup(ctx, -1); /* [in_val in_val] */
- new_len = duk__to_new_array_length_checked(thr); /* -> [in_val] */
+ old_len = a->length;
+ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
/*
* Writability check
*/
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
+ if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
return 0;
}
@@ -50418,15 +56371,8 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
*/
if (new_len >= old_len) {
- DUK_DDD(DUK_DDDPRINT("new length is higher than old length, just update length, no deletions"));
-
- DUK_ASSERT(desc.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tv, new_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions"));
+ a->length = new_len;
return 1;
}
@@ -50443,13 +56389,7 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
DUK_ASSERT(result_len >= new_len && result_len <= old_len);
- DUK_ASSERT(desc.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tv, result_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ a->length = result_len;
/* XXX: shrink array allocation or entries compaction here? */
@@ -50486,7 +56426,6 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
*/
DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_obj_copy;
duk_tval tv_key_copy;
duk_tval tv_val_copy;
@@ -50508,13 +56447,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_obj != NULL);
DUK_ASSERT(tv_key != NULL);
DUK_ASSERT(tv_val != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_putprop_all);
+
/*
* Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
* them being invalidated by a valstack resize.
@@ -50544,7 +56484,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
}
@@ -50564,9 +56504,15 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ /* Symbols (ES2015 or hidden) don't have virtual properties. */
+ curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
+ goto lookup;
+ }
+
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
goto fail_not_writable;
}
@@ -50612,31 +56558,40 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* tests/ecmascript/test-misc-array-fast-write.js
*/
- if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val, &desc) != 0) {
+ /* XXX: array .length? */
+
+#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
+ if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) {
DUK_DDD(DUK_DDDPRINT("array fast path success"));
+ DUK_STATS_INC(thr->heap, stats_putprop_arrayidx);
return 1;
}
+#endif
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
- DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufferobject fast path"));
+ DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path"));
+ DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx);
return 1;
}
+#endif
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
/* -> [ ... trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_val); /* V */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 4 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
+ DUK_STATS_INC(thr->heap, stats_putprop_proxy);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_push_tval(thr, tv_val); /* V */
+ duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
+ duk_call_method(thr, 4 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
+ duk_pop_nodecref_unsafe(thr);
if (!tmp_bool) {
goto fail_proxy_rejected;
}
@@ -50644,11 +56599,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_targ = duk_require_tval(ctx, -1);
+ duk_tval *tv_targ = duk_require_tval(thr, -1);
duk_bool_t datadesc_reject;
duk_bool_t accdesc_reject;
@@ -50670,9 +56625,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
} else {
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
return 1; /* success */
}
@@ -50707,11 +56662,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
@@ -50732,13 +56687,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
else
#endif
{
- duk_push_tval(ctx, tv_val);
- data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
+ duk_push_tval(thr, tv_val);
+ data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1);
pop_count++;
}
- duk_pop_n(ctx, pop_count);
+ duk_pop_n_unsafe(thr, pop_count);
DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
+ DUK_STATS_INC(thr->heap, stats_putprop_bufferidx);
return 1;
}
@@ -50746,22 +56702,19 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
- if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr) ||
- key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
goto fail_not_writable;
}
- DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
- curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
+ DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
+ curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
goto lookup; /* avoid double coercion */
}
@@ -50772,20 +56725,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
}
case DUK_TAG_LIGHTFUNC: {
- /* All lightfunc own properties are non-writable and the lightfunc
- * is considered non-extensible. However, the write may be captured
- * by an inherited setter which means we can't stop the lookup here.
+ /* Lightfuncs have no own properties and are considered non-extensible.
+ * However, the write may be captured by an inherited setter which
+ * means we can't stop the lookup here.
*/
-
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_writable;
- }
-
DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
+ curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
+ break;
}
#if defined(DUK_USE_FASTINT)
@@ -50801,7 +56747,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
}
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
lookup:
@@ -50839,16 +56785,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (!setter) {
goto fail_no_setter;
}
- duk_push_hobject(ctx, setter);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
- duk_push_tval(ctx, tv_val); /* [key setter this val] */
-#ifdef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
- duk_dup(ctx, -4);
- duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
+ duk_push_hobject(thr, setter);
+ duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
+ duk_push_tval(thr, tv_val); /* [key setter this val] */
+#if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT)
+ duk_dup_m4(thr);
+ duk_call_method(thr, 2); /* [key setter this val key] -> [key retval] */
#else
- duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
+ duk_call_method(thr, 1); /* [key setter this val] -> [key retval] */
#endif
- duk_pop(ctx); /* ignore retval -> [key] */
+ duk_pop_unsafe(thr); /* ignore retval -> [key] */
goto success_no_arguments_exotic;
}
@@ -50889,46 +56835,80 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
}
if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
- if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
- duk_hbufferobject *h_bufobj;
+
+ if (DUK_HOBJECT_IS_ARRAY(curr)) {
+ /*
+ * Write to 'length' of an array is a very complex case
+ * handled in a helper which updates both the array elements
+ * and writes the new 'length'. The write may result in an
+ * unconditional RangeError or a partial write (indicated
+ * by a return code).
+ *
+ * Note: the helper has an unnecessary writability check
+ * for 'length', we already know it is writable.
+ */
+ DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr)); /* only virtual array property */
+
+ DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
+
+ /* XXX: the helper currently assumes stack top contains new
+ * 'length' value and the whole calling convention is not very
+ * compatible with what we need.
+ */
+
+ duk_push_tval(thr, tv_val); /* [key val] */
+ rc = duk__handle_put_array_length(thr, orig);
+ duk_pop_unsafe(thr); /* [key val] -> [key] */
+ if (!rc) {
+ goto fail_array_length_partial;
+ }
+
+ /* key is 'length', cannot match argument exotic behavior */
+ goto success_no_arguments_exotic;
+ }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ else if (DUK_HOBJECT_IS_BUFOBJ(curr)) {
+ duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
- h_bufobj = (duk_hbufferobject *) curr;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_bufobj = (duk_hbufobj *) curr;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
/* Careful with wrapping: arr_idx upshift may easily wrap, whereas
* length downshift won't.
*/
- if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
+ if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
duk_uint8_t *data;
DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
/* Coerce to number before validating pointers etc so that the
- * number coercions in duk_hbufferobject_validated_write() are
+ * number coercions in duk_hbufobj_validated_write() are
* guaranteed to be side effect free and not invalidate the
* pointer checks we do here.
*/
- duk_push_tval(ctx, tv_val);
- duk_to_number(ctx, -1);
+ duk_push_tval(thr, tv_val);
+ (void) duk_to_number_m1(thr);
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
+ if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
} else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
+ DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
goto success_no_arguments_exotic;
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ DUK_D(DUK_DPRINT("should not happen, key %!O", key));
goto fail_internal; /* should not happen */
}
DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
@@ -50940,11 +56920,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* XXX: option to pretend property doesn't exist if sanity limit is
* hit might be useful.
*/
- if (sanity-- == 0) {
+ if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
+ } while (curr != NULL);
/*
* Property not found in prototype chain.
@@ -50991,41 +56971,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
- if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
- key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- /*
- * Write to 'length' of an array is a very complex case
- * handled in a helper which updates both the array elements
- * and writes the new 'length'. The write may result in an
- * unconditional RangeError or a partial write (indicated
- * by a return code).
- *
- * Note: the helper has an unnecessary writability check
- * for 'length', we already know it is writable.
- */
-
- DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
-
- /* XXX: the helper currently assumes stack top contains new
- * 'length' value and the whole calling convention is not very
- * compatible with what we need.
- */
-
- duk_push_tval(ctx, tv_val); /* [key val] */
- rc = duk__handle_put_array_length(thr, orig);
- duk_pop(ctx); /* [key val] -> [key] */
- if (!rc) {
- goto fail_array_length_partial;
- }
-
- /* key is 'length', cannot match argument exotic behavior */
- goto success_no_arguments_exotic;
- }
+ /* Array own property .length is handled above. */
+ DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
if (desc.e_idx >= 0) {
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */
/* don't touch property attributes or hash part */
DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
(long) desc.e_idx, (duk_tval *) tv));
@@ -51038,7 +56990,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(desc.a_idx >= 0);
tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; a_idx may be invalidated */
DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
(long) desc.a_idx, (duk_tval *) tv));
}
@@ -51066,6 +57018,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(orig != NULL);
+ /* Array own property .length is handled above. */
+ DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
+
#if defined(DUK_USE_ROM_OBJECTS)
/* This should not happen because DUK_TAG_OBJECT case checks
* for this already, but check just in case.
@@ -51086,15 +57041,19 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
arr_idx != DUK__NO_ARRAY_INDEX) {
/* automatic length update */
duk_uint32_t old_len;
+ duk_harray *a;
- old_len = duk__get_old_array_length(thr, orig, &desc);
+ a = (duk_harray *) orig;
+ DUK_ASSERT_HARRAY_VALID(a);
+
+ old_len = a->length;
if (arr_idx >= old_len) {
DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
"(arr_idx=%ld, old_len=%ld)",
(long) arr_idx, (long) old_len));
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
+ if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
goto fail_not_writable;
}
@@ -51227,7 +57186,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* refcount; may need a props allocation resize but doesn't
* 'recheck' the valstack.
*/
- e_idx = duk__alloc_entry_checked(thr, orig, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, orig, key);
DUK_ASSERT(e_idx >= 0);
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
@@ -51245,26 +57204,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
*/
if (new_array_length > 0) {
- /*
- * Note: zero works as a "no update" marker because the new length
- * can never be zero after a new property is written.
- *
- * Note: must re-lookup because calls above (e.g. duk__alloc_entry_checked())
- * may realloc and compact properties and hence change e_idx.
+ /* Note: zero works as a "no update" marker because the new length
+ * can never be zero after a new property is written.
*/
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig));
+
DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
(long) new_array_length));
- rc = duk__get_own_propdesc_raw(thr, orig, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &desc, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(desc.e_idx >= 0);
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no need for decref/incref because value is a number */
- DUK_TVAL_SET_FASTINT_U32(tv, new_array_length);
+ ((duk_harray *) orig)->length = new_array_length;
}
/*
@@ -51305,16 +57254,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* rework to use tv_val directly?
*/
- duk_push_tval(ctx, tv_val);
+ duk_push_tval(thr, tv_val);
(void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/* fall thru */
success_no_arguments_exotic:
/* shared exit path now */
DUK_DDD(DUK_DDDPRINT("result: success"));
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 1;
#if defined(DUK_USE_ES6_PROXY)
@@ -51334,10 +57283,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_not_extensible:
@@ -51345,7 +57294,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_not_writable:
@@ -51353,7 +57302,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
#if defined(DUK_USE_ROM_OBJECTS)
@@ -51366,11 +57315,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
#endif
fail_array_length_partial:
- DUK_DDD(DUK_DDDPRINT("result: error, array length write only partially successful"));
+ DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful"));
if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_no_setter:
@@ -51378,15 +57327,15 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_internal:
DUK_DDD(DUK_DDDPRINT("result: error, internal"));
if (throw_flag) {
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
}
@@ -51437,6 +57386,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
/* Currently there are no deletable virtual properties, but
* with force_flag we might attempt to delete one.
*/
+ DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)"));
goto fail_virtual;
}
@@ -51447,17 +57397,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
goto success;
} else {
- duk_hobject *h_get = NULL;
- duk_hobject *h_set = NULL;
- duk_tval tv_tmp;
-
DUK_ASSERT(desc.a_idx < 0);
- /* Set property slot to an empty state. Careful not to invoke
- * any side effects while using desc.e_idx so that it doesn't
- * get invalidated by a finalizer mutating our object.
- */
-
/* remove hash entry (no decref) */
#if defined(DUK_USE_HOBJECT_HASH_PART)
if (desc.h_idx >= 0) {
@@ -51474,41 +57415,47 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
#endif
- /* remove value */
+ /* Remove value. This requires multiple writes so avoid side
+ * effects via no-refzero macros so that e_idx is not
+ * invalidated.
+ */
DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
(long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
- DUK_MEMSET((void *) &tv_tmp, 0, sizeof(tv_tmp));
- DUK_TVAL_SET_UNDEFINED(&tv_tmp);
if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
- h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
- h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
+ duk_hobject *tmp;
+
+ tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
+ DUK_UNREF(tmp);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
+
+ tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
+ DUK_UNREF(tmp);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
} else {
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_TVAL_SET_TVAL(&tv_tmp, tv);
- DUK_TVAL_SET_UNDEFINED(tv);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
}
#if 0
/* Not strictly necessary because if key == NULL, flag MUST be ignored. */
DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
#endif
- /* remove key */
+ /* Remove key. */
DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
(long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
+ DUK_HSTRING_DECREF_NORZ(thr, key);
- /* Do decrefs only with safe pointers to avoid side effects
- * disturbing e_idx.
+ /* Trigger refzero side effects only when we're done as a
+ * finalizer might operate on the object and affect the
+ * e_idx we're supposed to use.
*/
- DUK_TVAL_DECREF(thr, &tv_tmp);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set);
- DUK_HSTRING_DECREF(thr, key);
+ DUK_REFZERO_CHECK_SLOW(thr);
goto success;
}
@@ -51541,14 +57488,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
DUK_DDD(DUK_DDDPRINT("delete successful"));
return 1;
- fail_virtual:
- DUK_DDD(DUK_DDDPRINT("delete failed: property found, force flag, but virtual"));
-
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
- }
- return 0;
-
+ fail_virtual: /* just use the same "not configurable" error message */
fail_not_configurable:
DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
@@ -51563,7 +57503,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
*/
DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *key = NULL;
#if defined(DUK_USE_ES6_PROXY)
duk_propdesc desc;
@@ -51576,7 +57515,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
(void *) thr, (void *) tv_obj, (void *) tv_key,
(duk_tval *) tv_obj, (duk_tval *) tv_key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(tv_obj != NULL);
@@ -51587,7 +57525,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
/* Storing the entry top is cheaper here to ensure stack is correct at exit,
* as there are several paths out.
*/
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
DUK_TVAL_IS_NULL(tv_obj)) {
@@ -51595,29 +57533,29 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
goto fail_invalid_base_uncond;
}
- duk_push_tval(ctx, tv_obj);
- duk_push_tval(ctx, tv_key);
+ duk_push_tval(thr, tv_obj);
+ duk_push_tval(thr, tv_key);
- tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
+ tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2);
if (DUK_TVAL_IS_OBJECT(tv_obj)) {
duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(obj != NULL);
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
/* Note: proxy handling must happen before key is string coerced. */
if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
- /* -> [ ... trap handler ] */
+ /* -> [ ... obj key trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_dup_m4(thr); /* P */
+ duk_call_method(thr, 2 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
+ duk_pop_nodecref_unsafe(thr);
if (!tmp_bool) {
goto fail_proxy_rejected; /* retval indicates delete failed */
}
@@ -51625,11 +57563,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- int desc_reject;
+ duk_small_int_t desc_reject;
DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
"conflicting property; desc.flags=0x%08lx, "
@@ -51651,29 +57590,29 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
}
#endif /* DUK_USE_ES6_PROXY */
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
goto done_rc;
} else if (DUK_TVAL_IS_STRING(tv_obj)) {
+ /* String has .length and array index virtual properties
+ * which can't be deleted. No need for a symbol check;
+ * no offending virtual symbols exist.
+ */
/* XXX: unnecessary string coercion for array indices,
* intentional to keep small.
*/
duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
DUK_ASSERT(h != NULL);
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
goto fail_not_configurable;
}
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
goto fail_not_configurable;
@@ -51686,32 +57625,25 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
DUK_ASSERT(h != NULL);
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
goto fail_not_configurable;
}
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
goto fail_not_configurable;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- /* Lightfunc virtual properties are non-configurable, so
- * reject if match any of them.
+ /* Lightfunc has no virtual properties since Duktape 2.2
+ * so success. Still must coerce key for side effects.
*/
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_configurable;
- }
+ DUK_UNREF(key);
}
/* non-object base, no offending virtual property */
@@ -51719,17 +57651,17 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
goto done_rc;
done_rc:
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return rc;
fail_invalid_base_uncond:
/* Note: unconditional throw */
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
+ DUK_ASSERT(duk_get_top(thr) == entry_top);
#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
@@ -51738,7 +57670,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return 0;
#endif
@@ -51746,7 +57678,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
}
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return 0;
}
@@ -51770,7 +57702,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_propdesc desc;
duk_uint32_t arr_idx;
duk_int_t e_idx;
@@ -51780,7 +57711,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
(void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
- (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
+ (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -51788,7 +57719,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
DUK_ASSERT(key != NULL);
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
+ DUK_ASSERT(duk_is_valid_index(thr, -1)); /* contains value */
arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
@@ -51824,7 +57755,19 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
goto pop_exit;
}
- DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> failure"));
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
+ duk_uint32_t new_len;
+#if defined(DUK_USE_DEBUG)
+ duk_uint32_t prev_len;
+ prev_len = ((duk_harray *) obj)->length;
+#endif
+ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
+ ((duk_harray *) obj)->length = new_len;
+ DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld",
+ (long) prev_len, (long) ((duk_harray *) obj)->length));
+ goto pop_exit;
+ }
+ DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure"));
goto error_virtual;
}
@@ -51848,7 +57791,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
}
DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
- e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); /* increases key refcount */
DUK_ASSERT(e_idx >= 0);
DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
@@ -51859,7 +57802,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
write_value:
/* tv1 points to value storage */
- tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
+ tv2 = duk_require_tval(thr, -1); /* late lookup, avoid side effects */
DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
(duk_tval *) tv1, (duk_tval *) tv2));
@@ -51867,15 +57810,12 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
goto pop_exit;
pop_exit:
- duk_pop(ctx); /* remove in_val */
+ duk_pop_unsafe(thr); /* remove in_val */
return;
+ error_virtual: /* share error message */
error_internal:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return;
-
- error_virtual:
- DUK_ERROR_TYPE(thr, DUK_STR_REDEFINE_VIRT_PROP);
+ DUK_ERROR_INTERNAL(thr);
return;
}
@@ -51886,14 +57826,13 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
*/
DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *key;
duk_tval *tv1, *tv2;
DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
"arr_idx=%ld, flags=0x%02lx, val=%!T",
(void *) thr, obj, (long) arr_idx, (unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -51914,179 +57853,154 @@ DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr,
DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- tv2 = duk_require_tval(ctx, -1);
+ tv2 = duk_require_tval(thr, -1);
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- duk_pop(ctx); /* [ ...val ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ...val ] -> [ ... ] */
return;
}
DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
- duk_push_uint(ctx, (duk_uint_t) arr_idx);
- key = duk_to_hstring(ctx, -1);
+ key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx);
DUK_ASSERT(key != NULL);
- duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
+ duk_insert(thr, -2); /* [ ... val key ] -> [ ... key val ] */
duk_hobject_define_property_internal(thr, obj, key, flags);
- duk_pop(ctx); /* [ ... key ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ... key ] -> [ ... ] */
}
/*
- * Internal helper for defining an accessor property, ignoring
- * normal semantics such as extensibility, write protection etc.
- * Overwrites any existing value and attributes. This is called
- * very rarely, so the implementation first sets a value to undefined
- * and then changes the entry to an accessor (this is to save code space).
+ * Internal helpers for managing object 'length'
*/
-DUK_INTERNAL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags) {
- duk_context *ctx = (duk_context *) thr;
- duk_int_t e_idx;
- duk_int_t h_idx;
-
- DUK_DDD(DUK_DDDPRINT("define new accessor (internal): thr=%p, obj=%!O, key=%!O, "
- "getter=%!O, setter=%!O, flags=0x%02lx",
- (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
- (duk_heaphdr *) getter, (duk_heaphdr *) setter,
- (unsigned long) propflags));
+DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
+ duk_double_t val;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT((propflags & ~DUK_PROPDESC_FLAGS_MASK) == 0);
- /* setter and/or getter may be NULL */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ /* Fast path for Arrays. */
+ if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
+ return ((duk_harray *) obj)->length;
+ }
- /* force the property to 'undefined' to create a slot for it */
- duk_push_undefined(ctx);
- duk_hobject_define_property_internal(thr, obj, key, propflags);
- duk_hobject_find_existing_entry(thr->heap, obj, key, &e_idx, &h_idx);
- DUK_DDD(DUK_DDDPRINT("accessor slot: e_idx=%ld, h_idx=%ld", (long) e_idx, (long) h_idx));
- DUK_ASSERT(e_idx >= 0);
- DUK_ASSERT((duk_uint32_t) e_idx < DUK_HOBJECT_GET_ENEXT(obj));
+ /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */
+ duk_push_hobject(thr, obj);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH);
+ (void) duk_hobject_getprop(thr,
+ DUK_GET_TVAL_NEGIDX(thr, -2),
+ DUK_GET_TVAL_NEGIDX(thr, -1));
+ val = duk_to_number_m1(thr);
+ duk_pop_3_unsafe(thr);
- /* no need to decref, as previous value is 'undefined' */
- DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, e_idx);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, getter);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, setter);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, getter);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, setter);
+ /* This isn't part of Ecmascript semantics; return a value within
+ * duk_size_t range, or 0 otherwise.
+ */
+ if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
+ return (duk_size_t) val;
+ }
+ return 0;
}
/*
- * Internal helpers for managing object 'length'
+ * Fast finalizer check for an object. Walks the prototype chain, checking
+ * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept
+ * in sync with the actual property when setting/removing the finalizer.
*/
-/* XXX: awkward helpers */
+#if defined(DUK_USE_HEAPPTR16)
+DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) {
+#else
+DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) {
+#endif
+ duk_uint_t sanity;
-DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
- duk_context *ctx = (duk_context *) thr;
- duk_push_hobject(ctx, obj);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- duk_push_u32(ctx, length);
- (void) duk_hobject_putprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -3),
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- 0);
- duk_pop_n(ctx, 3);
-}
+ DUK_ASSERT(obj != NULL);
-DUK_INTERNAL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
- duk_hobject_set_length(thr, obj, 0);
-}
+ sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
+ do {
+ if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) {
+ return 1;
+ }
+ if (DUK_UNLIKELY(sanity-- == 0)) {
+ DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false"));
+ return 0;
+ }
+#if defined(DUK_USE_HEAPPTR16)
+ DUK_ASSERT(heap != NULL);
+ obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj);
+#else
+ obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */
+#endif
+ } while (obj != NULL);
-DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_double_t val;
- duk_push_hobject(ctx, obj);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- (void) duk_hobject_getprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1));
- val = duk_to_number(ctx, -1);
- duk_pop_n(ctx, 3);
- if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {
- return (duk_uint32_t) val;
- }
return 0;
}
/*
* Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
*
- * This is an actual function call.
+ * [ ... key ] -> [ ... desc/undefined ]
*/
-DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) {
duk_hobject *obj;
duk_hstring *key;
duk_propdesc pd;
- duk_bool_t rc;
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- (void) duk_to_string(ctx, 1);
- key = duk_require_hstring(ctx, 1);
-
- DUK_ASSERT(obj != NULL);
+ obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ key = duk_to_property_key_hstring(thr, -1);
DUK_ASSERT(key != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
- if (!rc) {
- duk_push_undefined(ctx);
-
- /* [obj key undefined] */
- return 1;
+ if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) {
+ duk_push_undefined(thr);
+ duk_remove_m2(thr);
+ return;
}
- duk_push_object(ctx);
+ duk_push_object(thr);
- /* [obj key value desc] */
+ /* [ ... key value desc ] */
if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
/* If a setter/getter is missing (undefined), the descriptor must
* still have the property present with the value 'undefined'.
*/
if (pd.get) {
- duk_push_hobject(ctx, pd.get);
+ duk_push_hobject(thr, pd.get);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_GET);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET);
if (pd.set) {
- duk_push_hobject(ctx, pd.set);
+ duk_push_hobject(thr, pd.set);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET);
} else {
- duk_dup(ctx, -2); /* [obj key value desc value] */
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
-
- /* [obj key value desc] */
+ duk_dup_m2(thr);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE);
}
- duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE);
- /* [obj key value desc] */
- return 1;
+ /* [ ... key value desc ] */
+
+ duk_replace(thr, -3);
+ duk_pop_unsafe(thr); /* -> [ ... desc ] */
}
/*
@@ -52095,9 +58009,10 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex
* Internal helper which validates and normalizes a property descriptor
* represented as an Ecmascript object (e.g. argument to defineProperty()).
* The output of this conversion is a set of defprop_flags and possibly
- * some values pushed on the value stack; some subset of: property value,
- * getter, setter. Caller must manage stack top carefully because the
- * number of values pushed depends on the input property descriptor.
+ * some values pushed on the value stack to (1) ensure borrowed pointers
+ * remain valid, and (2) avoid unnecessary pops for footprint reasons.
+ * Caller must manage stack top carefully because the number of values
+ * pushed depends on the input property descriptor.
*
* The original descriptor object must not be altered in the process.
*/
@@ -52105,13 +58020,12 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex
/* XXX: very basic optimization -> duk_get_prop_stridx_top */
DUK_INTERNAL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
+void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
duk_idx_t idx_in,
duk_uint_t *out_defprop_flags,
duk_idx_t *out_idx_value,
duk_hobject **out_getter,
duk_hobject **out_setter) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_idx_t idx_value = -1;
duk_hobject *getter = NULL;
duk_hobject *setter = NULL;
@@ -52119,15 +58033,15 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
duk_bool_t is_acc_desc = 0;
duk_uint_t defprop_flags = 0;
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(out_defprop_flags != NULL);
DUK_ASSERT(out_idx_value != NULL);
DUK_ASSERT(out_getter != NULL);
DUK_ASSERT(out_setter != NULL);
+ DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */
/* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
- idx_in = duk_require_normalize_index(ctx, idx_in);
- (void) duk_require_hobject(ctx, idx_in);
+ idx_in = duk_require_normalize_index(thr, idx_in);
+ (void) duk_require_hobject(thr, idx_in);
/* The coercion order must match the ToPropertyDescriptor() algorithm
* so that side effects in coercion happen in the correct order.
@@ -52135,27 +58049,23 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* although it doesn't matter in practice.)
*/
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) {
is_data_desc = 1;
defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
- idx_value = duk_get_top_index(ctx);
- /* Leave 'value' on stack */
- } else {
- duk_pop(ctx);
+ idx_value = duk_get_top_index(thr);
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
is_data_desc = 1;
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
}
}
- duk_pop(ctx);
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) {
+ duk_tval *tv = duk_require_tval(thr, -1);
duk_hobject *h_get;
if (DUK_TVAL_IS_UNDEFINED(tv)) {
@@ -52166,7 +58076,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* lightfuncs don't fit into a property value slot. This
* has some side effects, see test-dev-lightfunc-accessor.js.
*/
- h_get = duk_get_hobject_or_lfunc_coerce(ctx, -1);
+ h_get = duk_get_hobject_promote_lfunc(thr, -1);
if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
goto type_error;
}
@@ -52174,13 +58084,10 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
}
is_acc_desc = 1;
defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
- /* Leave 'getter' on stack */
- } else {
- duk_pop(ctx);
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) {
+ duk_tval *tv = duk_require_tval(thr, -1);
duk_hobject *h_set;
if (DUK_TVAL_IS_UNDEFINED(tv)) {
@@ -52191,7 +58098,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* lightfuncs don't fit into a property value slot. This
* has some side effects, see test-dev-lightfunc-accessor.js.
*/
- h_set = duk_get_hobject_or_lfunc_coerce(ctx, -1);
+ h_set = duk_get_hobject_promote_lfunc(thr, -1);
if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
goto type_error;
}
@@ -52199,28 +58106,23 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
}
is_acc_desc = 1;
defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
- /* Leave 'setter' on stack */
- } else {
- duk_pop(ctx);
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
}
}
- duk_pop(ctx);
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
}
}
- duk_pop(ctx);
if (is_data_desc && is_acc_desc) {
goto type_error;
@@ -52231,7 +58133,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
*out_getter = getter;
*out_setter = setter;
- /* [ ... value? getter? setter? ] */
+ /* [ ... [multiple values] ] */
return;
type_error:
@@ -52239,7 +58141,8 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
}
/*
- * Object.defineProperty() related helper (E5 Section 15.2.3.6)
+ * Object.defineProperty() related helper (E5 Section 15.2.3.6).
+ * Also handles ES2015 Reflect.defineProperty().
*
* Inlines all [[DefineOwnProperty]] exotic behaviors.
*
@@ -52258,14 +58161,14 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
/* XXX: this is a major target for size optimization */
DUK_INTERNAL
-void duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set) {
- duk_hthread *thr = (duk_hthread *) ctx;
+duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
+ duk_uint_t defprop_flags,
+ duk_hobject *obj,
+ duk_hstring *key,
+ duk_idx_t idx_value,
+ duk_hobject *get,
+ duk_hobject *set,
+ duk_bool_t throw_flag) {
duk_uint32_t arr_idx;
duk_tval tv;
duk_bool_t has_enumerable;
@@ -52277,7 +58180,6 @@ void duk_hobject_define_property_helper(duk_context *ctx,
duk_bool_t is_enumerable;
duk_bool_t is_configurable;
duk_bool_t is_writable;
- duk_bool_t throw_flag;
duk_bool_t force_flag;
duk_small_uint_t new_flags;
duk_propdesc curr;
@@ -52288,7 +58190,6 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
/* idx_value may be < 0 (no value), set and get may be NULL */
@@ -52306,7 +58207,6 @@ void duk_hobject_define_property_helper(duk_context *ctx,
is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
- throw_flag = 1; /* Object.defineProperty() calls [[DefineOwnProperty]] with Throw=true */
force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
@@ -52322,14 +58222,14 @@ void duk_hobject_define_property_helper(duk_context *ctx,
"has_value=%ld value=%!T "
"has_get=%ld get=%p=%!O "
"has_set=%ld set=%p=%!O "
- "arr_idx=%ld",
+ "arr_idx=%ld throw_flag=!%ld",
(long) has_enumerable, (long) is_enumerable,
(long) has_configurable, (long) is_configurable,
(long) has_writable, (long) is_writable,
- (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
+ (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL),
(long) has_get, (void *) get, (duk_heaphdr *) get,
(long) has_set, (void *) set, (duk_heaphdr *) set,
- (long) arr_idx));
+ (long) arr_idx, (long) throw_flag));
/*
* Array exotic behaviors can be implemented at this point. The local variables
@@ -52342,6 +58242,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
+ duk_harray *a;
+
/* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
if (!has_value) {
DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
@@ -52354,13 +58256,14 @@ void duk_hobject_define_property_helper(duk_context *ctx,
* Get old and new length
*/
- /* Note: reuse 'curr' as a temp propdesc */
- arrlen_old_len = duk__get_old_array_length(thr, obj, &curr);
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+ arrlen_old_len = a->length;
- duk_dup(ctx, idx_value);
- arrlen_new_len = duk__to_new_array_length_checked(thr);
- duk_push_u32(ctx, arrlen_new_len);
- duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
+ DUK_ASSERT(idx_value >= 0);
+ arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value));
+ duk_push_u32(thr, arrlen_new_len);
+ duk_replace(thr, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
@@ -52372,9 +58275,11 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
/* XXX: consolidated algorithm step 15.f -> redundant? */
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && !force_flag) {
- /* Note: 'curr' refers to 'length' propdesc */
- goto fail_not_writable_array_length;
+ if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
+ /* Array .length is always non-configurable; if it's also
+ * non-writable, don't allow it to be written.
+ */
+ goto fail_not_configurable;
}
/* steps 3.h and 3.i */
@@ -52390,18 +58295,24 @@ void duk_hobject_define_property_helper(duk_context *ctx,
/* E5 Section 15.4.5.1, step 4 */
duk_uint32_t old_len;
+ duk_harray *a;
- /* Note: use 'curr' as a temp propdesc */
- old_len = duk__get_old_array_length(thr, obj, &curr);
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+
+ old_len = a->length;
if (arr_idx >= old_len) {
DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
"(arr_idx=%ld, old_len=%ld)",
(long) arr_idx, (long) old_len));
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- /* Note: 'curr' refers to 'length' propdesc */
- goto fail_not_writable_array_length;
+ if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
+ /* Array .length is always non-configurable, so
+ * if it's also non-writable, don't allow a value
+ * write. With force flag allow writing.
+ */
+ goto fail_not_configurable;
}
/* actual update happens once write has been completed without
@@ -52440,6 +58351,17 @@ void duk_hobject_define_property_helper(duk_context *ctx,
goto fail_not_extensible;
}
+#if defined(DUK_USE_ROM_OBJECTS)
+ /* ROM objects are never extensible but force flag may
+ * allow us to come here anyway.
+ */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj));
+ if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
+ DUK_D(DUK_DPRINT("attempt to define property on a read-only target object"));
+ goto fail_not_configurable;
+ }
+#endif
+
/* XXX: share final setting code for value and flags? difficult because
* refcount code is different. Share entry allocation? But can't allocate
* until array index checked.
@@ -52470,7 +58392,7 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
/* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
DUK_ASSERT(e_idx >= 0);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
@@ -52500,7 +58422,7 @@ void duk_hobject_define_property_helper(duk_context *ctx,
new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
}
if (has_value) {
- duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
+ duk_tval *tv_tmp = duk_require_tval(thr, idx_value);
DUK_TVAL_SET_TVAL(&tv, tv_tmp);
} else {
DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
@@ -52523,7 +58445,7 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
/* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
DUK_ASSERT(e_idx >= 0);
tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
DUK_TVAL_SET_TVAL(tv2, &tv);
@@ -52576,8 +58498,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
goto need_check;
}
- tmp1 = duk_require_tval(ctx, -1); /* curr value */
- tmp2 = duk_require_tval(ctx, idx_value); /* new value */
+ tmp1 = duk_require_tval(thr, -1); /* curr value */
+ tmp2 = duk_require_tval(thr, idx_value); /* new value */
if (!duk_js_samevalue(tmp1, tmp2)) {
goto need_check;
}
@@ -52646,15 +58568,19 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
}
- /* Reject attempt to change virtual properties: not part of the
- * standard algorithm, applies currently to e.g. virtual index
- * properties of buffer objects (which are virtual but writable).
- * (Cannot "force" modification of a virtual property.)
+ /* Virtual properties don't have backing so they can't mostly be
+ * edited. Some virtual properties are, however, writable: for
+ * example, virtual index properties of buffer objects and Array
+ * instance .length. These are not configurable so the checks
+ * above mostly cover attempts to change them, except when the
+ * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in
+ * that case we can't forcibly change the property attributes
+ * because they don't have concrete backing.
*/
- if (curr.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
- goto fail_virtual;
- }
+ /* XXX: for ROM objects too it'd be best if value modify was
+ * allowed if the value matches SameValue.
+ */
/* Reject attempt to change a read-only object. */
#if defined(DUK_USE_ROM_OBJECTS)
if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
@@ -52682,7 +58608,6 @@ void duk_hobject_define_property_helper(duk_context *ctx,
} else {
duk_bool_t rc;
duk_tval *tv1;
- duk_tval tv_tmp;
/* curr is data, desc is accessor */
if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
@@ -52693,21 +58618,22 @@ void duk_hobject_define_property_helper(duk_context *ctx,
if (curr.a_idx >= 0) {
DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
+ duk_pop_unsafe(thr); /* remove old value */
rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0);
DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
}
+ if (curr.e_idx < 0) {
+ DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0);
+ goto fail_virtual; /* safeguard for virtual property */
+ }
+ DUK_ASSERT(curr.e_idx >= 0);
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- /* Avoid side effects that might disturb curr.e_idx until
- * we're done editing the slot.
- */
tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
- DUK_TVAL_SET_UNDEFINED(tv1);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1); /* XXX: just decref */
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
@@ -52716,16 +58642,9 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
(unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
-
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
-
- /* re-lookup to update curr.flags
- * XXX: would be faster to update directly
- */
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
+ /* Update curr.flags; faster than a re-lookup. */
+ curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
+ curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR;
}
} else if (has_value || has_writable) {
/* IsDataDescriptor(desc) == true */
@@ -52733,28 +58652,30 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(!has_get);
if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- duk_bool_t rc;
- duk_hobject *h_get;
- duk_hobject *h_set;
+ duk_hobject *tmp;
/* curr is accessor, desc is data */
if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
goto fail_not_configurable;
}
- /* curr is accessor -> cannot be in array part */
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
+ /* curr is accessor -> cannot be in array part. */
+ DUK_ASSERT(curr.a_idx < 0);
+ if (curr.e_idx < 0) {
+ goto fail_virtual; /* safeguard; no virtual accessors now */
+ }
DUK_DDD(DUK_DDDPRINT("convert property to data property"));
- /* Avoid side effects that might disturb curr.e_idx until
- * we're done editing the slot.
- */
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
+ tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
+ DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
- h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
+ tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
+ DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
@@ -52763,16 +58684,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
(unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get); /* side effects */
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set); /* side effects */
-
- /* re-lookup to update curr.flags
- * XXX: would be faster to update directly
- */
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
+ /* Update curr.flags; faster than a re-lookup. */
+ curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR);
} else {
/* curr and desc are data */
if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
@@ -52781,8 +58694,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
/* Note: changing from writable to non-writable is OK */
if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
- duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
- duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
+ duk_tval *tmp1 = duk_require_tval(thr, -1); /* curr value */
+ duk_tval *tmp2 = duk_require_tval(thr, idx_value); /* new value */
if (!duk_js_samevalue(tmp1, tmp2)) {
goto fail_not_configurable;
}
@@ -52851,16 +58764,17 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
DUK_ASSERT(!has_set);
DUK_ASSERT(!has_get);
+ DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */
- tv2 = duk_require_tval(ctx, idx_value);
+ tv2 = duk_require_tval(thr, idx_value);
tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */
goto success_exotics;
}
DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
+ duk_pop_unsafe(thr); /* remove old value */
rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0);
@@ -52869,15 +58783,45 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
- /* array case is handled comprehensively above */
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
+ /* Array case is handled comprehensively above: either in entry
+ * part or a virtual property.
+ */
+ DUK_ASSERT(curr.a_idx < 0);
DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
+ if (curr.e_idx >= 0) {
+ DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
+ } else {
+ /* For Array .length the only allowed transition is for .length
+ * to become non-writable.
+ */
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
+ duk_harray *a;
+ a = (duk_harray *) obj;
+ DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx", (unsigned long) new_flags));
+ DUK_ASSERT_HARRAY_VALID(a);
+ if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) {
+ DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail"));
+ goto fail_virtual;
+ }
+ if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) {
+ DUK_HARRAY_SET_LENGTH_WRITABLE(a);
+ } else {
+ DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
+ }
+ }
+ }
if (has_set) {
duk_hobject *tmp;
+ /* Virtual properties are non-configurable but with a 'force'
+ * flag we might come here so check explicitly for virtual.
+ */
+ if (curr.e_idx < 0) {
+ goto fail_virtual;
+ }
+
DUK_DDD(DUK_DDDPRINT("update existing property setter"));
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
@@ -52885,11 +58829,15 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
}
if (has_get) {
duk_hobject *tmp;
+ if (curr.e_idx < 0) {
+ goto fail_virtual;
+ }
+
DUK_DDD(DUK_DDDPRINT("update existing property getter"));
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
@@ -52897,17 +58845,35 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
+ DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
}
if (has_value) {
duk_tval *tv1, *tv2;
DUK_DDD(DUK_DDDPRINT("update existing property value"));
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tv2 = duk_require_tval(ctx, idx_value);
- tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
+ if (curr.e_idx >= 0) {
+ DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
+ tv2 = duk_require_tval(thr, idx_value);
+ tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */
+ } else {
+ DUK_ASSERT(curr.a_idx < 0); /* array part case handled comprehensively previously */
+
+ DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property"));
+ /* XXX: Uint8Array and other typed array virtual writes not currently
+ * handled.
+ */
+ if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
+ duk_harray *a;
+ a = (duk_harray *) obj;
+ DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld", (long) arrlen_new_len));
+ DUK_ASSERT_HARRAY_VALID(a);
+ a->length = arrlen_new_len;
+ } else {
+ goto fail_virtual; /* should not happen */
+ }
+ }
}
/*
@@ -52924,13 +58890,19 @@ void duk_hobject_define_property_helper(duk_context *ctx,
success_exotics:
+ /* curr.a_idx or curr.e_idx may have been invalidated by side effects
+ * above.
+ */
+
/* [obj key desc value get set curr_value] */
if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
- if (arridx_new_array_length > 0) {
- duk_tval *tmp;
- duk_bool_t rc;
+ duk_harray *a;
+ a = (duk_harray *) obj;
+ DUK_ASSERT_HARRAY_VALID(a);
+
+ if (arridx_new_array_length > 0) {
/*
* Note: zero works as a "no update" marker because the new length
* can never be zero after a new property is written.
@@ -52941,31 +58913,19 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
(long) arridx_new_array_length));
- /* Note: reuse 'curr' */
- rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &curr, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(curr.e_idx >= 0);
-
- tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
- /* no need for decref/incref because value is a number */
- DUK_TVAL_SET_FASTINT_U32(tmp, arridx_new_array_length);
+ a->length = arridx_new_array_length;
}
+
if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
/*
* E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
* the error case 3.l.iii and the success case 3.m-3.n.
- *
- * Note: 'length' is always in entries part, so no array abandon issues for
- * 'writable' update.
*/
/* XXX: investigate whether write protect can be handled above, if we
* just update length here while ignoring its protected status
*/
- duk_tval *tmp;
duk_uint32_t result_len;
duk_bool_t rc;
@@ -52977,25 +58937,17 @@ void duk_hobject_define_property_helper(duk_context *ctx,
/* update length (curr points to length, and we assume it's still valid) */
DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
- DUK_ASSERT(curr.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tmp, result_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
+ a->length = result_len;
if (pending_write_protect) {
DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
- DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
+ DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
}
- /*
- * XXX: shrink array allocation or entries compaction here?
- */
-
+ /* XXX: shrink array allocation or entries compaction here? */
if (!rc) {
- goto fail_array_length_partial;
+ DUK_DD(DUK_DDPRINT("array length write only partially successful"));
+ goto fail_not_configurable;
}
}
} else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
@@ -53032,17 +58984,17 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
"update bound value (variable/argument)"));
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
"key=%!O, varname=%!O, value=%!T",
(duk_heaphdr *) key,
(duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, idx_value)));
+ (duk_tval *) duk_require_tval(thr, idx_value)));
/* strict flag for putvar comes from our caller (currently: fixed) */
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), throw_flag);
+ duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/);
}
if (has_writable && !is_writable) {
DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
@@ -53058,50 +59010,46 @@ void duk_hobject_define_property_helper(duk_context *ctx,
}
success_no_exotics:
- return;
-
- fail_virtual:
- DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
- return;
-
- fail_not_writable_array_length:
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_NOT_WRITABLE);
- return;
+ /* Some code paths use NORZ macros for simplicity, ensure refzero
+ * handling is completed.
+ */
+ DUK_REFZERO_CHECK_SLOW(thr);
+ return 1;
fail_not_extensible:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
- return;
+ if (throw_flag) {
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
+ }
+ return 0;
+ fail_virtual: /* just use the same "not configurable" error message" */
fail_not_configurable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
- return;
-
- fail_array_length_partial:
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
- return;
+ if (throw_flag) {
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ }
+ return 0;
}
/*
* Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
*/
-DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) {
duk_hstring *h_v;
duk_hobject *h_obj;
duk_propdesc desc;
duk_bool_t ret;
/* coercion order matters */
- h_v = duk_to_hstring(ctx, 0);
+ h_v = duk_to_hstring_acceptsymbol(thr, 0);
DUK_ASSERT(h_v != NULL);
- h_obj = duk_push_this_coercible_to_object(ctx);
+ h_obj = duk_push_this_coercible_to_object(thr);
DUK_ASSERT(h_obj != NULL);
ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
- duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
+ duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
return 1;
}
@@ -53239,25 +59187,27 @@ DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *
* and the Object built-in bindings.
*/
-/* Undefine local defines */
-
-#undef DUK__NO_ARRAY_INDEX
-#undef DUK__HASH_INITIAL
-#undef DUK__HASH_PROBE_STEP
-#undef DUK__HASH_UNUSED
+/* automatic undefs */
#undef DUK__HASH_DELETED
+#undef DUK__HASH_UNUSED
+#undef DUK__NO_ARRAY_INDEX
+#undef DUK__VALSTACK_PROXY_LOOKUP
#undef DUK__VALSTACK_SPACE
-#line 1 "duk_hstring_misc.c"
/*
* Misc support functions
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/*
+ * duk_hstring charCodeAt, with and without surrogate awareness
+ */
-DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos) {
+DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) {
duk_uint32_t boff;
const duk_uint8_t *p, *p_start, *p_end;
- duk_ucodepoint_t cp;
+ duk_ucodepoint_t cp1;
+ duk_ucodepoint_t cp2;
/* Caller must check character offset to be inside the string. */
DUK_ASSERT(thr != NULL);
@@ -53265,7 +59215,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
- boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
+ boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
(long) pos, (long) boff, (duk_heaphdr *) h));
DUK_ASSERT_DISABLE(boff >= 0);
@@ -53278,27 +59228,172 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
(const void *) p_start, (const void *) p_end,
(const void *) p));
- /* This may throw an error though not for valid E5 strings. */
- cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
- return cp;
+ /* For invalid UTF-8 (never happens for standard Ecmascript strings)
+ * return U+FFFD replacement character.
+ */
+ if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) {
+ if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) {
+ /* The decode helper is memory safe even if 'cp1' was
+ * decoded at the end of the string and 'p' is no longer
+ * within string memory range.
+ */
+ cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */
+ (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2);
+ if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) {
+ cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL);
+ }
+ }
+ } else {
+ cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ }
+
+ return cp1;
}
+/*
+ * duk_hstring charlen, when lazy charlen disabled
+ */
+
+#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
#if !defined(DUK_USE_HSTRING_CLEN)
-DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
- if (DUK_HSTRING_HAS_ASCII(h)) {
+#error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set
+#endif
+DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) {
+ duk_uint32_t clen;
+
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
+
+ clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+#if defined(DUK_USE_STRLEN16)
+ DUK_ASSERT(clen <= 0xffffUL); /* Bytelength checked during interning. */
+ h->clen16 = (duk_uint16_t) clen;
+#else
+ h->clen = (duk_uint32_t) clen;
+#endif
+ if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) {
+ DUK_HSTRING_SET_ASCII(h);
+ }
+}
+
+DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
+#if defined(DUK_USE_STRLEN16)
+ return h->clen16;
+#else
+ return h->clen;
+#endif
+}
+#endif /* !DUK_USE_HSTRING_LAZY_CLEN */
+
+/*
+ * duk_hstring charlen, when lazy charlen enabled
+ */
+
+#if defined(DUK_USE_HSTRING_LAZY_CLEN)
+#if defined(DUK_USE_HSTRING_CLEN)
+DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
+ duk_size_t res;
+
+ DUK_ASSERT(h->clen == 0); /* Checked by caller. */
+
+#if defined(DUK_USE_ROM_STRINGS)
+ /* ROM strings have precomputed clen, but if the computed clen is zero
+ * we can still come here and can't write anything.
+ */
+ if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
+ return 0;
+ }
+#endif
+
+ res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+#if defined(DUK_USE_STRLEN16)
+ DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */
+ h->clen16 = (duk_uint16_t) res;
+#else
+ h->clen = (duk_uint32_t) res;
+#endif
+ if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
+ DUK_HSTRING_SET_ASCII(h);
+ }
+ return res;
+}
+#else /* DUK_USE_HSTRING_CLEN */
+DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
+ if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) {
/* Most practical strings will go here. */
return DUK_HSTRING_GET_BYTELEN(h);
} else {
- return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+ /* ASCII flag is lazy, so set it here. */
+ duk_size_t res;
+
+ /* XXX: here we could use the strcache to speed up the
+ * computation (matters for 'i < str.length' loops).
+ */
+
+ res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+
+#if defined(DUK_USE_ROM_STRINGS)
+ if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
+ /* For ROM strings, can't write anything; ASCII flag
+ * is preset so we don't need to update it.
+ */
+ return res;
+ }
+#endif
+ if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
+ DUK_HSTRING_SET_ASCII(h);
+ }
+ return res;
+ }
+}
+#endif /* DUK_USE_HSTRING_CLEN */
+
+#if defined(DUK_USE_HSTRING_CLEN)
+DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
+#if defined(DUK_USE_STRLEN16)
+ if (DUK_LIKELY(h->clen16 != 0)) {
+ return h->clen16;
+ }
+#else
+ if (DUK_LIKELY(h->clen != 0)) {
+ return h->clen;
+ }
+#endif
+ return duk__hstring_get_charlen_slowpath(h);
+}
+#else /* DUK_USE_HSTRING_CLEN */
+DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
+ /* Always use slow path. */
+ return duk__hstring_get_charlen_slowpath(h);
+}
+#endif /* DUK_USE_HSTRING_CLEN */
+#endif /* DUK_USE_HSTRING_LAZY_CLEN */
+
+/*
+ * Compare duk_hstring to an ASCII cstring.
+ */
+
+DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) {
+ duk_size_t len;
+
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(cstr != NULL);
+
+ len = DUK_STRLEN(cstr);
+ if (len != DUK_HSTRING_GET_BYTELEN(h)) {
+ return 0;
}
+ if (DUK_MEMCMP((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
+ return 1;
+ }
+ return 0;
}
-#endif /* !DUK_USE_HSTRING_CLEN */
-#line 1 "duk_hthread_alloc.c"
/*
* duk_hthread allocation and freeing.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Allocate initial stacks for a thread. Note that 'thr' must be reachable
@@ -53314,22 +59409,21 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->valstack == NULL);
DUK_ASSERT(thr->valstack_end == NULL);
+ DUK_ASSERT(thr->valstack_alloc_end == NULL);
DUK_ASSERT(thr->valstack_bottom == NULL);
DUK_ASSERT(thr->valstack_top == NULL);
- DUK_ASSERT(thr->callstack == NULL);
- DUK_ASSERT(thr->catchstack == NULL);
+ DUK_ASSERT(thr->callstack_curr == NULL);
/* valstack */
+ DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE);
alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
if (!thr->valstack) {
goto fail;
}
DUK_MEMZERO(thr->valstack, alloc_size);
- thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
-#endif
+ thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM;
+ thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
thr->valstack_bottom = thr->valstack;
thr->valstack_top = thr->valstack;
@@ -53337,36 +59431,13 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr
DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
}
- /* callstack */
- alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
- thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
- if (!thr->callstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->callstack, alloc_size);
- thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->callstack_top == 0);
-
- /* catchstack */
- alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
- thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
- if (!thr->catchstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->catchstack, alloc_size);
- thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->catchstack_top == 0);
-
return 1;
fail:
DUK_FREE(heap, thr->valstack);
- DUK_FREE(heap, thr->callstack);
- DUK_FREE(heap, thr->catchstack);
+ DUK_ASSERT(thr->callstack_curr == NULL);
thr->valstack = NULL;
- thr->callstack = NULL;
- thr->catchstack = NULL;
return 0;
}
@@ -53377,49 +59448,24 @@ DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
DUK_UNREF(heap);
return (void *) thr->valstack;
}
-
-DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->callstack;
-}
-
-DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->catchstack;
-}
-#line 1 "duk_hthread_builtins.c"
/*
* Initialize built-in objects. Current thread must have a valstack
* and initialization errors may longjmp, so a setjmp() catch point
* must exist.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Encoding constants, must match genbuiltins.py
*/
-#define DUK__CLASS_BITS 5
-#define DUK__BIDX_BITS 7
-#define DUK__STRIDX_BITS 9 /* XXX: try to optimize to 8 (would now be possible, <200 used) */
-#define DUK__NATIDX_BITS 8
-#define DUK__NUM_NORMAL_PROPS_BITS 6
-#define DUK__NUM_FUNC_PROPS_BITS 6
#define DUK__PROP_FLAGS_BITS 3
-#define DUK__STRING_LENGTH_BITS 8
-#define DUK__STRING_CHAR_BITS 7
#define DUK__LENGTH_PROP_BITS 3
#define DUK__NARGS_BITS 3
#define DUK__PROP_TYPE_BITS 3
-#define DUK__MAGIC_BITS 16
#define DUK__NARGS_VARARGS_MARKER 0x07
-#define DUK__NO_CLASS_MARKER 0x00 /* 0 = DUK_HOBJECT_CLASS_UNUSED */
-#define DUK__NO_BIDX_MARKER 0x7f
-#define DUK__NO_STRIDX_MARKER 0xff
#define DUK__PROP_TYPE_DOUBLE 0
#define DUK__PROP_TYPE_STRING 1
@@ -53438,100 +59484,96 @@ DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
#if defined(DUK_USE_ROM_OBJECTS)
#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
- duk_context *ctx;
- duk_hobject *h1;
+ duk_hobject *h_global;
#if defined(DUK_USE_ROM_GLOBAL_CLONE)
- duk_hobject *h2;
+ duk_hobject *h_oldglobal;
duk_uint8_t *props;
duk_size_t alloc_size;
#endif
-
- ctx = (duk_context *) thr;
+ duk_hobject *h_objenv;
/* XXX: refactor into internal helper, duk_clone_hobject() */
#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
/* Inherit from ROM-based global object: less RAM usage, less transparent. */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
- DUK_BIDX_GLOBAL);
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
+ h_global = duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
+ DUK_BIDX_GLOBAL);
+ DUK_ASSERT(h_global != NULL);
#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
/* Clone the properties of the ROM-based global object to create a
* fully RAM-based global object. Uses more memory than the inherit
* model but more compliant.
*/
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
- DUK_BIDX_OBJECT_PROTOTYPE);
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
- h2 = thr->builtins[DUK_BIDX_GLOBAL];
- DUK_ASSERT(h2 != NULL);
+ h_global = duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
+ DUK_BIDX_OBJECT_PROTOTYPE);
+ DUK_ASSERT(h_global != NULL);
+ h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL];
+ DUK_ASSERT(h_oldglobal != NULL);
/* Copy the property table verbatim; this handles attributes etc.
* For ROM objects it's not necessary (or possible) to update
* refcounts so leave them as is.
*/
- alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
+ alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal);
DUK_ASSERT(alloc_size > 0);
- props = DUK_ALLOC(thr->heap, alloc_size);
- if (!props) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- return;
- }
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
- DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
+ props = DUK_ALLOC_CHECKED(thr, alloc_size);
+ DUK_ASSERT(props != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL);
+ DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);
/* XXX: keep property attributes or tweak them here?
* Properties will now be non-configurable even when they're
* normally configurable for the global object.
*/
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
- DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
- DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
- DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
- DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
- DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
+ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL);
+ DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props);
+ DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal));
+ DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal));
+ DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal));
+ DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal));
#else
-#error internal error in defines
+#error internal error in config defines
#endif
- duk_hobject_compact_props(thr, h1);
+ duk_hobject_compact_props(thr, h_global);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */
- thr->builtins[DUK_BIDX_GLOBAL] = h1;
- DUK_HOBJECT_INCREF(thr, h1);
- DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
-
+ DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */
+ thr->builtins[DUK_BIDX_GLOBAL] = h_global;
+ DUK_HOBJECT_INCREF(thr, h_global);
+ DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global));
/* Create a fresh object environment for the global scope. This is
* needed so that the global scope points to the newly created RAM-based
* global object.
*/
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype */
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
- duk_dup(ctx, -2);
- duk_dup(ctx, -1); /* -> [ ... new_global new_globalenv new_global new_global ] */
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
+ h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
+ DUK_ASSERT(h_objenv != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL);
+ duk_push_hobject(thr, h_objenv);
+
+ DUK_ASSERT(h_global != NULL);
+ ((duk_hobjenv *) h_objenv)->target = h_global;
+ DUK_HOBJECT_INCREF(thr, h_global);
+ DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0);
- duk_hobject_compact_props(thr, h1);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */
- thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
- DUK_HOBJECT_INCREF(thr, h1);
- DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
+ DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */
+ thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv;
+ DUK_HOBJECT_INCREF(thr, h_objenv);
+ DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv));
+
+ DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv);
- duk_pop_2(ctx);
+ duk_pop_2(thr); /* Pop global object and global env. */
}
#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
@@ -53558,34 +59600,37 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#endif
}
#else /* DUK_USE_ROM_OBJECTS */
-DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
duk_small_uint_t n;
- n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS);
+ n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring_stridx(ctx, n);
+ duk_push_hstring_stridx(thr, n);
}
-DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- duk_small_uint_t n;
- duk_small_uint_t i;
- duk_uint8_t *p;
+DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
+ /* XXX: built-ins data could provide a maximum length that is
+ * actually needed; bitpacked max length is now 256 bytes.
+ */
+ duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN];
+ duk_small_uint_t len;
- n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n);
- for (i = 0; i < n; i++) {
- *p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
- }
- duk_to_string(ctx, -1);
+ len = duk_bd_decode_bitpacked_string(bd, tmp);
+ duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len);
}
-DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- if (duk_bd_decode_flag(bd)) {
- duk__push_string(ctx, bd);
+DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
+ duk_small_uint_t n;
+
+ n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ if (n == 0) {
+ duk__push_string(thr, bd);
} else {
- duk__push_stridx(ctx, bd);
+ n--;
+ DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
+ duk_push_hstring_stridx(thr, n);
}
}
-DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
duk_double_union du;
duk_small_uint_t i;
@@ -53596,11 +59641,10 @@ DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
}
- duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
+ duk_push_number(thr, du.d); /* push operation normalizes NaNs */
}
DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_bitdecoder_ctx bd_ctx;
duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
duk_hobject *h;
@@ -53623,41 +59667,43 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* into thr->builtins[]. These are objects referenced in some way
* from thr->builtins[] roots but which don't need to be indexed by
* Duktape through thr->builtins[] (e.g. user custom objects).
+ *
+ * Internal prototypes will be incorrect (NULL) at this stage.
*/
- duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
+ duk_require_stack(thr, DUK_NUM_ALL_BUILTINS);
DUK_DD(DUK_DDPRINT("create empty built-ins"));
- DUK_ASSERT_TOP(ctx, 0);
+ DUK_ASSERT_TOP(thr, 0);
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
duk_small_uint_t class_num;
duk_small_int_t len = -1; /* must be signed */
- class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS);
- len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
+ class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
duk_small_uint_t natidx;
- duk_int_t c_nargs; /* must hold DUK_VARARGS */
+ duk_small_int_t c_nargs; /* must hold DUK_VARARGS */
duk_c_function c_func;
duk_int16_t magic;
DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
DUK_ASSERT(len >= 0);
- natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
+ natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ DUK_ASSERT(natidx != 0);
c_func = duk_bi_native_functions[natidx];
+ DUK_ASSERT(c_func != NULL);
- c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
+ c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/);
if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
c_nargs = DUK_VARARGS;
}
/* XXX: set magic directly here? (it could share the c_nargs arg) */
- duk_push_c_function_noexotic(ctx, c_func, c_nargs);
-
- h = duk_require_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
+ (void) duk_push_c_function_builtin(thr, c_func, c_nargs);
+ h = duk_known_hobject(thr, -1);
/* Currently all built-in native functions are strict.
* duk_push_c_function() now sets strict flag, so
@@ -53667,16 +59713,15 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* XXX: function properties */
- /* Built-in 'name' is not writable by default. Function '.name'
- * is writable to allow user code to set a '.name' on a native
- * function.
- */
- duk__push_stridx_or_string(ctx, bd);
- duk_xdef_prop_stridx(ctx,
- -2,
- DUK_STRIDX_NAME,
- (i == DUK_BIDX_FUNCTION_PROTOTYPE) ?
- DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE);
+ duk__push_stridx_or_string(thr, bd);
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ duk_xdef_prop_stridx_short(thr,
+ -2,
+ DUK_STRIDX_NAME,
+ DUK_PROPDESC_FLAGS_C);
+#else
+ duk_pop(thr); /* Not very ideal but good enough for now. */
+#endif
/* Almost all global level Function objects are constructable
* but not all: Function.prototype is a non-constructable,
@@ -53689,19 +59734,41 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
}
/* Cast converts magic to 16-bit signed value */
- magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
- ((duk_hnativefunction *) h)->magic = magic;
+ magic = (duk_int16_t) duk_bd_decode_varuint(bd);
+ ((duk_hnatfunc *) h)->magic = magic;
+ } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
+ duk_push_array(thr);
+ } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) {
+ duk_hobjenv *env;
+ duk_hobject *global;
+
+ DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV);
+ DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL);
+
+ env = duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
+ DUK_ASSERT(env->target == NULL);
+ duk_push_hobject(thr, (duk_hobject *) env);
+
+ global = duk_known_hobject(thr, DUK_BIDX_GLOBAL);
+ DUK_ASSERT(global != NULL);
+ env->target = global;
+ DUK_HOBJECT_INCREF(thr, global);
+ DUK_ASSERT(env->has_this == 0);
+
+ DUK_ASSERT_HOBJENV_VALID(env);
} else {
- /* XXX: ARRAY_PART for Array prototype? */
+ DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV);
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE,
- -1); /* no prototype or class yet */
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_EXTENSIBLE,
+ -1); /* no prototype or class yet */
- h = duk_require_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
}
+ h = duk_known_hobject(thr, -1);
DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
if (i < DUK_NUM_BUILTINS) {
@@ -53710,31 +59777,28 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
}
if (len >= 0) {
- /*
- * For top-level objects, 'length' property has the following
- * default attributes: non-writable, non-enumerable, non-configurable
- * (E5 Section 15).
+ /* In ES2015+ built-in function object .length property
+ * has property attributes C (configurable only):
+ * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects
*
- * However, 'length' property for Array.prototype has attributes
- * expected of an Array instance which are different: writable,
- * non-enumerable, non-configurable (E5 Section 15.4.5.2).
- *
- * This is currently determined implicitly based on class; there are
- * no attribute flags in the init data.
+ * Array.prototype remains an Array instance in ES2015+
+ * and its length has attributes W (writable only).
+ * Because .length is now virtual for duk_harray, it is
+ * not encoded explicitly in init data.
*/
- duk_push_int(ctx, len);
- duk_xdef_prop_stridx(ctx,
- -2,
- DUK_STRIDX_LENGTH,
- (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */
- DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
+ DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */
+ duk_push_int(thr, len);
+ duk_xdef_prop_stridx_short(thr,
+ -2,
+ DUK_STRIDX_LENGTH,
+ DUK_PROPDESC_FLAGS_C);
}
/* enable exotic behaviors last */
if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
- DUK_HOBJECT_SET_EXOTIC_ARRAY(h);
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */
}
if (class_num == DUK_HOBJECT_CLASS_STRING) {
DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
@@ -53744,17 +59808,16 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
/* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
- /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h));
+ /* DUK_HOBJECT_FLAG_NATFUNC varies */
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY);
/* DUK_HOBJECT_FLAG_STRICT varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */
DUK_HOBJECT_HAS_NEWENV(h));
DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
/* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
/* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
@@ -53764,7 +59827,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/*
* Then decode the builtins init data (see genbuiltins.py) to
- * init objects
+ * init objects. Internal prototypes are set at this stage,
+ * with thr->builtins[] populated.
*/
DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
@@ -53773,44 +59837,55 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_small_uint_t num;
DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
- h = duk_require_hobject(ctx, i);
- DUK_ASSERT(h != NULL);
+ h = duk_known_hobject(thr, (duk_idx_t) i);
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
+ t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ if (t > 0) {
+ t--;
DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t));
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t));
+ } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
+ /* Standard native built-ins cannot inherit from
+ * %NativeFunctionPrototype%, they are required to
+ * inherit from Function.prototype directly.
+ */
+ DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
}
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
+ t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ if (t > 0) {
/* 'prototype' property for all built-in objects (which have it) has attributes:
* [[Writable]] = false,
* [[Enumerable]] = false,
* [[Configurable]] = false
*/
+ t--;
DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, (duk_idx_t) t);
+ duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE);
}
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
+ t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ if (t > 0) {
/* 'constructor' property for all built-in objects (which have it) has attributes:
* [[Writable]] = true,
* [[Enumerable]] = false,
* [[Configurable]] = true
*/
+ t--;
DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
+ duk_dup(thr, (duk_idx_t) t);
+ duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);
}
/* normal valued properties */
- num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
+ num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
for (j = 0; j < num; j++) {
- duk_small_uint_t prop_flags;
+ duk_small_uint_t defprop_flags;
- duk__push_stridx_or_string(ctx, bd);
+ duk__push_stridx_or_string(thr, bd);
/*
* Property attribute defaults are defined in E5 Section 15 (first
@@ -53820,79 +59895,89 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
if (duk_bd_decode_flag(bd)) {
- prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
+ defprop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
} else {
- prop_flags = DUK_PROPDESC_FLAGS_WC;
+ defprop_flags = DUK_PROPDESC_FLAGS_WC;
}
+ defprop_flags |= DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_HAVE_VALUE |
+ DUK_DEFPROP_HAVE_WRITABLE |
+ DUK_DEFPROP_HAVE_ENUMERABLE |
+ DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */
+
+ /* The writable, enumerable, configurable flags in prop_flags
+ * match both duk_def_prop() and internal property flags.
+ */
+ DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
+ DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
+ DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
- (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t));
+ (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t));
switch (t) {
case DUK__PROP_TYPE_DOUBLE: {
- duk__push_double(ctx, bd);
+ duk__push_double(thr, bd);
break;
}
case DUK__PROP_TYPE_STRING: {
- duk__push_string(ctx, bd);
+ duk__push_string(thr, bd);
break;
}
case DUK__PROP_TYPE_STRIDX: {
- duk__push_stridx(ctx, bd);
+ duk__push_stridx(thr, bd);
break;
}
case DUK__PROP_TYPE_BUILTIN: {
duk_small_uint_t bidx;
- bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
- duk_dup(ctx, (duk_idx_t) bidx);
+ bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ duk_dup(thr, (duk_idx_t) bidx);
break;
}
case DUK__PROP_TYPE_UNDEFINED: {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
}
case DUK__PROP_TYPE_BOOLEAN_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
}
case DUK__PROP_TYPE_BOOLEAN_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
}
case DUK__PROP_TYPE_ACCESSOR: {
- duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
- duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
+ duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
+ duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd);
duk_c_function c_func_getter;
duk_c_function c_func_setter;
- /* XXX: this is a bit awkward because there is no exposed helper
- * in the API style, only this internal helper.
- */
DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
- (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
+ (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
c_func_getter = duk_bi_native_functions[natidx_getter];
+ if (c_func_getter != NULL) {
+ duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */
+ duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
+ defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
+ }
c_func_setter = duk_bi_native_functions[natidx_setter];
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
-
- /* XXX: magic for getter/setter? use duk_def_prop()? */
+ if (c_func_setter != NULL) {
+ duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */
+ duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
+ defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
+ }
- DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
+ /* Writable flag doesn't make sense for an accessor. */
+ DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
- prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
- duk_hobject_define_accessor_internal(thr,
- duk_require_hobject(ctx, i),
- duk_get_hstring(ctx, -3),
- duk_require_hobject(ctx, -2),
- duk_require_hobject(ctx, -1),
- prop_flags);
- duk_pop_3(ctx); /* key, getter and setter, now reachable through object */
- goto skip_value;
+ defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
+ defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
+ break;
}
default: {
/* exhaustive */
@@ -53900,15 +59985,12 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
}
}
- DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
- duk_xdef_prop(ctx, i, prop_flags);
-
- skip_value:
- continue; /* avoid empty label at the end of a compound statement */
+ duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
+ DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS);
}
/* native function properties */
- num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
+ num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
for (j = 0; j < num; j++) {
duk_hstring *h_key;
@@ -53917,19 +59999,18 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_small_uint_t c_length;
duk_int16_t magic;
duk_c_function c_func;
- duk_hnativefunction *h_func;
+ duk_hnatfunc *h_func;
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
duk_small_int_t lightfunc_eligible;
#endif
- duk__push_stridx_or_string(ctx, bd);
- h_key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_key != NULL);
+ duk__push_stridx_or_string(thr, bd);
+ h_key = duk_known_hstring(thr, -1);
DUK_UNREF(h_key);
- natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
+ natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
- c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
+ c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/);
if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
c_nargs = DUK_VARARGS;
}
@@ -53941,7 +60022,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
(c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
/* Cast converts magic to 16-bit signed value */
- magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
+ magic = (duk_int16_t) duk_bd_decode_varuint(bd);
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
lightfunc_eligible =
@@ -53949,25 +60030,33 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
(c_length <= DUK_LFUNC_LENGTH_MAX) &&
(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
- if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
- h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
- h_key == DUK_HTHREAD_STRING_RESUME(thr) ||
- h_key == DUK_HTHREAD_STRING_REQUIRE(thr)) {
- /* These functions have trouble working as lightfuncs.
- * Some of them have specific asserts and some may have
- * additional properties (e.g. 'require.id' may be written).
- */
- DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
+ /* These functions have trouble working as lightfuncs.
+ * Some of them have specific asserts and some may have
+ * additional properties (e.g. 'require.id' may be written).
+ */
+ if (c_func == duk_bi_global_object_eval) {
+ lightfunc_eligible = 0;
+ }
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+ if (c_func == duk_bi_thread_yield ||
+ c_func == duk_bi_thread_resume) {
+ lightfunc_eligible = 0;
+ }
+#endif
+ if (c_func == duk_bi_function_prototype_call ||
+ c_func == duk_bi_function_prototype_apply ||
+ c_func == duk_bi_reflect_apply ||
+ c_func == duk_bi_reflect_construct) {
lightfunc_eligible = 0;
}
if (lightfunc_eligible) {
duk_tval tv_lfunc;
- duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
+ duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
- duk_push_tval(ctx, &tv_lfunc);
- DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1)));
+ duk_push_tval(thr, &tv_lfunc);
+ DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(thr, -1)));
goto lightfunc_skip;
}
@@ -53976,10 +60065,21 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* [ (builtin objects) name ] */
- duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
- h_func = duk_require_hnativefunction(ctx, -1);
+ duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs);
+ h_func = duk_known_hnatfunc(thr, -1);
DUK_UNREF(h_func);
+ /* XXX: add into init data? */
+
+ /* Special call handling, not described in init data. */
+ if (c_func == duk_bi_global_object_eval ||
+ c_func == duk_bi_function_prototype_call ||
+ c_func == duk_bi_function_prototype_apply ||
+ c_func == duk_bi_reflect_apply ||
+ c_func == duk_bi_reflect_construct) {
+ DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func);
+ }
+
/* Currently all built-in native functions are strict.
* This doesn't matter for many functions, but e.g.
* String.prototype.charAt (and other string functions)
@@ -54000,16 +60100,16 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* [ (builtin objects) name func ] */
- duk_push_int(ctx, c_length);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_uint(thr, c_length);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup_m2(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
/* XXX: other properties of function instances; 'arguments', 'caller'. */
DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
- (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1)));
/* [ (builtin objects) name func ] */
@@ -54022,7 +60122,10 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
lightfunc_skip:
#endif
- duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
+ /* XXX: So far all ES builtins are 'wc' but e.g.
+ * performance.now() should be 'wec'.
+ */
+ duk_xdef_prop(thr, (duk_idx_t) i, DUK_PROPDESC_FLAGS_WC);
/* [ (builtin objects) ] */
}
@@ -54045,11 +60148,12 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* conditional in init data.
*/
- duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
- duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
+#if defined(DUK_USE_DATE_BUILTIN)
+ duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
+ duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
+#endif
- h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
- DUK_ASSERT(h != NULL);
+ h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
@@ -54063,7 +60167,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#endif
/* XXX: relocate */
- duk_push_string(ctx,
+ duk_push_string(thr,
/* Endianness indicator */
#if defined(DUK_USE_INTEGER_LE)
"l"
@@ -54095,12 +60199,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#endif
" "
/* Low memory options */
-#if defined(DUK_USE_STRTAB_CHAIN)
- "c" /* chain */
-#elif defined(DUK_USE_STRTAB_PROBE)
- "p" /* probe */
-#else
- "?"
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ "s"
#endif
#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
"n"
@@ -54168,26 +60268,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_USE_OS_STRING
" "
DUK_USE_COMPILER_STRING);
- duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
-
- /*
- * InitJS code - Ecmascript code evaluated from a built-in source
- * which provides e.g. backward compatibility. User can also provide
- * JS code to be evaluated at startup.
- */
-
-#ifdef DUK_USE_BUILTIN_INITJS
- /* XXX: compression */
- DUK_DD(DUK_DDPRINT("running built-in initjs"));
- duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */
- duk_pop(ctx);
-#endif /* DUK_USE_BUILTIN_INITJS */
-
-#ifdef DUK_USE_USER_INITJS
- /* XXX: compression (as an option) */
- DUK_DD(DUK_DDPRINT("running user initjs"));
- duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS);
-#endif /* DUK_USE_USER_INITJS */
+ duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
/*
* Since built-ins are not often extended, compact them.
@@ -54195,15 +60276,15 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("compact built-ins"));
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- duk_hobject_compact_props(thr, duk_require_hobject(ctx, i));
+ duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i));
}
DUK_D(DUK_DPRINT("INITBUILTINS END"));
-#ifdef DUK_USE_DDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
- (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
+ (long) i, (duk_heaphdr *) duk_require_hobject(thr, i)));
}
#endif
@@ -54213,8 +60294,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* through builtins[].
*/
- duk_set_top(ctx, 0);
- DUK_ASSERT_TOP(ctx, 0);
+ duk_set_top(thr, 0);
+ DUK_ASSERT_TOP(thr, 0);
}
#endif /* DUK_USE_ROM_OBJECTS */
@@ -54226,50 +60307,49 @@ DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_ht
DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
}
}
-#line 1 "duk_hthread_misc.c"
+
+/* automatic undefs */
+#undef DUK__LENGTH_PROP_BITS
+#undef DUK__NARGS_BITS
+#undef DUK__NARGS_VARARGS_MARKER
+#undef DUK__PROP_FLAGS_BITS
+#undef DUK__PROP_TYPE_ACCESSOR
+#undef DUK__PROP_TYPE_BITS
+#undef DUK__PROP_TYPE_BOOLEAN_FALSE
+#undef DUK__PROP_TYPE_BOOLEAN_TRUE
+#undef DUK__PROP_TYPE_BUILTIN
+#undef DUK__PROP_TYPE_DOUBLE
+#undef DUK__PROP_TYPE_STRIDX
+#undef DUK__PROP_TYPE_STRING
+#undef DUK__PROP_TYPE_UNDEFINED
/*
* Thread support.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
- /* Order of unwinding is important */
-
- duk_hthread_catchstack_unwind(thr, 0);
-
- duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
+ while (thr->callstack_curr != NULL) {
+ duk_hthread_activation_unwind_norz(thr);
+ }
thr->valstack_bottom = thr->valstack;
- duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
+ duk_set_top(thr, 0); /* unwinds valstack, updating refcounts */
thr->state = DUK_HTHREAD_STATE_TERMINATED;
/* Here we could remove references to built-ins, but it may not be
* worth the effort because built-ins are quite likely to be shared
* with another (unterminated) thread, and terminated threads are also
- * usually garbage collected quite quickly. Also, doing DECREFs
- * could trigger finalization, which would run on the current thread
- * and have access to only some of the built-ins. Garbage collection
- * deals with this correctly already.
+ * usually garbage collected quite quickly.
+ *
+ * We could also shrink the value stack here, but that also may not
+ * be worth the effort for the same reason.
*/
- /* XXX: Shrink the stacks to minimize memory usage? May not
- * be worth the effort because terminated threads are usually
- * garbage collected quite soon.
- */
-}
-
-DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
-
- if (thr->callstack_top > 0) {
- return thr->callstack + thr->callstack_top - 1;
- } else {
- return NULL;
- }
+ DUK_REFZERO_CHECK_SLOW(thr);
}
#if defined(DUK_USE_DEBUGGER_SUPPORT)
@@ -54281,8 +60361,8 @@ DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk
DUK_UNREF(thr);
/* XXX: store 'bcode' pointer to activation for faster lookup? */
- if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
- bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
+ if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
+ bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
return (duk_uint_fast32_t) (act->curr_pc - bcode);
}
return 0;
@@ -54297,8 +60377,8 @@ DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk
DUK_ASSERT(act != NULL);
DUK_UNREF(thr);
- if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
- bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
+ if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
+ bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
if (ret > 0) {
ret--;
@@ -54317,7 +60397,9 @@ DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
if (thr->ptr_curr_pc != NULL) {
/* ptr_curr_pc != NULL only when bytecode executor is active. */
DUK_ASSERT(thr->callstack_top > 0);
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
act->curr_pc = *thr->ptr_curr_pc;
}
}
@@ -54330,552 +60412,663 @@ DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
if (thr->ptr_curr_pc != NULL) {
/* ptr_curr_pc != NULL only when bytecode executor is active. */
DUK_ASSERT(thr->callstack_top > 0);
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
act->curr_pc = *thr->ptr_curr_pc;
thr->ptr_curr_pc = NULL;
}
}
-#line 1 "duk_hthread_stacks.c"
/*
- * Manipulation of thread stacks (valstack, callstack, catchstack).
- *
- * Ideally unwinding of stacks should have no side effects, which would
- * then favor separate unwinding and shrink check primitives for each
- * stack type. A shrink check may realloc and thus have side effects.
- *
- * However, currently callstack unwinding itself has side effects, as it
- * needs to DECREF multiple objects, close environment records, etc.
- * Stacks must thus be unwound in the correct order by the caller.
+ * Thread stack (mainly call stack) primitives: allocation of activations,
+ * unwinding catchers and activations, etc.
*
- * (XXX: This should be probably reworked so that there is a shared
- * unwind primitive which handles all stacks as requested, and knows
- * the proper order for unwinding.)
- *
- * Valstack entries above 'top' are always kept initialized to
- * "undefined unused". Callstack and catchstack entries above 'top'
- * are not zeroed and are left as garbage.
- *
- * Value stack handling is mostly a part of the API implementation.
+ * Value stack handling is a part of the API implementation.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-/* check that there is space for at least one new entry */
-DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
- duk_activation *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
+/* Unwind the topmost catcher of the current activation (caller must check that
+ * both exist) without side effects.
+ */
+DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) {
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- if (thr->callstack_top < thr->callstack_size) {
- return;
- }
-
- old_size = thr->callstack_size;
- new_size = old_size + DUK_CALLSTACK_GROW_STEP;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL); /* caller must check */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->callstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
- }
+ DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)", (void *) cat));
- DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
+ if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
+ duk_hobject *env;
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
+ env = act->lex_env; /* current lex_env of the activation (created for catcher) */
+ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
+ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
+ DUK_HOBJECT_INCREF(thr, act->lex_env);
+ DUK_HOBJECT_DECREF_NORZ(thr, env);
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ /* There is no need to decref anything else than 'env': if 'env'
+ * becomes unreachable, refzero will handle decref'ing its prototype.
+ */
}
- thr->callstack = new_ptr;
- thr->callstack_size = new_size;
- /* note: any entries above the callstack top are garbage and not zeroed */
+ act->cat = cat->parent;
+ duk_hthread_catcher_free(thr, cat);
}
-DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
- duk_size_t new_size;
- duk_activation *p;
+/* Same as above, but caller is certain no catcher-related lexenv may exist. */
+DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) {
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
- return;
- }
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL); /* caller must check */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
- new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->callstack_top);
+ DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)", (void *) cat));
- DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
+ DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat));
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
+ act->cat = cat->parent;
+ duk_hthread_catcher_free(thr, cat);
+}
- /* shrink failure is not fatal */
- p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (p) {
- thr->callstack = p;
- thr->callstack_size = new_size;
- } else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
- }
+DUK_LOCAL
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_NOINLINE
+#endif
+duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) {
+ duk_catcher *cat;
- /* note: any entries above the callstack top are garbage and not zeroed */
+ cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher));
+ DUK_ASSERT(cat != NULL);
+ return cat;
}
-DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
+ duk_catcher *cat;
- DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->callstack_top : (long) -1),
- (long) new_top));
+ DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
+ cat = thr->heap->catcher_free;
+ if (DUK_LIKELY(cat != NULL)) {
+ thr->heap->catcher_free = cat->parent;
+ return cat;
+ }
- /*
- * The loop below must avoid issues with potential callstack
- * reallocations. A resize (and other side effects) may happen
- * e.g. due to finalizer/errhandler calls caused by a refzero or
- * mark-and-sweep. Arbitrary finalizers may run, because when
- * an environment record is refzero'd, it may refer to arbitrary
- * values which also become refzero'd.
- *
- * So, the pointer 'p' is re-looked-up below whenever a side effect
- * might have changed it.
- */
+ return duk__hthread_catcher_alloc_slow(thr);
+}
+#else /* DUK_USE_CACHE_CATCHER */
+DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
+ return duk__hthread_catcher_alloc_slow(thr);
+}
+#endif /* DUK_USE_CACHE_CATCHER */
- idx = thr->callstack_top;
- while (idx > new_top) {
- duk_activation *act;
- duk_hobject *func;
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_hobject *tmp;
+DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(cat != NULL);
+
+#if defined(DUK_USE_CACHE_CATCHER)
+ /* Unconditional caching for now; freed in mark-and-sweep. */
+ cat->parent = thr->heap->catcher_free;
+ thr->heap->catcher_free = cat;
+#else
+ DUK_FREE_CHECKED(thr, (void *) cat);
#endif
-#ifdef DUK_USE_DEBUGGER_SUPPORT
- duk_heap *heap;
+}
+
+DUK_LOCAL
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_NOINLINE
#endif
+duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) {
+ duk_activation *act;
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
+ act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation));
+ DUK_ASSERT(act != NULL);
+ return act;
+}
- act = thr->callstack + idx;
- /* With lightfuncs, act 'func' may be NULL */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
+ duk_activation *act;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- /*
- * Restore 'caller' property for non-strict callee functions.
- */
+ DUK_ASSERT(thr != NULL);
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
- duk_tval *tv_caller;
- duk_tval tv_tmp;
- duk_hobject *h_tmp;
+ act = thr->heap->activation_free;
+ if (DUK_LIKELY(act != NULL)) {
+ thr->heap->activation_free = act->parent;
+ return act;
+ }
- tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
+ return duk__hthread_activation_alloc_slow(thr);
+}
+#else /* DUK_USE_CACHE_ACTIVATION */
+DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
+ return duk__hthread_activation_alloc_slow(thr);
+}
+#endif /* DUK_USE_CACHE_ACTIVATION */
- /* The act->prev_caller should only be set if the entry for 'caller'
- * exists (as it is only set in that case, and the property is not
- * configurable), but handle all the cases anyway.
- */
- if (tv_caller) {
- DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
- if (act->prev_caller) {
- /* Just transfer the refcount from act->prev_caller to tv_caller,
- * so no need for a refcount update. This is the expected case.
- */
- DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
- act->prev_caller = NULL;
- } else {
- DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
- DUK_ASSERT(act->prev_caller == NULL);
- }
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
- } else {
- h_tmp = act->prev_caller;
- if (h_tmp) {
- act->prev_caller = NULL;
- DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */
- }
- }
- act = thr->callstack + idx; /* avoid side effects */
- DUK_ASSERT(act->prev_caller == NULL);
- }
-#endif
+DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(act != NULL);
- /*
- * Unwind debugger state. If we unwind while stepping
- * (either step over or step into), pause execution.
- */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ /* Unconditional caching for now; freed in mark-and-sweep. */
+ act->parent = thr->heap->activation_free;
+ thr->heap->activation_free = act;
+#else
+ DUK_FREE_CHECKED(thr, (void *) act);
+#endif
+}
+/* Internal helper: process the unwind for the topmost activation of a thread,
+ * but leave the duk_activation in place for possible tailcall reuse.
+ */
+DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) {
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- heap = thr->heap;
- if (heap->dbg_step_thread == thr &&
- heap->dbg_step_csindex == idx) {
- /* Pause for all step types: step into, step over, step out.
- * This is the only place explicitly handling a step out.
- */
- DUK_HEAP_SET_PAUSED(heap);
- DUK_ASSERT(heap->dbg_step_thread == NULL);
- }
+ duk_heap *heap;
#endif
+ duk_activation *act;
+ duk_hobject *func;
+ duk_hobject *tmp;
- /*
- * Close environment record(s) if they exist.
- *
- * Only variable environments are closed. If lex_env != var_env, it
- * cannot currently contain any register bound declarations.
- *
- * Only environments created for a NEWENV function are closed. If an
- * environment is created for e.g. an eval call, it must not be closed.
- */
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->callstack_curr != NULL); /* caller must check */
+ DUK_ASSERT(thr->callstack_top > 0);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ /* With lightfuncs, act 'func' may be NULL. */
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
- DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
- goto skip_env_close;
- }
- /* func is NULL for lightfunc */
+ /* With duk_activation records allocated separately, 'act' is a stable
+ * pointer and not affected by side effects.
+ */
- DUK_ASSERT(act->lex_env == act->var_env);
- if (act->var_env != NULL) {
- DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
- (void *) act->var_env, (duk_heaphdr *) act->var_env));
- duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom);
- act = thr->callstack + idx; /* avoid side effect issues */
- }
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+ /*
+ * Restore 'caller' property for non-strict callee functions.
+ */
-#if 0
- if (act->lex_env != NULL) {
- if (act->lex_env == act->var_env) {
- /* common case, already closed, so skip */
- DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env "
- "already closed -> skip closing lex_env"));
- ;
+ func = DUK_ACT_GET_FUNC(act);
+ if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
+ duk_tval *tv_caller;
+ duk_tval tv_tmp;
+ duk_hobject *h_tmp;
+
+ tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
+
+ /* The act->prev_caller should only be set if the entry for 'caller'
+ * exists (as it is only set in that case, and the property is not
+ * configurable), but handle all the cases anyway.
+ */
+
+ if (tv_caller) {
+ DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
+ if (act->prev_caller) {
+ /* Just transfer the refcount from act->prev_caller to tv_caller,
+ * so no need for a refcount update. This is the expected case.
+ */
+ DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
+ act->prev_caller = NULL;
} else {
- DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O",
- (void *) act->lex_env, (duk_heaphdr *) act->lex_env));
- duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom);
- act = thr->callstack + idx; /* avoid side effect issues */
+ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
+ DUK_ASSERT(act->prev_caller == NULL);
+ }
+ DUK_TVAL_DECREF_NORZ(thr, &tv_tmp);
+ } else {
+ h_tmp = act->prev_caller;
+ if (h_tmp) {
+ act->prev_caller = NULL;
+ DUK_HOBJECT_DECREF_NORZ(thr, h_tmp);
}
}
+ DUK_ASSERT(act->prev_caller == NULL);
+ }
#endif
- DUK_ASSERT((act->lex_env == NULL) ||
- ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
-
- DUK_ASSERT((act->var_env == NULL) ||
- ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
+ /*
+ * Unwind debugger state. If we unwind while stepping
+ * (for any step type), pause execution. This is the
+ * only place explicitly handling a step out.
+ */
- skip_env_close:
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ heap = thr->heap;
+ if (heap->dbg_pause_act == thr->callstack_curr) {
+ if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit"));
+ duk_debug_set_paused(heap);
+ } else {
+ DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL"));
+ heap->dbg_pause_act = NULL; /* avoid stale pointers */
+ }
+ DUK_ASSERT(heap->dbg_pause_act == NULL);
+ }
+#endif
- /*
- * Update preventcount
- */
+ /*
+ * Unwind catchers.
+ *
+ * Since there are no references in the catcher structure,
+ * unwinding is quite simple. The only thing we need to
+ * look out for is popping a possible lexical environment
+ * established for an active catch clause.
+ */
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- DUK_ASSERT(thr->callstack_preventcount >= 1);
- thr->callstack_preventcount--;
- }
+ while (act->cat != NULL) {
+ duk_hthread_catcher_unwind_norz(thr, act);
+ }
- /*
- * Reference count updates
- *
- * Note: careful manipulation of refcounts. The top is
- * not updated yet, so all the activations are reachable
- * for mark-and-sweep (which may be triggered by decref).
- * However, the pointers are NULL so this is not an issue.
- */
+ /*
+ * Close environment record(s) if they exist.
+ *
+ * Only variable environments are closed. If lex_env != var_env, it
+ * cannot currently contain any register bound declarations.
+ *
+ * Only environments created for a NEWENV function are closed. If an
+ * environment is created for e.g. an eval call, it must not be closed.
+ */
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = act->var_env;
-#endif
- act->var_env = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
-#endif
+ func = DUK_ACT_GET_FUNC(act);
+ if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
+ DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
+ goto skip_env_close;
+ }
+ /* func is NULL for lightfunc */
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = act->lex_env;
-#endif
- act->lex_env = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
-#endif
+ /* Catch sites are required to clean up their environments
+ * in FINALLY part before propagating, so this should
+ * always hold here.
+ */
+ DUK_ASSERT(act->lex_env == act->var_env);
- /* Note: this may cause a corner case situation where a finalizer
- * may see a currently reachable activation whose 'func' is NULL.
- */
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = DUK_ACT_GET_FUNC(act);
-#endif
- act->func = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
- DUK_UNREF(act);
-#endif
+ /* XXX: Closing the environment record copies values from registers
+ * into the scope object. It's side effect free as such, but may
+ * currently run out of memory which causes an error throw. This is
+ * an actual sandboxing problem for error unwinds, and needs to be
+ * fixed e.g. by preallocating the scope property slots.
+ */
+ if (act->var_env != NULL) {
+ DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
+ (void *) act->var_env, (duk_heaphdr *) act->var_env));
+ duk_js_close_environment_record(thr, act->var_env);
}
- thr->callstack_top = new_top;
+ skip_env_close:
/*
- * We could clear the book-keeping variables for the topmost activation,
- * but don't do so now.
+ * Update preventcount
*/
-#if 0
- if (thr->callstack_top > 0) {
- duk_activation *act = thr->callstack + thr->callstack_top - 1;
- act->idx_retval = 0;
+
+ if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
+ DUK_ASSERT(thr->callstack_preventcount >= 1);
+ thr->callstack_preventcount--;
}
-#endif
- /* Note: any entries above the callstack top are garbage and not zeroed.
- * Also topmost activation idx_retval is garbage (not zeroed), and must
- * be ignored.
+ /*
+ * Reference count updates, using NORZ macros so we don't
+ * need to handle side effects.
+ *
+ * duk_activation pointers like act->var_env are intentionally
+ * left as garbage and not NULLed. Without side effects they
+ * can't be used when the values are dangling/garbage.
*/
-}
-DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
- duk_catcher *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env);
+ tmp = DUK_ACT_GET_FUNC(act);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
+ DUK_UNREF(tmp);
+}
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
+/* Unwind topmost duk_activation of a thread, caller must ensure that an
+ * activation exists. The call is side effect free, except that scope
+ * closure may currently throw an out-of-memory error.
+ */
+DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) {
+ duk_activation *act;
- if (thr->catchstack_top < thr->catchstack_size) {
- return;
- }
+ duk__activation_unwind_nofree_norz(thr);
- old_size = thr->catchstack_size;
- new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_top > 0);
+ act = thr->callstack_curr;
+ thr->callstack_curr = act->parent;
+ thr->callstack_top--;
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->catchstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
- }
+ /* Ideally we'd restore value stack reserve here to caller's value.
+ * This doesn't work for current unwind call sites however, because
+ * the current (unwound) value stack top may be above the reserve.
+ * Thus value stack reserve is restored by the call sites.
+ */
- DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
+ /* XXX: inline for performance builds? */
+ duk_hthread_activation_free(thr, act);
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
+ /* We could clear the book-keeping variables like retval_byteoff for
+ * the topmost activation, but don't do so now as it's not necessary.
*/
+}
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- thr->catchstack = new_ptr;
- thr->catchstack_size = new_size;
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
+DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) {
+ duk__activation_unwind_nofree_norz(thr);
}
-DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
- duk_size_t new_size;
- duk_catcher *p;
+/* Get duk_activation for given callstack level or NULL if level is invalid
+ * or deeper than the call stack. Level -1 refers to current activation, -2
+ * to its caller, etc. Starting from Duktape 2.2 finding the activation is
+ * a linked list scan which gets more expensive the deeper the lookup is.
+ */
+DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) {
+ duk_activation *act;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
+ if (level >= 0) {
+ return NULL;
+ }
+ act = thr->callstack_curr;
+ for (;;) {
+ if (act == NULL) {
+ return act;
+ }
+ if (level == -1) {
+ return act;
+ }
+ level++;
+ act = act->parent;
+ }
+ /* never here */
+}
- if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
+#if defined(DUK_USE_FINALIZER_TORTURE)
+DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
+ duk_size_t alloc_size;
+ duk_tval *new_ptr;
+ duk_ptrdiff_t alloc_end_off;
+ duk_ptrdiff_t end_off;
+ duk_ptrdiff_t bottom_off;
+ duk_ptrdiff_t top_off;
+
+ if (thr->valstack == NULL) {
+ DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL"));
return;
}
- new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->catchstack_top);
-
- DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
-
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
+ alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
+ end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
+ top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack);
+ alloc_size = (duk_size_t) alloc_end_off;
+ if (alloc_size == 0) {
+ DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero"));
+ return;
+ }
- /* shrink failure is not fatal */
- p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (p) {
- thr->catchstack = p;
- thr->catchstack_size = new_size;
+ /* Use DUK_ALLOC_RAW() to avoid side effects. */
+ new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size);
+ if (new_ptr != NULL) {
+ DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size);
+ DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size);
+ DUK_FREE_CHECKED(thr, (void *) thr->valstack);
+ thr->valstack = new_ptr;
+ thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off);
+ thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off);
+ thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off);
+ thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off);
} else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
+ DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore"));
}
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
}
+#endif /* DUK_USE_FINALIZER_TORTURE */
+/*
+ * Shared helpers for arithmetic operations
+ */
-DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
+/* #include duk_internal.h -> already included */
- DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->catchstack_top : (long) -1),
- (long) new_top));
+/* Ecmascript modulus ('%') does not match IEEE 754 "remainder" operation
+ * (implemented by remainder() in C99) but does seem to match ANSI C fmod().
+ * Compare E5 Section 11.5.3 and "man fmod".
+ */
+DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
+#if defined(DUK_USE_POW_WORKAROUNDS)
+ /* Specific fixes to common fmod() implementation issues:
+ * - test-bug-mingw-math-issues.js
+ */
+ if (DUK_ISINF(d2)) {
+ if (DUK_ISINF(d1)) {
+ return DUK_DOUBLE_NAN;
+ } else {
+ return d1;
+ }
+ } else if (d1 == 0.0) {
+ /* d1 +/-0 is returned as is (preserving sign) except when
+ * d2 is zero or NaN.
+ */
+ if (d2 == 0.0 || DUK_ISNAN(d2)) {
+ return DUK_DOUBLE_NAN;
+ } else {
+ return d1;
+ }
+ }
+#else
+ /* Some ISO C assumptions. */
+ DUK_ASSERT(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY) == 1.0);
+ DUK_ASSERT(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY) == -1.0);
+ DUK_ASSERT(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY) == 1.0);
+ DUK_ASSERT(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY) == -1.0);
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
+ DUK_ASSERT(DUK_FMOD(0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0);
+ DUK_ASSERT(DUK_FMOD(-0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0);
+ DUK_ASSERT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
+ DUK_ASSERT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0);
+ DUK_ASSERT(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
+ DUK_ASSERT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0);
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN)));
+ DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN)));
+#endif
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
+ return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
+}
- /*
- * Since there are no references in the catcher structure,
- * unwinding is quite simple. The only thing we need to
- * look out for is popping a possible lexical environment
- * established for an active catch clause.
+/* Shared helper for Math.pow() and exponentiation operator. */
+DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
+ /* The ANSI C pow() semantics differ from Ecmascript.
+ *
+ * E.g. when x==1 and y is +/- infinite, the Ecmascript required
+ * result is NaN, while at least Linux pow() returns 1.
*/
- idx = thr->catchstack_top;
- while (idx > new_top) {
- duk_catcher *p;
- duk_activation *act;
- duk_hobject *env;
-
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
+ duk_small_int_t cx, cy, sx;
- p = thr->catchstack + idx;
+ DUK_UNREF(cx);
+ DUK_UNREF(sx);
+ cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
- if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
- DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
- (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
+ if (cy == DUK_FP_NAN) {
+ goto ret_nan;
+ }
+ if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
+ goto ret_nan;
+ }
- /* XXX: Here we have a nasty dependency: the need to manipulate
- * the callstack means that catchstack must always be unwound by
- * the caller before unwinding the callstack. This should be fixed
- * later.
+#if defined(DUK_USE_POW_WORKAROUNDS)
+ /* Specific fixes to common pow() implementation issues:
+ * - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least)
+ * - test-bug-mingw-math-issues.js
+ */
+ cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
+ if (cx == DUK_FP_ZERO && y < 0.0) {
+ sx = (duk_small_int_t) DUK_SIGNBIT(x);
+ if (sx == 0) {
+ /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
+ * returns -Infinity instead when y is <0 and finite. The
+ * if-clause also catches y == -Infinity (which works even
+ * without the fix).
*/
-
- /* Note that multiple catchstack entries may refer to the same
- * callstack entry.
+ return DUK_DOUBLE_INFINITY;
+ } else {
+ /* Math.pow(-0,y) where y<0 should be:
+ * - -Infinity if y<0 and an odd integer
+ * - Infinity if y<0 but not an odd integer
+ * NetBSD pow() returns -Infinity for all finite y<0. The
+ * if-clause also catches y == -Infinity (which works even
+ * without the fix).
*/
- act = thr->callstack + p->callstack_index;
- DUK_ASSERT(act >= thr->callstack);
- DUK_ASSERT(act < thr->callstack + thr->callstack_top);
-
- DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
- (long) idx, (long) p->callstack_index,
- (duk_heaphdr *) act->lex_env));
- env = act->lex_env; /* current lex_env of the activation (created for catcher) */
- DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
- DUK_HOBJECT_DECREF(thr, env);
-
- /* There is no need to decref anything else than 'env': if 'env'
- * becomes unreachable, refzero will handle decref'ing its prototype.
+ /* fmod() return value has same sign as input (negative) so
+ * the result here will be in the range ]-2,0], -1 indicates
+ * odd. If x is -Infinity, NaN is returned and the odd check
+ * always concludes "not odd" which results in desired outcome.
+ */
+ double tmp = DUK_FMOD(y, 2);
+ if (tmp == -1.0) {
+ return -DUK_DOUBLE_INFINITY;
+ } else {
+ /* Not odd, or y == -Infinity */
+ return DUK_DOUBLE_INFINITY;
+ }
+ }
+ } else if (cx == DUK_FP_NAN) {
+ if (y == 0.0) {
+ /* NaN ** +/- 0 should always be 1, but is NaN on
+ * at least some Cygwin/MinGW versions.
*/
+ return 1.0;
}
}
+#else
+ /* Some ISO C assumptions. */
+ DUK_ASSERT(DUK_POW(DUK_DOUBLE_NAN, 0.0) == 1.0);
+ DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0);
+ DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0);
+ DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0);
+#endif
- thr->catchstack_top = new_top;
+ return DUK_POW(x, y);
- /* note: any entries above the catchstack top are garbage and not zeroed */
+ ret_nan:
+ return DUK_DOUBLE_NAN;
}
-#line 1 "duk_js_call.c"
/*
* Call handling.
*
- * Main functions are:
+ * duk_handle_call_unprotected():
*
- * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
- * Duktape/C function
- * - duk_handle_call_protected(): protected call to Ecmascript or
- * Duktape/C function
- * - duk_handle_safe_call(): make a protected C call within current
- * activation
- * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
- * (not always possible), including tail calls and coroutine resume
+ * - Unprotected call to Ecmascript or Duktape/C function, from native
+ * code or bytecode executor.
*
- * See 'execution.rst'.
+ * - Also handles Ecma-to-Ecma calls which reuses a currently running
+ * executor instance to avoid native recursion. Call setup is done
+ * normally, but just before calling the bytecode executor a special
+ * return code is used to indicate that a calling executor is reused.
+ *
+ * - Also handles tailcalls, i.e. reuse of current duk_activation.
+ *
+ * - Also handles setup for initial Duktape.Thread.resume().
+ *
+ * duk_handle_safe_call():
+ *
+ * - Protected C call within current activation.
*
- * Note: setjmp() and local variables have a nasty interaction,
- * see execution.rst; non-volatile locals modified after setjmp()
- * call are not guaranteed to keep their value.
+ * setjmp() and local variables have a nasty interaction, see execution.rst;
+ * non-volatile locals modified after setjmp() call are not guaranteed to
+ * keep their value and can cause compiler or compiler version specific
+ * difficult to replicate issues.
+ *
+ * See 'execution.rst'.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/* XXX: heap->error_not_allowed for success path too? */
/*
- * Forward declarations.
+ * Limit check helpers.
*/
-DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags,
- duk_idx_t idx_func);
-DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_valstack_end,
- duk_size_t entry_catchstack_top,
- duk_size_t entry_callstack_top,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc,
- duk_idx_t idx_func,
- duk_jmpbuf *old_jmpbuf_ptr);
-DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
- duk_safe_call_function func,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top);
-DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top,
- duk_jmpbuf *old_jmpbuf_ptr);
-DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc);
+/* Allow headroom for calls during error augmentation (see GH-191).
+ * We allow space for 10 additional recursions, with one extra
+ * for, e.g. a print() call at the deepest level, and an extra
+ * +1 for protected call wrapping.
+ */
+#define DUK__AUGMENT_CALL_RELAX_COUNT (10 + 2)
+
+DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) {
+ /* When augmenting an error, the effective limit is a bit higher.
+ * Check for it only if the fast path check fails.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (thr->heap->augmenting_error) {
+ if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) {
+ DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit"));
+ return;
+ }
+ }
+#endif
+
+ DUK_D(DUK_DPRINT("call prevented because C recursion limit reached"));
+ DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) {
+ DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
+ DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
+
+ /* This check is forcibly inlined because it's very cheap and almost
+ * always passes. The slow path is forcibly noinline.
+ */
+ if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) {
+ return;
+ }
+
+ duk__call_c_recursion_limit_check_slowpath(thr);
+}
+
+DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) {
+ /* When augmenting an error, the effective limit is a bit higher.
+ * Check for it only if the fast path check fails.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (thr->heap->augmenting_error) {
+ if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) {
+ DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit"));
+ return;
+ }
+ }
+#endif
+
+ /* XXX: error message is a bit misleading: we reached a recursion
+ * limit which is also essentially the same as a C callstack limit
+ * (except perhaps with some relaxed threading assumptions).
+ */
+ DUK_D(DUK_DPRINT("call prevented because call stack limit reached"));
+ DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) {
+ /* This check is forcibly inlined because it's very cheap and almost
+ * always passes. The slow path is forcibly noinline.
+ */
+ if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) {
+ return;
+ }
+
+ duk__call_callstack_limit_check_slowpath(thr);
+}
/*
* Interrupt counter fixup (for development only).
@@ -54924,9 +61117,7 @@ DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_th
DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
duk_hobject *func,
duk_hobject *varenv,
- duk_idx_t idx_argbase, /* idx of first argument on stack */
- duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
- duk_context *ctx = (duk_context *) thr;
+ duk_idx_t idx_args) {
duk_hobject *arg; /* 'arguments' */
duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
duk_idx_t i_arg;
@@ -54936,36 +61127,41 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
duk_idx_t i_argbase;
duk_idx_t n_formals;
duk_idx_t idx;
+ duk_idx_t num_stack_args;
duk_bool_t need_map;
- DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
- "idx_argbase=%ld, num_stack_args=%ld",
- (duk_heaphdr *) func, (duk_heaphdr *) varenv,
- (long) idx_argbase, (long) num_stack_args));
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
DUK_ASSERT(varenv != NULL);
- DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
- DUK_ASSERT(num_stack_args >= 0);
+
+ /* [ ... func this arg1(@idx_args) ... argN envobj ]
+ * [ arg1(@idx_args) ... argN envobj ] (for tailcalls)
+ */
need_map = 0;
- i_argbase = idx_argbase;
+ i_argbase = idx_args;
+ num_stack_args = duk_get_top(thr) - i_argbase - 1;
DUK_ASSERT(i_argbase >= 0);
+ DUK_ASSERT(num_stack_args >= 0);
- duk_push_hobject(ctx, func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FORMALS);
- formals = duk_get_hobject(ctx, -1);
- n_formals = 0;
+ duk_push_hobject(thr, func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS);
+ formals = duk_get_hobject(thr, -1);
if (formals) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
- n_formals = (duk_idx_t) duk_require_int(ctx, -1);
- duk_pop(ctx);
+ n_formals = (duk_idx_t) duk_get_length(thr, -1);
+ } else {
+ /* This shouldn't happen without tampering of internal
+ * properties: if a function accesses 'arguments', _Formals
+ * is kept. Check for the case anyway in case internal
+ * properties have been modified manually.
+ */
+ DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0"));
+ n_formals = 0;
}
- duk_remove(ctx, -2); /* leave formals on stack for later use */
- i_formals = duk_require_top_index(ctx);
+ duk_remove_m2(thr); /* leave formals on stack for later use */
+ i_formals = duk_require_top_index(thr);
DUK_ASSERT(n_formals >= 0);
DUK_ASSERT(formals != NULL || n_formals == 0);
@@ -54983,26 +61179,26 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
* - 'mappedNames' object: temporary value used during construction
*/
- i_arg = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_ARRAY_PART |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
- DUK_BIDX_OBJECT_PROTOTYPE);
- DUK_ASSERT(i_arg >= 0);
- arg = duk_require_hobject(ctx, -1);
+ arg = duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_ARRAY_PART |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
+ DUK_BIDX_OBJECT_PROTOTYPE);
DUK_ASSERT(arg != NULL);
-
- i_map = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- -1); /* no prototype */
- DUK_ASSERT(i_map >= 0);
-
- i_mappednames = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- -1); /* no prototype */
- DUK_ASSERT(i_mappednames >= 0);
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
+ -1); /* no prototype */
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
+ -1); /* no prototype */
+ i_arg = duk_get_top(thr) - 3;
+ i_map = i_arg + 1;
+ i_mappednames = i_arg + 2;
/* [ ... formals arguments map mappedNames ] */
@@ -55010,19 +61206,19 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
"mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
- (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
+ (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
+ (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
+ (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
/*
* Init arguments properties, map, etc.
*/
- duk_push_int(ctx, num_stack_args);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
+ duk_push_int(thr, num_stack_args);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
/*
- * Init argument related properties
+ * Init argument related properties.
*/
/* step 11 */
@@ -55032,8 +61228,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
(long) idx, (long) i_argbase, (long) (i_argbase + idx)));
DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
- duk_dup(ctx, i_argbase + idx);
- duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
+ duk_dup(thr, i_argbase + idx);
+ duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx);
DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
/* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
@@ -55043,12 +61239,12 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
(long) idx, (long) n_formals));
- duk_get_prop_index(ctx, i_formals, idx);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx);
+ DUK_ASSERT(duk_is_string(thr, -1));
- duk_dup(ctx, -1); /* [ ... name name ] */
+ duk_dup_top(thr); /* [ ... name name ] */
- if (!duk_has_prop(ctx, i_mappednames)) {
+ if (!duk_has_prop(thr, i_mappednames)) {
/* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
* differs from the reference model
*/
@@ -55058,24 +61254,23 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
need_map = 1;
DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
- (const char *) duk_get_string(ctx, -1),
+ (const char *) duk_get_string(thr, -1),
(long) idx));
- duk_dup(ctx, -1); /* name */
- duk_push_uint(ctx, (duk_uint_t) idx); /* index */
- duk_to_string(ctx, -1);
- duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
+ duk_dup_top(thr); /* name */
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx); /* index */
+ duk_xdef_prop_wec(thr, i_mappednames); /* out of spec, must be configurable */
DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
(long) idx,
- duk_get_string(ctx, -1)));
- duk_dup(ctx, -1); /* name */
- duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
+ duk_get_string(thr, -1)));
+ duk_dup_top(thr); /* name */
+ duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
} else {
/* duk_has_prop() popped the second 'name' */
}
/* [ ... name ] */
- duk_pop(ctx); /* pop 'name' */
+ duk_pop(thr); /* pop 'name' */
}
idx--;
@@ -55090,8 +61285,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
/* should never happen for a strict callee */
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
- duk_dup(ctx, i_map);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
+ duk_dup(thr, i_map);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
/* The variable environment for magic variable bindings needs to be
* given by the caller and recorded in the arguments object.
@@ -55102,8 +61297,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
* an explicit (internal) callee property is not needed.
*/
- duk_push_hobject(ctx, varenv);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
+ duk_push_hobject(thr, varenv);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
}
/* steps 13-14 */
@@ -55123,12 +61318,12 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE);
} else {
DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
- duk_push_hobject(ctx, func);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_hobject(thr, func);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
}
/* set exotic behavior only after we're done */
@@ -55156,179 +61351,560 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
"mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
- (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
+ (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
+ (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
+ (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
- /* [ args(n) [crud] formals arguments map mappednames ] */
+ /* [ args(n) envobj formals arguments map mappednames ] */
- duk_pop_2(ctx);
- duk_remove(ctx, -2);
+ duk_pop_2(thr);
+ duk_remove_m2(thr);
- /* [ args [crud] arguments ] */
+ /* [ args(n) envobj arguments ] */
}
/* Helper for creating the arguments object and adding it to the env record
- * on top of the value stack. This helper has a very strict dependency on
- * the shape of the input stack.
+ * on top of the value stack.
*/
DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
duk_hobject *func,
duk_hobject *env,
- duk_idx_t num_stack_args) {
- duk_context *ctx = (duk_context *) thr;
-
+ duk_idx_t idx_args) {
DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
DUK_ASSERT(env != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
/* [ ... arg1 ... argN envobj ] */
duk__create_arguments_object(thr,
func,
env,
- duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
- num_stack_args);
+ idx_args);
/* [ ... arg1 ... argN envobj argobj ] */
- duk_xdef_prop_stridx(ctx,
- -2,
- DUK_STRIDX_LC_ARGUMENTS,
- DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
- DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
+ duk_xdef_prop_stridx_short(thr,
+ -2,
+ DUK_STRIDX_LC_ARGUMENTS,
+ DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
+ DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
/* [ ... arg1 ... argN envobj ] */
}
/*
- * Helper for handling a "bound function" chain when a call is being made.
+ * Helpers for constructor call handling.
+ *
+ * There are two [[Construct]] operations in the specification:
+ *
+ * - E5 Section 13.2.2: for Function objects
+ * - E5 Section 15.3.4.5.2: for "bound" Function objects
+ *
+ * The chain of bound functions is resolved in Section 15.3.4.5.2,
+ * with arguments "piling up" until the [[Construct]] internal
+ * method is called on the final, actual Function object. Note
+ * that the "prototype" property is looked up *only* from the
+ * final object, *before* calling the constructor.
+ *
+ * Since Duktape 2.2 bound functions are represented with the
+ * duk_hboundfunc internal type, and bound function chains are
+ * collapsed when a bound function is created. As a result, the
+ * direct target of a duk_hboundfunc is always non-bound and the
+ * this/argument lists have been resolved.
+ *
+ * When constructing new Array instances, an unnecessary object is
+ * created and discarded now: the standard [[Construct]] creates an
+ * object, and calls the Array constructor. The Array constructor
+ * returns an Array instance, which is used as the result value for
+ * the "new" operation; the object created before the Array constructor
+ * call is discarded.
+ *
+ * This would be easy to fix, e.g. by knowing that the Array constructor
+ * will always create a replacement object and skip creating the fallback
+ * object in that case.
+ */
+
+/* Update default instance prototype for constructor call. */
+DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) {
+ duk_hobject *proto;
+ duk_hobject *fallback;
+
+ DUK_ASSERT(duk_is_constructable(thr, idx_func));
+
+ duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE);
+ proto = duk_get_hobject(thr, -1);
+ if (proto == NULL) {
+ DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
+ "-> leave standard Object prototype as fallback prototype"));
+ } else {
+ DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
+ "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
+ /* Original fallback (default instance) is untouched when
+ * resolving bound functions etc.
+ */
+ fallback = duk_known_hobject(thr, idx_func + 1);
+ DUK_ASSERT(fallback != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
+ }
+ duk_pop(thr);
+}
+
+/* Postprocess: return value special handling, error augmentation. */
+DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) {
+ /* Use either fallback (default instance) or retval depending
+ * on retval type. Needs to be called before unwind because
+ * the default instance is read from the current (immutable)
+ * 'this' binding.
+ *
+ * For Proxy 'construct' calls the return value must be an
+ * Object (we accept object-like values like buffers and
+ * lightfuncs too). If not, TypeError.
+ */
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_BUFFER |
+ DUK_TYPE_MASK_LIGHTFUNC)) {
+ DUK_DDD(DUK_DDDPRINT("replacement value"));
+ } else {
+ if (DUK_UNLIKELY(proxy_invariant != 0U)) {
+ /* Proxy 'construct' return value invariant violated. */
+ DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
+ }
+ /* XXX: direct value stack access */
+ duk_pop(thr);
+ duk_push_this(thr);
+ }
+
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ /* Augment created errors upon creation, not when they are thrown or
+ * rethrown. __FILE__ and __LINE__ are not desirable here; the call
+ * stack reflects the caller which is correct. Skip topmost, unwound
+ * activation when creating a traceback. If thr->ptr_curr_pc was !=
+ * NULL we'd need to sync the current PC so that the traceback comes
+ * out right; however it is always synced here so just assert for it.
+ */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE |
+ DUK_AUGMENT_FLAG_SKIP_ONE);
+#endif
+}
+
+/*
+ * Helper for handling a bound function when a call is being made.
*
- * Follows the bound function chain until a non-bound function is found.
- * Prepends the bound arguments to the value stack (at idx_func + 2),
- * updating 'num_stack_args' in the process. The 'this' binding is also
- * updated if necessary (at idx_func + 1). Note that for constructor calls
- * the 'this' binding is never updated by [[BoundThis]].
+ * Assumes that bound function chains have been "collapsed" so that either
+ * the target is non-bound or there is one bound function that points to a
+ * nonbound target.
*
- * XXX: bound function chains could be collapsed at bound function creation
- * time so that each bound function would point directly to a non-bound
- * function. This would make call time handling much easier.
+ * Prepends the bound arguments to the value stack (at idx_func + 2).
+ * The 'this' binding is also updated if necessary (at idx_func + 1).
+ * Note that for constructor calls the 'this' binding is never updated by
+ * [[BoundThis]].
*/
DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
duk_idx_t idx_func,
- duk_idx_t *p_num_stack_args, /* may be changed by call */
duk_bool_t is_constructor_call) {
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t num_stack_args;
duk_tval *tv_func;
duk_hobject *func;
- duk_uint_t sanity;
+ duk_idx_t len;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(p_num_stack_args != NULL);
/* On entry, item at idx_func is a bound, non-lightweight function,
* but we don't rely on that below.
*/
- num_stack_args = *p_num_stack_args;
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- duk_idx_t i, len;
-
- tv_func = duk_require_tval(ctx, idx_func);
- DUK_ASSERT(tv_func != NULL);
+ tv_func = duk_require_tval(thr, idx_func);
+ DUK_ASSERT(tv_func != NULL);
- if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
- /* Lightweight function: never bound, so terminate. */
- break;
- } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
- func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_HAS_BOUND(func)) {
- /* Normal non-bound function. */
- break;
- }
- } else {
- /* Function.prototype.bind() should never let this happen,
- * ugly error message is enough.
- */
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
+ if (DUK_TVAL_IS_OBJECT(tv_func)) {
+ func = DUK_TVAL_GET_OBJECT(tv_func);
- /* XXX: this could be more compact by accessing the internal properties
- * directly as own properties (they cannot be inherited, and are not
- * externally visible).
- */
+ /* XXX: separate helper function, out of fast path? */
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
+ duk_hboundfunc *h_bound;
+ duk_tval *tv_args;
+ duk_tval *tv_gap;
- DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
- (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
+ h_bound = (duk_hboundfunc *) func;
+ tv_args = h_bound->args;
+ len = h_bound->nargs;
+ DUK_ASSERT(len == 0 || tv_args != NULL);
- /* [ ... func this arg1 ... argN ] */
+ DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T",
+ (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func));
- if (is_constructor_call) {
- /* See: tests/ecmascript/test-spec-bound-constructor.js */
- DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
- } else {
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
- duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
- }
+ /* [ ... func this arg1 ... argN ] */
- /* [ ... func this arg1 ... argN ] */
+ if (is_constructor_call) {
+ /* See: tests/ecmascript/test-spec-bound-constructor.js */
+ DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
+ } else {
+ /* XXX: duk_replace_tval */
+ duk_push_tval(thr, &h_bound->this_binding);
+ duk_replace(thr, idx_func + 1); /* idx_this = idx_func + 1 */
+ }
- /* XXX: duk_get_length? */
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
- len = (duk_idx_t) duk_require_int(ctx, -1);
- duk_pop(ctx);
- for (i = 0; i < len; i++) {
- /* XXX: very slow - better to bulk allocate a gap, and copy
- * from args_array directly (we know it has a compact array
- * part, etc).
- */
+ /* [ ... func this arg1 ... argN ] */
- /* [ ... func this <some bound args> arg1 ... argN _Args ] */
- duk_get_prop_index(ctx, -1, i);
- duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
- }
- num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
- duk_pop(ctx);
+ duk_require_stack(thr, len);
- /* [ ... func this <bound args> arg1 ... argN ] */
+ tv_gap = duk_reserve_gap(thr, idx_func + 2, len);
+ duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len);
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
- duk_replace(ctx, idx_func); /* replace in stack */
+ /* [ ... func this <bound args> arg1 ... argN ] */
- DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
- (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
- } while (--sanity > 0);
+ duk_push_tval(thr, &h_bound->target);
+ duk_replace(thr, idx_func); /* replace in stack */
- if (sanity == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
+ DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T",
+ (long) idx_func, duk_get_tval(thr, idx_func)));
+ }
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ /* Lightweight function: never bound, so terminate. */
+ ;
+ } else {
+ /* Shouldn't happen, so ugly error is enough. */
+ DUK_ERROR_INTERNAL(thr);
}
- DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(thr, idx_func)));
#if defined(DUK_USE_ASSERTIONS)
- tv_func = duk_require_tval(ctx, idx_func);
+ tv_func = duk_require_tval(thr, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
if (DUK_TVAL_IS_OBJECT(tv_func)) {
func = DUK_TVAL_GET_OBJECT(tv_func);
DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) ||
+ DUK_HOBJECT_HAS_NATFUNC(func));
}
#endif
+}
+
+/*
+ * Helper for inline handling of .call(), .apply(), and .construct().
+ */
+
+DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hobject *func, duk_small_uint_t *call_flags, duk_bool_t first) {
+#if defined(DUK_USE_ASSERTIONS)
+ duk_c_function natfunc;
+#endif
+ duk_tval *tv_args;
+
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0); /* Caller. */
+
+#if defined(DUK_USE_ASSERTIONS)
+ natfunc = ((duk_hnatfunc *) func)->func;
+ DUK_ASSERT(natfunc != NULL);
+#endif
+
+ /* On every round of function resolution at least target function and
+ * 'this' binding are set. We can assume that here, and must guarantee
+ * it on exit. Value stack reserve is extended for bound function and
+ * .apply() unpacking so we don't need to extend it here when we need a
+ * few slots.
+ */
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ /* Handle native 'eval' specially. A direct eval check is only made
+ * for the first resolution attempt; e.g. a bound eval call is -not-
+ * a direct eval call.
+ */
+ if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) {
+ /* For now no special handling except for direct eval
+ * detection.
+ */
+ DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval);
+ if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) {
+ *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL;
+ }
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 1; /* stop resolving */
+ }
+
+ /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL
+ * flag; their magic value is used for switch-case.
+ *
+ * NOTE: duk_unpack_array_like() reserves value stack space
+ * for the result values (unlike most other value stack calls).
+ */
+ switch (((duk_hnatfunc *) func)->magic) {
+ case 0: { /* 0=Function.prototype.call() */
+ /* Value stack:
+ * idx_func + 0: Function.prototype.call() [removed]
+ * idx_func + 1: this binding for .call (target function)
+ * idx_func + 2: 1st argument to .call, desired 'this' binding
+ * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target
+ * ...
+ *
+ * Remove idx_func + 0 to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_function_prototype_call);
+ duk_remove_unsafe(thr, idx_func);
+ tv_args = thr->valstack_bottom + idx_func + 2;
+ if (thr->valstack_top < tv_args) {
+ DUK_ASSERT(tv_args <= thr->valstack_end);
+ thr->valstack_top = tv_args; /* at least target function and 'this' binding present */
+ }
+ break;
+ }
+ case 1: { /* 1=Function.prototype.apply() */
+ /* Value stack:
+ * idx_func + 0: Function.prototype.apply() [removed]
+ * idx_func + 1: this binding for .apply (target function)
+ * idx_func + 2: 1st argument to .apply, desired 'this' binding
+ * idx_func + 3: 2nd argument to .apply, argArray
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and unpack the argArray to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_function_prototype_apply);
+ duk_remove_unsafe(thr, idx_func);
+ goto apply_shared;
+ }
+#if defined(DUK_USE_REFLECT_BUILTIN)
+ case 2: { /* 2=Reflect.apply() */
+ /* Value stack:
+ * idx_func + 0: Reflect.apply() [removed]
+ * idx_func + 1: this binding for .apply (ignored, usually Reflect) [removed]
+ * idx_func + 2: 1st argument to .apply, target function
+ * idx_func + 3: 2nd argument to .apply, desired 'this' binding
+ * idx_func + 4: 3rd argument to .apply, argArray
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_reflect_apply);
+ duk_remove_n_unsafe(thr, idx_func, 2);
+ goto apply_shared;
+ }
+ case 3: { /* 3=Reflect.construct() */
+ /* Value stack:
+ * idx_func + 0: Reflect.construct() [removed]
+ * idx_func + 1: this binding for .construct (ignored, usually Reflect) [removed]
+ * idx_func + 2: 1st argument to .construct, target function
+ * idx_func + 3: 2nd argument to .construct, argArray
+ * idx_func + 4: 3rd argument to .construct, newTarget
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and idx_func + 1, unpack the argArray,
+ * and insert default instance (prototype not yet updated), to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding (default instance)
+ * idx_func + 2: constructor call arguments
+ * ...
+ *
+ * Call flags must be updated to reflect the fact that we're
+ * now dealing with a constructor call, and e.g. the 'this'
+ * binding cannot be overwritten if the target is bound.
+ *
+ * newTarget is checked but not yet passed onwards.
+ */
+
+ duk_idx_t top;
+
+ DUK_ASSERT(natfunc == duk_bi_reflect_construct);
+ *call_flags |= DUK_CALL_FLAG_CONSTRUCT;
+ duk_remove_n_unsafe(thr, idx_func, 2);
+ top = duk_get_top(thr);
+ if (!duk_is_constructable(thr, idx_func)) {
+ /* Target constructability must be checked before
+ * unpacking argArray (which may cause side effects).
+ * Just return; caller will throw the error.
+ */
+ duk_set_top_unsafe(thr, idx_func + 2); /* satisfy asserts */
+ break;
+ }
+ duk_push_object(thr);
+ duk_insert(thr, idx_func + 1); /* default instance */
+
+ /* [ ... func default_instance argArray newTarget? ] */
+
+ top = duk_get_top(thr);
+ if (top < idx_func + 3) {
+ /* argArray is a mandatory argument for Reflect.construct(). */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ if (top > idx_func + 3) {
+ if (!duk_strict_equals(thr, idx_func, idx_func + 3)) {
+ /* XXX: [[Construct]] newTarget currently unsupported */
+ DUK_ERROR_UNSUPPORTED(thr);
+ }
+ duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
+ }
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 3);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
+ (void) duk_unpack_array_like(thr, idx_func + 2); /* XXX: should also remove target to be symmetric with duk_pack()? */
+ duk_remove(thr, idx_func + 2);
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ break;
+ }
+#endif /* DUK_USE_REFLECT_BUILTIN */
+ default: {
+ DUK_ASSERT(0);
+ DUK_UNREACHABLE();
+ }
+ }
+
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 0; /* keep resolving */
+
+ apply_shared:
+ tv_args = thr->valstack_bottom + idx_func + 2;
+ if (thr->valstack_top <= tv_args) {
+ DUK_ASSERT(tv_args <= thr->valstack_end);
+ thr->valstack_top = tv_args; /* at least target func and 'this' binding present */
+ /* No need to check for argArray. */
+ } else {
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 3); /* idx_func + 2 covered above */
+ if (thr->valstack_top > tv_args + 1) {
+ duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
+ }
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
+ if (!duk_is_callable(thr, idx_func)) {
+ /* Avoid unpack side effects if the target isn't callable.
+ * Calling code will throw the actual error.
+ */
+ } else {
+ (void) duk_unpack_array_like(thr, idx_func + 2);
+ duk_remove(thr, idx_func + 2);
+ }
+ }
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 0; /* keep resolving */
+}
+
+/*
+ * Helper for Proxy handling.
+ */
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_LOCAL void duk__handle_proxy_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hproxy *h_proxy, duk_small_uint_t *call_flags) {
+ duk_bool_t rc;
+
+ /* Value stack:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: this binding for call
+ * idx_func + 2: 1st argument for call
+ * idx_func + 3: 2nd argument for call
+ * ...
+ *
+ * If Proxy doesn't have a trap for the call ('apply' or 'construct'),
+ * replace Proxy object with target object.
+ *
+ * If we're dealing with a normal call and the Proxy has an 'apply'
+ * trap, manipulate value stack to:
+ *
+ * idx_func + 0: trap
+ * idx_func + 1: Proxy's handler
+ * idx_func + 2: Proxy's target
+ * idx_func + 3: this binding for call (from idx_func + 1)
+ * idx_func + 4: call arguments packed to an array
+ *
+ * If we're dealing with a constructor call and the Proxy has a
+ * 'construct' trap, manipulate value stack to:
+ *
+ * idx_func + 0: trap
+ * idx_func + 1: Proxy's handler
+ * idx_func + 2: Proxy's target
+ * idx_func + 3: call arguments packed to an array
+ * idx_func + 4: newTarget == Proxy object here
+ *
+ * As we don't yet have proper newTarget support, the newTarget at
+ * idx_func + 3 is just the original constructor being called, i.e.
+ * the Proxy object (not the target). Note that the default instance
+ * (original 'this' binding) is dropped and ignored.
+ */
+
+ duk_push_hobject(thr, h_proxy->handler);
+ rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY);
+ if (rc == 0) {
+ /* Not found, continue to target. If this is a construct
+ * call, update default instance prototype using the Proxy,
+ * not the target.
+ */
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
+ *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
+ duk__update_default_instance_proto(thr, idx_func);
+ }
+ }
+ duk_pop_2(thr);
+ duk_push_hobject(thr, h_proxy->target);
+ duk_replace(thr, idx_func);
+ return;
+ }
+
+ /* Here we must be careful not to replace idx_func while
+ * h_proxy is still needed, otherwise h_proxy may become
+ * dangling. This could be improved e.g. using a
+ * duk_pack_slice() with a freeform slice.
+ */
+
+ /* Here:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: this binding for call
+ * idx_func + 2: 1st argument for call
+ * idx_func + 3: 2nd argument for call
+ * ...
+ * idx_func + N: handler
+ * idx_func + N + 1: trap
+ */
+
+ duk_insert(thr, idx_func + 1);
+ duk_insert(thr, idx_func + 2);
+ duk_push_hobject(thr, h_proxy->target);
+ duk_insert(thr, idx_func + 3);
+ duk_pack(thr, duk_get_top(thr) - (idx_func + 5));
+
+ /* Here:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: trap
+ * idx_func + 2: Proxy's handler
+ * idx_func + 3: Proxy's target
+ * idx_func + 4: this binding for call
+ * idx_func + 5: arguments array
+ */
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 6);
- /* write back */
- *p_num_stack_args = num_stack_args;
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY; /* Enable 'construct' trap return invariant check. */
+ *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT); /* Resume as non-constructor call to the trap. */
+
+ /* 'apply' args: target, thisArg, argArray
+ * 'construct' args: target, argArray, newTarget
+ */
+ duk_remove(thr, idx_func + 4);
+ duk_push_hobject(thr, (duk_hobject *) h_proxy);
+ }
+
+ /* Finalize value stack layout by removing Proxy reference. */
+ duk_remove(thr, idx_func);
+ h_proxy = NULL; /* invalidated */
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 5);
}
+#endif /* DUK_USE_ES6_PROXY */
/*
* Helper for setting up var_env and lex_env of an activation,
@@ -55338,35 +61914,27 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
duk_hobject *func,
duk_activation *act) {
- duk_tval *tv;
+ duk_hcompfunc *f;
+ duk_hobject *h_lex;
+ duk_hobject *h_var;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
DUK_ASSERT(act != NULL);
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
+ DUK_UNREF(thr);
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- act->lex_env = DUK_TVAL_GET_OBJECT(tv);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- act->var_env = DUK_TVAL_GET_OBJECT(tv);
- } else {
- act->var_env = act->lex_env;
- }
- } else {
- act->lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- act->var_env = act->lex_env;
- }
-
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->lex_env);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->var_env);
+ f = (duk_hcompfunc *) func;
+ h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
+ h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f);
+ DUK_ASSERT(h_lex != NULL); /* Always true for closures (not for templates) */
+ DUK_ASSERT(h_var != NULL);
+ act->lex_env = h_lex;
+ act->var_env = h_var;
+ DUK_HOBJECT_INCREF(thr, h_lex);
+ DUK_HOBJECT_INCREF(thr, h_var);
}
/*
@@ -55382,7 +61950,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound chain resolved */
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound chain resolved */
DUK_ASSERT(thr->callstack_top >= 1);
if (DUK_HOBJECT_HAS_STRICT(func)) {
@@ -55390,8 +61958,10 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
return;
}
- act_callee = thr->callstack + thr->callstack_top - 1;
- act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
+ DUK_ASSERT(thr->callstack_top > 0);
+ act_callee = thr->callstack_curr;
+ DUK_ASSERT(act_callee != NULL);
+ act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL);
/* XXX: check .caller writability? */
@@ -55408,7 +61978,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* because 'func' has been resolved to a non-bound function.
*/
- if (act_caller) {
+ if (act_caller != NULL) {
/* act_caller->func may be NULL in some finalization cases,
* just treat like we don't know the caller.
*/
@@ -55429,7 +61999,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* is transferred to prev_caller.
*/
- if (act_caller) {
+ if (act_caller != NULL) {
DUK_ASSERT(act_caller->func != NULL);
DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
DUK_TVAL_INCREF(thr, tv_caller);
@@ -55440,7 +62010,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
/* 'caller' must only take on 'null' or function value */
DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
DUK_ASSERT(act_callee->prev_caller == NULL);
- if (act_caller && act_caller->func) {
+ if (act_caller != NULL && act_caller->func) {
/* Tolerate act_caller->func == NULL which happens in
* some finalization cases; treat like unknown caller.
*/
@@ -55455,15 +62025,21 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
/*
- * Determine the effective 'this' binding and coerce the current value
- * on the valstack to the effective one (in-place, at idx_this).
+ * Shared helpers for resolving the final, non-bound target function of the
+ * call and the effective 'this' binding. Resolves bound functions and
+ * applies .call(), .apply(), and .construct() inline.
+ *
+ * Proxy traps are also handled inline so that if the target is a Proxy with
+ * a 'call' or 'construct' trap, the trap handler is called with a modified
+ * argument list.
*
- * The current this value in the valstack (at idx_this) represents either:
- * - the caller's requested 'this' binding; or
- * - a 'this' binding accumulated from the bound function chain
+ * Once the bound function / .call() / .apply() / .construct() sequence has
+ * been resolved, the value at idx_func + 1 may need coercion described in
+ * E5 Section 10.4.3.
*
- * The final 'this' binding for the target function may still be
- * different, and is determined as described in E5 Section 10.4.3.
+ * A call that begins as a non-constructor call may be converted into a
+ * constructor call during the resolution process if Reflect.construct()
+ * is invoked. This is handled by updating the caller's call_flags.
*
* For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
* that the caller has provided the correct 'this' binding explicitly
@@ -55473,28 +62049,17 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* - direct eval: this=copy from eval() caller's this binding
* - other eval: this=global object
*
- * Note: this function may cause a recursive function call with arbitrary
+ * The 'this' coercion may cause a recursive function call with arbitrary
* side effects, because ToObject() may be called.
*/
-DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
- duk_hobject *func,
- duk_idx_t idx_this) {
- duk_context *ctx = (duk_context *) thr;
+DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) {
duk_tval *tv_this;
duk_hobject *obj_global;
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- /* Lightfuncs are always considered strict. */
- DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
- return;
- }
-
- /* XXX: byte offset */
tv_this = thr->valstack_bottom + idx_this;
switch (DUK_TVAL_GET_TAG(tv_this)) {
case DUK_TAG_OBJECT:
- case DUK_TAG_LIGHTFUNC: /* lightfuncs are treated like objects and not coerced */
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
break;
case DUK_TAG_UNDEFINED:
@@ -55516,141 +62081,240 @@ DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
}
break;
default:
+ /* Plain buffers and lightfuncs are object coerced. Lightfuncs
+ * very rarely come here however, because the call target would
+ * need to be a non-strict non-lightfunc (lightfuncs are considered
+ * strict) with an explicit lightfunc 'this' binding.
+ */
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
- duk_to_object(ctx, idx_this); /* may have side effects */
+ duk_to_object(thr, idx_this); /* may have side effects */
break;
}
}
-/*
- * Shared helper for non-bound func lookup.
- *
- * Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
- */
+DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__resolve_target_fastpath_check(duk_hthread *thr, duk_idx_t idx_func, duk_hobject **out_func, duk_small_uint_t call_flags) {
+#if defined(DUK_USE_PREFER_SIZE)
+ DUK_UNREF(thr);
+ DUK_UNREF(idx_func);
+ DUK_UNREF(out_func);
+ DUK_UNREF(call_flags);
+#else /* DUK_USE_PREFER_SIZE */
+ duk_tval *tv_func;
+ duk_hobject *func;
-DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
- duk_idx_t idx_func,
- duk_idx_t *out_num_stack_args,
- duk_tval **out_tv_func,
- duk_small_uint_t call_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+ if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) {
+ return 0;
+ }
+
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
+ DUK_ASSERT(tv_func != NULL);
+
+ if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) {
+ func = DUK_TVAL_GET_OBJECT(tv_func);
+ if (DUK_HOBJECT_IS_CALLABLE(func) &&
+ !DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
+ !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) {
+ *out_func = func;
+
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ /* Strict function: no 'this' coercion. */
+ return 1;
+ }
+
+ duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
+ return 1;
+ }
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ *out_func = NULL;
+
+ /* Lightfuncs are considered strict, so 'this' binding is
+ * used as is. They're never bound, always constructable,
+ * and never special functions.
+ */
+ return 1;
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+ return 0; /* let slow path deal with it */
+}
+
+DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t *call_flags) {
duk_tval *tv_func;
duk_hobject *func;
+ duk_bool_t first;
- for (;;) {
- /* Use loop to minimize code size of relookup after bound function case */
- tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ for (first = 1;; first = 0) {
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
DUK_ASSERT(tv_func != NULL);
if (DUK_TVAL_IS_OBJECT(tv_func)) {
func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- goto not_callable_error;
+
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) {
+ goto not_constructable;
+ }
+ } else {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) {
+ goto not_callable;
+ }
}
- if (DUK_HOBJECT_HAS_BOUND(func)) {
- duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
- /* The final object may be a normal function or a lightfunc.
- * We need to re-lookup tv_func because it may have changed
- * (also value stack may have been resized). Loop again to
- * do that; we're guaranteed not to come here again.
+ if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
+ !DUK_HOBJECT_HAS_SPECIAL_CALL(func) &&
+ !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) {
+ /* Common case, so test for using a single bitfield test.
+ * Break out to handle this coercion etc.
*/
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
- DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
- continue;
+ break;
}
+
+ /* XXX: could set specialcall for boundfuncs too, simplify check above */
+
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
+ DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func));
+ DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func));
+
+ /* Callable/constructable flags are the same
+ * for the bound function and its target, so
+ * we don't need to check them here, we can
+ * check them from the target only.
+ */
+ duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT);
+
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) ||
+ DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func)));
+ } else {
+ DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func));
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) {
+ /* If no trap, resume processing from Proxy trap.
+ * If trap exists, helper converts call into a trap
+ * call; this may change a constructor call into a
+ * normal (non-constructor) trap call. We must
+ * continue processing even when a trap is found as
+ * the trap may be bound.
+ */
+ duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags);
+ }
+ else
+#endif
+ {
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func));
+ /* Constructable check already done above. */
+
+ if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) {
+ /* Encountered native eval call, normal call
+ * context. Break out, handle this coercion etc.
+ */
+ break;
+ }
+ }
+ }
+ /* Retry loop. */
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ /* Lightfuncs are:
+ * - Always strict, so no 'this' coercion.
+ * - Always callable.
+ * - Always constructable.
+ * - Never specialfuncs.
+ */
func = NULL;
+ goto finished;
} else {
- goto not_callable_error;
+ goto not_callable;
}
- break;
}
- DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
- DUK_TVAL_IS_LIGHTFUNC(tv_func));
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
-
- *out_tv_func = tv_func;
- return func;
-
- not_callable_error:
- DUK_ASSERT(tv_func != NULL);
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
-#else
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
-#endif
- DUK_UNREACHABLE();
- return NULL; /* never executed */
-}
-
-/*
- * Value stack resize and stack top adjustment helper.
- *
- * XXX: This should all be merged to duk_valstack_resize_raw().
- */
+ DUK_ASSERT(func != NULL);
-DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_idx_t idx_args,
- duk_idx_t nregs,
- duk_idx_t nargs,
- duk_hobject *func) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t vs_min_size;
- duk_bool_t adjusted_top = 0;
-
- vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- idx_args; /* bottom of new func */
-
- if (nregs >= 0) {
- DUK_ASSERT(nargs >= 0);
- DUK_ASSERT(nregs >= nargs);
- vs_min_size += nregs;
- } else {
- /* 'func' wants stack "as is" */
- vs_min_size += num_stack_args; /* num entries of new func at entry */
+ if (!DUK_HOBJECT_HAS_STRICT(func)) {
+ /* Non-strict target needs 'this' coercion.
+ * This has potential side effects invalidating
+ * 'tv_func'.
+ */
+ duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
}
- if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
+ *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
+ duk__update_default_instance_proto(thr, idx_func);
+ }
}
- vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
- /* XXX: We can't resize the value stack to a size smaller than the
- * current top, so the order of the resize and adjusting the stack
- * top depends on the current vs. final size of the value stack.
- * The operations could be combined to avoid this, but the proper
- * fix is to only grow the value stack on a function call, and only
- * shrink it (without throwing if the shrink fails) on function
- * return.
- */
+ finished:
+
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_tval *tv_tmp;
- if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
- DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
+ tv_tmp = duk_get_tval(thr, idx_func);
+ DUK_ASSERT(tv_tmp != NULL);
- DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
- adjusted_top = 1;
+ DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) ||
+ DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
+ DUK_HOBJECT_IS_NATFUNC(func)));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) ||
+ (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0));
}
+#endif
- (void) duk_valstack_resize_raw((duk_context *) thr,
- vs_min_size,
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ return func;
- if (!adjusted_top) {
- if (nregs >= 0) {
- DUK_ASSERT(nregs >= nargs);
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
+ not_callable:
+ DUK_ASSERT(tv_func != NULL);
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ /* GETPROPC delayed error handling: when target is not callable,
+ * GETPROPC replaces idx_func+0 with an Error (non-callable) with
+ * a hidden Symbol to signify it's to be thrown as is here. The
+ * hidden Symbol is only checked as an own property, not inherited
+ * (which would be dangerous).
+ */
+ if (DUK_TVAL_IS_OBJECT(tv_func)) {
+ if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) {
+ duk_push_tval(thr, tv_func);
+ (void) duk_throw(thr);
}
}
+#endif
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_get_type_name(thr, idx_func));
+#else
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(thr, tv_func));
+#endif
+#else
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
+#endif
+ DUK_UNREACHABLE();
+ return NULL; /* never executed */
+
+ not_constructable:
+ /* For now GETPROPC delayed error not needed for constructor calls. */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(thr, idx_func));
+#else
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_tval_readable(thr, tv_func));
+#endif
+#else
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
+#endif
+ DUK_UNREACHABLE();
+ return NULL; /* never executed */
}
/*
@@ -55664,7 +62328,6 @@ DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
*/
DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t idx_rcbase;
DUK_ASSERT(thr != NULL);
@@ -55672,551 +62335,399 @@ DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_re
DUK_ASSERT(num_stack_rets >= 0);
DUK_ASSERT(num_actual_rets >= 0);
- idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
+ idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */
+ if (DUK_UNLIKELY(idx_rcbase < 0)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
+ }
DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
"num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
- (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
+ (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr),
(long) idx_retbase, (long) idx_rcbase));
DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
- /* Ensure space for final configuration (idx_retbase + num_stack_rets)
- * and intermediate configurations.
+ /* Space for num_stack_rets was reserved before the safe call.
+ * Because value stack reserve cannot shrink except in call returns,
+ * the reserve is still in place. Adjust valstack, carefully
+ * ensuring we don't overstep the reserve.
*/
- duk_require_stack_top(ctx,
- (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
- num_stack_rets);
-
- /* Chop extra retvals away / extend with undefined. */
- duk_set_top(ctx, idx_rcbase + num_stack_rets);
- if (idx_rcbase >= idx_retbase) {
+ /* Match idx_rcbase with idx_retbase so that the return values
+ * start at the correct index.
+ */
+ if (idx_rcbase > idx_retbase) {
duk_idx_t count = idx_rcbase - idx_retbase;
- duk_idx_t i;
DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
"(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
- /* nuke values at idx_retbase to get the first retval (initially
- * at idx_rcbase) to idx_retbase
+ /* Remove values between irc_rcbase (start of intended return
+ * values) and idx_retbase to lower return values to idx_retbase.
*/
-
- DUK_ASSERT(count >= 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block remove primitive */
- duk_remove(ctx, idx_retbase);
- }
+ DUK_ASSERT(count > 0);
+ duk_remove_n(thr, idx_retbase, count); /* may be NORZ */
} else {
duk_idx_t count = idx_retbase - idx_rcbase;
- duk_idx_t i;
DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
"(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
- /* insert 'undefined' values at idx_rcbase to get the
- * return values to idx_retbase
+ /* Insert 'undefined' at idx_rcbase (start of intended return
+ * values) to lift return values to idx_retbase.
*/
-
- DUK_ASSERT(count > 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block insert primitive */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_rcbase);
- }
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count); /* reserve cannot shrink */
+ duk_insert_undefined_n(thr, idx_rcbase, count);
}
-}
-/*
- * Misc shared helpers.
- */
-
-/* Get valstack index for the func argument or throw if insane stack. */
-DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
- duk_size_t off_stack_top;
- duk_size_t off_stack_args;
- duk_size_t off_stack_all;
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
-
- /* Argument validation and func/args offset. */
- off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
- off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
- off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
- if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
- /* Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return 0;
- }
- idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
- return idx_func;
+ /* Chop extra retvals away / extend with undefined. */
+ duk_set_top_unsafe(thr, idx_retbase + num_stack_rets);
}
/*
- * duk_handle_call_protected() and duk_handle_call_unprotected():
- * call into a Duktape/C or an Ecmascript function from any state.
- *
- * Input stack (thr):
- *
- * [ func this arg1 ... argN ]
- *
- * Output stack (thr):
- *
- * [ retval ] (DUK_EXEC_SUCCESS)
- * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
- *
- * Even when executing a protected call an error may be thrown in rare cases
- * such as an insane num_stack_args argument. If there is no catchpoint for
- * such errors, the fatal error handler is called.
- *
- * The error handling path should be error free, even for out-of-memory
- * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
- * yet the case, see XXX notes below.)
+ * Activation setup for tailcalls and non-tailcalls.
*/
-DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_valstack_end;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- duk_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+#if defined(DUK_USE_TAILCALL)
+DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func,
+ duk_hobject *func,
+ duk_size_t entry_valstack_bottom_byteoff,
+ duk_size_t entry_valstack_end_byteoff,
+ duk_idx_t *out_nargs,
+ duk_idx_t *out_nregs,
+ duk_size_t *out_vs_min_bytes,
+ duk_activation **out_act) {
+ duk_activation *act;
+ duk_tval *tv1, *tv2;
+ duk_idx_t idx_args;
+ duk_small_uint_t flags1, flags2;
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_activation *prev_pause_act;
+#endif
- /* XXX: Multiple tv_func lookups are now avoided by making a local
- * copy of tv_func. Another approach would be to compute an offset
- * for tv_func from valstack bottom and recomputing the tv_func
- * pointer quickly as valstack + offset instead of calling duk_get_tval().
- */
+ DUK_UNREF(entry_valstack_end_byteoff);
- ctx = (duk_context *) thr;
- DUK_UNREF(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(num_stack_args >= 0);
- /* XXX: currently NULL allocations are not supported; remove if later allowed */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
+ /* Tailcall cannot be flagged to resume calls, and a
+ * previous frame must exist.
+ */
+ DUK_ASSERT(thr->callstack_top >= 1);
- /* Argument validation and func/args offset. */
- idx_func = duk__get_idx_func(thr, num_stack_args);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ *out_act = act;
- /* Preliminaries, required by setjmp() handler. Must be careful not
- * to throw an unintended error here.
+ if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function"));
+ return 0;
+ }
+ if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD"));
+ return 0;
+ }
+ /* Tailcall is only allowed if current and candidate
+ * function have identical return value handling. There
+ * are three possible return value handling cases:
+ * 1. Normal function call, no special return value handling.
+ * 2. Constructor call, return value replacement object check.
+ * 3. Proxy 'construct' trap call, return value invariant check.
*/
-
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
-#if defined(DUK_USE_PREFER_SIZE)
- entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
-#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- entry_valstack_end = thr->valstack_size;
+ flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0)
+#if defined(DUK_USE_ES6_PROXY)
+ | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0)
#endif
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
-
- DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
- "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) duk_get_top(ctx),
- (long) idx_func,
- (long) (idx_func + 2),
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
-
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
+ ;
+ flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0)
+#if defined(DUK_USE_ES6_PROXY)
+ | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0);
#endif
- /* Call handling and success path. Success path exit cleans
- * up almost all state.
- */
- duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
+ ;
+ if (flags1 != flags2) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling"));
+ return 0;
+ }
+ DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) ||
+ (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT)));
+ DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) ||
+ (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)));
+ if (DUK_HOBJECT_HAS_NOTAIL(func)) {
+ /* See: test-bug-tailcall-preventyield-assert.c. */
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag"));
+ return 0;
+ }
- /* Success path handles */
- DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
- DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
+ /*
+ * Tailcall handling
+ *
+ * Although the callstack entry is reused, we need to explicitly unwind
+ * the current activation (or simulate an unwind). In particular, the
+ * current activation must be closed, otherwise something like
+ * test-bug-reduce-judofyr.js results. Also catchers need to be unwound
+ * because there may be non-error-catching label entries in valid tail calls.
+ *
+ * Special attention is needed for debugger and pause behavior when
+ * reusing an activation.
+ * - Disable StepOut processing for the activation unwind because
+ * we reuse the activation, see:
+ * https://github.com/svaarala/duktape/issues/1684.
+ * - Disable line change pause flag permanently if act == dbg_pause_act
+ * (if set) because it would no longer be relevant, see:
+ * https://github.com/svaarala/duktape/issues/1726,
+ * https://github.com/svaarala/duktape/issues/1786.
+ * - Check for function entry (e.g. StepInto) pause flag here, because
+ * the executor pause check won't trigger due to shared activation, see:
+ * https://github.com/svaarala/duktape/issues/1726.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
+ (long) (thr->callstack_top - 1)));
+
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA);
+
+ /* Unwind the topmost callstack entry before reusing it. This
+ * also unwinds the catchers related to the topmost entry.
+ */
+ DUK_ASSERT(thr->callstack_top > 0);
+ DUK_ASSERT(thr->callstack_curr != NULL);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ if (act == thr->heap->dbg_pause_act) {
+ thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
+ }
- /* Longjmp state is kept clean in success path */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
- DUK_ASSERT(thr->heap->lj.iserror == 0);
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+ prev_pause_act = thr->heap->dbg_pause_act;
+ thr->heap->dbg_pause_act = NULL;
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)"));
+ duk_debug_set_paused(thr->heap);
+ }
+#endif
+ duk_hthread_activation_unwind_reuse_norz(thr);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ thr->heap->dbg_pause_act = prev_pause_act;
+#endif
+ DUK_ASSERT(act == thr->callstack_curr);
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+ /* XXX: We could restore the caller's value stack reserve
+ * here, as if we did an actual unwind-and-call. Without
+ * the restoration, value stack reserve may remain higher
+ * than would otherwise be possible until we return to a
+ * non-tailcall.
+ */
- return DUK_EXEC_SUCCESS;
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- } catch (duk_internal_exception &exc) {
-#else
- } else {
+ /* Then reuse the unwound activation. */
+ act->cat = NULL;
+ act->var_env = NULL;
+ act->lex_env = NULL;
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
+ act->func = func; /* don't want an intermediate exposed state with func == NULL */
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+ act->prev_caller = NULL;
#endif
- /* Error; error value is in heap->lj.value1. */
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- DUK_UNREF(exc);
+ /* don't want an intermediate exposed state with invalid pc */
+ act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ act->prev_line = 0;
#endif
+ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
+ DUK_HOBJECT_INCREF(thr, func);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
-
- /* Longjmp state is cleaned up by error handling */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
- DUK_ASSERT(thr->heap->lj.iserror == 0);
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
- return DUK_EXEC_ERROR;
+ act->flags = DUK_ACT_FLAG_TAILCALLED;
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ act->flags |= DUK_ACT_FLAG_STRICT;
}
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- catch (std::exception &exc) {
- const char *what = exc.what();
- if (!what) {
- what = "unknown";
- }
- DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
- DUK_UNREF(exc);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
- return DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
- DUK_UNREF(exc);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
- return DUK_EXEC_ERROR;
- }
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT;
+ }
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
}
#endif
-}
-
-DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
-
- /* Argument validation and func/args offset. */
- idx_func = duk__get_idx_func(thr, num_stack_args);
-
- duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
-}
-
-DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags,
- duk_idx_t idx_func) {
- duk_context *ctx;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_valstack_end;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
- duk_tval tv_func_copy; /* to avoid relookups */
- duk_activation *act;
- duk_hobject *env;
- duk_ret_t rc;
-
- ctx = (duk_context *) thr;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(num_stack_args >= 0);
- /* XXX: currently NULL allocations are not supported; remove if later allowed */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
-
- DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
- (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
- /*
- * Store entry state.
- */
-
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
-#if defined(DUK_USE_PREFER_SIZE)
- entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
-#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- entry_valstack_end = thr->valstack_size;
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
+ DUK_ASSERT(act->var_env == NULL);
+ DUK_ASSERT(act->lex_env == NULL);
+ act->bottom_byteoff = entry_valstack_bottom_byteoff; /* tail call -> reuse current "frame" */
+#if 0
+ /* Topmost activation retval_byteoff is considered garbage, no need to init. */
+ act->retval_byteoff = 0;
#endif
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
-
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur.
+ /* Filled in when final reserve is known, dummy value doesn't matter
+ * even in error unwind because reserve_byteoff is only used when
+ * returning to -this- activation.
*/
- duk_hthread_sync_and_null_currpc(thr);
-
- DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
- "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) duk_get_top(ctx),
- (long) idx_func,
- (long) (idx_func + 2),
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
-
+ act->reserve_byteoff = 0;
/*
- * Thread state check and book-keeping.
+ * Manipulate valstack so that args are on the current bottom and the
+ * previous caller's 'this' binding (which is the value preceding the
+ * current bottom) is replaced with the new 'this' binding:
+ *
+ * [ ... this_old | (crud) func this_new arg1 ... argN ]
+ * --> [ ... this_new | arg1 ... argN ]
+ *
+ * For tail calling to work properly, the valstack bottom must not grow
+ * here; otherwise crud would accumulate on the valstack.
*/
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
+ tv1 = thr->valstack_bottom - 1;
+ tv2 = thr->valstack_bottom + idx_func + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
+ DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ idx_args = idx_func + 2;
+ duk_remove_n(thr, 0, idx_args); /* may be NORZ */
- /*
- * C call recursion depth check, which provides a reasonable upper
- * bound on maximum C stack size (arbitrary C stack growth is only
- * possible by recursive handle_call / handle_safe_call calls).
- */
+ idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
+ idx_args = 0;
- /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
- * reclimit bump?
- */
+ *out_nargs = ((duk_hcompfunc *) func)->nargs;
+ *out_nregs = ((duk_hcompfunc *) func)->nregs;
+ DUK_ASSERT(*out_nregs >= 0);
+ DUK_ASSERT(*out_nregs >= *out_nargs);
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
- DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
- DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
- if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
- DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
- } else {
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
- thr->heap->call_recursion_depth++;
- }
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * Lightfunc detection happens here too. Note that lightweight functions
- * can be wrapped by (non-lightweight) bound functions so we must resolve
- * the bound function chain first.
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+#if defined(DUK_USE_TAILCALL)
+#error incorrect options: tail calls enabled with function caller property
+#endif
+ /* XXX: This doesn't actually work properly for tail calls, so
+ * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+ * is in use.
*/
+ duk__update_func_caller_prop(thr, func);
+#endif
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
- tv_func = &tv_func_copy; /* local copy to avoid relookups */
+ /* [ ... this_new | arg1 ... argN ] */
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
+ return 1;
+}
+#endif /* DUK_USE_TAILCALL */
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
+DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func,
+ duk_hobject *func,
+ duk_size_t entry_valstack_bottom_byteoff,
+ duk_size_t entry_valstack_end_byteoff,
+ duk_idx_t *out_nargs,
+ duk_idx_t *out_nregs,
+ duk_size_t *out_vs_min_bytes,
+ duk_activation **out_act) {
+ duk_activation *act;
+ duk_activation *new_act;
- /* [ ... func this arg1 ... argN ] */
+ DUK_UNREF(entry_valstack_end_byteoff);
- /*
- * Setup a preliminary activation and figure out nargs/nregs.
- *
- * Don't touch valstack_bottom or valstack_top yet so that Duktape API
- * calls work normally.
- */
+ DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
+ (long) (thr->callstack_top)));
- duk_hthread_callstack_grow(thr);
+ duk__call_callstack_limit_check(thr);
+ new_act = duk_hthread_activation_alloc(thr);
+ DUK_ASSERT(new_act != NULL);
- if (thr->callstack_top > 0) {
+ act = thr->callstack_curr;
+ if (act != NULL) {
/*
- * Update idx_retval of current activation.
+ * Update return value stack index of current activation (if any).
*
* Although it might seem this is not necessary (bytecode executor
* does this for Ecmascript-to-Ecmascript calls; other calls are
* handled here), this turns out to be necessary for handling yield
* and resume. For them, an Ecmascript-to-native call happens, and
- * the Ecmascript call's idx_retval must be set for things to work.
+ * the Ecmascript call's retval_byteoff must be set for things to work.
*/
- (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
+ act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval);
}
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
+ new_act->parent = act;
+ thr->callstack_curr = new_act;
thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
+ act = new_act;
+ *out_act = act;
+
DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
- act->flags = 0;
+ act->cat = NULL;
- /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
- act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
- if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
+ act->flags = 0;
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
act->flags |= DUK_ACT_FLAG_CONSTRUCT;
}
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
+ }
+#endif
if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
}
- /* These base values are never used, but if the compiler doesn't know
- * that DUK_ERROR() won't return, these are needed to silence warnings.
- * On the other hand, scan-build will warn about the values not being
- * used, so add a DUK_UNREF.
- */
- nargs = 0; DUK_UNREF(nargs);
- nregs = 0; DUK_UNREF(nregs);
-
+ /* start of arguments: idx_func + 2. */
+ act->func = func; /* NULL for lightfunc */
if (DUK_LIKELY(func != NULL)) {
+ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
if (DUK_HOBJECT_HAS_STRICT(func)) {
act->flags |= DUK_ACT_FLAG_STRICT;
}
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /* Note: nargs (and nregs) may be negative for a native,
- * function, which indicates that the function wants the
- * input stack "as is" (i.e. handles "vararg" arguments).
- */
- nargs = ((duk_hnativefunction *) func)->nargs;
- nregs = nargs;
+ if (DUK_HOBJECT_IS_COMPFUNC(func)) {
+ *out_nargs = ((duk_hcompfunc *) func)->nargs;
+ *out_nregs = ((duk_hcompfunc *) func)->nregs;
+ DUK_ASSERT(*out_nregs >= 0);
+ DUK_ASSERT(*out_nregs >= *out_nargs);
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
} else {
- /* XXX: this should be an assert */
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
+ /* True because of call target lookup checks. */
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
+
+ *out_nargs = ((duk_hnatfunc *) func)->nargs;
+ *out_nregs = *out_nargs;
+ if (*out_nargs >= 0) {
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ } else {
+ /* Vararg function. */
+ duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
+ *out_vs_min_bytes = valstack_top_byteoff +
+ sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ }
}
} else {
duk_small_uint_t lf_flags;
+ duk_tval *tv_func;
+
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
+
lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = -1; /* vararg */
+ *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) {
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ } else {
+ duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
+ *out_vs_min_bytes = valstack_top_byteoff +
+ sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ *out_nargs = -1; /* vararg */
}
- nregs = nargs;
-
- act->flags |= DUK_ACT_FLAG_STRICT;
+ *out_nregs = *out_nargs;
}
- act->func = func; /* NULL for lightfunc */
act->var_env = NULL;
act->lex_env = NULL;
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
@@ -56226,20 +62737,15 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
#if defined(DUK_USE_DEBUGGER_SUPPORT)
act->prev_line = 0;
#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U);
+#if 0
+ act->retval_byteoff = 0; /* topmost activation retval_byteoff is considered garbage, no need to init */
#endif
- DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
-
- /* XXX: remove the preventcount and make yield walk the callstack?
- * Or perhaps just use a single flag, not a counter, faster to just
- * set and restore?
+ /* Filled in when final reserve is known, dummy value doesn't matter
+ * even in error unwind because reserve_byteoff is only used when
+ * returning to -this- activation.
*/
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- /* duk_hthread_callstack_unwind() will decrease this on unwind */
- thr->callstack_preventcount++;
- }
+ act->reserve_byteoff = 0; /* filled in by caller */
/* XXX: Is this INCREF necessary? 'func' is always a borrowed
* reference reachable through the value stack? If changed, stack
@@ -56251,25 +62757,17 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
if (func) {
duk__update_func_caller_prop(thr, func);
}
- act = thr->callstack + thr->callstack_top - 1;
#endif
+}
- /* [ ... func this arg1 ... argN ] */
+/*
+ * Environment setup.
+ */
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * This handling is now identical for C and Ecmascript functions.
- * C functions always have the 'NEWENV' flag set, so their
- * environment record initialization is delayed (which is good).
- *
- * Delayed creation (on demand) is handled in duk_js_var.c.
- */
+DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) {
+ duk_hobject *env;
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function has already been resolved */
if (DUK_LIKELY(func != NULL)) {
if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
@@ -56285,23 +62783,22 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
* We need to initialize it right now.
*/
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */
+ env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
DUK_ASSERT(env != NULL);
/* [ ... func this arg1 ... argN envobj ] */
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
+ duk__handle_createargs_for_call(thr, func, env, idx_args);
/* [ ... func this arg1 ... argN envobj ] */
- act = thr->callstack + thr->callstack_top - 1;
act->lex_env = env;
act->var_env = env;
DUK_HOBJECT_INCREF(thr, env);
DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
- duk_pop(ctx);
+ duk_pop(thr);
}
} else {
/* Use existing env (e.g. for non-strict eval); cannot have
@@ -56320,50 +62817,324 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
DUK_ASSERT(act->lex_env == NULL);
DUK_ASSERT(act->var_env == NULL);
}
+}
+
+/*
+ * Misc shared helpers.
+ */
+
+/* Check thread state, update current thread. */
+DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) {
+ DUK_ASSERT(thr != NULL);
+
+ if (DUK_LIKELY(thr == thr->heap->curr_thread)) {
+ if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) {
+ /* Should actually never happen, but check anyway. */
+ goto thread_state_error;
+ }
+ } else {
+ DUK_ASSERT(thr->heap->curr_thread == NULL ||
+ thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
+ if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) {
+ goto thread_state_error;
+ }
+ DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
+ thr->state = DUK_HTHREAD_STATE_RUNNING;
+
+ /* Multiple threads may be simultaneously in the RUNNING
+ * state, but not in the same "resume chain".
+ */
+ }
+ DUK_ASSERT(thr->heap->curr_thread == thr);
+ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ return;
+
+ thread_state_error:
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+}
+
+/*
+ * Main unprotected call handler, handles:
+ *
+ * - All combinations of native/Ecmascript caller and native/Ecmascript
+ * target.
+ *
+ * - Optimized Ecmascript-to-Ecmascript call where call handling only
+ * sets up a new duk_activation but reuses an existing bytecode executor
+ * (the caller) without native recursion.
+ *
+ * - Tailcalls, where an activation is reused without increasing call
+ * stack (duk_activation) depth.
+ *
+ * - Setup for an initial Duktape.Thread.resume().
+ *
+ * The call handler doesn't provide any protection guarantees, protected calls
+ * must be implemented e.g. by wrapping the call in a duk_safe_call().
+ * Call setup may fail at any stage, even when the new activation is in
+ * place; the only guarantee is that the state is consistent for unwinding.
+ */
+
+DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t call_flags) {
+#if defined(DUK_USE_ASSERTIONS)
+ duk_activation *entry_act;
+ duk_size_t entry_callstack_top;
+#endif
+ duk_size_t entry_valstack_bottom_byteoff;
+ duk_size_t entry_valstack_end_byteoff;
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
+ duk_instr_t **entry_ptr_curr_pc;
+ duk_idx_t idx_args;
+ duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
+ duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
+ duk_size_t vs_min_bytes; /* minimum value stack size (bytes) for handling call */
+ duk_hobject *func; /* 'func' on stack (borrowed reference) */
+ duk_activation *act;
+ duk_ret_t rc;
+ duk_small_uint_t use_tailcall;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or
+ * any other thread (e.g. when heap thread is used to run finalizers).
+ */
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ DUK_ASSERT(idx_func >= 0);
+
+ DUK_STATS_INC(thr->heap, stats_call_all);
+
+ /* If a tail call:
+ * - an Ecmascript activation must be on top of the callstack
+ * - there cannot be any catch stack entries that would catch
+ * a return
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ if (call_flags & DUK_CALL_FLAG_TAILCALL) {
+ duk_activation *tmp_act;
+ duk_catcher *tmp_cat;
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
+
+ /* No entry in the catch stack which would actually catch a
+ * throw can refer to the callstack entry being reused.
+ * There *can* be catch stack entries referring to the current
+ * callstack entry as long as they don't catch (e.g. label sites).
+ */
+
+ tmp_act = thr->callstack_curr;
+ for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */
+ }
+ }
+#endif /* DUK_USE_ASSERTIONS */
+
+ /*
+ * Store entry state.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+ entry_act = thr->callstack_curr;
+ entry_callstack_top = thr->callstack_top;
+#endif
+ entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
+ entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
+
+ /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
+ * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
+ * activation when side effects occur.
+ */
+ duk_hthread_sync_and_null_currpc(thr);
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+
+ DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, "
+ "call_flags=0x%08lx (constructor=%ld), "
+ "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
+ "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, "
+ "entry_call_recursion_depth=%ld, "
+ "entry_curr_thread=%p, entry_thread_state=%ld",
+ (void *) thr,
+ (long) idx_func,
+ (unsigned long) call_flags,
+ (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0),
+ (long) duk_get_top(thr),
+ (long) idx_func,
+ (long) (idx_func + 2),
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (long) entry_valstack_bottom_byteoff,
+ (long) entry_valstack_end_byteoff,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
+
+ /*
+ * Thread state check and book-keeping.
+ */
+
+ duk__call_thread_state_update(thr);
+
+ /*
+ * Resolve final target function; handle bound functions and special
+ * functions like .call() and .apply(). Also figure out the effective
+ * 'this' binding, which replaces the current value at idx_func + 1.
+ */
+
+ if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) {
+ DUK_DDD(DUK_DDDPRINT("fast path target resolve"));
+ } else {
+ DUK_DDD(DUK_DDDPRINT("slow path target resolve"));
+ func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags);
+ }
+ DUK_ASSERT(duk_get_top(thr) - idx_func >= 2); /* at least func and this present */
+
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
+ DUK_HOBJECT_IS_NATFUNC(func)));
/* [ ... func this arg1 ... argN ] */
/*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
+ * Setup a preliminary activation and figure out nargs/nregs and
+ * value stack minimum size.
+ *
+ * Don't touch valstack_bottom or valstack_top yet so that Duktape API
+ * calls work normally.
*
- * Value stack may either grow or shrink, depending on the
- * number of func registers and the number of actual arguments.
- * If nregs >= 0, func wants args clamped to 'nargs'; else it
- * wants all args (= 'num_stack_args').
+ * Because 'act' is not zeroed, all fields must be filled in.
*/
- /* XXX: optimize value stack operation */
- /* XXX: don't want to shrink allocation here */
+#if defined(DUK_USE_TAILCALL)
+ use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL);
+ if (use_tailcall) {
+ use_tailcall = duk__call_setup_act_attempt_tailcall(thr,
+ call_flags,
+ idx_func,
+ func,
+ entry_valstack_bottom_byteoff,
+ entry_valstack_end_byteoff,
+ &nargs,
+ &nregs,
+ &vs_min_bytes,
+ &act);
+ }
+#else
+ DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0); /* compiler ensures this */
+ use_tailcall = 0;
+#endif
- duk__adjust_valstack_and_top(thr,
- num_stack_args,
- idx_func + 2,
- nregs,
- nargs,
- func);
+ if (use_tailcall) {
+ idx_args = 0;
+ DUK_STATS_INC(thr->heap, stats_call_tailcall);
+ } else {
+ duk__call_setup_act_not_tailcall(thr,
+ call_flags,
+ idx_func,
+ func,
+ entry_valstack_bottom_byteoff,
+ entry_valstack_end_byteoff,
+ &nargs,
+ &nregs,
+ &vs_min_bytes,
+ &act);
+ idx_args = idx_func + 2;
+ }
+ /* After this point idx_func is no longer valid for tailcalls. */
+
+ DUK_ASSERT(act != NULL);
+
+ /* [ ... func this arg1 ... argN ] */
/*
- * Determine call type, then finalize activation, shift to
- * new value stack bottom, and call the target.
+ * Environment record creation and 'arguments' object creation.
+ * Named function expression name binding is handled by the
+ * compiler; the compiled function's parent env will contain
+ * the (immutable) binding already.
+ *
+ * This handling is now identical for C and Ecmascript functions.
+ * C functions always have the 'NEWENV' flag set, so their
+ * environment record initialization is delayed (which is good).
+ *
+ * Delayed creation (on demand) is handled in duk_js_var.c.
*/
- if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+ duk__call_env_setup(thr, func, act, idx_args);
+
+ /* [ ... func this arg1 ... argN ] */
+
+ /*
+ * Setup value stack: clamp to 'nargs', fill up to 'nregs',
+ * ensure value stack size matches target requirements, and
+ * switch value stack bottom. Valstack top is kept.
+ *
+ * Value stack can only grow here.
+ */
+
+ duk_valstack_grow_check_throw(thr, vs_min_bytes);
+ act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+
+ if (use_tailcall) {
+ DUK_ASSERT(nregs >= 0);
+ DUK_ASSERT(nregs >= nargs);
+ duk_set_top_and_wipe(thr, nregs, nargs);
+ } else {
+ if (nregs >= 0) {
+ DUK_ASSERT(nregs >= nargs);
+ duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs);
+ } else {
+ ;
+ }
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ }
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+
+ /*
+ * Make the actual call. For Ecma-to-Ecma calls detect that
+ * setup is complete, then return with a status code that allows
+ * the caller to reuse the running executor.
+ */
+
+ if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
/*
- * Ecmascript call
+ * Ecmascript call.
*/
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
+ act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
- thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) {
+ DUK_DD(DUK_DDPRINT("avoid native call, use existing executor"));
+ DUK_STATS_INC(thr->heap, stats_call_ecmatoecma);
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ DUK_REFZERO_CHECK_FAST(thr);
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ return 1; /* 1=reuse executor */
+ }
+ DUK_ASSERT(use_tailcall == 0);
+
+ /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ thr->callstack_preventcount++;
+
+ /* XXX: we could just do this on entry regardless of reuse, as long
+ * as recursion depth is decreased for e2e case.
+ */
+ duk__call_c_recursion_limit_check(thr);
+ thr->heap->call_recursion_depth++;
/* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
@@ -56384,257 +63155,122 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
duk_js_execute_bytecode(thr);
DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
-
- /* Unwind. */
-
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
-
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
-
- /* Return value handling. */
-
- /* [ ... func this (crud) retval ] */
-
- tv_ret = thr->valstack_bottom + idx_func;
- tv_funret = thr->valstack_top - 1;
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE(tv_funret);
-#endif
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
} else {
/*
* Native call.
*/
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
- thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
+ DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL);
+ DUK_ASSERT(use_tailcall == 0);
/* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
+ /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ thr->callstack_preventcount++;
+
+ /* XXX: we could just do this on entry regardless of reuse, as long
+ * as recursion depth is decreased for e2e case.
+ */
+ duk__call_c_recursion_limit_check(thr);
+ thr->heap->call_recursion_depth++;
+
/* For native calls must be NULL so we don't sync back */
DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* XXX: native funcptr could come out of call setup. */
if (func) {
- rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
+ rc = ((duk_hnatfunc *) func)->func(thr);
} else {
- duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
- rc = funcptr((duk_context *) thr);
+ duk_tval *tv_func;
+ duk_c_function funcptr;
+
+ tv_func = &act->tv_func;
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
+ rc = funcptr(thr);
}
/* Automatic error throwing, retval check. */
- if (rc < 0) {
+ if (rc == 0) {
+ DUK_ASSERT(thr->valstack < thr->valstack_end);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
+ thr->valstack_top++;
+ } else if (rc == 1) {
+ ;
+ } else if (rc < 0) {
duk_error_throw_from_negative_rc(thr, rc);
DUK_UNREACHABLE();
- } else if (rc > 1) {
- DUK_ERROR_API(thr, "c function returned invalid rc");
- }
- DUK_ASSERT(rc == 0 || rc == 1);
-
- /* Unwind. */
-
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
-
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
-
- /* Return value handling. */
-
- /* XXX: should this happen in the callee's activation or after unwinding? */
- tv_ret = thr->valstack_bottom + idx_func;
- if (rc == 0) {
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
} else {
- /* [ ... func this (crud) retval ] */
- tv_funret = thr->valstack_top - 1;
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE(tv_funret);
-#endif
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
}
}
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_ASSERT(use_tailcall == 0);
- duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
-
- /* [ ... retval ] */
-
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
- */
-
- /* XXX: we should never shrink here; when we error out later, we'd
- * need to potentially grow the value stack in error unwind which could
- * cause another error.
+ /*
+ * Constructor call post processing.
*/
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
-
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
-
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = (duk_uint8_t) entry_thread_state;
-
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
-
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* If the debugger is active we need to force an interrupt so that
- * debugger breakpoints are rechecked. This is important for function
- * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
- * GH-303. Only needed for success path, error path always causes a
- * breakpoint recheck in the executor. It would be enough to set this
- * only when returning to an Ecmascript activation, but setting the flag
- * on every return should have no ill effect.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
- DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
- thr->interrupt_init -= thr->interrupt_counter;
- thr->interrupt_counter = 0;
- thr->heap->dbg_force_restart = 1;
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) {
+ duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY);
+ }
+#else
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ duk_call_construct_postprocess(thr, 0);
}
#endif
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk__interrupt_fixup(thr, entry_curr_thread);
-#endif
-
- return;
-
- thread_state_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return; /* never executed */
-}
-
-DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_valstack_end,
- duk_size_t entry_catchstack_top,
- duk_size_t entry_callstack_top,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc,
- duk_idx_t idx_func,
- duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
- duk_tval *tv_ret;
+ /*
+ * Unwind, restore valstack bottom and other book-keeping.
+ */
- ctx = (duk_context *) thr;
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent == entry_act);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_activation_unwind_norz(thr);
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
- /* Other longjmp types are handled by executor before propagating
- * the error here.
- */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ /* Return value handling. */
- /* We don't need to sync back thr->ptr_curr_pc here because
- * the bytecode executor always has a setjmp catchpoint which
- * does that before errors propagate to here.
- */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* [ ... func this (crud) retval ] */
- /* Restore the previous setjmp catcher so that any error in
- * error handling will propagate outwards rather than re-enter
- * the same handler. However, the error handling path must be
- * designed to be error free so that sandboxing guarantees are
- * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
- */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- /* XXX: callstack unwind may now throw an error when closing
- * scopes; this is a sandboxing issue, described in:
- * https://github.com/svaarala/duktape/issues/476
- */
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
+ {
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
+ tv_ret = thr->valstack_bottom + idx_func;
+ tv_funret = thr->valstack_top - 1;
#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE(tv_ret);
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
#endif
- duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
-
- /* [ ... errobj ] */
-
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
- */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ }
- /* XXX: this needs to be reworked so that we never shrink the value
- * stack on function entry so that we never need to grow it here.
- * Needing to grow here is a sandboxing issue because we need to
- * allocate which may cause an error in the error handling path
- * and thus propagate an error out of a protected call.
- */
+ duk_set_top_unsafe(thr, idx_func + 1);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
+ /* [ ... retval ] */
+ /* Restore caller's value stack reserve (cannot fail). */
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff);
- /* These are just convenience "wiping" of state. Side effects should
- * not be an issue here: thr->heap and thr->heap->lj have a stable
- * pointer. Finalizer runs etc capture even out-of-memory errors so
- * nothing should throw here.
+ /* XXX: Trial value stack shrink would be OK here, but we'd need
+ * to prevent side effects of the potential realloc.
*/
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -56642,9 +63278,12 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
thr->state = (duk_uint8_t) entry_thread_state;
+ /* Disabled assert: triggered with some torture tests. */
+#if 0
DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
(thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
(thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
+#endif
thr->heap->call_recursion_depth = entry_call_recursion_depth;
@@ -56657,7 +63296,7 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
* on every return should have no ill effect.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (duk_debug_is_attached(thr->heap)) {
DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
thr->interrupt_init -= thr->interrupt_counter;
@@ -56669,6 +63308,33 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
+
+ /* Restored by success path. */
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
+
+ DUK_REFZERO_CHECK_FAST(thr);
+
+ return 0; /* 0=call handled inline */
+}
+
+DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr,
+ duk_idx_t nargs,
+ duk_small_uint_t call_flags) {
+ duk_idx_t idx_func;
+ DUK_ASSERT(duk_get_top(thr) >= nargs + 2);
+ idx_func = duk_get_top(thr) - (nargs + 2);
+ DUK_ASSERT(idx_func >= 0);
+ return duk_handle_call_unprotected(thr, idx_func, call_flags);
+}
+
+DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t call_flags) {
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ DUK_ASSERT(idx_func >= 0);
+ return duk__handle_call_raw(thr, idx_func, call_flags);
}
/*
@@ -56676,254 +63342,52 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
* current activation.
*
* The allowed thread states for making a call are the same as for
- * duk_handle_call_xxx().
+ * duk_handle_call_protected().
*
- * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
- * (and result in a fatal error) for insane arguments.
+ * Even though this call is protected, errors are thrown for insane arguments
+ * and may result in a fatal error unless there's another protected call which
+ * catches such errors.
+ *
+ * The error handling path should be error free, even for out-of-memory
+ * errors, to ensure safe sandboxing. (As of Duktape 2.2.0 this is not
+ * yet the case for environment closing which may run out of memory, see
+ * XXX notes below.)
*/
-/* XXX: bump preventcount by one for the duration of this call? */
-
-DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
- duk_safe_call_function func,
- duk_idx_t num_stack_args,
- duk_idx_t num_stack_rets) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- duk_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- duk_idx_t idx_retbase;
- duk_int_t retval;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
-
- /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
- DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
- "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (long) num_stack_rets,
- (long) duk_get_top(ctx),
- (long) idx_retbase,
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
-
- if (idx_retbase < 0) {
- /* Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
-
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /* setjmp catchpoint setup */
-
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
- /* Success path. */
-#endif
- DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
-
- duk__handle_safe_call_inner(thr,
- func,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top);
-
- /* Longjmp state is kept clean in success path */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
- DUK_ASSERT(thr->heap->lj.iserror == 0);
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- retval = DUK_EXEC_SUCCESS;
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- } catch (duk_internal_exception &exc) {
- DUK_UNREF(exc);
-#else
- } else {
- /* Error path. */
-#endif
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
-
- /* Longjmp state is cleaned up by error handling */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
- DUK_ASSERT(thr->heap->lj.iserror == 0);
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
-
- retval = DUK_EXEC_ERROR;
- }
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- catch (std::exception &exc) {
- const char *what = exc.what();
- if (!what) {
- what = "unknown";
- }
- DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
- DUK_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
- DUK_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- }
-#endif
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
-
- duk__handle_safe_call_shared(thr,
- idx_retbase,
- num_stack_rets,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc);
-
- return retval;
-}
-
DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
duk_safe_call_function func,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
+ void *udata,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_valstack_bottom_byteoff,
duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top) {
- duk_context *ctx;
+#endif
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets) {
duk_ret_t rc;
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(entry_valstack_bottom_index);
- DUK_UNREF(entry_callstack_top);
- DUK_UNREF(entry_catchstack_top);
+ DUK_ASSERT_CTX_VALID(thr);
/*
* Thread state check and book-keeping.
*/
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
-
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
-
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ duk__call_thread_state_update(thr);
/*
* Recursion limit check.
- *
- * Note: there is no need for an "ignore recursion limit" flag
- * for duk_handle_safe_call now.
*/
- DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
- DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
+ duk__call_c_recursion_limit_check(thr);
thr->heap->call_recursion_depth++;
/*
- * Valstack spare check
- */
-
- duk_require_stack(ctx, 0); /* internal spare */
-
- /*
- * Make the C call
+ * Make the C call.
*/
- rc = func(ctx);
+ rc = func(thr, udata);
DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
@@ -56933,44 +63397,35 @@ DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
/* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- if (rc < 0) {
+ if (DUK_UNLIKELY(rc < 0)) {
duk_error_throw_from_negative_rc(thr, rc);
}
DUK_ASSERT(rc >= 0);
- if (duk_get_top(ctx) < rc) {
- DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
- }
-
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+ duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); /* throws for insane rc */
- duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
- return;
-
- thread_state_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
}
DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_activation *entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_callstack_top,
+#endif
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
duk_idx_t idx_retbase,
duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top,
+ duk_size_t entry_valstack_bottom_byteoff,
duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
-
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
/*
* Error during call. The error value is at heap->lj.value1.
@@ -56986,86 +63441,99 @@ DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
* the error here.
*/
DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ DUK_ASSERT_LJSTATE_SET(thr->heap);
- /* Note: either pointer may be NULL (at entry), so don't assert. */
+ /* Either pointer may be NULL (at entry), so don't assert. */
thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ /* XXX: callstack unwind may now throw an error when closing
+ * scopes; this is a sandboxing issue, described in:
+ * https://github.com/svaarala/duktape/issues/476
+ */
+ /* XXX: "unwind to" primitive? */
+
DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ while (thr->callstack_curr != entry_act) {
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ duk_hthread_activation_unwind_norz(thr);
+ }
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+
+ /* Switch active thread before any side effects to avoid a
+ * dangling curr_thread pointer.
+ */
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
+
+ DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
+ DUK_ASSERT(thr->state == entry_thread_state);
+
+ /* Restore valstack bottom. */
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
/* [ ... | (crud) ] */
- /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
- duk_push_tval(ctx, &thr->heap->lj.value1);
+ /* XXX: ensure space in valstack (now relies on internal reserve)? */
+ duk_push_tval(thr, &thr->heap->lj.value1);
/* [ ... | (crud) errobj ] */
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
-
- /* check that the valstack has space for the final amount and any
- * intermediate space needed; this is unoptimal but should be safe
- */
- duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
- duk_require_stack(ctx, num_stack_rets);
+ DUK_ASSERT(duk_get_top(thr) >= 1); /* at least errobj must be on stack */
duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
/* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
- /* These are just convenience "wiping" of state. Side effects should
- * not be an issue here: thr->heap and thr->heap->lj have a stable
- * pointer. Finalizer runs etc capture even out-of-memory errors so
- * nothing should throw here.
- */
+ /* Reset longjmp state. */
thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
thr->heap->lj.iserror = 0;
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
-}
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2);
-DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc) {
- duk_context *ctx;
+ /* Error handling complete, remove side effect protections. Caller
+ * will process pending finalizers.
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(thr->heap->error_not_allowed == 1);
+ thr->heap->error_not_allowed = 0;
+#endif
+ DUK_ASSERT(thr->heap->pf_prevent_count > 0);
+ thr->heap->pf_prevent_count--;
+ DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count));
+ /* thr->ptr_curr_pc is restored by
+ * duk__handle_safe_call_shared_unwind() which is also used for
+ * success path.
+ */
+}
+
+DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_callstack_top,
+#endif
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_instr_t **entry_ptr_curr_pc) {
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_UNREF(idx_retbase);
DUK_UNREF(num_stack_rets);
+ DUK_UNREF(entry_curr_thread);
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
- * risk of pointing to an already freed thread. This was indeed the
- * case in test-bug-multithread-valgrind.c, until duk_handle_call()
- * was fixed to restore thr->heap->curr_thread before rethrowing an
- * uncaught error.
+ /* Restore entry thread executor curr_pc stack frame pointer.
+ * XXX: would be enough to do in error path only, should nest
+ * cleanly in success path.
*/
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = (duk_uint8_t) entry_thread_state;
-
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
+ thr->ptr_curr_pc = entry_ptr_curr_pc;
thr->heap->call_recursion_depth = entry_call_recursion_depth;
/* stack discipline consistency check */
- DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
+ DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
/* A debugger forced interrupt check is not needed here, as
* problematic safe calls are not caused by side effects.
@@ -57076,471 +63544,291 @@ DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
#endif
}
-/*
- * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
- * function (initial) Duktape.Thread.resume().
- *
- * Compared to normal calls handled by duk_handle_call(), there are a
- * bunch of differences:
- *
- * - the call is never protected
- * - there is no C recursion depth increase (hence an "ignore recursion
- * limit" flag is not applicable)
- * - instead of making the call, this helper just performs the thread
- * setup and returns; the bytecode executor then restarts execution
- * internally
- * - ecmascript functions are never 'vararg' functions (they access
- * varargs through the 'arguments' object)
- *
- * The callstack of the target contains an earlier Ecmascript call in case
- * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
- * is empty in case of an initial Duktape.Thread.resume().
- *
- * The first thing to do here is to figure out whether an ecma-to-ecma
- * call is actually possible. It's not always the case if the target is
- * a bound function; the final function may be native. In that case,
- * return an error so caller can fall back to a normal call path.
- */
-
-DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t entry_valstack_bottom_index;
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
- duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
- duk_idx_t nargs; /* # argument registers target function wants (< 0 => never for ecma calls) */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
- duk_activation *act;
- duk_hobject *env;
- duk_bool_t use_tailcall;
+DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
+ duk_safe_call_function func,
+ void *udata,
+ duk_idx_t num_stack_args,
+ duk_idx_t num_stack_rets) {
+ duk_activation *entry_act;
+ duk_size_t entry_valstack_bottom_byteoff;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_valstack_end_byteoff;
+ duk_size_t entry_callstack_top;
+ duk_size_t entry_callstack_preventcount;
+#endif
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
+ duk_jmpbuf *old_jmpbuf_ptr = NULL;
+ duk_jmpbuf our_jmpbuf;
+ duk_idx_t idx_retbase;
+ duk_int_t retval;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
+ DUK_ASSERT(duk_get_top(thr) >= num_stack_args); /* Caller ensures. */
- /* XXX: assume these? */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
+ DUK_STATS_INC(thr->heap, stats_safecall_all);
- /* no need to handle thread state book-keeping here */
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
- (thr->state == DUK_HTHREAD_STATE_RUNNING &&
- thr->heap->curr_thread == thr));
-
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur. If we end up not making the
- * call we must restore the value.
+ /* Value stack reserve handling: safe call assumes caller has reserved
+ * space for nrets (assuming optimal unwind processing). Value stack
+ * reserve is not stored/restored as for normal calls because a safe
+ * call conceptually happens in the same activation.
*/
- entry_ptr_curr_pc = thr->ptr_curr_pc;
- duk_hthread_sync_and_null_currpc(thr);
- /* if a tail call:
- * - an Ecmascript activation must be on top of the callstack
- * - there cannot be any active catchstack entries
- */
+ /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */
+ entry_act = thr->callstack_curr;
+ entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
#if defined(DUK_USE_ASSERTIONS)
- if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
- duk_size_t our_callstack_index;
- duk_size_t i;
-
- DUK_ASSERT(thr->callstack_top >= 1);
- our_callstack_index = thr->callstack_top - 1;
- DUK_ASSERT_DISABLE(our_callstack_index >= 0);
- DUK_ASSERT(our_callstack_index < thr->callstack_size);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
-
- /* No entry in the catchstack which would actually catch a
- * throw can refer to the callstack entry being reused.
- * There *can* be catchstack entries referring to the current
- * callstack entry as long as they don't catch (e.g. label sites).
- */
-
- for (i = 0; i < thr->catchstack_top; i++) {
- DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
- DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
- }
- }
-#endif /* DUK_USE_ASSERTIONS */
+ entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ entry_callstack_top = thr->callstack_top;
+ entry_callstack_preventcount = thr->callstack_preventcount;
+#endif
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
+ idx_retbase = duk_get_top(thr) - num_stack_args; /* not a valid stack index if num_stack_args == 0 */
+ DUK_ASSERT(idx_retbase >= 0);
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
- /* XXX: rework */
- idx_func = duk_normalize_index(thr, -num_stack_args - 2);
- idx_args = idx_func + 2;
+ DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args); /* Caller ensures. */
+ DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets); /* Caller ensures. */
- DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
- "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
- "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
+ /* Cannot portably debug print a function pointer, hence 'func' not printed! */
+ DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
+ "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
+ "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, "
+ "entry_curr_thread=%p, entry_thread_state=%ld",
(void *) thr,
(long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
- (long) idx_func,
- (long) idx_args,
- (long) entry_valstack_bottom_index));
+ (long) num_stack_rets,
+ (long) duk_get_top(thr),
+ (long) idx_retbase,
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (void *) entry_act,
+ (long) entry_valstack_bottom_byteoff,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
- if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
- /* XXX: assert? compiler is responsible for this never happening */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
+ /* Setjmp catchpoint setup. */
+ old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
+ thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * If the final target function cannot be handled by an ecma-to-ecma
- * call, return to the caller with a return value indicating this case.
- * The bound chain is resolved and the caller can resume with a plain
- * function call.
+ /* Prevent yields for the duration of the safe call. This only
+ * matters if the executor makes safe calls to functions that
+ * yield, this doesn't currently happen.
*/
+ thr->callstack_preventcount++;
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- if (func == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
- thr->ptr_curr_pc = entry_ptr_curr_pc;
- return 0;
- }
- /* XXX: tv_func is not actually needed */
-
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func));
-
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- duk_get_tval(ctx, idx_func + 1)));
-
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
-
- /* [ ... func this arg1 ... argN ] */
-
- /*
- * Preliminary activation record and valstack manipulation.
- * The concrete actions depend on whether the we're dealing
- * with a tail call (reuse an existing activation), a resume,
- * or a normal call.
- *
- * The basic actions, in varying order, are:
- *
- * - Check stack size for call handling
- * - Grow call stack if necessary (non-tail-calls)
- * - Update current activation (idx_retval) if necessary
- * (non-tail, non-resume calls)
- * - Move start of args (idx_args) to valstack bottom
- * (tail calls)
- *
- * Don't touch valstack_bottom or valstack_top yet so that Duktape API
- * calls work normally.
- */
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
+ if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
+ /* Success path. */
+#endif
+ DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
- /* XXX: some overlapping code; cleanup */
- use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
-#if !defined(DUK_USE_TAILCALL)
- DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
+ duk__handle_safe_call_inner(thr,
+ func,
+ udata,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_valstack_bottom_byteoff,
+ entry_callstack_top,
#endif
- if (use_tailcall) {
- /* tailcall cannot be flagged to resume calls, and a
- * previous frame must exist
- */
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets);
- act = thr->callstack + thr->callstack_top - 1;
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- /* See: test-bug-tailcall-preventyield-assert.c. */
- DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
- use_tailcall = 0;
- } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
- DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
- use_tailcall = 0;
- }
- }
+ DUK_STATS_INC(thr->heap, stats_safecall_nothrow);
- if (use_tailcall) {
- duk_tval *tv1, *tv2;
- duk_size_t cs_index;
- duk_int_t i_stk; /* must be signed for loop structure */
- duk_idx_t i_arg;
+ /* Either pointer may be NULL (at entry), so don't assert */
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- /*
- * Tailcall handling
- *
- * Although the callstack entry is reused, we need to explicitly unwind
- * the current activation (or simulate an unwind). In particular, the
- * current activation must be closed, otherwise something like
- * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
- * because there may be non-error-catching label entries in valid tail calls.
+ /* If calls happen inside the safe call, these are restored by
+ * whatever calls are made. Reserve cannot decrease.
*/
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
- DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
- (long) (thr->callstack_top - 1)));
-
- /* 'act' already set above */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
-
- /* Unwind catchstack entries referring to the callstack entry we're reusing */
- cs_index = thr->callstack_top - 1;
- DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
- for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
- duk_catcher *cat = thr->catchstack + i_stk;
- if (cat->callstack_index != cs_index) {
- /* 'i' is the first entry we'll keep */
- break;
- }
- }
- duk_hthread_catchstack_unwind(thr, i_stk + 1);
-
- /* Unwind the topmost callstack entry before reusing it */
- DUK_ASSERT(thr->callstack_top > 0);
- duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
-
- /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
- thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
- act = thr->callstack + thr->callstack_top - 1;
-
- /* Start filling in the activation */
- act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- /* don't want an intermediate exposed state with invalid pc */
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_HOBJECT_INCREF(thr, func);
- act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
-#endif
-
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
-#if defined(DUK_USE_TAILCALL)
-#error incorrect options: tail calls enabled with function caller property
-#endif
- /* XXX: this doesn't actually work properly for tail calls, so
- * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- * is in use.
- */
- duk__update_func_caller_prop(thr, func);
- act = thr->callstack + thr->callstack_top - 1;
+ retval = DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+ DUK_UNREF(exc);
+#else
+ } else {
+ /* Error path. */
#endif
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
- DUK_ACT_FLAG_TAILCALLED);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
- DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
- DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
- act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
- /*
- * Manipulate valstack so that args are on the current bottom and the
- * previous caller's 'this' binding (which is the value preceding the
- * current bottom) is replaced with the new 'this' binding:
- *
- * [ ... this_old | (crud) func this_new arg1 ... argN ]
- * --> [ ... this_new | arg1 ... argN ]
- *
- * For tail calling to work properly, the valstack bottom must not grow
- * here; otherwise crud would accumulate on the valstack.
- */
-
- tv1 = thr->valstack_bottom - 1;
- tv2 = thr->valstack_bottom + idx_func + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
- DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
-
- for (i_arg = 0; i_arg < idx_args; i_arg++) {
- /* XXX: block removal API primitive */
- /* Note: 'func' is popped from valstack here, but it is
- * already reachable from the activation.
- */
- duk_remove(ctx, 0);
+ retval = DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
+ if (!what) {
+ what = "unknown";
}
- idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
- idx_args = 0;
-
- /* [ ... this_new | arg1 ... argN ] */
- } else {
- DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
- (long) (thr->callstack_top)));
-
- duk_hthread_callstack_grow(thr);
-
- if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
- DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
- } else {
- DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
- act->idx_retval = entry_valstack_bottom_index + idx_func;
- }
-
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
- thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
-
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT :
- 0);
- act->func = func;
- act->var_env = NULL;
- act->lex_env = NULL;
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ DUK_UNREF(exc);
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-
- DUK_HOBJECT_INCREF(thr, func); /* act->func */
-
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- duk__update_func_caller_prop(thr, func);
- act = thr->callstack + thr->callstack_top - 1;
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
+ retval = DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
+ try {
+ DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ DUK_UNREF(exc);
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
+ retval = DUK_EXEC_ERROR;
+ }
}
+#endif
- /* [ ... func this arg1 ... argN ] (not tail call)
- * [ this | arg1 ... argN ] (tail call)
- *
- * idx_args updated to match
- */
-
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * Delayed creation (on demand) is handled in duk_js_var.c.
- */
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
- /* XXX: unify handling with native call. */
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ duk__handle_safe_call_shared_unwind(thr,
+ idx_retbase,
+ num_stack_rets,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
+#endif
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_ptr_curr_pc);
- if (!DUK_HOBJECT_HAS_NEWENV(func)) {
- /* use existing env (e.g. for non-strict eval); cannot have
- * an own 'arguments' object (but can refer to the existing one)
- */
+ /* Restore preventcount. */
+ thr->callstack_preventcount--;
+ DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount);
- duk__handle_oldenv_for_call(thr, func, act);
+ /* Final asserts. */
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
+ DUK_ASSERT(thr->state == entry_thread_state);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
+ DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
+ /* Pending side effects. */
+ DUK_REFZERO_CHECK_FAST(thr);
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
+ return retval;
+}
- if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
- /* no need to create environment record now; leave as NULL */
- DUK_ASSERT(act->lex_env == NULL);
- DUK_ASSERT(act->var_env == NULL);
- goto env_done;
- }
+/*
+ * Property-based call (foo.noSuch()) error setup: replace target function
+ * on stack top with a specially tagged (hidden Symbol) error which gets
+ * thrown in call handling at the proper spot to follow Ecmascript semantics.
+ */
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
- DUK_ASSERT(env != NULL);
+#if defined(DUK_USE_VERBOSE_ERRORS)
+DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key) {
+ const char *str1, *str2, *str3;
+ duk_idx_t entry_top;
- /* [ ... arg1 ... argN envobj ] */
+ entry_top = duk_get_top(thr);
- /* original input stack before nargs/nregs handling must be
- * intact for 'arguments' object
+ /* Must stabilize pointers first. Argument convention is a bit awkward,
+ * it comes from the executor call site where some arguments may not be
+ * on the value stack (consts).
*/
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
-
- /* [ ... arg1 ... argN envobj ] */
-
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, act->lex_env);
- DUK_HOBJECT_INCREF(thr, act->var_env);
- duk_pop(ctx);
+ duk_push_tval(thr, tv_base);
+ duk_push_tval(thr, tv_key);
+ duk_push_tval(thr, tv_targ);
- env_done:
- /* [ ... arg1 ... argN ] */
+ DUK_GC_TORTURE(thr->heap);
- /*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
+ /* We only push an error, replacing the call target (at idx_func)
+ * with the error to ensure side effects come out correctly:
+ * - Property read
+ * - Call argument evaluation
+ * - Callability check and error thrown.
+ *
+ * A hidden Symbol on the error object pushed here is used by
+ * call handling to figure out the error is to be thrown as is.
+ * It is CRITICAL that the hidden Symbol can never occur on a
+ * user visible object that may get thrown.
*/
- duk__adjust_valstack_and_top(thr,
- num_stack_args,
- idx_args,
- nregs,
- nargs,
- func);
-
- /*
- * Shift to new valstack_bottom.
- */
+#if defined(DUK_USE_PARANOID_ERRORS)
+ str1 = duk_get_type_name(thr, -1);
+ str2 = duk_get_type_name(thr, -2);
+ str3 = duk_get_type_name(thr, -3);
+ duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
+#else
+ str1 = duk_push_string_readable(thr, -1);
+ str2 = duk_push_string_readable(thr, -3);
+ str3 = duk_push_string_readable(thr, -5);
+ duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
+#endif
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ duk_push_true(thr);
+ duk_put_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET); /* Marker property, reuse _Target. */
- /*
- * Return to bytecode executor, which will resume execution from
- * the topmost activation.
- */
+ /* [ <nregs> propValue <variable> error ] */
+ duk_replace(thr, entry_top - 1);
+ duk_set_top(thr, entry_top);
- return 1;
+ DUK_ASSERT(!duk_is_callable(thr, -1)); /* Critical so that call handling will throw the error. */
}
-#line 1 "duk_js_compiler.c"
+#endif /* DUK_USE_VERBOSE_ERRORS */
+
+/* automatic undefs */
+#undef DUK__AUGMENT_CALL_RELAX_COUNT
/*
* Ecmascript compiler.
*
@@ -57552,8 +63840,8 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* statement level, and an operator precedence based top-down approach
* for the expression level. The attempt is to minimize the C stack
* depth. Bytecode is generated directly without an intermediate
- * representation (tree), at the cost of needing two passes over each
- * function.
+ * representation (tree), at the cost of needing two (and sometimes
+ * three) passes over each function.
*
* The top-down recursive parser functions are named "duk__parse_XXX".
*
@@ -57564,17 +63852,32 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
*
* A few typing notes:
*
- * - duk_regconst_t: unsigned, no marker value for "none"
- * - duk_reg_t: signed, < 0 = none
+ * - duk_regconst_t: signed, highest bit set (< 0) means constant,
+ * some call sites use -1 for "none" (equivalent to constant 0x7fffffff)
* - PC values: duk_int_t, negative values used as markers
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-/* if highest bit of a register number is set, it refers to a constant instead */
-#define DUK__CONST_MARKER DUK_JS_CONST_MARKER
+/* If highest bit of a register number is set, it refers to a constant instead.
+ * When interpreted as a signed value, this means const values are always
+ * negative (when interpreted as two's complement). For example DUK__ISREG_TEMP()
+ * uses this approach to avoid an explicit DUK__ISREG() check (the condition is
+ * logically "'x' is a register AND 'x' >= temp_first").
+ */
+#define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER
+#define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER)
+#define DUK__ISREG(x) ((x) >= 0)
+#define DUK__ISCONST(x) ((x) < 0)
+#define DUK__ISREG_TEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= temp_first && x >= 0 by comparing as signed. */
+#define DUK__ISREG_NOTTEMP(comp_ctx,x) ((duk_uint32_t) (x) < (duk_uint32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= 0 && x < temp_first by interpreting as unsigned. */
+#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
+#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
+#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
+#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
+#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
-/* for array and object literals */
+/* Init value set size for array and object literals. */
#define DUK__MAX_ARRAY_INIT_VALUES 20
#define DUK__MAX_OBJECT_INIT_PAIRS 10
@@ -57582,23 +63885,27 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
#define DUK__GETCONST_MAX_CONSTS_CHECK 256
/* These limits are based on bytecode limits. Max temps is limited
- * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
+ * by duk_hcompfunc nargs/nregs fields being 16 bits.
*/
#define DUK__MAX_CONSTS DUK_BC_BC_MAX
#define DUK__MAX_FUNCS DUK_BC_BC_MAX
#define DUK__MAX_TEMPS 0xffffL
/* Initial bytecode size allocation. */
-#define DUK__BC_INITIAL_INSTS 256
+#if defined(DUK_USE_PREFER_SIZE)
+#define DUK__BC_INITIAL_INSTS 16
+#else
+#define DUK__BC_INITIAL_INSTS 256
+#endif
#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_increase((comp_ctx)); \
+ duk__comp_recursion_increase((comp_ctx)); \
} while (0)
#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_decrease((comp_ctx)); \
+ duk__comp_recursion_decrease((comp_ctx)); \
} while (0)
/* Value stack slot limits: these are quite approximate right now, and
@@ -57631,30 +63938,27 @@ DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
/* function helpers */
DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
-DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind);
+DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg);
+DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
/* code emission */
DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
-#if 0 /* unused */
DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
-#endif
DUK_LOCAL_DECL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c);
DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b);
+DUK_LOCAL_DECL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c);
#if 0 /* unused */
DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
+DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b);
#endif
DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc);
+DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc);
DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
-DUK_LOCAL_DECL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c);
-DUK_LOCAL_DECL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b);
-DUK_LOCAL_DECL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc);
-DUK_LOCAL_DECL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags);
-DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
-DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
+DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
+DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
@@ -57666,44 +63970,47 @@ DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regco
DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
/* ivalue/ispec helpers */
+DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst);
+DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h);
DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
-DUK_LOCAL_DECL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
+DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
+DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
+DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next);
DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL
duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
-DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg);
+DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg);
DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL
duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags);
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
#endif
DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
/* identifier handling */
-DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
+DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
+DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
/* label handling */
DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id);
DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest);
-DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
+DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len);
/* top-down expression parser */
DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
@@ -57717,23 +64024,23 @@ DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_sma
/* convenience helpers */
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
-DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
-DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
@@ -57743,10 +64050,9 @@ DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_
DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags);
/* statement parsing */
-DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
+DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
@@ -57764,8 +64070,14 @@ DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allo
DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token);
DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
-DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
+DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
+DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
+
+#define DUK__FUNC_FLAG_DECL (1 << 0) /* Parsing a function declaration. */
+#define DUK__FUNC_FLAG_GETSET (1 << 1) /* Parsing an object literal getter/setter. */
+#define DUK__FUNC_FLAG_METDEF (1 << 2) /* Parsing an object literal method definition shorthand. */
+#define DUK__FUNC_FLAG_PUSHNAME_PASS1 (1 << 3) /* Push function name when creating template (first pass only). */
+#define DUK__FUNC_FLAG_USE_PREVTOKEN (1 << 4) /* Use prev_token to start function parsing (workaround for object literal). */
/*
* Parser control values for tokens. The token table is ordered by the
@@ -57799,14 +64111,15 @@ DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, d
#define DUK__BP_SHIFT 26
#define DUK__BP_ADDITIVE 28
#define DUK__BP_MULTIPLICATIVE 30
-#define DUK__BP_POSTFIX 32
-#define DUK__BP_CALL 34
-#define DUK__BP_MEMBER 36
+#define DUK__BP_EXPONENTIATION 32
+#define DUK__BP_POSTFIX 34
+#define DUK__BP_CALL 36
+#define DUK__BP_MEMBER 38
#define DUK__TOKEN_LBP_BP_MASK 0x1f
#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
-#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
+#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* unused */
#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
@@ -57885,6 +64198,7 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
+ DUK__MK_LBP(DUK__BP_EXPONENTIATION), /* DUK_TOK_EXP */
DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */
DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */
DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
@@ -57905,6 +64219,7 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
+ DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EXP_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
@@ -57920,7 +64235,7 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
* Misc helpers
*/
-DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(comp_ctx != NULL);
DUK_ASSERT(comp_ctx->recursion_depth >= 0);
if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
@@ -57929,7 +64244,7 @@ DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
comp_ctx->recursion_depth++;
}
-DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(comp_ctx != NULL);
DUK_ASSERT(comp_ctx->recursion_depth > 0);
comp_ctx->recursion_depth--;
@@ -57957,10 +64272,10 @@ DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compil
DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t regexp;
- DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
+ DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0); /* unsigned */
+ DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
/*
* Use current token to decide whether a RegExp can follow.
@@ -57980,7 +64295,7 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
regexp = 0;
}
- if (expect >= 0 && comp_ctx->curr_token.t != expect) {
+ if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) {
DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
(long) expect, (long) comp_ctx->curr_token.t));
DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
@@ -57988,8 +64303,8 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
/* make current token the previous; need to fiddle with valstack "backing store" */
DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
- duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
- duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
+ duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
+ duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
/* parse new token */
duk_lexer_parse_js_input_element(&comp_ctx->lex,
@@ -58003,14 +64318,14 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
(long) comp_ctx->curr_token.t_nores,
(long) comp_ctx->curr_token.start_line,
(long) comp_ctx->curr_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx),
(long) comp_ctx->prev_token.t,
(long) comp_ctx->prev_token.t_nores,
(long) comp_ctx->prev_token.start_line,
(long) comp_ctx->prev_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx)));
}
/* advance, expecting current token to be a specific token; parse next token in regexp context */
@@ -58031,13 +64346,12 @@ DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_idx_t entry_top;
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
func->h_name = NULL;
func->h_consts = NULL;
func->h_funcs = NULL;
@@ -58048,46 +64362,46 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
func->h_varmap = NULL;
#endif
- duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
+ duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
/* code_idx = entry_top + 0 */
- duk_push_array(ctx);
+ duk_push_array(thr);
func->consts_idx = entry_top + 1;
- func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
+ func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1);
DUK_ASSERT(func->h_consts != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->funcs_idx = entry_top + 2;
- func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
+ func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2);
DUK_ASSERT(func->h_funcs != NULL);
DUK_ASSERT(func->fnum_next == 0);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->decls_idx = entry_top + 3;
- func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
+ func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3);
DUK_ASSERT(func->h_decls != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->labelnames_idx = entry_top + 4;
- func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
+ func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4);
DUK_ASSERT(func->h_labelnames != NULL);
- duk_push_dynamic_buffer(ctx, 0);
+ duk_push_dynamic_buffer(thr, 0);
func->labelinfos_idx = entry_top + 5;
- func->h_labelinfos = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 5);
+ func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5);
DUK_ASSERT(func->h_labelinfos != NULL);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
- duk_push_array(ctx);
+ duk_push_array(thr);
func->argnames_idx = entry_top + 6;
- func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
+ func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6);
DUK_ASSERT(func->h_argnames != NULL);
- duk_push_object_internal(ctx);
+ duk_push_bare_object(thr);
func->varmap_idx = entry_top + 7;
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
+ func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7);
DUK_ASSERT(func->h_varmap != NULL);
}
@@ -58095,25 +64409,24 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
/* reset bytecode buffer but keep current size; pass 2 will
* require same amount or more.
*/
DUK_BW_RESET_SIZE(thr, &func->bw_code);
- duk_hobject_set_length_zero(thr, func->h_consts);
+ duk_set_length(thr, func->consts_idx, 0);
/* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
func->fnum_next = 0;
- /* duk_hobject_set_length_zero(thr, func->h_funcs); */
- duk_hobject_set_length_zero(thr, func->h_labelnames);
+ /* duk_set_length(thr, func->funcs_idx, 0); */
+ duk_set_length(thr, func->labelnames_idx, 0);
duk_hbuffer_reset(thr, func->h_labelinfos);
/* keep func->h_argnames; it is fixed for all passes */
/* truncated in case pass 3 needed */
- duk_push_object_internal(ctx);
- duk_replace(ctx, func->varmap_idx);
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
+ duk_push_bare_object(thr);
+ duk_replace(thr, func->varmap_idx);
+ func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx);
DUK_ASSERT(func->h_varmap != NULL);
}
@@ -58122,7 +64435,6 @@ DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
*/
DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h_varmap;
duk_hstring *h_key;
duk_tval *tv;
@@ -58131,7 +64443,7 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
/* [ ... varmap ] */
- h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
+ h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1);
DUK_ASSERT(h_varmap != NULL);
ret = 0;
@@ -58162,20 +64474,19 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
}
}
- duk_compact(ctx, -1);
+ duk_compact_m1(thr);
return ret;
}
-/* convert duk_compiler_func into a function template, leaving the result
+/* Convert duk_compiler_func into a function template, leaving the result
* on top of stack.
*/
/* XXX: awkward and bloated asm -- use faster internal accesses */
-DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind) {
+DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hcompiledfunction *h_res;
+ duk_hcompfunc *h_res;
duk_hbuffer_fixed *h_data;
duk_size_t consts_count;
duk_size_t funcs_count;
@@ -58188,6 +64499,11 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
duk_instr_t *p_instr;
duk_compiler_instr *q_instr;
duk_tval *tv;
+ duk_bool_t keep_varmap;
+ duk_bool_t keep_formals;
+#if !defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_size_t formals_length;
+#endif
DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
@@ -58197,9 +64513,10 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
/* Valstack should suffice here, required on function valstack init */
- (void) duk_push_compiledfunction(ctx);
- h_res = (duk_hcompiledfunction *) DUK_GET_HOBJECT_NEGIDX(ctx, -1); /* XXX: specific getter */
+ h_res = duk_push_hcompfunc(thr);
DUK_ASSERT(h_res != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */
if (func->is_function) {
DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
@@ -58228,7 +64545,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
}
- if (func->is_function && !func->is_decl && func->h_name != NULL && !force_no_namebind) {
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ if (func->is_function && func->is_namebinding && func->h_name != NULL) {
/* Object literal set/get functions have a name (property
* name) but must not have a lexical name binding, see
* test-bug-getset-func-name.js.
@@ -58236,6 +64554,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
}
+#endif
if (func->is_strict) {
DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
@@ -58247,6 +64566,11 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
}
+ if (func->is_constructable) {
+ DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE"));
+ DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res);
+ }
+
/*
* Build function fixed size 'data' buffer, which contains bytecode,
* constants, and inner function references.
@@ -58272,11 +64596,10 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
(long) funcs_count, (long) sizeof(duk_hobject *),
(long) code_size, (long) data_size));
- duk_push_fixed_buffer(ctx, data_size);
- h_data = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_data != NULL);
+ duk_push_fixed_buffer_nozero(thr, data_size);
+ h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(thr, -1);
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
+ DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
DUK_HEAPHDR_INCREF(thr, h_data);
p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
@@ -58292,7 +64615,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
}
p_func = (duk_hobject **) p_const;
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_res, p_func);
+ DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func);
for (i = 0; i < funcs_count; i++) {
duk_hobject *h;
DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
@@ -58301,7 +64624,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h));
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h));
*p_func++ = h;
DUK_HOBJECT_INCREF(thr, h);
@@ -58310,7 +64633,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
}
p_instr = (duk_instr_t *) p_func;
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_res, p_instr);
+ DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr);
/* copy bytecode instructions one at a time */
q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
@@ -58321,7 +64644,26 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
- duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
+ duk_pop(thr); /* 'data' (and everything in it) is reachable through h_res now */
+
+ /*
+ * Init non-property result fields
+ *
+ * 'nregs' controls how large a register frame is allocated.
+ *
+ * 'nargs' controls how many formal arguments are written to registers:
+ * r0, ... r(nargs-1). The remaining registers are initialized to
+ * undefined.
+ */
+
+ DUK_ASSERT(func->temp_max >= 0);
+ h_res->nregs = (duk_uint16_t) func->temp_max;
+ h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
+ DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ h_res->start_line = (duk_uint32_t) func->min_line;
+ h_res->end_line = (duk_uint32_t) func->max_line;
+#endif
/*
* Init object properties
@@ -58334,48 +64676,89 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
/* [ ... res ] */
- /* _Varmap: omitted if function is guaranteed not to do slow path identifier
- * accesses or if it would turn out to be empty of actual register mappings
- * after a cleanup. When debugging is enabled, we always need the varmap to
- * be able to lookup variables at any point.
+ /* _Varmap: omitted if function is guaranteed not to do a slow path
+ * identifier access that might be caught by locally declared variables.
+ * The varmap can also be omitted if it turns out empty of actual
+ * register mappings after a cleanup. When debugging is enabled, we
+ * always need the varmap to be able to lookup variables at any point.
*/
+
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (1) {
+ DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled"));
+ keep_varmap = 1;
#else
- if (func->id_access_slow || /* directly uses slow accesses */
- func->may_direct_eval || /* may indirectly slow access through a direct eval */
- funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
+ if (func->id_access_slow_own || /* directly uses slow accesses that may match own variables */
+ func->id_access_arguments || /* accesses 'arguments' directly */
+ func->may_direct_eval || /* may indirectly slow access through a direct eval */
+ funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
+ DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions"));
+ keep_varmap = 1;
+ } else {
+ DUK_DD(DUK_DDPRINT("dropping _Varmap"));
+ keep_varmap = 0;
+ }
#endif
+
+ if (keep_varmap) {
duk_int_t num_used;
- duk_dup(ctx, func->varmap_idx);
+ duk_dup(thr, func->varmap_idx);
num_used = duk__cleanup_varmap(comp_ctx);
DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
+ (duk_tval *) duk_get_tval(thr, -1), (long) num_used));
if (num_used > 0) {
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
} else {
- DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
- duk_pop(ctx);
+ DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add"));
+ duk_pop(thr);
}
}
- /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
- if (1) {
- /* XXX: Add a proper condition. If formals list is omitted, recheck
- * handling for 'length' in duk_js_push_closure(); it currently relies
- * on _Formals being set. Removal may need to be conditional to debugging
- * being enabled/disabled too.
+ /* _Formals: omitted if function is guaranteed not to need a (non-strict)
+ * arguments object, and _Formals.length matches nargs exactly.
+ *
+ * Non-arrow functions can't see an outer function's 'argument' binding
+ * (because they have their own), but arrow functions can. When arrow
+ * functions are added, this condition would need to be added:
+ * inner_arrow_funcs_count > 0 inner arrow functions may access 'arguments'
+ */
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled"));
+ keep_formals = 1;
+#else
+ formals_length = duk_get_length(thr, func->argnames_idx);
+ if (formals_length != (duk_size_t) h_res->nargs) {
+ /* Nargs not enough for closure .length: keep _Formals regardless
+ * of its length. Shouldn't happen in practice at the moment.
*/
- duk_dup(ctx, func->argnames_idx);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
+ DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs"));
+ keep_formals = 1;
+ } else if ((func->id_access_arguments || func->may_direct_eval) &&
+ (formals_length > 0)) {
+ /* Direct eval (may access 'arguments') or accesses 'arguments'
+ * explicitly: keep _Formals unless it is zero length.
+ */
+ DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0"));
+ keep_formals = 1;
+ } else {
+ DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added"));
+ keep_formals = 0;
+ }
+#endif
+
+ if (keep_formals) {
+ duk_dup(thr, func->argnames_idx);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
}
/* name */
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
if (func->h_name) {
- duk_push_hstring(ctx, func->h_name);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_hstring(thr, func->h_name);
+ DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(thr, -1)));
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
}
+#endif /* DUK_USE_FUNC_NAME_PROPERTY */
/* _Source */
#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
@@ -58419,8 +64802,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
*/
#if 0
- duk_push_string(ctx, "XXX");
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_string(thr, "XXX");
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
#endif
}
#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
@@ -58434,7 +64817,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
/* XXX: if assertions enabled, walk through all valid PCs
* and check line mapping.
@@ -58443,55 +64826,38 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
#endif /* DUK_USE_PC2LINE */
/* fileName */
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
if (comp_ctx->h_filename) {
/*
* Source filename (or equivalent), for identifying thrown errors.
*/
- duk_push_hstring(ctx, comp_ctx->h_filename);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_hstring(thr, comp_ctx->h_filename);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
}
-
- /*
- * Init remaining result fields
- *
- * 'nregs' controls how large a register frame is allocated.
- *
- * 'nargs' controls how many formal arguments are written to registers:
- * r0, ... r(nargs-1). The remaining registers are initialized to
- * undefined.
- */
-
- DUK_ASSERT(func->temp_max >= 0);
- h_res->nregs = (duk_uint16_t) func->temp_max;
- h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
- DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- h_res->start_line = (duk_uint32_t) func->min_line;
- h_res->end_line = (duk_uint32_t) func->max_line;
#endif
DUK_DD(DUK_DDPRINT("converted function: %!ixT",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Compact the function template.
*/
- duk_compact(ctx, -1);
+ duk_compact_m1(thr);
/*
* Debug dumping
*/
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
{
- duk_hcompiledfunction *h;
+ duk_hcompfunc *h;
duk_instr_t *p, *p_start, *p_end;
- h = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- p_start = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, h);
- p_end = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, h);
+ h = (duk_hcompfunc *) duk_get_hobject(thr, -1);
+ p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h);
+ p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h);
p = p_start;
while (p < p_end) {
@@ -58516,7 +64882,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
* Some emission helpers understand the range of target and source reg/const
* values and automatically emit shuffling code if necessary. This is the
* case when the slot in question (A, B, C) is used in the standard way and
- * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
+ * for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ).
*
* The standard way is that:
* - slot A is a target register
@@ -58542,7 +64908,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
*/
/* Code emission flags, passed in the 'opcode' field. Opcode + flags
- * fit into 16 bits for now, so use duk_small_uint.t.
+ * fit into 16 bits for now, so use duk_small_uint_t.
*/
#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
@@ -58550,12 +64916,9 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
-#define DUK__EMIT_FLAG_B_IS_TARGETSOURCE (1 << 14) /* slot B is both a target and a source (used by extraops like DUK_EXTRAOP_INSTOF */
+#define DUK__EMIT_FLAG_BC_REGCONST (1 << 14) /* slots B and C are reg/const */
#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
-/* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
-/* XXX: opcode specific assertions on when consts are allowed */
-
/* XXX: macro smaller than call? */
DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func;
@@ -58606,7 +64969,7 @@ DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
instr->ins = ins;
#if defined(DUK_USE_PC2LINE)
- instr->line = line;
+ instr->line = (duk_uint32_t) line;
#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (line < comp_ctx->curr_func.min_line) {
@@ -58664,11 +65027,9 @@ DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
#endif
}
-#if 0 /* unused */
DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
}
-#endif
/* Important main primitive. */
DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) {
@@ -58677,6 +65038,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
duk_int_t b_out = -1;
duk_int_t c_out = -1;
duk_int_t tmp;
+ duk_small_uint_t op = op_flags & 0xffU;
DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
(unsigned long) op_flags, (long) a, (long) b, (long) c));
@@ -58690,6 +65052,9 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
+ DUK_ASSERT(DUK__ISREG(a));
+ DUK_ASSERT(b != -1); /* Not 'none'. */
+ DUK_ASSERT(c != -1); /* Not 'none'. */
/* Input shuffling happens before the actual operation, while output
* shuffling happens afterwards. Output shuffling decisions are still
@@ -58697,7 +65062,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
* are recorded into X_out variables.
*/
- /* Slot A */
+ /* Slot A: currently no support for reg/const. */
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
@@ -58714,20 +65079,21 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
} else {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) {
- /* Special handling for call setup instructions. The target
- * is expressed indirectly, but there is no output shuffling.
+ /* Output shuffle needed after main operation */
+ a_out = a;
+
+ /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are
+ * consecutive.
+ */
+ DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) ||
+ (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1));
+ if (op == DUK_OP_CSVAR) {
+ /* For CSVAR the limit is one smaller because output shuffle
+ * must be able to express 'a + 1' in BC.
*/
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
- duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
- DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
- DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
- DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
- op_flags++; /* indirect opcode follows direct */
- } else {
- /* Output shuffle needed after main operation */
- a_out = a;
+ if (a + 1 > DUK_BC_BC_MAX) {
+ goto error_outofregs;
+ }
}
}
a = tmp;
@@ -58736,20 +65102,24 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
goto error_outofregs;
}
- /* Slot B */
+ /* Slot B: reg/const support, mapped to bit 0 of opcode. */
- if (b & DUK__CONST_MARKER) {
+ if ((b & DUK__CONST_MARKER) != 0) {
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
- DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
- DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
b = b & ~DUK__CONST_MARKER;
#if defined(DUK_USE_SHUFFLE_TORTURE)
if (0) {
#else
if (b <= 0xff) {
#endif
- ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
+ if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
+ /* Opcode follows B/C reg/const convention. */
+ DUK_ASSERT((op & 0x01) == 0);
+ ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0); /* const flag for B */
+ } else {
+ DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x", op_flags));
+ }
} else if (b <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
tmp = comp_ctx->curr_func.shuffle2;
@@ -58779,19 +65149,15 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Output shuffle needed after main operation */
b_out = b;
}
- if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET) || (op_flags & DUK__EMIT_FLAG_B_IS_TARGETSOURCE)) {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_CALL || op == DUK_OP_NEW ||
- op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
- /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
+ if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) {
+ if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
+ /* Special handling for MPUTOBJ/MPUTARR shuffling.
* For each, slot B identifies the first register of a range
* of registers, so normal shuffling won't work. Instead,
* an indirect version of the opcode is used.
*/
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
- DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
- DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
op_flags++; /* indirect opcode follows direct */
@@ -58806,9 +65172,9 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
}
}
- /* Slot C */
+ /* Slot C: reg/const support, mapped to bit 1 of opcode. */
- if (c & DUK__CONST_MARKER) {
+ if ((c & DUK__CONST_MARKER) != 0) {
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
c = c & ~DUK__CONST_MARKER;
@@ -58817,7 +65183,13 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
#else
if (c <= 0xff) {
#endif
- ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
+ if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
+ /* Opcode follows B/C reg/const convention. */
+ DUK_ASSERT((op & 0x02) == 0);
+ ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0); /* const flag for C */
+ } else {
+ DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x", op_flags));
+ }
} else if (c <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
tmp = comp_ctx->curr_func.shuffle3;
@@ -58847,21 +65219,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Output shuffle needed after main operation */
c_out = c;
} else {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_EXTRA &&
- (a == DUK_EXTRAOP_INITGET || a == DUK_EXTRAOP_INITSET)) {
- /* Special shuffling for INITGET/INITSET, where slot C
- * identifies a register pair and cannot be shuffled
- * normally. Use an indirect variant instead.
- */
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
- duk__emit_load_int32_noshuffle(comp_ctx, tmp, c);
- DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
- DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
- a++; /* indirect opcode follows direct */
- } else {
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
- }
+ duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
}
c = tmp;
} else {
@@ -58872,11 +65230,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Main operation */
- DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
+ DUK_ASSERT(a >= DUK_BC_A_MIN);
DUK_ASSERT(a <= DUK_BC_A_MAX);
- DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
+ DUK_ASSERT(b >= DUK_BC_B_MIN);
DUK_ASSERT(b <= DUK_BC_B_MAX);
- DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
+ DUK_ASSERT(c >= DUK_BC_C_MIN);
DUK_ASSERT(c <= DUK_BC_C_MAX);
ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
@@ -58903,6 +65261,16 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ASSERT(b_out < 0);
DUK_ASSERT(c_out < 0);
duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
+
+ if (op == DUK_OP_CSVAR) {
+ /* Special handling for CSVAR shuffling. The variable lookup
+ * results in a <value, this binding> pair in successive
+ * registers so use two shuffle registers and two output
+ * loads. (In practice this is dead code because temp/const
+ * limit is reached first.)
+ */
+ duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1));
+ }
} else if (b_out >= 0) {
DUK_ASSERT(a_out < 0);
DUK_ASSERT(c_out < 0);
@@ -58919,13 +65287,44 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
}
+/* For many of the helpers below it'd be technically correct to add
+ * "no shuffle" flags for parameters passed in as zero. For example,
+ * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and
+ * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags. However, since the
+ * C value is 0, it'll never get shuffled so adding the flag is just
+ * unnecessary additional code. This is unfortunately not true for
+ * "shuffle torture" mode which needs special handling.
+ */
+
DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) {
- duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, b, 0);
+#if defined(DUK_USE_SHUFFLE_TORTURE)
+ op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C;
+#endif
+ duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
+}
+
+DUK_LOCAL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c) {
+#if defined(DUK_USE_SHUFFLE_TORTURE)
+ op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
+#endif
+ duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c);
}
#if 0 /* unused */
DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
- duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, 0, 0);
+#if defined(DUK_USE_SHUFFLE_TORTURE)
+ op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C;
+#endif
+ duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
+}
+#endif
+
+#if 0 /* unused */
+DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) {
+#if defined(DUK_USE_SHUFFLE_TORTURE)
+ op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C;
+#endif
+ duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0);
}
#endif
@@ -58934,11 +65333,12 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
duk_int_t tmp;
/* allow caller to give a const number with the DUK__CONST_MARKER */
+ DUK_ASSERT(bc != -1); /* Not 'none'. */
bc = bc & (~DUK__CONST_MARKER);
DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
- DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
+ DUK_ASSERT(bc >= DUK_BC_BC_MIN);
DUK_ASSERT(bc <= DUK_BC_BC_MAX);
DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
@@ -58958,6 +65358,13 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
duk__emit(comp_ctx, ins);
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
goto error_outofregs;
+ } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) {
+ comp_ctx->curr_func.needs_shuffle = 1;
+ tmp = comp_ctx->curr_func.shuffle1;
+ duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
+ op_flags |= DUK_BC_CALL_FLAG_INDIRECT;
+ ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
+ duk__emit(comp_ctx, ins);
} else if (a <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
tmp = comp_ctx->curr_func.shuffle1;
@@ -58978,6 +65385,13 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
}
+DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) {
+#if defined(DUK_USE_SHUFFLE_TORTURE)
+ op |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
+#endif
+ duk__emit_a_bc(comp_ctx, op, 0, bc);
+}
+
DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
duk_instr_t ins;
@@ -58986,6 +65400,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
+ DUK_ASSERT(abc != -1); /* Not 'none'. */
if (abc <= DUK_BC_ABC_MAX) {
;
@@ -59004,59 +65419,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
}
-DUK_LOCAL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- b,
- c);
-}
-
-DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- b,
- 0);
-}
-
-DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc) {
- DUK_ASSERT_DISABLE(extraop >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT(extraop <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_bc(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- extraop,
- bc);
-}
-
-DUK_LOCAL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B |
- DUK__EMIT_FLAG_NO_SHUFFLE_C | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- 0,
- 0);
-}
-
-DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
+DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
/* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
* would only shuffle once (instead of twice). The current code works
* though, and has a smaller compiler footprint.
@@ -59077,7 +65440,7 @@ DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t re
}
}
-DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
}
@@ -59085,11 +65448,11 @@ DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, d
/* Used by duk__emit*() calls so that we don't shuffle the loadints that
* are needed to handle indirect opcodes.
*/
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
}
#else
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
/* When torture not enabled, can just use the same helper because
* 'reg' won't get spilled.
*/
@@ -59113,7 +65476,7 @@ DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
duk_int_t ret;
ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
- duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
+ duk__emit_op_only(comp_ctx, DUK_OP_JUMP);
return ret;
}
@@ -59127,7 +65490,8 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump
duk_compiler_instr *instr;
duk_size_t offset;
- offset = jump_pc * sizeof(duk_compiler_instr),
+ DUK_ASSERT(jump_pc >= 0);
+ offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr);
instr = (duk_compiler_instr *) (void *)
DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
&comp_ctx->curr_func.bw_code,
@@ -59139,7 +65503,7 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump
#endif
instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
#if defined(DUK_USE_PC2LINE)
- instr->line = line;
+ instr->line = (duk_uint32_t) line;
#endif
DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
@@ -59186,7 +65550,7 @@ DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_p
DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) {
duk_compiler_instr *instr;
- DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
+ DUK_ASSERT(DUK__ISREG(reg_catch));
instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
@@ -59211,7 +65575,7 @@ DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst
/* No catch variable, e.g. a try-finally; replace LDCONST with
* NOP to avoid a bogus LDCONST.
*/
- instr->ins = DUK_ENC_OP_A(DUK_OP_EXTRA, DUK_EXTRAOP_NOP);
+ instr->ins = DUK_ENC_OP(DUK_OP_NOP);
}
instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
@@ -59222,23 +65586,21 @@ DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst
}
DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 0 /*false*/,
- regconst,
- 0 /*unused*/);
+ duk_small_uint_t op;
+
+ op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C;
+ duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
}
DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 1 /*true*/,
- regconst,
- 0 /*unused*/);
+ duk_small_uint_t op;
+
+ op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C;
+ duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
}
DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_INVALID, 0);
+ duk__emit_op_only(comp_ctx, DUK_OP_INVALID);
}
/*
@@ -59275,7 +65637,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
continue;
}
- target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
+ target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
DUK_ASSERT(target_pc1 >= 0);
DUK_ASSERT(target_pc1 < n);
@@ -59290,7 +65652,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
continue;
}
- target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
+ target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
(long) i, (long) target_pc1, (long) target_pc2));
@@ -59312,24 +65674,18 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
* Intermediate value helpers
*/
-#define DUK__ISREG(comp_ctx,x) (((x) & DUK__CONST_MARKER) == 0)
-#define DUK__ISCONST(comp_ctx,x) (((x) & DUK__CONST_MARKER) != 0)
-#define DUK__ISTEMP(comp_ctx,x) (DUK__ISREG((comp_ctx), (x)) && (duk_regconst_t) (x) >= (duk_regconst_t) ((comp_ctx)->curr_func.temp_first))
-#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
-#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
-#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
-#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
-#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
-
/* Flags for intermediate value coercions. A flag for using a forced reg
* is not needed, the forced_reg argument suffices and generates better
* code (it is checked as it is used).
*/
+/* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented
+ * by ispec/ivalue operations.
+ */
#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
-/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
+/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */
#if 0 /* enable manually for dumping */
#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
@@ -59338,7 +65694,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
(long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
+ duk_get_tval(comp_ctx->thr, x->valstack_idx)));
}
DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
@@ -59346,58 +65702,58 @@ DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
"x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
(long) x->t, (long) x->op,
(long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
+ duk_get_tval(comp_ctx->thr, x->x1.valstack_idx),
(long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
+ duk_get_tval(comp_ctx->thr, x->x2.valstack_idx)));
}
#else
#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
#endif
-DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
+DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) {
+ x->t = DUK_IVAL_PLAIN;
+ x->x1.t = DUK_ISPEC_REGCONST;
+ x->x1.regconst = regconst;
+}
+
+DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+ x->t = DUK_IVAL_PLAIN;
+ x->x1.t = DUK_ISPEC_VALUE;
+ duk_replace(comp_ctx->thr, x->x1.valstack_idx);
+}
+
+DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+ x->t = DUK_IVAL_VAR;
+ x->x1.t = DUK_ISPEC_VALUE;
+ duk_replace(comp_ctx->thr, x->x1.valstack_idx);
+}
+
+DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) {
+ DUK_ASSERT(h != NULL);
+ duk_push_hstring(comp_ctx->thr, h);
+ duk__ivalue_var_fromstack(comp_ctx, x);
+}
+DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
dst->t = src->t;
dst->regconst = src->regconst;
- duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
+ duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx);
}
DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
-
dst->t = src->t;
dst->op = src->op;
dst->x1.t = src->x1.t;
dst->x1.regconst = src->x1.regconst;
dst->x2.t = src->x2.t;
dst->x2.regconst = src->x2.regconst;
- duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
- duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
+ duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx);
+ duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx);
}
-/* XXX: to util */
-DUK_LOCAL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
- duk_small_int_t c;
- duk_int32_t t;
-
- c = DUK_FPCLASSIFY(x);
- if (c == DUK_FP_NORMAL || (c == DUK_FP_ZERO && !DUK_SIGNBIT(x))) {
- /* Don't allow negative zero as it will cause trouble with
- * LDINT+LDINTX. But positive zero is OK.
- */
- t = (duk_int32_t) x;
- if ((duk_double_t) t == x) {
- *ival = t;
- return 1;
- }
- }
-
- return 0;
-}
-
-DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
- duk_reg_t res;
+DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
+ duk_regconst_t res;
res = comp_ctx->curr_func.temp_next;
comp_ctx->curr_func.temp_next += num;
@@ -59414,11 +65770,11 @@ DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t
return res;
}
-DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
return duk__alloctemps(comp_ctx, 1);
}
-DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
+DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) {
comp_ctx->curr_func.temp_next = temp_next;
if (temp_next > comp_ctx->curr_func.temp_max) {
comp_ctx->curr_func.temp_max = temp_next;
@@ -59428,19 +65784,18 @@ DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_
/* get const for value at valstack top */
DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_compiler_func *f = &comp_ctx->curr_func;
duk_tval *tv1;
duk_int_t i, n, n_check;
- n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
+ n = (duk_int_t) duk_get_length(thr, f->consts_idx);
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv1 != NULL);
#if defined(DUK_USE_FASTINT)
/* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE(tv1);
+ DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1);
#endif
/* Sanity workaround for handling functions with a large number of
@@ -59457,8 +65812,8 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
if (duk_js_samevalue(tv1, tv2)) {
DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
(duk_tval *) tv1, (long) i));
- duk_pop(ctx);
- return (duk_regconst_t) (i | DUK__CONST_MARKER);
+ duk_pop(thr);
+ return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER;
}
}
@@ -59468,8 +65823,26 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
(duk_tval *) tv1, (long) n));
- (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
- return (duk_regconst_t) (n | DUK__CONST_MARKER);
+ (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n); /* invalidates tv1, tv2 */
+ return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER;
+}
+
+DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) {
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_compiler_func *f = &comp_ctx->curr_func;
+ duk_bool_t ret;
+
+ DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
+ (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc);
+ ret = !duk_is_number(comp_ctx->thr, -1); /* now only number/string, so conservative check */
+ duk_pop(comp_ctx->thr);
+ return ret;
+#else
+ DUK_UNREF(comp_ctx);
+ DUK_UNREF(rc);
+ DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
+ return 0;
+#endif
}
/* Get the value represented by an duk_ispec to a register or constant.
@@ -59491,16 +65864,15 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL
duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
"forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
(long) x->t,
(long) x->regconst,
- (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->valstack_idx),
(long) forced_reg,
(unsigned long) flags,
(long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
@@ -59511,7 +65883,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
case DUK_ISPEC_VALUE: {
duk_tval *tv;
- tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -59520,21 +65892,21 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
* values can occur during compilation as a result of e.g.
* the 'void' operator.
*/
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest);
+ return dest;
}
case DUK_TAG_NULL: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDNULL, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest);
+ return dest;
}
case DUK_TAG_BOOLEAN: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx,
- (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_EXTRAOP_LDTRUE : DUK_EXTRAOP_LDFALSE),
- (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk__emit_bc(comp_ctx,
+ (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE),
+ dest);
+ return dest;
}
case DUK_TAG_POINTER: {
DUK_UNREACHABLE();
@@ -59542,7 +65914,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
case DUK_TAG_STRING: {
duk_hstring *h;
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_regconst_t constidx;
h = DUK_TVAL_GET_STRING(tv);
@@ -59557,7 +65929,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
/* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
}
#endif
- duk_dup(ctx, x->valstack_idx);
+ duk_dup(thr, x->valstack_idx);
constidx = duk__getconst(comp_ctx);
if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
@@ -59565,8 +65937,8 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
+ return dest;
}
case DUK_TAG_OBJECT: {
DUK_UNREACHABLE();
@@ -59585,7 +65957,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
#endif
default: {
/* number */
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_regconst_t constidx;
duk_double_t dval;
duk_int32_t ival;
@@ -59601,53 +65973,53 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
* Currently always prefer LDINT+LDINTX over a double constant.
*/
- if (duk__is_whole_get_int32(dval, &ival)) {
+ if (duk_is_whole_get_int32_nonegzero(dval, &ival)) {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
duk__emit_load_int32(comp_ctx, dest, ival);
- return (duk_regconst_t) dest;
+ return dest;
}
}
- duk_dup(ctx, x->valstack_idx);
+ duk_dup(thr, x->valstack_idx);
constidx = duk__getconst(comp_ctx);
if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
return constidx;
} else {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
+ return dest;
}
}
} /* end switch */
}
case DUK_ISPEC_REGCONST: {
if (forced_reg >= 0) {
- if (x->regconst & DUK__CONST_MARKER) {
+ if (DUK__ISCONST(x->regconst)) {
duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
- } else if (x->regconst != (duk_regconst_t) forced_reg) {
+ } else if (x->regconst != forced_reg) {
duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
} else {
; /* already in correct reg */
}
- return (duk_regconst_t) forced_reg;
+ return forced_reg;
}
DUK_ASSERT(forced_reg < 0);
- if (x->regconst & DUK__CONST_MARKER) {
+ if (DUK__ISCONST(x->regconst)) {
if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
+ return dest;
}
return x->regconst;
}
- DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
- if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
+ DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst));
+ if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) {
+ duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
+ return dest;
}
return x->regconst;
}
@@ -59656,11 +66028,11 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
}
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
return 0;
}
-DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
(void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
}
@@ -59670,17 +66042,16 @@ DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x,
* The duk_ivalue argument ('x') is converted into a plain value as a
* side effect.
*/
-DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
"forced_reg=%ld",
(long) x->t, (long) x->op,
(long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
(long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
(long) forced_reg));
switch (x->t) {
@@ -59688,11 +66059,10 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
return;
}
/* XXX: support unary arithmetic ivalues (useful?) */
- case DUK_IVAL_ARITH:
- case DUK_IVAL_ARITH_EXTRAOP: {
+ case DUK_IVAL_ARITH: {
duk_regconst_t arg1;
duk_regconst_t arg2;
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_tval *tv1;
duk_tval *tv2;
@@ -59701,8 +66071,8 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
/* inline arithmetic check for constant values */
/* XXX: use the exactly same arithmetic function here as in executor */
if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
- tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
- tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
+ tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx);
+ tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx);
DUK_ASSERT(tv1 != NULL);
DUK_ASSERT(tv2 != NULL);
@@ -59714,19 +66084,39 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
duk_double_t d3;
- duk_bool_t accept = 1;
+ duk_bool_t accept_fold = 1;
DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
(double) d1, (double) d2, (long) x->op));
switch (x->op) {
- case DUK_OP_ADD: d3 = d1 + d2; break;
- case DUK_OP_SUB: d3 = d1 - d2; break;
- case DUK_OP_MUL: d3 = d1 * d2; break;
- case DUK_OP_DIV: d3 = d1 / d2; break;
- default: accept = 0; break;
+ case DUK_OP_ADD: {
+ d3 = d1 + d2;
+ break;
+ }
+ case DUK_OP_SUB: {
+ d3 = d1 - d2;
+ break;
+ }
+ case DUK_OP_MUL: {
+ d3 = d1 * d2;
+ break;
+ }
+ case DUK_OP_DIV: {
+ d3 = d1 / d2;
+ break;
+ }
+ case DUK_OP_EXP: {
+ d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
+ break;
+ }
+ default: {
+ d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */
+ accept_fold = 0;
+ break;
+ }
}
- if (accept) {
+ if (accept_fold) {
duk_double_union du;
du.d = d3;
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
@@ -59738,11 +66128,13 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
return;
}
} else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
- /* inline string concatenation */
- duk_dup(ctx, x->x1.valstack_idx);
- duk_dup(ctx, x->x2.valstack_idx);
- duk_concat(ctx, 2);
- duk_replace(ctx, x->x1.valstack_idx);
+ /* Inline string concatenation. No need to check for
+ * symbols, as all inputs are valid Ecmascript strings.
+ */
+ duk_dup(thr, x->x1.valstack_idx);
+ duk_dup(thr, x->x2.valstack_idx);
+ duk_concat(thr, 2);
+ duk_replace(thr, x->x1.valstack_idx);
x->t = DUK_IVAL_PLAIN;
DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
return;
@@ -59754,73 +66146,28 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
/* If forced reg, use it as destination. Otherwise try to
* use either coerced ispec if it is a temporary.
- *
- * When using extraops, avoid reusing arg2 as dest because that
- * would lead to an LDREG shuffle below. We still can't guarantee
- * dest != arg2 because we may have a forced_reg.
*/
if (forced_reg >= 0) {
dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2) && x->t != DUK_IVAL_ARITH_EXTRAOP) {
- dest = (duk_reg_t) arg2;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
+ dest = arg1;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
+ dest = arg2;
} else {
dest = DUK__ALLOCTEMP(comp_ctx);
}
- /* Extraop arithmetic opcodes must have destination same as
- * first source. If second source matches destination we need
- * a temporary register to avoid clobbering the second source.
- *
- * XXX: change calling code to avoid this situation in most cases.
- */
+ DUK_ASSERT(DUK__ISREG(dest));
+ duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2);
- if (x->t == DUK_IVAL_ARITH_EXTRAOP) {
- if (!(DUK__ISREG(comp_ctx, arg1) && (duk_reg_t) arg1 == dest)) {
- if (DUK__ISREG(comp_ctx, arg2) && (duk_reg_t) arg2 == dest) {
- /* arg2 would be clobbered so reassign it to a temp. */
- duk_reg_t tempreg;
- tempreg = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, tempreg, arg2);
- arg2 = tempreg;
- }
-
- if (DUK__ISREG(comp_ctx, arg1)) {
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, arg1);
- } else {
- DUK_ASSERT(DUK__ISCONST(comp_ctx, arg1));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, arg1);
- }
- }
-
- /* Note: special DUK__EMIT_FLAG_B_IS_TARGETSOURCE
- * used to indicate that B is both a source and a
- * target register. When shuffled, it needs to be
- * both input and output shuffled.
- */
- DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
- duk__emit_extraop_b_c(comp_ctx,
- x->op | DUK__EMIT_FLAG_B_IS_TARGET |
- DUK__EMIT_FLAG_B_IS_TARGETSOURCE,
- (duk_regconst_t) dest,
- (duk_regconst_t) arg2);
-
- } else {
- DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
- duk__emit_a_b_c(comp_ctx, x->op, (duk_regconst_t) dest, arg1, arg2);
- }
-
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
+ duk__ivalue_regconst(x, dest);
return;
}
case DUK_IVAL_PROP: {
/* XXX: very similar to DUK_IVAL_ARITH - merge? */
duk_regconst_t arg1;
duk_regconst_t arg2;
- duk_reg_t dest;
+ duk_regconst_t dest;
/* Need a short reg/const, does not have to be a mutable temp. */
arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
@@ -59837,40 +66184,38 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
if (forced_reg >= 0) {
dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2)) {
- dest = (duk_reg_t) arg2;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
+ dest = arg1;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
+ dest = arg2;
} else {
dest = DUK__ALLOCTEMP(comp_ctx);
}
- duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, (duk_regconst_t) dest, arg1, arg2);
+ duk__emit_a_b_c(comp_ctx,
+ DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
+ dest,
+ arg1,
+ arg2);
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
+ duk__ivalue_regconst(x, dest);
return;
}
case DUK_IVAL_VAR: {
/* x1 must be a string */
- duk_reg_t dest;
- duk_reg_t reg_varbind;
+ duk_regconst_t dest;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
- duk_dup(ctx, x->x1.valstack_idx);
+ duk_dup(thr, x->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) reg_varbind;
+ duk__ivalue_regconst(x, reg_varbind);
} else {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
+ duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname);
+ duk__ivalue_regconst(x, dest);
}
return;
}
@@ -59881,7 +66226,7 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
}
}
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
return;
}
@@ -59892,7 +66237,7 @@ DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- duk_reg_t temp;
+ duk_regconst_t temp;
/* If duk__ivalue_toplain_raw() allocates a temp, forget it and
* restore next temp state.
@@ -59911,21 +66256,19 @@ DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue
DUK_LOCAL
duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_regconst_t reg;
DUK_UNREF(thr);
- DUK_UNREF(ctx);
DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
"forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
(long) x->t, (long) x->op,
(long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
(long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
(long) forced_reg,
(unsigned long) flags,
(long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
@@ -59938,18 +66281,17 @@ duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
/* then to a register */
reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = reg;
+ duk__ivalue_regconst(x, reg);
return reg;
}
-DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
}
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
}
#endif
@@ -59979,21 +66321,19 @@ DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk
* Identifier handling
*/
-DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_varname;
- duk_reg_t ret;
+ duk_regconst_t ret;
DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Special name handling
*/
- h_varname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_varname != NULL);
+ h_varname = duk_known_hstring(thr, -1);
if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
@@ -60007,7 +66347,7 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
if (comp_ctx->curr_func.with_depth > 0) {
DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
- goto slow_path;
+ goto slow_path_own;
}
/*
@@ -60018,23 +66358,40 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
* name will use slow path.
*/
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_number(ctx, -1)) {
- ret = duk_to_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ if (duk_is_number(thr, -1)) {
+ ret = duk_to_int(thr, -1);
+ duk_pop(thr);
} else {
- duk_pop(ctx);
- goto slow_path;
+ duk_pop(thr);
+ if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) {
+ DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap"));
+ goto slow_path_own;
+ } else {
+ /* In this case we're doing a variable lookup that doesn't
+ * match our own variables, so _Varmap won't be needed at
+ * run time.
+ */
+ DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap"));
+ goto slow_path_notown;
+ }
}
DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
return ret;
- slow_path:
- DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
+ slow_path_notown:
+ DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable"));
comp_ctx->curr_func.id_access_slow = 1;
- return (duk_reg_t) -1;
+ return (duk_regconst_t) -1;
+
+ slow_path_own:
+ DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable"));
+
+ comp_ctx->curr_func.id_access_slow = 1;
+ comp_ctx->curr_func.id_access_slow_own = 1;
+ return (duk_regconst_t) -1;
}
/* Lookup an identifier name in the current varmap, indicating whether the
@@ -60045,21 +66402,20 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
* return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
* is unsigned and doesn't have a "unused" / none value.
*/
-DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
+DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
/* [ ... varname ] */
- duk_dup_top(ctx);
+ duk_dup_top(thr);
reg_varbind = duk__lookup_active_register_binding(comp_ctx);
if (reg_varbind >= 0) {
*out_reg_varbind = reg_varbind;
*out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
} else {
rc_varname = duk__getconst(comp_ctx);
@@ -60079,7 +66435,6 @@ DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_
DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_size_t n;
duk_size_t new_size;
duk_uint8_t *p;
@@ -60107,13 +66462,13 @@ DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label,
}
}
- duk_push_hstring(ctx, h_label);
+ duk_push_hstring(thr, h_label);
DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
- (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
+ (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
new_size = (n + 1) * sizeof(duk_labelinfo);
duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
- /* XXX: spare handling, slow now */
+ /* XXX: slack handling, slow now */
/* relookup after possible realloc */
p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
@@ -60184,7 +66539,6 @@ DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t lab
/* XXX: awkward, especially the bunch of separate output values -> output struct? */
DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t *p;
duk_labelinfo *li_start, *li_end, *li;
duk_bool_t match = 0;
@@ -60192,7 +66546,7 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring
DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
(duk_heaphdr *) h_label, (long) is_break));
- DUK_UNREF(ctx);
+ DUK_UNREF(thr);
p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
li_start = (duk_labelinfo *) (void *) p;
@@ -60255,16 +66609,11 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring
*out_is_closest = (li == li_end - 1);
}
-DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
+DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_size_t new_size;
- /* XXX: duk_set_length */
- new_size = sizeof(duk_labelinfo) * (duk_size_t) len;
- duk_push_int(ctx, len);
- duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
- duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
+ duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len);
+ duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len);
}
/*
@@ -60282,15 +66631,19 @@ DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t
DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_reg_t reg_obj; /* result reg */
- duk_reg_t reg_temp; /* temp reg */
- duk_reg_t temp_start; /* temp reg value for start of loop */
+ duk_regconst_t reg_obj; /* result reg */
+ duk_regconst_t reg_temp; /* temp reg */
+ duk_regconst_t temp_start; /* temp reg value for start of loop */
duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
duk_small_uint_t num_values; /* number of values in current MPUTARR set */
duk_uarridx_t curr_idx; /* current (next) array index */
duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
duk_bool_t require_comma; /* next loop requires a comma */
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_int_t pc_newarr;
+ duk_compiler_instr *instr;
+#endif
/* DUK_TOK_LBRACKET already eaten, current token is right after that */
DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
@@ -60298,10 +66651,10 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
reg_obj = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_obj,
- 0); /* XXX: patch initial size afterwards? */
+#if !defined(DUK_USE_PREFER_SIZE)
+ pc_newarr = duk__get_current_pc(comp_ctx);
+#endif
+ duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */
temp_start = DUK__GETTEMP(comp_ctx);
/*
@@ -60391,15 +66744,23 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
DUK_OP_MPUTARR |
DUK__EMIT_FLAG_NO_SHUFFLE_C |
DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) temp_start,
- (duk_regconst_t) num_values);
+ reg_obj,
+ temp_start,
+ (duk_regconst_t) (num_values + 1));
init_idx = start_idx + num_values;
/* num_values and temp_start reset at top of outer loop */
}
}
+ /* Update initil size for NEWARR, doesn't need to be exact and is
+ * capped at A field limit.
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
+ instr = duk__get_instr_ptr(comp_ctx, pc_newarr);
+ instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx);
+#endif
+
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
duk__advance(comp_ctx);
@@ -60412,107 +66773,96 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_SETALEN,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) reg_temp);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE,
+ reg_obj,
+ reg_temp);
}
DUK__SETTEMP(comp_ctx, temp_start);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_obj;
+ duk__ivalue_regconst(res, reg_obj);
return;
syntax_error:
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
}
-/* duplicate/invalid key checks; returns 1 if syntax error */
-DUK_LOCAL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t key_flags;
-
- /* [ ... key_obj key ] */
-
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- /*
- * 'key_obj' tracks keys encountered so far by associating an
- * integer with flags with already encountered keys. The checks
- * below implement E5 Section 11.1.5, step 4 for production:
- *
- * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
- */
-
- duk_dup(ctx, -1); /* [ ... key_obj key key ] */
- duk_get_prop(ctx, -3); /* [ ... key_obj key val ] */
- key_flags = duk_to_int(ctx, -1);
- duk_pop(ctx); /* [ ... key_obj key ] */
-
- if (new_key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
- if ((key_flags & DUK__OBJ_LIT_KEY_PLAIN) && comp_ctx->curr_func.is_strict) {
- /* step 4.a */
- DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
- return 1;
- }
- if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
- /* step 4.c */
- DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
- return 1;
- }
+typedef struct {
+ duk_regconst_t reg_obj;
+ duk_regconst_t temp_start;
+ duk_small_uint_t num_pairs;
+ duk_small_uint_t num_total_pairs;
+} duk__objlit_state;
+
+DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) {
+ if (st->num_pairs > 0) {
+ /* - A is a source register (it's not a write target, but used
+ * to identify the target object) but can be shuffled.
+ * - B cannot be shuffled normally because it identifies a range
+ * of registers, the emitter has special handling for this
+ * (the "no shuffle" flag must not be set).
+ * - C is a non-register number and cannot be shuffled, but
+ * never needs to be.
+ */
+ DUK_ASSERT(st->num_pairs > 0);
+ duk__emit_a_b_c(comp_ctx,
+ DUK_OP_MPUTOBJ |
+ DUK__EMIT_FLAG_NO_SHUFFLE_C |
+ DUK__EMIT_FLAG_A_IS_SOURCE,
+ st->reg_obj,
+ st->temp_start,
+ (duk_regconst_t) (st->num_pairs * 2));
+ st->num_total_pairs += st->num_pairs;
+ st->num_pairs = 0;
+ }
+ DUK__SETTEMP(comp_ctx, st->temp_start);
+}
+
+DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) {
+ if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) {
+ /* same handling for identifiers and strings */
+ DUK_ASSERT(tok->str1 != NULL);
+ duk_push_hstring(comp_ctx->thr, tok->str1);
+ } else if (tok->t == DUK_TOK_NUMBER) {
+ /* numbers can be loaded as numbers and coerced on the fly */
+ duk_push_number(comp_ctx->thr, tok->num);
} else {
- if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
- /* step 4.b */
- DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
- return 1;
- }
- if (key_flags & new_key_flags) {
- /* step 4.d */
- DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
- return 1;
- }
+ return 1; /* error */
}
- new_key_flags |= key_flags;
- DUK_DDD(DUK_DDDPRINT("setting/updating key %!T flags: 0x%08lx -> 0x%08lx",
- (duk_tval *) duk_get_tval(ctx, -1),
- (unsigned long) key_flags,
- (unsigned long) new_key_flags));
- duk_dup(ctx, -1);
- duk_push_int(ctx, new_key_flags); /* [ ... key_obj key key flags ] */
- duk_put_prop(ctx, -4); /* [ ... key_obj key ] */
-
+ duk__ivalue_plain_fromstack(comp_ctx, res);
+ DUK__SETTEMP(comp_ctx, reg_temp + 1);
+ duk__ivalue_toforcedreg(comp_ctx, res, reg_temp);
+ DUK__SETTEMP(comp_ctx, reg_temp + 1);
return 0;
}
DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_obj; /* result reg */
- duk_reg_t reg_key; /* temp reg for key literal */
- duk_reg_t reg_temp; /* temp reg */
- duk_reg_t temp_start; /* temp reg value for start of loop */
+ duk__objlit_state st;
+ duk_regconst_t reg_temp; /* temp reg */
duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
- duk_small_uint_t num_pairs; /* number of pairs in current MPUTOBJ set */
duk_bool_t first; /* first value: comma must not precede the value */
duk_bool_t is_set, is_get; /* temps */
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_int_t pc_newobj;
+ duk_compiler_instr *instr;
+#endif
DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
- reg_obj = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_obj,
- 0); /* XXX: patch initial size afterwards? */
- temp_start = DUK__GETTEMP(comp_ctx);
+ st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */
+ st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */
+ st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */
+ st.num_total_pairs = 0; /* number of key/value pairs emitted overall */
- /* temp object for tracking / detecting duplicate keys */
- duk_push_object(ctx);
+#if !defined(DUK_USE_PREFER_SIZE)
+ pc_newobj = duk__get_current_pc(comp_ctx);
+#endif
+ duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj);
/*
* Emit initializers in sets of maximum max_init_pairs keys.
@@ -60523,207 +66873,198 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
first = 1;
for (;;) {
- num_pairs = 0;
- DUK__SETTEMP(comp_ctx, temp_start);
+ /*
+ * ES5 and ES2015+ provide a lot of different PropertyDefinition
+ * formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer.
+ *
+ * PropertyName can be IdentifierName (includes reserved words), a string
+ * literal, or a number literal. Note that IdentifierName allows 'get' and
+ * 'set' too, so we need to look ahead to the next token to distinguish:
+ *
+ * { get : 1 }
+ *
+ * and
+ *
+ * { get foo() { return 1 } }
+ * { get get() { return 1 } } // 'get' as getter propertyname
+ *
+ * Finally, a trailing comma is allowed.
+ *
+ * Key name is coerced to string at compile time (and ends up as a
+ * a string constant) even for numeric keys (e.g. "{1:'foo'}").
+ * These could be emitted using e.g. LDINT, but that seems hardly
+ * worth the effort and would increase code size.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld",
+ (long) comp_ctx->curr_token.t));
if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
break;
}
- for (;;) {
- /*
- * Three possible element formats:
- * 1) PropertyName : AssignmentExpression
- * 2) get PropertyName () { FunctionBody }
- * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
- *
- * PropertyName can be IdentifierName (includes reserved words), a string
- * literal, or a number literal. Note that IdentifierName allows 'get' and
- * 'set' too, so we need to look ahead to the next token to distinguish:
- *
- * { get : 1 }
- *
- * and
- *
- * { get foo() { return 1 } }
- * { get get() { return 1 } } // 'get' as getter propertyname
- *
- * Finally, a trailing comma is allowed.
- *
- * Key name is coerced to string at compile time (and ends up as a
- * a string constant) even for numeric keys (e.g. "{1:'foo'}").
- * These could be emitted using e.g. LDINT, but that seems hardly
- * worth the effort and would increase code size.
- */
-
- DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
- (long) comp_ctx->curr_token.t));
-
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- /* the outer loop will recheck and exit */
- break;
+ if (first) {
+ first = 0;
+ } else {
+ if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
+ goto syntax_error;
}
- if (num_pairs >= max_init_pairs) {
- /* MPUTOBJ emitted by outer loop */
+ duk__advance(comp_ctx);
+ if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
+ /* trailing comma followed by rcurly */
break;
}
+ }
- if (first) {
- first = 0;
- } else {
- if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
- goto syntax_error;
- }
- duk__advance(comp_ctx);
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- /* trailing comma followed by rcurly */
- break;
- }
+ /* Advance to get one step of lookup. */
+ duk__advance(comp_ctx);
+
+ /* Flush current MPUTOBJ if enough many pairs gathered. */
+ if (st.num_pairs >= max_init_pairs) {
+ duk__objlit_flush_keys(comp_ctx, &st);
+ DUK_ASSERT(st.num_pairs == 0);
+ }
+
+ /* Reset temp register state and reserve reg_temp and
+ * reg_temp + 1 for handling the current property.
+ */
+ DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs);
+ reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
+
+ /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
+ * currently treats them always like ordinary identifiers (DUK_TOK_GET
+ * and DUK_TOK_SET are unused). They need to be detected based on the
+ * identifier string content.
+ */
+
+ is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
+ comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
+ is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
+ comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
+ if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
+ /* getter/setter */
+ duk_int_t fnum;
+
+ duk__objlit_flush_keys(comp_ctx, &st);
+ DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); /* 2 regs are guaranteed to be allocated w.r.t. temp_max */
+ reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
+
+ if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) {
+ goto syntax_error;
}
- /* advance to get one step of lookup */
- duk__advance(comp_ctx);
+ /* curr_token = get/set name */
+ fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET);
- /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
- * currently treats them always like ordinary identifiers (DUK_TOK_GET
- * and DUK_TOK_SET are unused). They need to be detected based on the
- * identifier string content.
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_CLOSURE,
+ st.temp_start + 1,
+ (duk_regconst_t) fnum);
+
+ /* Slot C is used in a non-standard fashion (range of regs),
+ * emitter code has special handling for it (must not set the
+ * "no shuffle" flag).
*/
+ duk__emit_a_bc(comp_ctx,
+ (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE,
+ st.reg_obj,
+ st.temp_start); /* temp_start+0 = key, temp_start+1 = closure */
+
+ DUK_ASSERT(st.num_pairs == 0); /* temp state is reset on next loop */
+#if defined(DUK_USE_ES6)
+ } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
+ (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) {
+ duk_bool_t load_rc;
+
+ load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp);
+ DUK_UNREF(load_rc);
+ DUK_ASSERT(load_rc == 0); /* always succeeds because token is identifier */
+
+ duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1);
+ DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1);
+ duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1);
+
+ st.num_pairs++;
+ } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER ||
+ comp_ctx->prev_token.t == DUK_TOK_STRING ||
+ comp_ctx->prev_token.t == DUK_TOK_NUMBER) &&
+ comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
+ duk_int_t fnum;
- is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
- comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
- is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
- comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
- if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
- /* getter/setter */
- duk_int_t fnum;
-
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->curr_token.t_nores == DUK_TOK_STRING) {
- /* same handling for identifiers and strings */
- DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->curr_token.num);
- duk_to_string(ctx, -1);
- } else {
- goto syntax_error;
- }
+ /* Parsing-wise there's a small hickup here: the token parsing
+ * state is one step too advanced for the function parse helper
+ * compared to other cases. The current solution is an extra
+ * flag to indicate whether function parsing should use the
+ * current or the previous token to starting parsing from.
+ */
- DUK_ASSERT(duk_is_string(ctx, -1));
- if (duk__nud_object_literal_key_check(comp_ctx,
- (is_get ? DUK__OBJ_LIT_KEY_GET : DUK__OBJ_LIT_KEY_SET))) {
- goto syntax_error;
- }
- reg_key = duk__getconst(comp_ctx);
-
- if (num_pairs > 0) {
- /* - A is a source register (it's not a write target, but used
- * to identify the target object) but can be shuffled.
- * - B cannot be shuffled normally because it identifies a range
- * of registers, the emitter has special handling for this
- * (the "no shuffle" flag must not be set).
- * - C is a non-register number and cannot be shuffled, but
- * never needs to be.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_MPUTOBJ |
- DUK__EMIT_FLAG_NO_SHUFFLE_C |
- DUK__EMIT_FLAG_A_IS_SOURCE,
- reg_obj,
- temp_start,
- num_pairs);
- num_pairs = 0;
- DUK__SETTEMP(comp_ctx, temp_start);
- }
+ if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
+ goto syntax_error;
+ }
- /* curr_token = get/set name */
- fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
+ fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF);
- DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_key);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) fnum);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_CLOSURE,
+ reg_temp + 1,
+ (duk_regconst_t) fnum);
- /* Slot C is used in a non-standard fashion (range of regs),
- * emitter code has special handling for it (must not set the
- * "no shuffle" flag).
+ st.num_pairs++;
+#endif /* DUK_USE_ES6 */
+ } else {
+#if defined(DUK_USE_ES6)
+ if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) {
+ /* ES2015 computed property name. Executor ToPropertyKey()
+ * coerces the key at runtime.
*/
- duk__emit_extraop_b_c(comp_ctx,
- (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
- reg_obj,
- temp_start); /* temp_start+0 = key, temp_start+1 = closure */
-
- DUK__SETTEMP(comp_ctx, temp_start);
- } else {
- /* normal key/value */
- if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
- /* same handling for identifiers and strings */
- DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->prev_token.str1);
- } else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->prev_token.num);
- duk_to_string(ctx, -1);
- } else {
- goto syntax_error;
- }
-
- DUK_ASSERT(duk_is_string(ctx, -1));
- if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
+ DUK__SETTEMP(comp_ctx, reg_temp);
+ duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp);
+ duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
+
+ /* XXX: If next token is '(' we're dealing with
+ * the method shorthand with a computed name,
+ * e.g. { [Symbol.for('foo')](a,b) {} }. This
+ * form is not yet supported and causes a
+ * SyntaxError on the DUK_TOK_COLON check below.
+ */
+ }
+ else
+#endif /* DUK_USE_ES6 */
+ {
+ if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
goto syntax_error;
}
- reg_key = duk__getconst(comp_ctx);
+ }
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_key);
- duk__advance_expect(comp_ctx, DUK_TOK_COLON);
+ duk__advance_expect(comp_ctx, DUK_TOK_COLON);
- reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
- DUK__SETTEMP(comp_ctx, reg_temp);
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_temp + 1);
+ DUK__SETTEMP(comp_ctx, reg_temp + 1);
+ duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/);
- num_pairs++;
- }
+ st.num_pairs++;
}
+ } /* property loop */
- if (num_pairs > 0) {
- /* See MPUTOBJ comments above. */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_MPUTOBJ |
- DUK__EMIT_FLAG_NO_SHUFFLE_C |
- DUK__EMIT_FLAG_A_IS_SOURCE,
- reg_obj,
- temp_start,
- num_pairs);
+ /* Flush remaining properties. */
+ duk__objlit_flush_keys(comp_ctx, &st);
+ DUK_ASSERT(st.num_pairs == 0);
+ DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);
- /* num_pairs and temp_start reset at top of outer loop */
- }
- }
+ /* Update initial size for NEWOBJ. The init size doesn't need to be
+ * exact as the purpose is just to avoid object resizes in common
+ * cases. The size is capped to field A limit, and will be too high
+ * if the object literal contains duplicate keys (this is harmless but
+ * increases memory traffic if the object is compacted later on).
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
+ instr = duk__get_instr_ptr(comp_ctx, pc_newobj);
+ instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs);
+#endif
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
duk__advance(comp_ctx);
- DUK__SETTEMP(comp_ctx, temp_start);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_obj;
-
- DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop(ctx);
+ duk__ivalue_regconst(res, st.reg_obj);
return;
syntax_error:
@@ -60736,7 +67077,7 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
*/
DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_int_t nargs = 0;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
/* Note: expect that caller has already eaten the left paren */
@@ -60786,10 +67127,9 @@ DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_token *tk;
- duk_reg_t temp_at_entry;
- duk_small_int_t tok;
+ duk_regconst_t temp_at_entry;
+ duk_small_uint_t tok;
duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
/*
@@ -60815,47 +67155,42 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
/* PRIMARY EXPRESSIONS */
case DUK_TOK_THIS: {
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDTHIS,
- (duk_regconst_t) reg_temp);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__emit_bc(comp_ctx,
+ DUK_OP_LDTHIS,
+ reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
case DUK_TOK_IDENTIFIER: {
- res->t = DUK_IVAL_VAR;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_push_hstring(ctx, tk->str1);
- duk_replace(ctx, res->x1.valstack_idx);
+ duk__ivalue_var_hstring(comp_ctx, res, tk->str1);
return;
}
case DUK_TOK_NULL: {
- duk_push_null(ctx);
+ duk_push_null(thr);
goto plain_value;
}
case DUK_TOK_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
goto plain_value;
}
case DUK_TOK_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
goto plain_value;
}
case DUK_TOK_NUMBER: {
- duk_push_number(ctx, tk->num);
+ duk_push_number(thr, tk->num);
goto plain_value;
}
case DUK_TOK_STRING: {
DUK_ASSERT(tk->str1 != NULL);
- duk_push_hstring(ctx, tk->str1);
+ duk_push_hstring(thr, tk->str1);
goto plain_value;
}
case DUK_TOK_REGEXP: {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_reg_t reg_temp;
+#if defined(DUK_USE_REGEXP_SUPPORT)
+ duk_regconst_t reg_temp;
duk_regconst_t rc_re_bytecode; /* const */
duk_regconst_t rc_re_source; /* const */
@@ -60867,8 +67202,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
(duk_heaphdr *) tk->str2));
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_push_hstring(ctx, tk->str1);
- duk_push_hstring(ctx, tk->str2);
+ duk_push_hstring(thr, tk->str1);
+ duk_push_hstring(thr, tk->str2);
/* [ ... pattern flags ] */
@@ -60880,14 +67215,12 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
rc_re_source = duk__getconst(comp_ctx);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_REGEXP,
- (duk_regconst_t) reg_temp /*a*/,
+ DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp /*a*/,
rc_re_bytecode /*b*/,
rc_re_source /*c*/);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
return;
#else /* DUK_USE_REGEXP_SUPPORT */
goto syntax_error;
@@ -60935,14 +67268,41 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* and testcases/test-dev-new.js for a bunch of documented tests.
*/
- duk_reg_t reg_target;
+ duk_regconst_t reg_target;
duk_int_t nargs;
DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
- reg_target = DUK__ALLOCTEMP(comp_ctx);
+ reg_target = DUK__ALLOCTEMPS(comp_ctx, 2);
+
+#if defined(DUK_USE_ES6)
+ if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) {
+ /* new.target */
+ DUK_DDD(DUK_DDDPRINT("new.target"));
+ duk__advance(comp_ctx);
+ if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER ||
+ !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target")) {
+ goto syntax_error_newtarget;
+ }
+ if (comp_ctx->curr_func.is_global) {
+ goto syntax_error_newtarget;
+ }
+ duk__advance(comp_ctx);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_NEWTARGET,
+ reg_target);
+ duk__ivalue_regconst(res, reg_target);
+ return;
+ }
+#endif /* DUK_USE_ES6 */
+
duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_target + 1);
+ duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1); /* default instance */
+ DUK__SETTEMP(comp_ctx, reg_target + 2);
+
+ /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which
+ * makes the error message worse than for obj.noSuch().
+ */
if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
/* 'new' MemberExpression Arguments */
@@ -60956,20 +67316,14 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
nargs = 0;
}
- /* Opcode slot C is used in a non-standard way, so shuffling
- * is not allowed.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 0 /*unused*/,
- reg_target /*target*/,
- nargs /*num_args*/);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT,
+ nargs /*num_args*/,
+ reg_target /*target*/);
DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_target;
+ duk__ivalue_regconst(res, reg_target);
return;
}
@@ -60987,23 +67341,21 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* duk__parse_func_like_fnum().
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t fnum;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
/* curr_token follows 'function' */
- fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 0 /*is_setget*/);
+ fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/);
DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp /*a*/,
+ reg_temp /*a*/,
(duk_regconst_t) fnum /*bc*/);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -61022,8 +67374,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* resolving cases (the specification description is a bit confusing).
*/
- duk_reg_t reg_temp;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_temp;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
if (comp_ctx->curr_func.is_strict) {
@@ -61033,26 +67385,24 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK__SETTEMP(comp_ctx, temp_at_entry);
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
/* register bound variables are non-configurable -> always false */
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDFALSE,
- (duk_regconst_t) reg_temp);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_LDFALSE,
+ reg_temp);
} else {
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
rc_varname = duk__getconst(comp_ctx);
- duk__emit_a_b(comp_ctx,
- DUK_OP_DELVAR,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) rc_varname);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_DELVAR,
+ reg_temp,
+ rc_varname);
}
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
} else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_temp;
- duk_reg_t reg_obj;
+ duk_regconst_t reg_temp;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
DUK__SETTEMP(comp_ctx, temp_at_entry);
@@ -61060,24 +67410,22 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_DELPROP,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
+ DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp,
+ reg_obj,
rc_key);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
} else {
/* non-Reference deletion is always 'true', even in strict mode */
- duk_push_true(ctx);
+ duk_push_true(thr);
goto plain_value;
}
return;
}
case DUK_TOK_VOID: {
duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
goto plain_value;
}
case DUK_TOK_TYPEOF: {
@@ -61089,61 +67437,58 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
"at compile time, need to use special run-time handling"));
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_temp,
- rc_varname);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_TYPEOFID,
+ reg_temp,
+ rc_varname);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
}
- args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
- goto unary_extraop;
+ args = DUK_OP_TYPEOF;
+ goto unary;
}
case DUK_TOK_INCREMENT: {
- args = (DUK_OP_PREINCR << 8) + 0;
+ args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR;
goto preincdec;
}
case DUK_TOK_DECREMENT: {
- args = (DUK_OP_PREDECR << 8) + 0;
+ args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR;
goto preincdec;
}
case DUK_TOK_ADD: {
/* unary plus */
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
+ duk_is_number(thr, res->x1.valstack_idx)) {
/* unary plus of a number is identity */
- ;
return;
}
- args = (DUK_EXTRAOP_UNP << 8) + 0;
- goto unary_extraop;
+ args = DUK_OP_UNP;
+ goto unary;
}
case DUK_TOK_SUB: {
/* unary minus */
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
+ duk_is_number(thr, res->x1.valstack_idx)) {
/* this optimization is important to handle negative literals
* (which are not directly provided by the lexical grammar)
*/
duk_tval *tv_num;
duk_double_union du;
- tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
+ tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
DUK_ASSERT(tv_num != NULL);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
du.d = DUK_TVAL_GET_NUMBER(tv_num);
@@ -61152,13 +67497,13 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK_TVAL_SET_NUMBER(tv_num, du.d);
return;
}
- args = (DUK_EXTRAOP_UNM << 8) + 0;
- goto unary_extraop;
+ args = DUK_OP_UNM;
+ goto unary;
}
case DUK_TOK_BNOT: {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- args = (DUK_EXTRAOP_BNOT << 8) + 0;
- goto unary_extraop;
+ args = DUK_OP_BNOT;
+ goto unary;
}
case DUK_TOK_LNOT: {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
@@ -61168,7 +67513,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
*/
duk_tval *tv_val;
- tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
+ tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
DUK_ASSERT(tv_val != NULL);
if (DUK_TVAL_IS_NUMBER(tv_val)) {
duk_double_t d;
@@ -61184,7 +67529,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
return;
}
} else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
- duk_small_int_t v;
+ duk_small_uint_t v;
v = DUK_TVAL_GET_BOOLEAN(tv_val);
DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
DUK_ASSERT(v == 0 || v == 1);
@@ -61192,8 +67537,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
return;
}
}
- args = (DUK_EXTRAOP_LNOT << 8) + 0;
- goto unary_extraop;
+ args = DUK_OP_LNOT;
+ goto unary;
}
} /* end switch */
@@ -61201,105 +67546,110 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
return;
- unary_extraop:
+ unary:
{
- /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
- * is a reg-mapped variable works correctly (does not mutate the variable register).
- */
-
- duk_reg_t reg_temp;
- reg_temp = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
- duk__emit_extraop_bc(comp_ctx,
- (args >> 8),
- (duk_regconst_t) reg_temp);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ /* Unary opcodes use just the 'BC' register source because it
+ * matches current shuffle limits, and maps cleanly to 16 high
+ * bits of the opcode.
+ */
+
+ duk_regconst_t reg_src, reg_res;
+
+ reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/);
+ if (DUK__ISREG_TEMP(comp_ctx, reg_src)) {
+ reg_res = reg_src;
+ } else {
+ reg_res = DUK__ALLOCTEMP(comp_ctx);
+ }
+ duk__emit_a_bc(comp_ctx,
+ args,
+ reg_res,
+ reg_src);
+ duk__ivalue_regconst(res, reg_res);
return;
}
preincdec:
{
/* preincrement and predecrement */
- duk_reg_t reg_res;
- duk_small_uint_t args_op = args >> 8;
+ duk_regconst_t reg_res;
+ duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */
+ duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */
/* Specific assumptions for opcode numbering. */
DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
- DUK_ASSERT(DUK_OP_PREINCR + 8 == DUK_OP_PREINCP);
- DUK_ASSERT(DUK_OP_PREDECR + 8 == DUK_OP_PREDECP);
reg_res = DUK__ALLOCTEMP(comp_ctx);
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
+ h_varname = duk_known_hstring(thr, res->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
goto syntax_error;
}
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
- args_op, /* e.g. DUK_OP_PREINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
+ args_op1, /* e.g. DUK_OP_PREINCR */
+ reg_res,
+ reg_varbind);
} else {
duk__emit_a_bc(comp_ctx,
- args_op + 4, /* e.g. DUK_OP_PREINCV */
- (duk_regconst_t) reg_res,
+ args_op1 + 4, /* e.g. DUK_OP_PREINCV */
+ reg_res,
rc_varname);
}
DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
(duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
} else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
+ duk_regconst_t reg_obj; /* allocate to reg only (not const) */
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
- args_op + 8, /* e.g. DUK_OP_PREINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
+ args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */
+ reg_res,
+ reg_obj,
rc_key);
} else {
/* Technically return value is not needed because INVLHS will
* unconditially throw a ReferenceError. Coercion is necessary
* for proper semantics (consider ToNumber() called for an object).
- * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
+ * Use DUK_OP_UNP with a dummy register to get ToNumber().
*/
duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_UNP,
- reg_res); /* for side effects, result ignored */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
- }
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_res;
+ duk__emit_bc(comp_ctx,
+ DUK_OP_UNP,
+ reg_res); /* for side effects, result ignored */
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_INVLHS);
+ }
DUK__SETTEMP(comp_ctx, reg_res + 1);
+ duk__ivalue_regconst(res, reg_res);
return;
}
plain_value:
{
/* Stack top contains plain value */
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_replace(ctx, res->x1.valstack_idx);
+ duk__ivalue_plain_fromstack(comp_ctx, res);
return;
}
+#if defined(DUK_USE_ES6)
+ syntax_error_newtarget:
+ DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET);
+#endif
+
syntax_error:
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
}
@@ -61310,9 +67660,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
*/
DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_token *tk;
- duk_small_int_t tok;
+ duk_small_uint_t tok;
duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
/*
@@ -61362,8 +67711,8 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
res->t = DUK_IVAL_PROP;
duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- duk_replace(ctx, res->x2.valstack_idx);
+ duk_push_hstring(thr, comp_ctx->curr_token.str1);
+ duk_replace(thr, res->x2.valstack_idx);
res->x2.t = DUK_ISPEC_VALUE;
/* special RegExp literal handling after IdentifierName */
@@ -61405,16 +67754,12 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
case DUK_TOK_LPAREN: {
/* function call */
- duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
+ duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
duk_int_t nargs;
- duk_small_uint_t call_flags = 0;
+ duk_small_uint_t call_op = DUK_OP_CALL0;
- /*
- * XXX: attempt to get the call result to "next temp" whenever
- * possible to avoid unnecessary register shuffles.
- *
- * XXX: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
- * if the call target is a temporary register and at the top of the temp reg "stack".
+ /* XXX: attempt to get the call result to "next temp" whenever
+ * possible to avoid unnecessary register shuffles.
*/
/*
@@ -61427,13 +67772,12 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
/* Potential direct eval call detected, flag the CALL
* so that a run-time "direct eval" check is made and
@@ -61441,89 +67785,124 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* does not prevent 'eval' from being register bound.
*/
DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
- "-> enabling EVALCALL flag, marking function "
+ "-> using EVALCALL, marking function "
"as may_direct_eval"));
- call_flags |= DUK_BC_CALL_FLAG_EVALCALL;
-
+ call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL;
comp_ctx->curr_func.may_direct_eval = 1;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__emit_a_b(comp_ctx,
- DUK_OP_CSREG,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) reg_varbind);
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
+ reg_varbind,
+ reg_cs + 0);
} else {
+ /* XXX: expand target register or constant field to
+ * reduce shuffling.
+ */
+ DUK_ASSERT(DUK__ISCONST(rc_varname));
duk__emit_a_b(comp_ctx,
- DUK_OP_CSVAR,
- (duk_regconst_t) (reg_cs + 0),
+ DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_cs + 0,
rc_varname);
}
} else if (left->t == DUK_IVAL_PROP) {
+ /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i,
+ * E5 Section 10.4.3. There used to be a separate CSPROP opcode
+ * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST,
+ * CSPROP) and the same can be achieved with ordinary loads.
+ */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ duk_regconst_t reg_key;
+#endif
+
DUK_DDD(DUK_DDDPRINT("function call with property base"));
- duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 0); /* base */
- duk__ispec_toforcedreg(comp_ctx, &left->x2, reg_cs + 1); /* key */
+ /* XXX: For Math.sin() this generates: LDCONST + LDREG +
+ * GETPROPC + call. The LDREG is unnecessary because LDCONST
+ * could be loaded directly into reg_cs + 1. This doesn't
+ * happen now because a variable cannot be in left->x1 of a
+ * DUK_IVAL_PROP. We could notice that left->x1 is a temp
+ * and reuse, but it would still be in the wrong position
+ * (reg_cs + 0 rather than reg_cs + 1).
+ */
+ duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_CSPROP,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 1)); /* in-place setup */
+ DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_cs + 0,
+ reg_cs + 1,
+ reg_key);
+#else
+ duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */
+#endif
} else {
DUK_DDD(DUK_DDDPRINT("function call with register base"));
duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
- duk__emit_a_b(comp_ctx,
- DUK_OP_CSREG,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
+#if 0
+ duk__emit_a_bc(comp_ctx,
+ DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
+ reg_cs + 0,
+ reg_cs + 0); /* in-place setup */
+#endif
+ /* Because of in-place setup, REGCS is equivalent to
+ * just this LDUNDEF.
+ */
+ duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1);
}
DUK__SETTEMP(comp_ctx, reg_cs + 2);
nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
- /* Tailcalls are handled by back-patching the TAILCALL flag to the
- * already emitted instruction later (in return statement parser).
- * Since A and C have a special meaning here, they cannot be "shuffled".
+ /* Tailcalls are handled by back-patching the already emitted opcode
+ * later in return statement parser.
*/
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_CALL | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- (duk_regconst_t) call_flags /*flags*/,
- (duk_regconst_t) reg_cs /*basereg*/,
- (duk_regconst_t) nargs /*numargs*/);
+ duk__emit_a_bc(comp_ctx,
+ call_op,
+ (duk_regconst_t) nargs /*numargs*/,
+ reg_cs /*basereg*/);
DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_cs;
+ duk__ivalue_regconst(res, reg_cs);
return;
}
/* POSTFIX EXPRESSION */
case DUK_TOK_INCREMENT: {
- args = (DUK_OP_POSTINCR << 8) + 0;
+ args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0;
goto postincdec;
}
case DUK_TOK_DECREMENT: {
- args = (DUK_OP_POSTDECR << 8) + 0;
+ args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0;
goto postincdec;
}
+ /* EXPONENTIATION EXPRESSION */
+
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_TOK_EXP: {
+ args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1; /* UnaryExpression */
+ goto binary;
+ }
+#endif
+
/* MULTIPLICATIVE EXPRESSION */
case DUK_TOK_MUL: {
- args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
+ args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
goto binary;
}
case DUK_TOK_DIV: {
- args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
+ args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
goto binary;
}
case DUK_TOK_MOD: {
- args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
+ args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
goto binary;
}
@@ -61576,11 +67955,11 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
goto binary;
}
case DUK_TOK_INSTANCEOF: {
- args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF << 8) + DUK__BP_RELATIONAL;
+ args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL;
goto binary;
}
case DUK_TOK_IN: {
- args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN << 8) + DUK__BP_RELATIONAL;
+ args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL;
goto binary;
}
@@ -61637,7 +68016,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
* but only if it really is a temp. Nothing fancy here now.
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t pc_jump1;
duk_int_t pc_jump2;
@@ -61653,9 +68032,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__patch_jump_here(comp_ctx, pc_jump2);
DUK__SETTEMP(comp_ctx, reg_temp + 1);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -61701,6 +68078,13 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
goto assign;
}
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_TOK_EXP_EQ: {
+ /* right associative */
+ args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1;
+ goto assign;
+ }
+#endif
case DUK_TOK_ALSHIFT_EQ: {
/* right associative */
args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
@@ -61764,7 +68148,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/*
* Shared handling of binary operations
*
- * args = (is_extraop << 16) + (opcode << 8) + rbp
+ * args = (opcode << 8) + rbp
*/
{
duk__ivalue_toplain(comp_ctx, left);
@@ -61774,16 +68158,16 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
- res->t = (args >> 16) ? DUK_IVAL_ARITH_EXTRAOP : DUK_IVAL_ARITH;
+ res->t = DUK_IVAL_ARITH;
res->op = (args >> 8) & 0xff;
res->x2.t = res->x1.t;
res->x2.regconst = res->x1.regconst;
- duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
+ duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx);
res->x1.t = left->x1.t;
res->x1.regconst = left->x1.regconst;
- duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
+ duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx);
DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
(long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
@@ -61811,7 +68195,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
*/
{
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t pc_jump;
duk_small_uint_t args_truthval = args >> 8;
duk_small_uint_t args_rbp = args & 0xff;
@@ -61821,17 +68205,15 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
- duk__emit_a_b(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) args_truthval,
- (duk_regconst_t) reg_temp); /* skip jump conditionally */
+ DUK_ASSERT(DUK__ISREG(reg_temp));
+ duk__emit_bc(comp_ctx,
+ (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
+ reg_temp); /* skip jump conditionally */
pc_jump = duk__emit_jump_empty(comp_ctx);
duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
duk__patch_jump_here(comp_ctx, pc_jump);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -61896,18 +68278,17 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
/* E5 Section 11.13.1 (and others for other assignments), step 4. */
goto syntax_error_lvalue;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
if (args_op == DUK_OP_NONE) {
@@ -61919,8 +68300,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* 'res' must be a plain ivalue, and not register-bound variable. */
DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
- (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
- !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
+ DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) {
duk__ivalue_totempconst(comp_ctx, res);
}
}
@@ -61930,13 +68310,13 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* can change X, but when we do <op> we must use
* the pre-op value.
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
if (reg_varbind >= 0) {
- duk_reg_t reg_res;
- duk_reg_t reg_src;
+ duk_regconst_t reg_res;
+ duk_regconst_t reg_src;
duk_int_t pc_temp_load;
duk_int_t pc_before_rhs;
duk_int_t pc_after_rhs;
@@ -61967,7 +68347,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
pc_temp_load = duk__get_current_pc(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_temp,
+ reg_temp,
reg_varbind);
pc_before_rhs = duk__get_current_pc(comp_ctx);
@@ -61985,7 +68365,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* one instruction, so use explicit PC computation.
*/
DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
- DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
+ DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (duk_size_t) (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
reg_src = reg_varbind;
} else {
DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
@@ -61993,15 +68373,15 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_src,
+ args_op | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_res,
+ reg_src,
res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_res;
+ res->x1.regconst = reg_res;
/* Ensure compact use of temps. */
- if (DUK__ISTEMP(comp_ctx, reg_res)) {
+ if (DUK__ISREG_TEMP(comp_ctx, reg_res)) {
DUK__SETTEMP(comp_ctx, reg_res + 1);
}
} else {
@@ -62011,18 +68391,18 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_a_bc(comp_ctx,
DUK_OP_GETVAR,
- (duk_regconst_t) reg_temp,
+ reg_temp,
rc_varname);
duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
+ args_op | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp,
+ reg_temp,
res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ res->x1.regconst = reg_temp;
}
DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
@@ -62075,10 +68455,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* 'res' contains expression value */
} else if (left->t == DUK_IVAL_PROP) {
/* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
- duk_reg_t reg_obj;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
duk_regconst_t rc_res;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
/* Property access expressions ('a[b]') are critical to correct
* LHS evaluation ordering, see test-dev-assign-eval-order*.js.
@@ -62110,31 +68490,29 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
} else {
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_GETPROP,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
+ DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp,
+ reg_obj,
rc_key);
duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
+ args_op | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp,
+ reg_temp,
res->x1.regconst);
- rc_res = (duk_regconst_t) reg_temp;
+ rc_res = reg_temp;
}
duk__emit_a_b_c(comp_ctx,
- DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
+ DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_obj,
rc_key,
rc_res);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = rc_res;
+ duk__ivalue_regconst(res, rc_res);
} else {
/* No support for lvalues returned from new or function call expressions.
* However, these must NOT cause compile-time SyntaxErrors, but run-time
@@ -62158,12 +68536,9 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
*/
rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
+ duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = rc_res;
+ duk__ivalue_regconst(res, rc_res);
}
return;
@@ -62182,73 +68557,69 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* the previous expression if a LineTerminator occurs before '++'/'--'.
*/
- duk_reg_t reg_res;
- duk_small_uint_t args_op = args >> 8;
+ duk_regconst_t reg_res;
+ duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */
+ duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */
/* Specific assumptions for opcode numbering. */
DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
- DUK_ASSERT(DUK_OP_POSTINCR + 8 == DUK_OP_POSTINCP);
- DUK_ASSERT(DUK_OP_POSTDECR + 8 == DUK_OP_POSTDECP);
reg_res = DUK__ALLOCTEMP(comp_ctx);
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
goto syntax_error;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
- args_op, /* e.g. DUK_OP_POSTINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
+ args_op1, /* e.g. DUK_OP_POSTINCR */
+ reg_res,
+ reg_varbind);
} else {
duk__emit_a_bc(comp_ctx,
- args_op + 4, /* e.g. DUK_OP_POSTINCV */
- (duk_regconst_t) reg_res,
+ args_op1 + 4, /* e.g. DUK_OP_POSTINCV */
+ reg_res,
rc_varname);
}
DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
(duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
} else if (left->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
+ duk_regconst_t reg_obj; /* allocate to reg only (not const) */
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
- args_op + 8, /* e.g. DUK_OP_POSTINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
+ args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */
+ reg_res,
+ reg_obj,
rc_key);
} else {
/* Technically return value is not needed because INVLHS will
* unconditially throw a ReferenceError. Coercion is necessary
* for proper semantics (consider ToNumber() called for an object).
- * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
+ * Use DUK_OP_UNP with a dummy register to get ToNumber().
*/
duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_UNP,
- reg_res); /* for side effects, result ignored */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_UNP,
+ reg_res); /* for side effects, result ignored */
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_INVLHS);
}
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_res;
DUK__SETTEMP(comp_ctx, reg_res + 1);
+ duk__ivalue_regconst(res, reg_res);
return;
}
@@ -62262,9 +68633,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
- duk_small_int_t tok = comp_ctx->curr_token.t;
+ duk_small_uint_t tok = comp_ctx->curr_token.t;
- DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
+ DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL); /* unsigned */
+ DUK_ASSERT(tok <= DUK_TOK_MAXVAL);
DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
/* XXX: integrate support for this into led() instead?
@@ -62307,14 +68679,13 @@ DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
/* main expression parser function */
DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
duk_ivalue *tmp = &tmp_alloc;
duk_small_uint_t rbp;
DUK__RECURSION_INCREASE(comp_ctx, thr);
- duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
+ duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS);
/* filter out flags from exprtop rbp_flags here to save space */
rbp = rbp_flags & DUK__EXPR_RBP_MASK;
@@ -62324,10 +68695,10 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
(long) comp_ctx->curr_func.paren_level));
DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
- tmp->x1.valstack_idx = duk_get_top(ctx);
+ tmp->x1.valstack_idx = duk_get_top(thr);
tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
/* XXX: where to release temp regs in intermediate expressions?
* e.g. 1+2+3 -> don't inflate temp register count when parsing this.
@@ -62344,10 +68715,8 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
}
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_push_undefined(ctx);
- duk_replace(ctx, res->x1.valstack_idx);
+ duk_push_undefined(thr);
+ duk__ivalue_plain_fromstack(comp_ctx, res);
goto cleanup;
}
@@ -62362,7 +68731,7 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
cleanup:
/* final result is already in 'res' */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
DUK__RECURSION_DECREASE(comp_ctx, thr);
}
@@ -62393,20 +68762,20 @@ DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_sma
*/
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__expr(comp_ctx, res, rbp_flags);
return duk__ivalue_toreg(comp_ctx, res);
}
#endif
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__expr(comp_ctx, res, rbp_flags);
return duk__ivalue_totemp(comp_ctx, res);
}
#endif
-DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
duk__expr(comp_ctx, res, rbp_flags);
duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
@@ -62434,19 +68803,19 @@ DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *
duk__ivalue_toplain_ignore(comp_ctx, res);
}
-DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__exprtop(comp_ctx, res, rbp_flags);
return duk__ivalue_toreg(comp_ctx, res);
}
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__exprtop(comp_ctx, res, rbp_flags);
return duk__ivalue_totemp(comp_ctx, res);
}
#endif
-DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
duk__exprtop(comp_ctx, res, rbp_flags);
duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
@@ -62476,22 +68845,6 @@ DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalu
* the token after the terminator).
*/
-#ifdef DUK__HAS_VAL
-#undef DUK__HAS_VAL
-#endif
-#ifdef DUK__HAS_TERM
-#undef DUK__HAS_TERM
-#endif
-#ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
-#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
-#endif
-#ifdef DUK__STILL_PROLOGUE
-#undef DUK__STILL_PROLOGUE
-#endif
-#ifdef DUK__IS_TERMINAL
-#undef DUK__IS_TERMINAL
-#endif
-
#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
@@ -62516,11 +68869,10 @@ DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalu
* as is done in 'for-in' parsing.
*/
-DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
+DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
/* assume 'var' has been eaten */
@@ -62543,17 +68895,17 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
duk_uarridx_t n;
DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
(duk_heaphdr *) h_varname));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- duk_push_hstring(ctx, h_varname);
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
+ duk_push_hstring(thr, h_varname);
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
+ duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8));
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
}
- duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
+ duk_push_hstring(thr, h_varname); /* push before advancing to keep reachable */
/* register binding lookup is based on varmap (even in first pass) */
- duk_dup_top(ctx);
+ duk_dup_top(thr);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
duk__advance(comp_ctx); /* eat identifier */
@@ -62569,11 +68921,11 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
if (reg_varbind >= 0) {
duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
} else {
- duk_reg_t reg_val;
+ duk_regconst_t reg_val;
reg_val = duk__ivalue_toreg(comp_ctx, res);
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_val,
+ reg_val,
rc_varname);
}
} else {
@@ -62583,7 +68935,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
}
}
- duk_pop(ctx); /* pop varname */
+ duk_pop(thr); /* pop varname */
*out_rc_varname = rc_varname;
*out_reg_varbind = reg_varbind;
@@ -62595,7 +68947,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
}
DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
duk__advance(comp_ctx); /* eat 'var' */
@@ -62613,10 +68965,9 @@ DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
- duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
- duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
+ duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
+ duk_regconst_t temp_reset; /* knock back "next temp" to this whenever possible */
+ duk_regconst_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
@@ -62659,7 +69010,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
* Variant 2 or 4
*/
- duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
+ duk_regconst_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
duk__advance(comp_ctx); /* eat 'var' */
@@ -62676,12 +69027,12 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
if (reg_varbind >= 0) {
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
+ reg_varbind,
+ reg_temps + 0);
} else {
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
+ reg_temps + 0,
rc_varname);
}
goto parse_3_or_4;
@@ -62728,38 +69079,38 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
}
if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
+ reg_varbind,
+ reg_temps + 0);
} else {
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
+ reg_temps + 0,
rc_varname);
}
} else if (res->t == DUK_IVAL_PROP) {
/* Don't allow a constant for the object (even for a number etc), as
* it goes into the 'A' field of the opcode.
*/
- duk_reg_t reg_obj;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
+ DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_obj,
rc_key,
- (duk_regconst_t) (reg_temps + 0));
+ reg_temps + 0);
} else {
duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_INVLHS);
}
goto parse_3_or_4;
} else {
@@ -62875,7 +69226,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
{
duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
- duk_reg_t reg_target;
+ duk_regconst_t reg_target;
DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
@@ -62908,10 +69259,10 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
pc_l2 = duk__get_current_pc(comp_ctx);
reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
- (duk_regconst_t) (reg_temps + 1),
- (duk_regconst_t) reg_target);
+ duk__emit_b_c(comp_ctx,
+ DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
+ reg_temps + 1,
+ reg_target);
pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
DUK__SETTEMP(comp_ctx, temp_reset);
@@ -62928,10 +69279,10 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
* not needed if the enum is finished).
*/
pc_l4 = duk__get_current_pc(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
- (duk_regconst_t) (reg_temps + 0),
- (duk_regconst_t) (reg_temps + 1));
+ duk__emit_b_c(comp_ctx,
+ DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
+ reg_temps + 0,
+ reg_temps + 1);
pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
@@ -62968,10 +69319,10 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
duk_hthread *thr = comp_ctx->thr;
- duk_reg_t temp_at_loop;
+ duk_regconst_t temp_at_loop;
duk_regconst_t rc_switch; /* reg/const for switch value */
duk_regconst_t rc_case; /* reg/const for case value */
- duk_reg_t reg_temp; /* general temp register */
+ duk_regconst_t reg_temp; /* general temp register */
duk_int_t pc_prevcase = -1;
duk_int_t pc_prevstmt = -1;
duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
@@ -63014,7 +69365,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
for (;;) {
duk_int_t num_stmts;
- duk_small_int_t tok;
+ duk_small_uint_t tok;
/* sufficient for keeping temp reg numbers in check */
DUK__SETTEMP(comp_ctx, temp_at_loop);
@@ -63045,11 +69396,11 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_b_c(comp_ctx,
- DUK_OP_SEQ,
- (duk_regconst_t) reg_temp,
+ DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_temp,
rc_switch,
rc_case);
- duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
+ duk__emit_if_true_skip(comp_ctx, reg_temp);
/* jump to next case clause */
pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
@@ -63166,7 +69517,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
}
DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t temp_reset;
+ duk_regconst_t temp_reset;
duk_regconst_t rc_cond;
duk_int_t pc_jump_false;
@@ -63240,7 +69591,7 @@ DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, d
}
DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_reg_t temp_reset;
+ duk_regconst_t temp_reset;
duk_regconst_t rc_cond;
duk_int_t pc_start;
duk_int_t pc_jump_false;
@@ -63321,16 +69672,15 @@ DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk
(long) is_break, (long) label_id, (long) label_is_closest,
(long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
- duk__emit_extraop_bc(comp_ctx,
- is_break ? DUK_EXTRAOP_BREAK : DUK_EXTRAOP_CONTINUE,
- (duk_regconst_t) label_id);
+ duk__emit_bc(comp_ctx,
+ is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE,
+ (duk_regconst_t) label_id);
}
}
DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
duk_regconst_t rc_val;
- duk_small_uint_t ret_flags;
duk__advance(comp_ctx); /* eat 'return' */
@@ -63341,13 +69691,11 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
}
- ret_flags = 0;
-
if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
- rc_val = 0;
+ duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
} else {
duk_int_t pc_before_expr;
duk_int_t pc_after_expr;
@@ -63361,8 +69709,8 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
pc_after_expr = duk__get_current_pc(comp_ctx);
- /* Tail call check: if last opcode emitted was CALL(I), and
- * the context allows it, change the CALL(I) to a tail call.
+ /* Tail call check: if last opcode emitted was CALL, and
+ * the context allows it, add a tailcall flag to the CALL.
* This doesn't guarantee that a tail call will be allowed at
* runtime, so the RETURN must still be emitted. (Duktape
* 0.10.0 avoided this and simulated a RETURN if a tail call
@@ -63371,7 +69719,7 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
* test-bug-tailcall-thread-yield-resume.js for discussion.)
*
* In addition to the last opcode being CALL, we also need to
- * be sure that 'rc_val' is the result register of the CALL(I).
+ * be sure that 'rc_val' is the result register of the CALL.
* For instance, for the expression 'return 0, (function ()
* { return 1; }), 2' the last opcode emitted is CALL (no
* bytecode is emitted for '2') but 'rc_val' indicates
@@ -63400,35 +69748,41 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
duk_compiler_instr *instr;
+ duk_instr_t ins;
duk_small_uint_t op;
instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
DUK_ASSERT(instr != NULL);
- op = (duk_small_uint_t) DUK_DEC_OP(instr->ins);
- if ((op == DUK_OP_CALL || op == DUK_OP_CALLI) &&
- DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
+ ins = instr->ins;
+ op = (duk_small_uint_t) DUK_DEC_OP(ins);
+ if ((op & ~0x0fU) == DUK_OP_CALL0 &&
+ DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) {
DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
"catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
"and last instruction is a CALL "
- "-> set TAILCALL flag"));
- /* Just flip the single bit. */
- instr->ins |= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL, 0, 0);
+ "-> change to TAILCALL"));
+ ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL);
+ instr->ins = ins;
}
}
#endif /* DUK_USE_TAILCALL */
- ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
+ if (DUK__ISREG(rc_val)) {
+ duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val);
+ } else {
+ rc_val = DUK__REMOVECONST(rc_val);
+ if (duk__const_needs_refcount(comp_ctx, rc_val)) {
+ duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val);
+ } else {
+ duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val);
+ }
+ }
}
-
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) ret_flags /*flags*/,
- rc_val /*reg*/);
}
DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t reg_val;
+ duk_regconst_t reg_val;
duk__advance(comp_ctx); /* eat 'throw' */
@@ -63439,15 +69793,14 @@ DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res
}
reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_THROW,
- (duk_regconst_t) reg_val);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_THROW,
+ reg_val);
}
DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
+ duk_regconst_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
duk_regconst_t rc_varname = 0;
duk_small_uint_t trycatch_flags = 0;
duk_int_t pc_ldconst = -1;
@@ -63495,8 +69848,8 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
/* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDTRY);
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_ENDTRY);
if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
/*
@@ -63521,7 +69874,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk_hstring *h_var;
duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
- DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(thr)));
trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
@@ -63537,7 +69890,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
h_var = comp_ctx->curr_token.str1;
DUK_ASSERT(h_var != NULL);
- duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
+ duk_push_hstring(thr, h_var); /* keep in on valstack, use borrowed ref below */
if (comp_ctx->curr_func.is_strict &&
((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
@@ -63546,7 +69899,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
goto syntax_error;
}
- duk_dup_top(ctx);
+ duk_dup_top(thr);
rc_varname = duk__getconst(comp_ctx);
DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
(unsigned long) rc_varname, (long) rc_varname));
@@ -63557,63 +69910,63 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_undefined(ctx, -1)) {
+ duk_dup_top(thr);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ if (duk_is_undefined(thr, -1)) {
varmap_value = -2;
- } else if (duk_is_null(ctx, -1)) {
+ } else if (duk_is_null(thr, -1)) {
varmap_value = -1;
} else {
- DUK_ASSERT(duk_is_number(ctx, -1));
- varmap_value = duk_get_int(ctx, -1);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ varmap_value = duk_get_int(thr, -1);
DUK_ASSERT(varmap_value >= 0);
}
- duk_pop(ctx);
+ duk_pop(thr);
#if 0
/* It'd be nice to do something like this - but it doesn't
* work for closures created inside the catch clause.
*/
- duk_dup_top(ctx);
- duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_dup_top(thr);
+ duk_push_int(thr, (duk_int_t) (reg_catch + 0));
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
#endif
- duk_dup_top(ctx);
- duk_push_null(ctx);
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_dup_top(thr);
+ duk_push_null(thr);
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_catch + 0) /*value*/,
+ reg_catch + 0 /*value*/,
rc_varname /*varname*/);
DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
/* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
if (varmap_value == -2) {
/* not present */
- duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_del_prop(thr, comp_ctx->curr_func.varmap_idx);
} else {
if (varmap_value == -1) {
- duk_push_null(ctx);
+ duk_push_null(thr);
} else {
DUK_ASSERT(varmap_value >= 0);
- duk_push_int(ctx, varmap_value);
+ duk_push_int(thr, varmap_value);
}
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
}
/* varname is popped by above code */
DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDCATCH);
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_ENDCATCH);
/*
* XXX: for now, indicate that an expensive catch binding
@@ -63623,7 +69976,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
- DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(thr)));
}
if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
@@ -63636,9 +69989,9 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
/* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- duk__emit_extraop_b(comp_ctx,
- DUK_EXTRAOP_ENDFIN,
- reg_catch); /* rethrow */
+ duk__emit_abc(comp_ctx,
+ DUK_OP_ENDFIN,
+ reg_catch); /* rethrow */
}
if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
@@ -63682,7 +70035,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_int_t pc_trycatch;
duk_int_t pc_finished;
- duk_reg_t reg_catch;
+ duk_regconst_t reg_catch;
duk_small_uint_t trycatch_flags;
if (comp_ctx->curr_func.is_strict) {
@@ -63704,13 +70057,13 @@ DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__emit_a_bc(comp_ctx,
DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) trycatch_flags /*a*/,
- (duk_regconst_t) reg_catch /*bc*/);
+ reg_catch /*bc*/);
duk__emit_invalid(comp_ctx); /* catch jump */
duk__emit_invalid(comp_ctx); /* finished jump */
duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDTRY);
+ duk__emit_op_only(comp_ctx,
+ DUK_OP_ENDTRY);
pc_finished = duk__get_current_pc(comp_ctx);
@@ -63728,9 +70081,9 @@ DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t l
label_id = comp_ctx->curr_func.label_next++;
DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LABEL,
- (duk_regconst_t) label_id);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_LABEL,
+ (duk_regconst_t) label_id);
duk__emit_invalid(comp_ctx);
duk__emit_invalid(comp_ctx);
@@ -63744,21 +70097,21 @@ DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t l
*/
DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
- duk_reg_t temp_at_entry;
- duk_uarridx_t labels_len_at_entry;
+ duk_regconst_t temp_at_entry;
+ duk_size_t labels_len_at_entry;
duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
duk_int_t stmt_id;
duk_small_uint_t stmt_flags = 0;
duk_int_t label_id = -1;
duk_small_uint_t tok;
+ duk_bool_t test_func_decl;
DUK__RECURSION_INCREASE(comp_ctx, thr);
temp_at_entry = DUK__GETTEMP(comp_ctx);
pc_at_entry = duk__get_current_pc(comp_ctx);
- labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
+ labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx);
stmt_id = comp_ctx->curr_func.stmt_next++;
dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
@@ -63818,17 +70171,15 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
* for function statements are modelled after V8, see
* test-dev-func-decl-outside-top.js.
*/
-
+ test_func_decl = allow_source_elem;
#if defined(DUK_USE_NONSTD_FUNC_STMT)
/* Lenient: allow function declarations outside top level in
* non-strict mode but reject them in strict mode.
*/
- if (allow_source_elem || !comp_ctx->curr_func.is_strict)
-#else /* DUK_USE_NONSTD_FUNC_STMT */
- /* Strict: never allow function declarations outside top level. */
- if (allow_source_elem)
+ test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict;
#endif /* DUK_USE_NONSTD_FUNC_STMT */
- {
+ /* Strict: never allow function declarations outside top level. */
+ if (test_func_decl) {
/* FunctionDeclaration: not strictly a statement but handled as such.
*
* O(depth^2) parse count for inner functions is handled by recording a
@@ -63838,30 +70189,40 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
*/
duk_int_t fnum;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_idx_t top_before;
+#endif
DUK_DDD(DUK_DDDPRINT("function declaration statement"));
+#if defined(DUK_USE_ASSERTIONS)
+ top_before = duk_get_top(thr);
+#endif
+
duk__advance(comp_ctx); /* eat 'function' */
- fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
+ fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1);
+ /* The value stack convention here is a bit odd: the function
+ * name is only pushed on pass 1 (in_scanning), and is needed
+ * to process function declarations.
+ */
if (comp_ctx->curr_func.in_scanning) {
duk_uarridx_t n;
- duk_hstring *h_funcname;
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); /* -> [ ... func name ] */
- h_funcname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_funcname != NULL);
-
- DUK_DDD(DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %ld",
- (duk_heaphdr *) h_funcname, (long) fnum));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- duk_push_hstring(ctx, h_funcname);
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
- duk_pop_n(ctx, 2);
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(duk_get_top(thr) == top_before + 1);
+#endif
+ DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld",
+ duk_get_tval(thr, -1), (long) fnum));
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
+ /* funcname is at index -1 */
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
+ duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
+ } else {
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(duk_get_top(thr) == top_before);
+#endif
}
/* no statement value (unlike function expression) */
@@ -64010,7 +70371,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
duk__advance(comp_ctx);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
- duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_DEBUGGER);
+ duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER);
#else
DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
#endif
@@ -64071,7 +70432,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
/* expected ival */
DUK_ASSERT(res->t == DUK_IVAL_VAR);
DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
+ DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
h_lab = comp_ctx->prev_token.str1;
DUK_ASSERT(h_lab != NULL);
@@ -64109,7 +70470,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
/* expected ival */
DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
+ DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
h_dir = comp_ctx->prev_token.str1;
DUK_ASSERT(h_dir != NULL);
@@ -64177,7 +70538,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
*/
if (stmt_flags & DUK__HAS_VAL) {
- duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
+ duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
if (reg_stmt_value >= 0) {
duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
} else {
@@ -64229,9 +70590,9 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
*/
if (label_id >= 0) {
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_ENDLABEL,
- (duk_regconst_t) label_id);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_ENDLABEL,
+ (duk_regconst_t) label_id);
}
DUK__SETTEMP(comp_ctx, temp_at_entry);
@@ -64243,10 +70604,6 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
DUK__RECURSION_DECREASE(comp_ctx, thr);
}
-#undef DUK__HAS_VAL
-#undef DUK__HAS_TERM
-#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
-
/*
* Parse a statement list.
*
@@ -64260,13 +70617,12 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_ivalue res_alloc;
duk_ivalue *res = &res_alloc;
/* Setup state. Initial ivalue is 'undefined'. */
- duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
+ duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS);
/* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
* intermediate values suffice for parsing of each function. Nesting is needed
@@ -64276,10 +70632,10 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
res->t = DUK_IVAL_PLAIN;
res->x1.t = DUK_ISPEC_VALUE;
- res->x1.valstack_idx = duk_get_top(ctx);
+ res->x1.valstack_idx = duk_get_top(thr);
res->x2.valstack_idx = res->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
/* Parse statements until a closing token (EOF or '}') is found. */
@@ -64311,7 +70667,7 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
/* Tear down state. */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
}
/*
@@ -64346,9 +70702,8 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
* handle cases with a very large number of variables?
*/
-DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
+DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_name;
duk_bool_t configurable_bindings;
duk_uarridx_t num_args;
@@ -64356,12 +70711,12 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
duk_regconst_t rc_name;
duk_small_uint_t declvar_flags;
duk_uarridx_t i;
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
#endif
-#ifdef DUK_USE_ASSERTIONS
- entry_top = duk_get_top(ctx);
+#if defined(DUK_USE_ASSERTIONS)
+ entry_top = duk_get_top(thr);
#endif
/*
@@ -64378,22 +70733,21 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* (there's no support for shuffling them now).
*/
- num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
+ num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
/* XXX: check num_args */
for (i = 0; i < num_args; i++) {
- duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
- h_name = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_name != NULL);
+ duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i);
+ h_name = duk_known_hstring(thr, -1);
if (comp_ctx->curr_func.is_strict) {
if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
goto error_argname;
}
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ duk_dup_top(thr);
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
goto error_argname;
}
@@ -64418,14 +70772,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
/* only functions can have arguments */
DUK_ASSERT(comp_ctx->curr_func.is_function);
- duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
+ duk_push_uarridx(thr, i); /* -> [ ... name index ] */
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
/* no code needs to be emitted, the regs already have values */
}
/* use temp_next for tracking register allocations */
- DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
+ DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args);
/*
* After arguments, allocate special registers (like shuffling temps)
@@ -64435,7 +70789,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
*out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
}
if (comp_ctx->curr_func.needs_shuffle) {
- duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
+ duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
comp_ctx->curr_func.shuffle1 = shuffle_base;
comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
@@ -64453,47 +70807,47 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* Function declarations
*/
- num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
+ num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
(long) num_decls,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx)));
for (i = 0; i < num_decls; i += 2) {
duk_int_t decl_type;
duk_int_t fnum;
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
+ decl_type = duk_to_int(thr, -1);
fnum = decl_type >> 8; /* XXX: macros */
decl_type = decl_type & 0xff;
- duk_pop(ctx);
+ duk_pop(thr);
if (decl_type != DUK_DECL_TYPE_FUNC) {
continue;
}
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
/* XXX: spilling */
if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind;
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ duk_regconst_t reg_bind;
+ duk_dup_top(thr);
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
/* shadowed; update value */
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
+ duk_dup_top(thr);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ reg_bind = duk_to_int(thr, -1); /* [ ... name reg_bind ] */
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
+ reg_bind,
(duk_regconst_t) fnum);
} else {
/* function: always register bound */
reg_bind = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
+ reg_bind,
(duk_regconst_t) fnum);
- duk_push_int(ctx, (duk_int_t) reg_bind);
+ duk_push_int(thr, (duk_int_t) reg_bind);
}
} else {
/* Function declaration for global/eval code is emitted even
@@ -64504,14 +70858,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* update the binding value.
*/
- duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_dup_top(ctx);
+ duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
+ duk_dup_top(thr);
rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
+ duk_push_null(thr);
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp,
+ reg_temp,
(duk_regconst_t) fnum);
declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
@@ -64523,19 +70877,22 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
}
duk__emit_a_b_c(comp_ctx,
- DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
+ DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
- (duk_regconst_t) reg_temp /*value*/);
+ reg_temp /*value*/);
DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
}
DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1)));
+#endif
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
}
/*
@@ -64545,7 +70902,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* 'arguments' is referenced inside the function body.
*/
- if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
+ if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
"-> arguments object creation can be skipped"));
comp_ctx->curr_func.is_arguments_shadowed = 1;
@@ -64562,23 +70919,22 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
for (i = 0; i < num_decls; i += 2) {
duk_int_t decl_type;
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
+ decl_type = duk_to_int(thr, -1);
decl_type = decl_type & 0xff;
- duk_pop(ctx);
+ duk_pop(thr);
if (decl_type != DUK_DECL_TYPE_VAR) {
continue;
}
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
/* shadowed, ignore */
} else {
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
- h_name = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_name != NULL);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ h_name = duk_known_hstring(thr, -1);
if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
!comp_ctx->curr_func.is_arguments_shadowed) {
@@ -64586,35 +70942,34 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
"but appears as a variable declaration -> treat as "
"a no-op for variable declaration purposes"));
- duk_pop(ctx);
+ duk_pop(thr);
continue;
}
/* XXX: spilling */
if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
+ duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
/* no need to init reg, it will be undefined on entry */
- duk_push_int(ctx, (duk_int_t) reg_bind);
+ duk_push_int(thr, (duk_int_t) reg_bind);
} else {
- duk_dup_top(ctx);
+ duk_dup_top(thr);
rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
+ duk_push_null(thr);
declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
- DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
+ DUK_PROPDESC_FLAG_ENUMERABLE;
if (configurable_bindings) {
declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
}
duk__emit_a_b_c(comp_ctx,
- DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
+ DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
- (duk_regconst_t) 0 /*value*/);
+ 0 /*value*/);
}
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
}
}
@@ -64623,10 +70978,10 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
*/
DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx),
(long) comp_ctx->curr_func.is_arguments_shadowed));
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
return;
error_outofregs:
@@ -64677,16 +71032,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) {
duk_compiler_func *func;
duk_hthread *thr;
- duk_context *ctx;
- duk_reg_t reg_stmt_value = -1;
+ duk_regconst_t reg_stmt_value = -1;
duk_lexer_point lex_pt;
- duk_reg_t temp_first;
+ duk_regconst_t temp_first;
duk_small_int_t compile_round = 1;
DUK_ASSERT(comp_ctx != NULL);
thr = comp_ctx->thr;
- ctx = (duk_context *) thr;
DUK_ASSERT(thr != NULL);
func = &comp_ctx->curr_func;
@@ -64694,7 +71047,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
DUK__RECURSION_INCREASE(comp_ctx, thr);
- duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
+ duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
/*
* Store lexer position for a later rewind
@@ -64723,9 +71076,9 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
* it here.
*/
#if 0
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDUNDEF,
- 0);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_LDUNDEF,
+ 0);
#endif
}
@@ -64741,6 +71094,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
func->may_direct_eval = 0;
func->id_access_arguments = 0;
func->id_access_slow = 0;
+ func->id_access_slow_own = 0;
func->reg_stmt_value = reg_stmt_value;
#if defined(DUK_USE_DEBUGGER_SUPPORT)
func->min_line = DUK_INT_MAX;
@@ -64830,6 +71184,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
/* XXX: init or assert catch depth etc -- all values */
func->id_access_arguments = 0;
func->id_access_slow = 0;
+ func->id_access_slow_own = 0;
/*
* Check function name validity now that we know strictness.
@@ -64864,9 +71219,9 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
if (implicit_return_value) {
/* Default implicit return value. */
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDUNDEF,
- 0);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_LDUNDEF,
+ 0);
}
DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
@@ -64884,7 +71239,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
if (compile_round >= 3) {
/* Should never happen but avoid infinite loop just in case. */
DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
}
DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
}
@@ -64906,15 +71261,10 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
if (reg_stmt_value >= 0) {
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) DUK_BC_RETURN_FLAG_HAVE_RETVAL /*flags*/,
- (duk_regconst_t) reg_stmt_value /*reg*/);
+ DUK_ASSERT(DUK__ISREG(reg_stmt_value));
+ duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/);
} else {
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) 0 /*flags*/,
- (duk_regconst_t) 0 /*reg(ignored)*/);
+ duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
}
/*
@@ -64955,7 +71305,6 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
/* Parse formals. */
DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t first = 1;
duk_uarridx_t n;
@@ -64981,7 +71330,7 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
*/
if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
- DUK_ERROR_SYNTAX(thr, "expected identifier");
+ DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
}
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
@@ -64989,9 +71338,9 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
(duk_heaphdr *) comp_ctx->curr_token.str1));
/* XXX: append primitive */
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
- duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
+ duk_push_hstring(thr, comp_ctx->curr_token.str1);
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
+ duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n);
duk__advance(comp_ctx); /* eat identifier */
}
@@ -65001,16 +71350,16 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
* correctly set up. Assumes that curr_token is just after 'function' (or
* 'set'/'get' etc).
*/
-DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
+DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
+ duk_token *tok;
+ duk_bool_t no_advance;
DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
- DUK_ASSERT(comp_ctx->curr_func.is_setget == is_setget);
- DUK_ASSERT(comp_ctx->curr_func.is_decl == is_decl);
+ DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0));
duk__update_lineinfo_currtoken(comp_ctx);
@@ -65025,43 +71374,55 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t i
* be an Identifer (excludes reserved words). For setter/getter
* it is a PropertyName which allows reserved words and also
* strings and numbers (e.g. "{ get 1() { ... } }").
+ *
+ * Function parsing may start either from prev_token or curr_token
+ * (object literal method definition uses prev_token for example).
+ * This is dealt with for the initial token.
*/
- if (is_setget) {
+ no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN);
+ if (no_advance) {
+ tok = &comp_ctx->prev_token;
+ } else {
+ tok = &comp_ctx->curr_token;
+ }
+
+ if (flags & DUK__FUNC_FLAG_GETSET) {
/* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->curr_token.t == DUK_TOK_STRING) {
- duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
- } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->curr_token.num);
- duk_to_string(ctx, -1);
+ if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) {
+ duk_push_hstring(thr, tok->str1); /* keep in valstack */
+ } else if (tok->t == DUK_TOK_NUMBER) {
+ duk_push_number(thr, tok->num);
+ duk_to_string(thr, -1);
} else {
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
}
- comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
- DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
- duk__advance(comp_ctx);
+ comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
} else {
/* Function name is an Identifier (not IdentifierName), but we get
* the raw name (not recognizing keywords) here and perform the name
* checks only after pass 1.
*/
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER) {
- duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
- comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
- DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
- duk__advance(comp_ctx);
+ if (tok->t_nores == DUK_TOK_IDENTIFIER) {
+ duk_push_hstring(thr, tok->str1); /* keep in valstack */
+ comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
} else {
/* valstack will be unbalanced, which is OK */
- DUK_ASSERT(!is_setget);
- if (is_decl) {
+ DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0);
+ DUK_ASSERT(comp_ctx->curr_func.h_name == NULL);
+ no_advance = 1;
+ if (flags & DUK__FUNC_FLAG_DECL) {
DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
}
}
}
- DUK_DDD(DUK_DDDPRINT("function name: %!O",
- (duk_heaphdr *) comp_ctx->curr_func.h_name));
+ DUK_DD(DUK_DDPRINT("function name: %!O",
+ (duk_heaphdr *) comp_ctx->curr_func.h_name));
+
+ if (!no_advance) {
+ duk__advance(comp_ctx);
+ }
/*
* Formal argument list
@@ -65092,7 +71453,7 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t i
* to the parent function table.
*/
- duk__convert_to_func_template(comp_ctx, is_setget /*force_no_namebind*/); /* -> [ ... func ] */
+ duk__convert_to_func_template(comp_ctx); /* -> [ ... func ] */
}
/* Parse an inner function, adding the function template to the current function's
@@ -65109,9 +71470,8 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t i
* need that information at the moment, but it would allow some optimizations if it
* were used.
*/
-DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
+DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_compiler_func old_func;
duk_idx_t entry_top;
duk_int_t fnum;
@@ -65124,12 +71484,12 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
duk_lexer_point lex_pt;
fnum = comp_ctx->curr_func.fnum_next++;
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- lex_pt.offset = duk_to_int(ctx, -1);
- duk_pop(ctx);
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
- lex_pt.line = duk_to_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
+ lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1);
+ duk_pop(thr);
+ duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
+ lex_pt.line = duk_to_int(thr, -1);
+ duk_pop(thr);
DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
(long) lex_pt.offset, (long) lex_pt.line));
@@ -65148,7 +71508,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
* to restore it later, and switch to using a new function in comp_ctx.
*/
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
(long) entry_top, (long) comp_ctx->curr_token.start_offset));
@@ -65161,18 +71521,26 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
/* inherit initial strictness from parent */
comp_ctx->curr_func.is_strict = old_func.is_strict;
+ /* XXX: It might be better to just store the flags into the curr_func
+ * struct and use them as is without this flag interpretation step
+ * here.
+ */
DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
comp_ctx->curr_func.is_function = 1;
DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
- comp_ctx->curr_func.is_setget = is_setget;
- comp_ctx->curr_func.is_decl = is_decl;
+ comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0);
+ comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET |
+ DUK__FUNC_FLAG_METDEF |
+ DUK__FUNC_FLAG_DECL)); /* no name binding for: declarations, objlit getset, objlit method def */
+ comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET |
+ DUK__FUNC_FLAG_METDEF)); /* not constructable: objlit getset, objlit method def */
/*
* Parse inner function
*/
- duk__parse_func_like_raw(comp_ctx, is_decl, is_setget); /* pushes function template */
+ duk__parse_func_like_raw(comp_ctx, flags); /* pushes function template */
/* prev_token.start_offset points to the closing brace here; when skipping
* we're going to reparse the closing brace to ensure semicolon insertion
@@ -65183,7 +71551,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
/* XXX: append primitive */
- DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
+ DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
fnum = old_func.fnum_next++;
if (fnum > DUK__MAX_FUNCS) {
@@ -65191,20 +71559,28 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
}
/* array writes autoincrement length */
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
- duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- duk_push_int(ctx, comp_ctx->prev_token.start_line);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
+ duk_push_size_t(thr, comp_ctx->prev_token.start_offset);
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
+ duk_push_int(thr, comp_ctx->prev_token.start_line);
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
/*
* Cleanup: restore original function, restore valstack state.
+ *
+ * Function declaration handling needs the function name to be pushed
+ * on the value stack.
*/
+ if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) {
+ DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
+ duk_push_hstring(thr, comp_ctx->curr_func.h_name);
+ duk_replace(thr, entry_top);
+ duk_set_top(thr, entry_top + 1);
+ } else {
+ duk_set_top(thr, entry_top);
+ }
DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
- duk_set_top(ctx, entry_top);
-
- DUK_ASSERT_TOP(ctx, entry_top);
return fnum;
}
@@ -65223,8 +71599,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bo
/* XXX: source code property */
-DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) {
duk_hstring *h_filename;
duk__compiler_stkstate *comp_stk;
duk_compiler_ctx *comp_ctx;
@@ -65237,33 +71612,34 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
duk_small_uint_t flags;
DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(udata != NULL);
/*
* Arguments check
*/
- entry_top = duk_get_top(ctx);
- DUK_ASSERT(entry_top >= 2);
+ entry_top = duk_get_top(thr);
+ DUK_ASSERT(entry_top >= 1);
- comp_stk = (duk__compiler_stkstate *) duk_require_pointer(ctx, -1);
+ comp_stk = (duk__compiler_stkstate *) udata;
comp_ctx = &comp_stk->comp_ctx_alloc;
lex_pt = &comp_stk->lex_pt_alloc;
DUK_ASSERT(comp_ctx != NULL);
DUK_ASSERT(lex_pt != NULL);
flags = comp_stk->flags;
- is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
- is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
- is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
+ is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0);
+ is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0);
+ is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0);
- h_filename = duk_get_hstring(ctx, -2); /* may be undefined */
+ h_filename = duk_get_hstring(thr, -1); /* may be undefined */
/*
* Init compiler and lexer contexts
*/
func = &comp_ctx->curr_func;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
comp_ctx->thr = NULL;
comp_ctx->h_filename = NULL;
comp_ctx->prev_token.str1 = NULL;
@@ -65272,13 +71648,13 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
comp_ctx->curr_token.str2 = NULL;
#endif
- duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
+ duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS);
- duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
- duk_push_undefined(ctx); /* entry_top + 1 */
- duk_push_undefined(ctx); /* entry_top + 2 */
- duk_push_undefined(ctx); /* entry_top + 3 */
- duk_push_undefined(ctx); /* entry_top + 4 */
+ duk_push_dynamic_buffer(thr, 0); /* entry_top + 0 */
+ duk_push_undefined(thr); /* entry_top + 1 */
+ duk_push_undefined(thr); /* entry_top + 2 */
+ duk_push_undefined(thr); /* entry_top + 3 */
+ duk_push_undefined(thr); /* entry_top + 4 */
comp_ctx->thr = thr;
comp_ctx->h_filename = h_filename;
@@ -65296,8 +71672,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
comp_ctx->lex.buf_idx = entry_top + 0;
- comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
- DUK_ASSERT(comp_ctx->lex.buf != NULL);
+ comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
@@ -65320,9 +71695,9 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
*/
DUK_ASSERT(func->h_name == NULL);
} else {
- duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
+ duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL :
DUK_STRIDX_GLOBAL));
- func->h_name = duk_get_hstring(ctx, -1);
+ func->h_name = duk_get_hstring(thr, -1);
}
/*
@@ -65330,24 +71705,27 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
* on flags.
*/
- func->is_strict = is_strict;
- func->is_setget = 0;
- func->is_decl = 0;
+ DUK_ASSERT(func->is_setget == 0);
+ func->is_strict = (duk_uint8_t) is_strict;
+ DUK_ASSERT(func->is_notail == 0);
if (is_funcexpr) {
func->is_function = 1;
- func->is_eval = 0;
- func->is_global = 0;
+ DUK_ASSERT(func->is_eval == 0);
+ DUK_ASSERT(func->is_global == 0);
+ func->is_namebinding = 1;
+ func->is_constructable = 1;
duk__advance(comp_ctx); /* init 'curr_token' */
duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
- (void) duk__parse_func_like_raw(comp_ctx,
- 0, /* is_decl */
- 0); /* is_setget */
+ (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/);
} else {
- func->is_function = 0;
- func->is_eval = is_eval;
- func->is_global = !is_eval;
+ DUK_ASSERT(func->is_function == 0);
+ DUK_ASSERT(is_eval == 0 || is_eval == 1);
+ func->is_eval = (duk_uint8_t) is_eval;
+ func->is_global = (duk_uint8_t) !is_eval;
+ DUK_ASSERT(func->is_namebinding == 0);
+ DUK_ASSERT(func->is_constructable == 0);
duk__parse_func_body(comp_ctx,
1, /* expect_eof */
@@ -65359,7 +71737,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
* Convert duk_compiler_func to a function template
*/
- duk__convert_to_func_template(comp_ctx, 0 /*force_no_namebind*/);
+ duk__convert_to_func_template(comp_ctx);
/*
* Wrapping duk_safe_call() will mangle the stack, just return stack top
@@ -65371,16 +71749,10 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
}
DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk__compiler_stkstate comp_stk;
duk_compiler_ctx *prev_ctx;
duk_ret_t safe_rc;
- /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
- * is a bit heavy at the moment. The wrapper compiles to ~180 bytes on x64.
- * Alternatives would be nice.
- */
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(src_buffer != NULL);
@@ -65390,34 +71762,167 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer
DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
comp_stk.comp_ctx_alloc.lex.input = src_buffer;
comp_stk.comp_ctx_alloc.lex.input_length = src_length;
+ comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */
- duk_push_pointer(ctx, (void *) &comp_stk);
-
- /* [ ... filename &comp_stk ] */
+ /* [ ... filename ] */
prev_ctx = thr->compile_ctx;
thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
- safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/);
+ safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
if (safe_rc != DUK_EXEC_SUCCESS) {
- duk_throw(ctx);
+ DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1)));
+ (void) duk_throw(thr);
}
/* [ ... template ] */
}
-#line 1 "duk_js_executor.c"
+
+/* automatic undefs */
+#undef DUK__ALLOCTEMP
+#undef DUK__ALLOCTEMPS
+#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
+#undef DUK__BC_INITIAL_INSTS
+#undef DUK__BP_ADDITIVE
+#undef DUK__BP_ASSIGNMENT
+#undef DUK__BP_BAND
+#undef DUK__BP_BOR
+#undef DUK__BP_BXOR
+#undef DUK__BP_CALL
+#undef DUK__BP_CLOSING
+#undef DUK__BP_COMMA
+#undef DUK__BP_CONDITIONAL
+#undef DUK__BP_EOF
+#undef DUK__BP_EQUALITY
+#undef DUK__BP_EXPONENTIATION
+#undef DUK__BP_FOR_EXPR
+#undef DUK__BP_INVALID
+#undef DUK__BP_LAND
+#undef DUK__BP_LOR
+#undef DUK__BP_MEMBER
+#undef DUK__BP_MULTIPLICATIVE
+#undef DUK__BP_POSTFIX
+#undef DUK__BP_RELATIONAL
+#undef DUK__BP_SHIFT
+#undef DUK__COMPILE_ENTRY_SLOTS
+#undef DUK__CONST_MARKER
+#undef DUK__DUMP_ISPEC
+#undef DUK__DUMP_IVALUE
+#undef DUK__EMIT_FLAG_A_IS_SOURCE
+#undef DUK__EMIT_FLAG_BC_REGCONST
+#undef DUK__EMIT_FLAG_B_IS_TARGET
+#undef DUK__EMIT_FLAG_C_IS_TARGET
+#undef DUK__EMIT_FLAG_NO_SHUFFLE_A
+#undef DUK__EMIT_FLAG_NO_SHUFFLE_B
+#undef DUK__EMIT_FLAG_NO_SHUFFLE_C
+#undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT
+#undef DUK__EXPR_FLAG_ALLOW_EMPTY
+#undef DUK__EXPR_FLAG_REJECT_IN
+#undef DUK__EXPR_FLAG_REQUIRE_INIT
+#undef DUK__EXPR_RBP_MASK
+#undef DUK__FUNCTION_BODY_REQUIRE_SLOTS
+#undef DUK__FUNCTION_INIT_REQUIRE_SLOTS
+#undef DUK__FUNC_FLAG_DECL
+#undef DUK__FUNC_FLAG_GETSET
+#undef DUK__FUNC_FLAG_METDEF
+#undef DUK__FUNC_FLAG_PUSHNAME_PASS1
+#undef DUK__FUNC_FLAG_USE_PREVTOKEN
+#undef DUK__GETCONST_MAX_CONSTS_CHECK
+#undef DUK__GETTEMP
+#undef DUK__HAS_TERM
+#undef DUK__HAS_VAL
+#undef DUK__ISCONST
+#undef DUK__ISREG
+#undef DUK__ISREG_NOTTEMP
+#undef DUK__ISREG_TEMP
+#undef DUK__IS_TERMINAL
+#undef DUK__IVAL_FLAG_ALLOW_CONST
+#undef DUK__IVAL_FLAG_REQUIRE_SHORT
+#undef DUK__IVAL_FLAG_REQUIRE_TEMP
+#undef DUK__MAX_ARRAY_INIT_VALUES
+#undef DUK__MAX_CONSTS
+#undef DUK__MAX_FUNCS
+#undef DUK__MAX_OBJECT_INIT_PAIRS
+#undef DUK__MAX_TEMPS
+#undef DUK__MK_LBP
+#undef DUK__MK_LBP_FLAGS
+#undef DUK__OBJ_LIT_KEY_GET
+#undef DUK__OBJ_LIT_KEY_PLAIN
+#undef DUK__OBJ_LIT_KEY_SET
+#undef DUK__PARSE_EXPR_SLOTS
+#undef DUK__PARSE_STATEMENTS_SLOTS
+#undef DUK__RECURSION_DECREASE
+#undef DUK__RECURSION_INCREASE
+#undef DUK__REMOVECONST
+#undef DUK__SETTEMP
+#undef DUK__SETTEMP_CHECKMAX
+#undef DUK__STILL_PROLOGUE
+#undef DUK__TOKEN_LBP_BP_MASK
+#undef DUK__TOKEN_LBP_FLAG_NO_REGEXP
+#undef DUK__TOKEN_LBP_FLAG_TERMINATES
+#undef DUK__TOKEN_LBP_FLAG_UNUSED
+#undef DUK__TOKEN_LBP_GET_BP
/*
* Ecmascript bytecode executor.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Local declarations.
*/
-DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
+DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act);
+
+/*
+ * Misc helpers.
+ */
+
+/* Forced inline declaration, only applied for performance oriented build. */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+#define DUK__INLINE_PERF
+#define DUK__NOINLINE_PERF
+#else
+#define DUK__INLINE_PERF DUK_ALWAYS_INLINE
+#define DUK__NOINLINE_PERF DUK_NOINLINE
+#endif
+
+/* Replace value stack top to value at 'tv_ptr'. Optimize for
+ * performance by only applying the net refcount change.
+ */
+#define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \
+ duk_hthread *duk__thr; \
+ duk_tval *duk__tvsrc; \
+ duk_tval *duk__tvdst; \
+ duk_tval duk__tvtmp; \
+ duk__thr = (thr); \
+ duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \
+ duk__tvdst = (tv_ptr); \
+ DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \
+ DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \
+ DUK_TVAL_SET_UNDEFINED(duk__tvsrc); /* value stack init policy */ \
+ duk__thr->valstack_top = duk__tvsrc; \
+ DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \
+ } while (0)
+
+/* XXX: candidate of being an internal shared API call */
+#if 0 /* unused */
+DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) {
+ duk_tval *tv_dst;
+ duk_size_t copy_size;
+ duk_size_t i;
+
+ tv_dst = thr->valstack_top;
+ copy_size = sizeof(duk_tval) * count;
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, copy_size);
+ for (i = 0; i < count; i++) {
+ DUK_TVAL_INCREF(thr, tv_dst);
+ tv_dst++;
+ }
+ thr->valstack_top = tv_dst;
+}
+#endif
/*
* Arithmetic, binary, and logical helpers.
@@ -65434,19 +71939,17 @@ DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, du
* possible.
*/
-DUK_LOCAL duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
- /*
- * Ecmascript modulus ('%') does not match IEEE 754 "remainder"
- * operation (implemented by remainder() in C99) but does seem
- * to match ANSI C fmod().
- *
- * Compare E5 Section 11.5.3 and "man fmod".
- */
+DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
+ return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2);
+}
- return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) {
+ return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
}
+#endif
-DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
/*
* Addition operator is different from other arithmetic
* operations in that it also provides string concatenation.
@@ -65463,15 +71966,13 @@ DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_
* Custom types also have special behavior implemented here.
*/
- duk_context *ctx = (duk_context *) thr;
duk_double_union du;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
/*
* Fast paths
@@ -65491,7 +71992,7 @@ DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_
v2 = DUK_TVAL_GET_FASTINT(tv_y);
v3 = v1 + v2;
v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
+ if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
return;
@@ -65503,14 +72004,20 @@ DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_
#endif /* DUK_USE_FASTINT */
if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
+#if !defined(DUK_USE_EXEC_PREFER_SIZE)
duk_tval *tv_z;
+#endif
du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_push_number(thr, du.d); /* will NaN normalize result */
+ duk_replace(thr, (duk_idx_t) idx_z);
+#else /* DUK_USE_EXEC_PREFER_SIZE */
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
return;
}
@@ -65518,42 +72025,38 @@ DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_
* Slow path: potentially requires function calls for coercion
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
- duk_to_primitive(ctx, -1, DUK_HINT_NONE);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
+ duk_to_primitive(thr, -1, DUK_HINT_NONE);
- /* As a first approximation, buffer values are coerced to strings
- * for addition. This means that adding two buffers currently
- * results in a string.
- */
- if (duk_check_type_mask(ctx, -2, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER) ||
- duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER)) {
- duk_to_string(ctx, -2);
- duk_to_string(ctx, -1);
- duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
- duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
+ /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */
+ if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) {
+ /* Symbols shouldn't technically be handled here, but should
+ * go into the default ToNumber() coercion path instead and
+ * fail there with a TypeError. However, there's a ToString()
+ * in duk_concat_2() which also fails with TypeError so no
+ * explicit check is needed.
+ */
+ duk_concat_2(thr); /* [... s1 s2] -> [... s1+s2] */
} else {
duk_double_t d1, d2;
- d1 = duk_to_number(ctx, -2);
- d2 = duk_to_number(ctx, -1);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
+ DUK_ASSERT(duk_is_number(thr, -2));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
du.d = d1 + d2;
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
- duk_pop_2(ctx);
- duk_push_number(ctx, du.d);
- duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
+ duk_pop_2_unsafe(thr);
+ duk_push_number(thr, du.d); /* will NaN normalize result */
}
+ duk_replace(thr, (duk_idx_t) idx_z); /* side effects */
}
-DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_idx_t idx_z, duk_small_uint_fast_t opcode) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
/*
* Arithmetic operations other than '+' have number-only semantics
* and are implemented here. The separate switch-case here means a
@@ -65562,17 +72065,20 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
* E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
*/
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
duk_double_t d1, d2;
duk_double_union du;
+ duk_small_uint_fast_t opcode_shifted;
+#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_tval *tv_z;
+#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
+
+ opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
@@ -65582,26 +72088,26 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
v1 = DUK_TVAL_GET_FASTINT(tv_x);
v2 = DUK_TVAL_GET_FASTINT(tv_y);
- switch (opcode) {
- case DUK_OP_SUB: {
+ switch (opcode_shifted) {
+ case DUK_OP_SUB >> 2: {
v3 = v1 - v2;
break;
}
- case DUK_OP_MUL: {
+ case DUK_OP_MUL >> 2: {
/* Must ensure result is 64-bit (no overflow); a
* simple and sufficient fast path is to allow only
* 32-bit inputs. Avoid zero inputs to avoid
* negative zero issues (-1 * 0 = -0, for instance).
*/
- if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
- v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
+ if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 &&
+ v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) {
v3 = v1 * v2;
} else {
goto skip_fastint;
}
break;
}
- case DUK_OP_DIV: {
+ case DUK_OP_DIV >> 2: {
/* Don't allow a zero divisor. Fast path check by
* "verifying" with multiplication. Also avoid zero
* dividend to avoid negative zero issues (0 / -1 = -0
@@ -65616,7 +72122,7 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
}
break;
}
- case DUK_OP_MOD: {
+ case DUK_OP_MOD >> 2: {
/* Don't allow a zero divisor. Restrict both v1 and
* v2 to positive values to avoid compiler specific
* behavior.
@@ -65631,13 +72137,13 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
break;
}
default: {
- DUK_UNREACHABLE();
+ /* Possible with DUK_OP_EXP. */
goto skip_fastint;
}
}
v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
+ if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
return;
@@ -65652,34 +72158,40 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
d1 = DUK_TVAL_GET_NUMBER(tv_x);
d2 = DUK_TVAL_GET_NUMBER(tv_y);
} else {
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- d1 = duk_to_number(ctx, -2); /* side effects */
- d2 = duk_to_number(ctx, -1);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ d1 = duk_to_number_m2(thr); /* side effects */
+ d2 = duk_to_number_m1(thr);
+ DUK_ASSERT(duk_is_number(thr, -2));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
}
- switch (opcode) {
- case DUK_OP_SUB: {
+ switch (opcode_shifted) {
+ case DUK_OP_SUB >> 2: {
du.d = d1 - d2;
break;
}
- case DUK_OP_MUL: {
+ case DUK_OP_MUL >> 2: {
du.d = d1 * d2;
break;
}
- case DUK_OP_DIV: {
+ case DUK_OP_DIV >> 2: {
du.d = d1 / d2;
break;
}
- case DUK_OP_MOD: {
+ case DUK_OP_MOD >> 2: {
du.d = duk__compute_mod(d1, d2);
break;
}
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_OP_EXP >> 2: {
+ du.d = duk__compute_exp(d1, d2);
+ break;
+ }
+#endif
default: {
DUK_UNREACHABLE();
du.d = DUK_DOUBLE_NAN; /* should not happen */
@@ -65687,15 +72199,19 @@ DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tva
}
}
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_push_number(thr, du.d); /* will NaN normalize result */
+ duk_replace(thr, (duk_idx_t) idx_z);
+#else /* DUK_USE_EXEC_PREFER_SIZE */
/* important to use normalized NaN with 8-byte tagged types */
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
}
-DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
/*
* Binary bitwise operations use different coercions (ToInt32, ToUint32)
* depending on the operation. We coerce the arguments first using
@@ -65706,8 +72222,6 @@ DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_t
* E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
*/
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
duk_int32_t i1, i2, i3;
duk_uint32_t u1, u2, u3;
#if defined(DUK_USE_FASTINT)
@@ -65715,13 +72229,18 @@ DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_t
#else
duk_double_t d3;
#endif
+ duk_small_uint_fast_t opcode_shifted;
+#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_tval *tv_z;
+#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
+
+ opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
@@ -65731,52 +72250,52 @@ DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_t
else
#endif /* DUK_USE_FASTINT */
{
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- i1 = duk_to_int32(ctx, -2);
- i2 = duk_to_int32(ctx, -1);
- duk_pop_2(ctx);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ i1 = duk_to_int32(thr, -2);
+ i2 = duk_to_int32(thr, -1);
+ duk_pop_2_unsafe(thr);
}
- switch (opcode) {
- case DUK_OP_BAND: {
+ switch (opcode_shifted) {
+ case DUK_OP_BAND >> 2: {
i3 = i1 & i2;
break;
}
- case DUK_OP_BOR: {
+ case DUK_OP_BOR >> 2: {
i3 = i1 | i2;
break;
}
- case DUK_OP_BXOR: {
+ case DUK_OP_BXOR >> 2: {
i3 = i1 ^ i2;
break;
}
- case DUK_OP_BASL: {
+ case DUK_OP_BASL >> 2: {
/* Signed shift, named "arithmetic" (asl) because the result
* is signed, e.g. 4294967295 << 1 -> -2. Note that result
* must be masked.
*/
u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
- i3 = i1 << (u2 & 0x1f); /* E5 Section 11.7.1, steps 7 and 8 */
- i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
+ i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */
+ i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
break;
}
- case DUK_OP_BASR: {
+ case DUK_OP_BASR >> 2: {
/* signed shift */
u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
- i3 = i1 >> (u2 & 0x1f); /* E5 Section 11.7.2, steps 7 and 8 */
+ i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
break;
}
- case DUK_OP_BLSR: {
+ case DUK_OP_BLSR >> 2: {
/* unsigned shift */
u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
/* special result value handling */
- u3 = u1 >> (u2 & 0x1f); /* E5 Section 11.7.2, steps 7 and 8 */
+ u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
#if defined(DUK_USE_FASTINT)
fi3 = (duk_int64_t) u3;
goto fastint_result_set;
@@ -65802,20 +72321,25 @@ DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_t
fastint_result_set:
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
-#else
+#else /* DUK_USE_FASTINT */
d3 = (duk_double_t) i3;
result_set:
DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_push_number(thr, d3); /* would NaN normalize result, but unnecessary */
+ duk_replace(thr, (duk_idx_t) idx_z);
+#else /* DUK_USE_EXEC_PREFER_SIZE */
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
-#endif
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+#endif /* DUK_USE_FASTINT */
}
/* In-place unary operation. */
-DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_t idx_x, duk_small_uint_fast_t opcode) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst, duk_small_uint_fast_t opcode) {
/*
* Arithmetic operations other than '+' have number-only semantics
* and are implemented here. The separate switch-case here means a
@@ -65824,137 +72348,271 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
* E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
*/
- duk_context *ctx = (duk_context *) thr;
+ duk_tval *tv;
duk_double_t d1;
duk_double_union du;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNM || opcode == DUK_EXTRAOP_UNP);
- DUK_ASSERT(tv_x != NULL);
- DUK_ASSERT(idx_x >= 0);
+ DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP);
+ DUK_ASSERT_DISABLE(idx_src >= 0);
+ DUK_ASSERT_DISABLE(idx_dst >= 0);
+
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x)) {
+ if (DUK_TVAL_IS_FASTINT(tv)) {
duk_int64_t v1, v2;
- v1 = DUK_TVAL_GET_FASTINT(tv_x);
- if (opcode == DUK_EXTRAOP_UNM) {
+ v1 = DUK_TVAL_GET_FASTINT(tv);
+ if (opcode == DUK_OP_UNM) {
/* The smallest fastint is no longer 48-bit when
* negated. Positive zero becames negative zero
* (cannot be represented) when negated.
*/
if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
v2 = -v1;
- DUK_TVAL_SET_FASTINT(tv_x, v2); /* no refcount changes */
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
return;
}
} else {
/* ToNumber() for a fastint is a no-op. */
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
+ DUK_ASSERT(opcode == DUK_OP_UNP);
+ v2 = v1;
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
return;
}
/* fall through if overflow etc */
}
#endif /* DUK_USE_FASTINT */
- if (!DUK_TVAL_IS_NUMBER(tv_x)) {
- duk_to_number(ctx, idx_x); /* side effects, perform in-place */
- tv_x = DUK_GET_TVAL_POSIDX(ctx, idx_x);
- DUK_ASSERT(tv_x != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
- }
-
- d1 = DUK_TVAL_GET_NUMBER(tv_x);
- if (opcode == DUK_EXTRAOP_UNM) {
- du.d = -d1;
+ if (DUK_TVAL_IS_NUMBER(tv)) {
+ d1 = DUK_TVAL_GET_NUMBER(tv);
} else {
- /* ToNumber() for a double is a no-op. */
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
- du.d = d1;
+ d1 = duk_to_number_tval(thr, tv); /* side effects */
}
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
-
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ if (opcode == DUK_OP_UNP) {
+ /* ToNumber() for a double is a no-op, but unary plus is
+ * used to force a fastint check so do that here.
+ */
+ du.d = d1;
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
#if defined(DUK_USE_FASTINT)
- /* Unary plus is used to force a fastint check, so must include
- * downgrade check.
- */
- DUK_TVAL_SET_NUMBER_CHKFAST(tv_x, du.d); /* no refcount changes */
-#else
- DUK_TVAL_SET_NUMBER(tv_x, du.d); /* no refcount changes */
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */
+ return;
#endif
+ } else {
+ DUK_ASSERT(opcode == DUK_OP_UNM);
+ du.d = -d1;
+ DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ }
+
+ /* XXX: size optimize: push+replace? */
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d);
}
-DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
/*
* E5 Section 11.4.8
*/
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
+ duk_tval *tv;
duk_int32_t i1, i2;
-#if !defined(DUK_USE_FASTINT)
- duk_double_t d2;
-#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT_DISABLE(idx_z >= 0);
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT_DISABLE(idx_src >= 0);
+ DUK_ASSERT_DISABLE(idx_dst >= 0);
+ DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
+ DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
+
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x)) {
- i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
+ if (DUK_TVAL_IS_FASTINT(tv)) {
+ i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv);
}
else
#endif /* DUK_USE_FASTINT */
{
- duk_push_tval(ctx, tv_x);
- i1 = duk_to_int32(ctx, -1);
- duk_pop(ctx);
+ duk_push_tval(thr, tv);
+ i1 = duk_to_int32(thr, -1); /* side effects */
+ duk_pop_unsafe(thr);
}
- i2 = ~i1;
-
-#if defined(DUK_USE_FASTINT)
/* Result is always fastint compatible. */
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv_z, i2); /* side effects */
-#else
- d2 = (duk_double_t) i2;
-
- DUK_ASSERT(!DUK_ISNAN(d2)); /* 'val' is never NaN, so no need to normalize */
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); /* always normalized */
-
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d2); /* side effects */
-#endif
+ i2 = ~i1;
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */
}
-DUK_LOCAL void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_z) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
/*
* E5 Section 11.4.9
*/
+ duk_tval *tv;
duk_bool_t res;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT(tv_z != NULL); /* reg */
-
- DUK_UNREF(thr); /* w/o refcounts */
+ DUK_ASSERT_DISABLE(idx_src >= 0);
+ DUK_ASSERT_DISABLE(idx_dst >= 0);
+ DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
+ DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
/* ToBoolean() does not require any operations with side effects so
* we can do it efficiently. For footprint it would be better to use
* duk_js_toboolean() and then push+replace to the result slot.
*/
- res = duk_js_toboolean(tv_x); /* does not modify tv_x */
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
+ res = duk_js_toboolean(tv); /* does not modify 'tv' */
DUK_ASSERT(res == 0 || res == 1);
res ^= 1;
- DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv_z, res); /* side effects */
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
+ /* XXX: size optimize: push+replace? */
+ DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */
+}
+
+/* XXX: size optimized variant */
+DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) {
+ duk_double_t x, y, z;
+
+ /* Two lowest bits of opcode are used to distinguish
+ * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
+ */
+ DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
+ DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
+ DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
+ DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
+
+#if defined(DUK_USE_FASTINT)
+ if (DUK_TVAL_IS_FASTINT(tv_src)) {
+ duk_int64_t x_fi, y_fi, z_fi;
+ x_fi = DUK_TVAL_GET_FASTINT(tv_src);
+ if (op & 0x01) {
+ if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) {
+ goto skip_fastint;
+ }
+ y_fi = x_fi - 1;
+ } else {
+ if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) {
+ goto skip_fastint;
+ }
+ y_fi = x_fi + 1;
+ }
+
+ DUK_TVAL_SET_FASTINT(tv_src, y_fi); /* no need for refcount update */
+
+ z_fi = (op & 0x02) ? x_fi : y_fi;
+ DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi); /* side effects */
+ return;
+ }
+ skip_fastint:
+#endif
+ if (DUK_TVAL_IS_NUMBER(tv_src)) {
+ /* Fast path for the case where the register
+ * is a number (e.g. loop counter).
+ */
+
+ x = DUK_TVAL_GET_NUMBER(tv_src);
+ if (op & 0x01) {
+ y = x - 1.0;
+ } else {
+ y = x + 1.0;
+ }
+
+ DUK_TVAL_SET_NUMBER(tv_src, y); /* no need for refcount update */
+ } else {
+ /* Preserve duk_tval pointer(s) across a potential valstack
+ * resize by converting them into offsets temporarily.
+ */
+ duk_idx_t bc;
+ duk_size_t off_dst;
+
+ off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom);
+ bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */
+ tv_src = NULL; /* no longer referenced */
+
+ x = duk_to_number(thr, bc);
+ if (op & 0x01) {
+ y = x - 1.0;
+ } else {
+ y = x + 1.0;
+ }
+
+ duk_push_number(thr, y);
+ duk_replace(thr, bc);
+
+ tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst);
+ }
+
+ z = (op & 0x02) ? x : y;
+ DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */
+}
+
+DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_small_uint_t is_strict) {
+ duk_activation *act;
+ duk_double_t x, y;
+ duk_hstring *name;
+
+ /* XXX: The pre/post inc/dec for an identifier lookup is
+ * missing the important fast path where the identifier
+ * has a storage location e.g. in a scope object so that
+ * it can be updated in-place. In particular, the case
+ * where the identifier has a storage location AND the
+ * previous value is a number should be optimized because
+ * it's side effect free.
+ */
+
+ /* Two lowest bits of opcode are used to distinguish
+ * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
+ */
+ DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
+ DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
+ DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
+ DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
+
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id));
+ name = DUK_TVAL_GET_STRING(tv_id);
+ DUK_ASSERT(name != NULL);
+ act = thr->callstack_curr;
+ (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */
+
+ /* XXX: Fastint fast path would be useful here. Also fastints
+ * now lose their fastint status in current handling which is
+ * not intuitive.
+ */
+
+ x = duk_to_number_m2(thr);
+ if (op & 0x01) {
+ y = x - 1.0;
+ } else {
+ y = x + 1.0;
+ }
+
+ /* [... x this] */
+
+ if (op & 0x02) {
+ duk_push_number(thr, y); /* -> [ ... x this y ] */
+ DUK_ASSERT(act == thr->callstack_curr);
+ duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
+ duk_pop_2_unsafe(thr); /* -> [ ... x ] */
+ } else {
+ duk_pop_2_unsafe(thr); /* -> [ ... ] */
+ duk_push_number(thr, y); /* -> [ ... y ] */
+ DUK_ASSERT(act == thr->callstack_curr);
+ duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
+ }
+
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_replace(thr, (duk_idx_t) idx_dst);
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst));
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
}
/*
@@ -65978,117 +72636,118 @@ DUK_LOCAL void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *t
* top are combined into one pass.
*/
-/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
-DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
+/* Reconfigure value stack for return to an Ecmascript function at
+ * callstack top (caller unwinds).
+ */
+DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) {
duk_activation *act;
- duk_hcompiledfunction *h_func;
+ duk_hcompfunc *h_func;
duk_idx_t clamp_top;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
/* Clamp so that values at 'clamp_top' and above are wiped and won't
* retain reachable garbage. Then extend to 'nregs' because we're
* returning to an Ecmascript function.
*/
- act = thr->callstack + act_idx;
- h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
+ h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(act->idx_retval >= act->idx_bottom);
- clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff);
+ clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval)); /* +1 = one retval */
+ duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
- duk_set_top((duk_context *) thr, h_func->nregs);
+ /* XXX: a best effort shrink check would be OK here */
}
-DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
- duk_activation *act;
+/* Reconfigure value stack for an Ecmascript catcher. Use topmost catcher
+ * in 'act'.
+ */
+DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) {
duk_catcher *cat;
- duk_hcompiledfunction *h_func;
+ duk_hcompfunc *h_func;
+ duk_size_t idx_bottom;
duk_idx_t clamp_top;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
-
- act = thr->callstack + act_idx;
- cat = thr->catchstack + cat_idx;
- h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
-
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(cat->idx_base >= act->idx_bottom);
- clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
- cat = NULL;
-
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-
- duk_set_top((duk_context *) thr, h_func->nregs);
-}
-
-/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
-DUK_LOCAL void duk__set_catcher_regs(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+
+ h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
+
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+ DUK_ASSERT(cat->idx_base >= idx_bottom);
+ clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
+ duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
+
+ DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
+
+ /* XXX: a best effort shrink check would be OK here */
+}
+
+/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type.
+ * No side effects.
+ */
+DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_tval *tv1;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
+ tv1 = thr->valstack + cat->idx_base;
DUK_ASSERT(tv1 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable);
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
+ tv1++;
+ DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1);
DUK_ASSERT(tv1 < thr->valstack_top);
-
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
+ DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type);
}
-DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
- duk_context *ctx;
+DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- ctx = (duk_context *) thr;
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
- duk_hthread_catchstack_unwind(thr, cat_idx + 1);
- duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
+ duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ duk__reconfig_valstack_ecma_catcher(thr, act);
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
- act = NULL;
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+
+ act->curr_pc = cat->pc_base + 0; /* +0 = catch */
/*
* If entering a 'catch' block which requires an automatic
@@ -66100,41 +72759,39 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
* which implies the binding is not deletable.
*/
- if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
- duk_hobject *new_env;
- duk_hobject *act_lex_env;
+ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) {
+ duk_hdecenv *new_env;
DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
- /* Note: 'act' is dangerous here because it may get invalidate at many
- * points, so we re-lookup it multiple times.
- */
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
if (act->lex_env == NULL) {
DUK_ASSERT(act->var_env == NULL);
DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
- /* this may have side effects, so re-lookup act */
duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_UNREF(act); /* unreferenced without assertions */
- act = thr->callstack + thr->callstack_top - 1;
- act_lex_env = act->lex_env;
- act = NULL; /* invalidated */
-
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- act_lex_env);
- new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
+ /* XXX: If an out-of-memory happens here, longjmp state asserts
+ * will be triggered at present and a try-catch fails to catch.
+ * That's not sandboxing fatal (C API protected calls are what
+ * matters), and script catch code can immediately throw anyway
+ * for almost any operation.
+ */
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
/* Note: currently the catch binding is handled without a register
@@ -66143,112 +72800,126 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
* record regbases etc.
*/
- DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
- duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
- duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
-
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = new_env;
- DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */
+ /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */
+ DUK_ASSERT(cat->h_varname != NULL);
+ duk_push_hstring(thr, cat->h_varname);
+ duk_push_tval(thr, thr->valstack + cat->idx_base);
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
+
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env);
+ act->lex_env = (duk_hobject *) new_env;
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */
+ /* Net refcount change to act->lex_env is 0: incref for new_env's
+ * prototype, decref for act->lex_env overwrite.
+ */
- DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
+ DUK_CAT_SET_LEXENV_ACTIVE(cat);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
}
- DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
+ DUK_CAT_CLEAR_CATCH_ENABLED(cat);
}
-DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
+DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
- duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
- duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
+ duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ duk__reconfig_valstack_ecma_catcher(thr, act);
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
- act = NULL;
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+
+ act->curr_pc = cat->pc_base + 1; /* +1 = finally */
- DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
}
-DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
+DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
-
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
/* +0 = break, +1 = continue */
- act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
- act = NULL; /* invalidated */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
- duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */
- /* no need to unwind callstack */
+ act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
/* valstack should not need changes */
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
- (duk_size_t) ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act))->nregs);
+ (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs);
#endif
}
/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
* when a RETURN opcode terminates a thread and yields to the resumer.
+ * Caller unwinds so that top of callstack is the activation we return to.
*/
-DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) {
+ duk_activation *act_resumer;
duk_tval *tv1;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(resumer != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
-
- tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
+ act_resumer = resumer->callstack_curr;
+ DUK_ASSERT(act_resumer != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ecmascript func */
- duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */
+ tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */
- /* no need to unwind catchstack */
- duk__reconfig_valstack_ecma_return(resumer, act_idx);
+ duk__reconfig_valstack_ecma_return(resumer);
/* caller must change active thread, and set thr->resumer to NULL */
}
+#endif /* DUK_USE_COROUTINE_SUPPORT */
-DUK_LOCAL
-duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
- duk_size_t entry_callstack_index;
+DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act) {
duk_small_uint_t retval = DUK__LONGJMP_RESTART;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
- DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
-
- entry_callstack_index = entry_callstack_top - 1;
+ DUK_ASSERT(entry_act != NULL);
/* 'thr' is the current thread, as no-one resumes except us and we
* switch 'thr' in that case.
@@ -66275,6 +72946,7 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
switch (thr->heap->lj.type) {
+#if defined(DUK_USE_COROUTINE_SUPPORT)
case DUK_LJ_TYPE_RESUME: {
/*
* Note: lj.value1 is 'value', lj.value2 is 'resumee'.
@@ -66283,19 +72955,17 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
duk_tval *tv;
duk_tval *tv2;
- duk_size_t act_idx;
duk_hthread *resumee;
/* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume);
tv = &thr->heap->lj.value2; /* resumee */
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
@@ -66310,20 +72980,11 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield));
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2)))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */
+ (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL &&
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield));
DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
- (resumee->valstack_top == resumee->valstack + 1 &&
- DUK_TVAL_IS_OBJECT(resumee->valstack_top - 1) &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(resumee->valstack_top - 1))));
if (thr->heap->lj.iserror) {
/*
@@ -66336,7 +72997,9 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* which we simply ignore.
*/
+ DUK_ASSERT(resumee->resumer == NULL);
resumee->resumer = thr;
+ DUK_HTHREAD_INCREF(thr, thr);
resumee->state = DUK_HTHREAD_STATE_RUNNING;
thr->state = DUK_HTHREAD_STATE_RESUMED;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
@@ -66352,21 +73015,32 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
goto check_longjmp;
} else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
- act_idx = resumee->callstack_top - 2; /* Ecmascript function */
- DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
+ /* Unwind previous Duktape.Thread.yield() call. The
+ * activation remaining must always be an Ecmascript
+ * call now (yield() accepts calls from Ecmascript
+ * only).
+ */
+ duk_activation *act_resumee;
- tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
+ DUK_ASSERT(resumee->callstack_top >= 2);
+ act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */
+ DUK_ASSERT(act_resumee != NULL);
+ act_resumee = act_resumee->parent; /* Ecmascript call site for yield() */
+ DUK_ASSERT(act_resumee != NULL);
+
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */
DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
tv2 = &thr->heap->lj.value1;
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
-
- duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ /* XXX: avoid side effects */
- /* no need to unwind catchstack */
+ duk_hthread_activation_unwind_norz(resumee); /* unwind to 'yield' caller */
+ /* no need to unwind catch stack */
- duk__reconfig_valstack_ecma_return(resumee, act_idx);
+ duk__reconfig_valstack_ecma_return(resumee);
+ DUK_ASSERT(resumee->resumer == NULL);
resumee->resumer = thr;
+ DUK_HTHREAD_INCREF(thr, thr);
resumee->state = DUK_HTHREAD_STATE_RUNNING;
thr->state = DUK_HTHREAD_STATE_RESUMED;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
@@ -66377,28 +73051,33 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
retval = DUK__LONGJMP_RESTART;
goto wipe_and_return;
} else {
+ /* Initial resume call. */
duk_small_uint_t call_flags;
- duk_bool_t setup_rc;
+ duk_int_t setup_rc;
/* resumee: [... initial_func] (currently actually: [initial_func]) */
- duk_push_undefined((duk_context *) resumee);
+ duk_push_undefined(resumee);
tv = &thr->heap->lj.value1;
- duk_push_tval((duk_context *) resumee, tv);
+ duk_push_tval(resumee, tv);
/* resumee: [... initial_func undefined(= this) resume_value ] */
- call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
+ call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA; /* not tailcall, ecma-to-ecma (assumed to succeed) */
- setup_rc = duk_handle_ecma_call_setup(resumee,
- 1, /* num_stack_args */
- call_flags); /* call_flags */
+ setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags);
if (setup_rc == 0) {
- /* Shouldn't happen but check anyway. */
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ /* This shouldn't happen; Duktape.Thread.resume()
+ * should make sure of that. If it does happen
+ * this internal error will propagate out of the
+ * executor which can be quite misleading.
+ */
+ DUK_ERROR_INTERNAL(thr);
}
+ DUK_ASSERT(resumee->resumer == NULL);
resumee->resumer = thr;
+ DUK_HTHREAD_INCREF(thr, thr);
resumee->state = DUK_HTHREAD_STATE_RUNNING;
thr->state = DUK_HTHREAD_STATE_RESUMED;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
@@ -66428,31 +73107,36 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
/* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
+#if 0 /* entry_thread not available for assert */
DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
+#endif
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an Ecmascript function */
resumer = thr->resumer;
DUK_ASSERT(resumer != NULL);
DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(resumer->callstack_curr != NULL);
+ DUK_ASSERT(resumer->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL &&
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an Ecmascript function */
if (thr->heap->lj.iserror) {
thr->state = DUK_HTHREAD_STATE_YIELDED;
thr->resumer = NULL;
+ DUK_HTHREAD_DECREF_NORZ(thr, resumer);
resumer->state = DUK_HTHREAD_STATE_RUNNING;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
thr = resumer;
@@ -66464,10 +73148,12 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
goto check_longjmp;
} else {
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
+ duk_hthread_activation_unwind_norz(resumer);
+ duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
thr->state = DUK_HTHREAD_STATE_YIELDED;
thr->resumer = NULL;
+ DUK_HTHREAD_DECREF_NORZ(thr, resumer);
resumer->state = DUK_HTHREAD_STATE_RUNNING;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
#if 0
@@ -66481,6 +73167,7 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_UNREACHABLE();
break; /* never here */
}
+#endif /* DUK_USE_COROUTINE_SUPPORT */
case DUK_LJ_TYPE_THROW: {
/*
@@ -66501,76 +73188,75 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* Ecmascript activations.
*/
+ duk_activation *act;
duk_catcher *cat;
duk_hthread *resumer;
- cat = thr->catchstack + thr->catchstack_top - 1;
- while (cat >= thr->catchstack) {
- if (thr == entry_thread &&
- cat->callstack_index < entry_callstack_index) {
- /* entry level reached */
+ for (;;) {
+ act = thr->callstack_curr;
+ if (act == NULL) {
break;
}
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
+ break;
+ }
- duk__handle_catch(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
+ if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
+ duk__handle_catch(thr,
+ &thr->heap->lj.value1,
+ DUK_LJ_TYPE_THROW);
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
+ DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
+ retval = DUK__LONGJMP_RESTART;
+ goto wipe_and_return;
+ }
- duk__handle_finally(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
+ DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
+ duk__handle_finally(thr,
+ &thr->heap->lj.value1,
+ DUK_LJ_TYPE_THROW);
- cat--;
- }
+ DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
+ retval = DUK__LONGJMP_RESTART;
+ goto wipe_and_return;
+ }
- if (thr == entry_thread) {
- /* not caught by anything before entry level; rethrow and let the
- * final catcher unwind everything
- */
-#if 0
- duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
+ duk_hthread_catcher_unwind_norz(thr, act);
+ }
-#endif
- DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
- retval = DUK__LONGJMP_RETHROW;
- goto just_return;
- /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
+ if (act == entry_act) {
+ /* Not caught by anything before entry level; rethrow and let the
+ * final catcher finish unwinding (esp. value stack).
+ */
+ DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
+ retval = DUK__LONGJMP_RETHROW;
+ goto just_return;
+ }
+
+ duk_hthread_activation_unwind_norz(thr);
}
DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
- /* not caught by current thread, thread terminates (yield error to resumer);
+ /* Not caught by current thread, thread terminates (yield error to resumer);
* note that this may cause a cascade if the resumer terminates with an uncaught
- * exception etc (this is OK, but needs careful testing)
+ * exception etc (this is OK, but needs careful testing).
*/
DUK_ASSERT(thr->resumer != NULL);
DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
+ DUK_ASSERT(thr->resumer->callstack_curr != NULL);
+ DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */
resumer = thr->resumer;
@@ -66583,6 +73269,7 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
thr->resumer = NULL;
+ DUK_HTHREAD_DECREF_NORZ(thr, resumer);
resumer->state = DUK_HTHREAD_STATE_RUNNING;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
thr = resumer;
@@ -66611,6 +73298,8 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
+ DUK_GC_TORTURE(thr->heap);
+
just_return:
return retval;
@@ -66619,7 +73308,7 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* but it's better for internal errors to bubble outwards so that we won't
* infinite loop in this catchpoint.
*/
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
DUK_UNREACHABLE();
return retval;
}
@@ -66628,72 +73317,63 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* handling because it has a measurable performance impact in ordinary
* environments and an extreme impact in Emscripten (GH-342).
*/
-DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
- duk_uint_t label_id,
- duk_small_uint_t lj_type) {
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr,
+ duk_uint_t label_id,
+ duk_small_uint_t lj_type) {
+ duk_activation *act;
duk_catcher *cat;
- duk_size_t orig_callstack_index;
DUK_ASSERT(thr != NULL);
- /*
- * Find a matching label catcher or 'finally' catcher in
- * the same function.
+ /* Find a matching label catcher or 'finally' catcher in
+ * the same function, unwinding catchers as we go.
*
- * A label catcher must always exist and will match unless
- * a 'finally' captures the break/continue first. It is the
- * compiler's responsibility to ensure that labels are used
- * correctly.
- */
-
- /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
- * initially. This is OK and intended.
+ * A label catcher must always exist and will match unless
+ * a 'finally' captures the break/continue first. It is the
+ * compiler's responsibility to ensure that labels are used
+ * correctly.
*/
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(thr->callstack_top > 0);
- orig_callstack_index = thr->callstack_top - 1;
- DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
- (long) label_id, (long) cat->callstack_index));
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
break;
}
- DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
- (long) (cat - thr->catchstack),
+
+ DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld",
+ (void *) cat,
(long) DUK_CAT_GET_TYPE(cat),
(long) DUK_CAT_GET_LABEL(cat)));
+ /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */
+
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
duk_tval tv_tmp;
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
- DUK_TVAL_SET_FASTINT_U32(&tv_tmp, (duk_uint32_t) label_id);
- duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
+ DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id);
+ duk__handle_finally(thr, &tv_tmp, lj_type);
DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
return;
}
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
(duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack);
- duk__handle_label(thr, cat_idx, lj_type);
+ duk__handle_label(thr, lj_type);
DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
return;
}
- cat--;
+
+ duk_hthread_catcher_unwind_norz(thr, act);
}
- /* should never happen, but be robust */
+ /* Should never happen, but be robust. */
DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
return;
}
@@ -66701,23 +73381,22 @@ DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
* it has a measurable performance impact in ordinary environments and an extreme
* impact in Emscripten (GH-342). Return value is on value stack top.
*/
-DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
+DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) {
duk_tval *tv1;
duk_tval *tv2;
+#if defined(DUK_USE_COROUTINE_SUPPORT)
duk_hthread *resumer;
+#endif
+ duk_activation *act;
duk_catcher *cat;
- duk_size_t new_cat_top;
- duk_size_t orig_callstack_index;
/* We can directly access value stack here. */
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
+ DUK_ASSERT(entry_act != NULL);
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
tv1 = thr->valstack_top - 1;
- DUK_TVAL_CHKFAST_INPLACE(tv1); /* fastint downgrade check for return values */
+ DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */
/*
* Four possible outcomes:
@@ -66742,113 +73421,134 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack != NULL);
- /* XXX: does not work if thr->catchstack is NULL */
- /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
-
- cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
- DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
- orig_callstack_index = thr->callstack_top - 1;
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
break;
}
+
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
+ duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
return DUK__RETHAND_RESTART;
}
- cat--;
- }
- /* If out of catchstack, cat = thr->catchstack - 1;
- * new_cat_top will be 0 in that case.
- */
- new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
- cat = NULL; /* avoid referencing, invalidated */
- DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
+ duk_hthread_catcher_unwind_norz(thr, act);
+ }
- if (thr == entry_thread &&
- thr->callstack_top == entry_callstack_top) {
- /* Return to the bytecode executor caller which will unwind stacks.
+ if (act == entry_act) {
+ /* Return to the bytecode executor caller who will unwind stacks
+ * and handle constructor post-processing.
* Return value is already on the stack top: [ ... retval ].
*/
- /* XXX: could unwind catchstack here, so that call handling
- * didn't need to do that?
- */
DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
return DUK__RETHAND_FINISHED;
}
if (thr->callstack_top >= 2) {
/* There is a caller; it MUST be an Ecmascript caller (otherwise it would
- * match entry level check)
+ * match entry_act check).
*/
-
- DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
- (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
+ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, retval_byteoff=%ld, lj_value1=%!T",
+ (long) (thr->callstack_curr->parent->retval_byteoff),
(duk_tval *) &thr->heap->lj.value1));
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ecmascript */
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) {
+ duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY); /* side effects */
+ }
+#else
+ if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) {
+ duk_call_construct_postprocess(thr, 0); /* side effects */
+ }
+#endif
- tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
+ tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff);
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
tv2 = thr->valstack_top - 1;
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
- (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
- (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval)));
+ /* Catch stack unwind happens inline in callstack unwind. */
+ duk_hthread_activation_unwind_norz(thr);
- duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
- duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
+ duk__reconfig_valstack_ecma_return(thr);
DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
return DUK__RETHAND_RESTART;
}
+#if defined(DUK_USE_COROUTINE_SUPPORT)
DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
DUK_ASSERT(thr->resumer != NULL);
DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(thr->resumer->callstack_curr != NULL);
+ DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL &&
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
resumer = thr->resumer;
- /* Share yield longjmp handler. */
+ /* Share yield longjmp handler.
+ *
+ * This sequence of steps is a bit fragile (see GH-1845):
+ * - We need the return value from 'thr' (resumed thread) value stack.
+ * The termination unwinds its value stack, losing the value.
+ * - We need a refcounted reference for 'thr', which may only exist
+ * in the caller value stack. We can't unwind or reconfigure the
+ * caller's value stack without potentially freeing 'thr'.
+ *
+ * Current approach is to capture the 'thr' return value and store
+ * a reference to 'thr' in the caller value stack temporarily. This
+ * keeps 'thr' reachable until final yield/return handling which
+ * removes the references atomatically.
+ */
+
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
+ duk_hthread_activation_unwind_norz(resumer); /* May remove last reference to 'thr', but is NORZ. */
+ duk_push_tval(resumer, thr->valstack_top - 1); /* Capture return value, side effect free. */
+ duk_push_hthread(resumer, thr); /* Make 'thr' reachable again, before side effects. */
- duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
+ duk_hthread_terminate(thr); /* Updates thread state, minimizes its allocations. */
+ thr->resumer = NULL;
+ DUK_HTHREAD_DECREF(thr, resumer);
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
- thr->resumer = NULL;
resumer->state = DUK_HTHREAD_STATE_RUNNING;
DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
+
+ DUK_ASSERT(resumer->valstack_top - 2 >= resumer->valstack_bottom);
+ duk__handle_yield(thr, resumer, resumer->valstack_top - 2);
+ thr = NULL; /* 'thr' invalidated by call */
+
#if 0
thr = resumer; /* not needed */
#endif
DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
return DUK__RETHAND_RESTART;
+#else
+ /* Without coroutine support this case should never happen. */
+ DUK_ERROR_INTERNAL(thr);
+ return DUK__RETHAND_FINISHED; /* not executed */
+#endif
}
/*
@@ -66883,7 +73583,6 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
- duk_context *ctx;
duk_activation *act;
duk_breakpoint *bp;
duk_breakpoint **bp_active;
@@ -66893,8 +73592,8 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
- ctx = (duk_context *) thr;
- act = thr->callstack + thr->callstack_top - 1;
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
/* It might seem that replacing 'thr->heap' with just 'heap' below
* might be a good idea, but it increases code size slightly
@@ -66902,25 +73601,30 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
*/
/*
+ * Single opcode step check
+ */
+
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step"));
+ duk_debug_set_paused(thr->heap);
+ }
+
+ /*
* Breakpoint and step state checks
*/
if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- (thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
+ (thr->heap->dbg_pause_act == thr->callstack_curr)) {
line = duk_debug_curr_line(thr);
if (act->prev_line != line) {
/* Stepped? Step out is handled by callstack unwind. */
- if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- (thr->heap->dbg_step_thread == thr) &&
- (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
- (line != thr->heap->dbg_step_startline)) {
- DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
+ if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ (thr->heap->dbg_pause_act == thr->callstack_curr) &&
+ (line != thr->heap->dbg_pause_startline)) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld",
(long) line));
-
- DUK_HEAP_SET_PAUSED(thr->heap);
+ duk_debug_set_paused(thr->heap);
}
/* Check for breakpoints only on line transition.
@@ -66944,17 +73648,16 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
DUK_ASSERT(bp->filename != NULL);
if (act->prev_line != bp->line && line == bp->line) {
- DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld",
(duk_heaphdr *) bp->filename, (long) bp->line));
-
- DUK_HEAP_SET_PAUSED(thr->heap);
+ duk_debug_set_paused(thr->heap);
}
}
} else {
;
}
- act->prev_line = line;
+ act->prev_line = (duk_uint32_t) line;
}
/*
@@ -66970,7 +73673,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
*/
process_messages = 0;
- if (thr->heap->dbg_state_dirty || thr->heap->dbg_paused || thr->heap->dbg_detaching) {
+ if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) {
/* Enter message processing loop for sending Status notifys and
* to finish a pending detach.
*/
@@ -66978,7 +73681,8 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
}
/* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
- thr->heap->dbg_exec_counter += thr->interrupt_init;
+ DUK_ASSERT(thr->interrupt_init >= 0);
+ thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init;
if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
/* Overflow of the execution counter is fine and doesn't break
* anything here.
@@ -66987,12 +73691,14 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
duk_double_t now, diff_last;
thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
- now = DUK_USE_DATE_GET_NOW(ctx);
+ now = duk_time_get_monotonic_time(thr);
diff_last = now - thr->heap->dbg_last_time;
if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
- /* Negative value checked so that a "time jump" works
- * reasonably.
+ /* Monotonic time should not experience time jumps,
+ * but the provider may be missing and we're actually
+ * using Ecmascript time. So, tolerate negative values
+ * so that a time jump works reasonably.
*
* Same interval is now used for status sending and
* peeking.
@@ -67019,7 +73725,6 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
* detaching.
*/
- act = NULL; /* may be changed */
if (process_messages) {
DUK_ASSERT(thr->heap->dbg_processing == 0);
processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
@@ -67034,14 +73739,14 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
* above, so we must recheck attach status.
*/
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */
+ if (duk_debug_is_attached(thr->heap)) {
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
- thr->heap->dbg_paused) {
+ (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) ||
+ ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ thr->heap->dbg_pause_act == thr->callstack_curr) ||
+ DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
*out_immediate = 1;
}
@@ -67051,6 +73756,13 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
if (processed_messages) {
DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
*out_interrupt_retval = DUK__INT_RESTART;
+ } else {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) {
+ /* Set 'pause after one opcode' active only when we're
+ * actually just about to execute code.
+ */
+ thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE;
+ }
}
} else {
DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
@@ -67058,16 +73770,15 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
+DUK_LOCAL DUK__NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
duk_int_t ctr;
duk_activation *act;
- duk_hcompiledfunction *fun;
+ duk_hcompfunc *fun;
duk_bool_t immediate = 0;
duk_small_uint_t retval;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(thr->callstack != NULL);
DUK_ASSERT(thr->callstack_top > 0);
#if defined(DUK_USE_DEBUG)
@@ -67108,10 +73819,11 @@ DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
}
DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
- act = thr->callstack + thr->callstack_top - 1;
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION((duk_hobject *) fun));
+ fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun));
DUK_UNREF(fun);
@@ -67144,8 +73856,7 @@ DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
* detaching (to finish off the pending detach).
*/
duk__interrupt_handle_debugger(thr, &immediate, &retval);
- act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
+ DUK_ASSERT(act == thr->callstack_curr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
@@ -67183,7 +73894,7 @@ DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompiledfunction *fun) {
+DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) {
duk_heap *heap;
duk_tval *tv_tmp;
duk_hstring *filename;
@@ -67235,7 +73946,7 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
duk_hobject **funcs, **funcs_end;
- duk_hcompiledfunction *inner_fun;
+ duk_hcompfunc *inner_fun;
duk_bool_t bp_match;
if (bp->filename == filename &&
@@ -67250,11 +73961,11 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
(long) fun->start_line,
(long) fun->end_line));
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, fun);
+ funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun);
+ funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun);
while (funcs != funcs_end) {
- inner_fun = (duk_hcompiledfunction *) *funcs;
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) inner_fun));
+ inner_fun = (duk_hcompfunc *) *funcs;
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun));
if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
bp_match = 0;
@@ -67281,21 +73992,19 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
/* Force pause if we were doing "step into" in another activation. */
- if (thr->heap->dbg_step_thread != NULL &&
- thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
- (thr->heap->dbg_step_thread != thr ||
- thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
- DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
- DUK_HEAP_SET_PAUSED(thr->heap);
+ if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) &&
+ thr->heap->dbg_pause_act != thr->callstack_curr) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry"));
+ duk_debug_set_paused(thr->heap);
}
/* Force interrupt right away if we're paused or in "checked mode".
* Step out is handled by callstack unwind.
*/
- if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
- thr->heap->dbg_paused ||
- (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
+ if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
+ DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ||
+ ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ thr->heap->dbg_pause_act == thr->callstack_curr)) {
/* We'll need to interrupt early so recompute the init
* counter to reflect the number of bytecode instructions
* executed so that step counts for e.g. debugger rate
@@ -67309,6 +74018,519 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
+ * Opcode handlers for opcodes with a lot of code and which are relatively
+ * rare; NOINLINE to reduce amount of code in main bytecode dispatcher.
+ */
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET);
+ duk_uint_fast_t idx;
+ duk_uint_t defprop_flags;
+
+ /* A -> object register (acts as a source)
+ * BC -> BC+0 contains key, BC+1 closure (value)
+ */
+
+ /* INITSET/INITGET are only used to initialize object literal keys.
+ * There may be a previous propery in ES2015 because duplicate property
+ * names are allowed.
+ */
+
+ /* This could be made more optimal by accessing internals directly. */
+
+ idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
+ duk_dup(thr, (duk_idx_t) (idx + 0)); /* key */
+ duk_dup(thr, (duk_idx_t) (idx + 1)); /* getter/setter */
+ if (is_set) {
+ defprop_flags = DUK_DEFPROP_HAVE_SETTER |
+ DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE;
+ } else {
+ defprop_flags = DUK_DEFPROP_HAVE_GETTER |
+ DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE;
+ }
+ duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_small_uint_fast_t a;
+ duk_small_uint_fast_t bc;
+
+ /* A -> flags
+ * BC -> reg_catch; base register for two registers used both during
+ * trycatch setup and when catch is triggered
+ *
+ * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
+ * reg_catch + 0: catch binding variable name (string).
+ * Automatic declarative environment is established for
+ * the duration of the 'catch' clause.
+ *
+ * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
+ * reg_catch + 0: with 'target value', which is coerced to
+ * an object and then used as a bindind object for an
+ * environment record. The binding is initialized here, for
+ * the 'try' clause.
+ *
+ * Note that a TRYCATCH generated for a 'with' statement has no
+ * catch or finally parts.
+ */
+
+ /* XXX: TRYCATCH handling should be reworked to avoid creating
+ * an explicit scope unless it is actually needed (e.g. function
+ * instances or eval is executed inside the catch block). This
+ * rework is not trivial because the compiler doesn't have an
+ * intermediate representation. When the rework is done, the
+ * opcode format can also be made more straightforward.
+ */
+
+ /* XXX: side effect handling is quite awkward here */
+
+ DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
+ "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
+ (long) DUK_DEC_BC(ins),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
+ (unsigned long) DUK_DEC_A(ins)));
+
+ a = DUK_DEC_A(ins);
+ bc = DUK_DEC_BC(ins);
+
+ /* Registers 'bc' and 'bc + 1' are written in longjmp handling
+ * and if their previous values (which are temporaries) become
+ * unreachable -and- have a finalizer, there'll be a function
+ * call during error handling which is not supported now (GH-287).
+ * Ensure that both 'bc' and 'bc + 1' have primitive values to
+ * guarantee no finalizer calls in error handling. Scrubbing also
+ * ensures finalizers for the previous values run here rather than
+ * later. Error handling related values are also written to 'bc'
+ * and 'bc + 1' but those values never become unreachable during
+ * error handling, so there's no side effect problem even if the
+ * error value has a finalizer.
+ */
+ duk_dup(thr, (duk_idx_t) bc); /* Stabilize value. */
+ duk_to_undefined(thr, (duk_idx_t) bc);
+ duk_to_undefined(thr, (duk_idx_t) (bc + 1));
+
+ /* Allocate catcher and populate it. Doesn't have to
+ * be fully atomic, but the catcher must be in a
+ * consistent state if side effects (such as finalizer
+ * calls) occur.
+ */
+
+ cat = duk_hthread_catcher_alloc(thr);
+ DUK_ASSERT(cat != NULL);
+
+ cat->flags = DUK_CAT_TYPE_TCF;
+ cat->h_varname = NULL;
+ cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
+ cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
+
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat->parent = act->cat;
+ act->cat = cat;
+
+ if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
+ cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
+ }
+ if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
+ cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
+ }
+ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
+ DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
+ cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+
+ /* borrowed reference; although 'tv1' comes from a register,
+ * its value was loaded using LDCONST so the constant will
+ * also exist and be reachable.
+ */
+ cat->h_varname = DUK_TVAL_GET_STRING(tv1);
+ } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
+ duk_hobjenv *env;
+ duk_hobject *target;
+
+ /* Delayed env initialization for activation (if needed). */
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ if (act->lex_env == NULL) {
+ DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
+ DUK_ASSERT(act->var_env == NULL);
+
+ duk_js_init_activation_environment_records_delayed(thr, act);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
+ }
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_ASSERT(act->var_env != NULL);
+
+ /* Coerce 'with' target. */
+ target = duk_to_hobject(thr, -1);
+ DUK_ASSERT(target != NULL);
+
+ /* Create an object environment; it is not pushed
+ * so avoid side effects very carefully until it is
+ * referenced.
+ */
+ env = duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
+ DUK_ASSERT(env != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
+ env->target = target; /* always provideThis=true */
+ DUK_HOBJECT_INCREF(thr, target);
+ env->has_this = 1;
+ DUK_ASSERT_HOBJENV_VALID(env);
+ DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env));
+
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env);
+ act->lex_env = (duk_hobject *) env; /* Now reachable. */
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) env);
+ /* Net refcount change to act->lex_env is 0: incref for env's
+ * prototype, decref for act->lex_env overwrite.
+ */
+
+ /* Set catcher lex_env active (affects unwind)
+ * only when the whole setup is complete.
+ */
+ cat = act->cat; /* XXX: better to relookup? not mandatory because 'cat' is stable */
+ cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
+ } else {
+ ;
+ }
+
+ DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, "
+ "idx_base=%ld, h_varname=%!O",
+ (unsigned long) cat->flags,
+ (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
+
+ duk_pop_unsafe(thr);
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_instr_t *pc_base;
+
+ DUK_UNREF(ins);
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
+
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
+ DUK_CAT_CLEAR_CATCH_ENABLED(cat);
+
+ pc_base = cat->pc_base;
+
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
+
+ tv1 = thr->valstack + cat->idx_base;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ tv1 = NULL;
+
+ tv1 = thr->valstack + cat->idx_base + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
+ tv1 = NULL;
+
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
+ } else {
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
+
+ duk_hthread_catcher_unwind_norz(thr, act); /* lexenv may be set for 'with' binding */
+ /* no need to unwind callstack */
+ }
+
+ return pc_base + 1; /* new curr_pc value */
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_instr_t *pc_base;
+
+ DUK_UNREF(ins);
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
+
+ if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
+ duk_hobject *prev_env;
+
+ /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
+ DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
+ DUK_ASSERT(act->lex_env != NULL);
+
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
+
+ prev_env = act->lex_env;
+ DUK_ASSERT(prev_env != NULL);
+ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
+ DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
+ DUK_HOBJECT_INCREF(thr, act->lex_env);
+ DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
+
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ }
+
+ pc_base = cat->pc_base;
+
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
+
+ tv1 = thr->valstack + cat->idx_base;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ tv1 = NULL;
+
+ tv1 = thr->valstack + cat->idx_base + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
+ tv1 = NULL;
+
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
+ } else {
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
+
+ duk_hthread_catcher_unwind_norz(thr, act);
+ /* no need to unwind callstack */
+ }
+
+ return pc_base + 1; /* new curr_pc value */
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) {
+ duk_activation *act;
+ duk_tval *tv1;
+ duk_uint_t reg_catch;
+ duk_small_uint_t cont_type;
+ duk_small_uint_t ret_result;
+
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ reg_catch = DUK_DEC_ABC(ins);
+
+ /* CATCH flag may be enabled or disabled here; it may be enabled if
+ * the statement has a catch block but the try block does not throw
+ * an error.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
+ (duk_tval *) (thr->valstack_bottom + reg_catch + 0),
+ (duk_tval *) (thr->valstack_bottom + reg_catch + 1)));
+
+ tv1 = thr->valstack_bottom + reg_catch + 1; /* type */
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
+#else
+ cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
+#endif
+
+ tv1--; /* value */
+
+ switch (cont_type) {
+ case DUK_LJ_TYPE_NORMAL: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
+ "dismantle catcher, resume execution after ENDFIN"));
+
+ duk_hthread_catcher_unwind_norz(thr, act);
+ /* no need to unwind callstack */
+ return 0; /* restart execution */
+ }
+ case DUK_LJ_TYPE_RETURN: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
+ "catcher, handle return, lj.value1=%!T", tv1));
+
+ /* Not necessary to unwind catch stack: return handling will
+ * do it. The finally flag of 'cat' is no longer set. The
+ * catch flag may be set, but it's not checked by return handling.
+ */
+
+ duk_push_tval(thr, tv1);
+ ret_result = duk__handle_return(thr, entry_act);
+ if (ret_result == DUK__RETHAND_RESTART) {
+ return 0; /* restart execution */
+ }
+ DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
+
+ DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
+ return 1; /* exit executor */
+ }
+ case DUK_LJ_TYPE_BREAK:
+ case DUK_LJ_TYPE_CONTINUE: {
+ duk_uint_t label_id;
+ duk_small_uint_t lj_type;
+
+ /* Not necessary to unwind catch stack: break/continue
+ * handling will do it. The finally flag of 'cat' is
+ * no longer set. The catch flag may be set, but it's
+ * not checked by break/continue handling.
+ */
+
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
+#else
+ label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
+#endif
+ lj_type = cont_type;
+ duk__handle_break_or_continue(thr, label_id, lj_type);
+ return 0; /* restart execution */
+ }
+ default: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
+ "dismantle catcher, re-throw error",
+ (long) cont_type));
+
+ duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1);
+ /* No debugger Throw notify check on purpose (rethrow). */
+
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+ duk_err_longjmp(thr);
+ DUK_UNREACHABLE();
+ }
+ }
+
+ DUK_UNREACHABLE();
+ return 0;
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_small_uint_t b;
+ duk_small_uint_t c;
+
+ /*
+ * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
+ * If called with 'null' or 'undefined', this opcode returns 'null' as
+ * the enumerator, which is special cased in NEXTENUM. This simplifies
+ * the compiler part
+ */
+
+ /* B -> register for writing enumerator object
+ * C -> value to be enumerated (register)
+ */
+ b = DUK_DEC_B(ins);
+ c = DUK_DEC_C(ins);
+
+ if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) {
+ duk_push_null(thr);
+ duk_replace(thr, (duk_idx_t) b);
+ } else {
+ duk_dup(thr, (duk_idx_t) c);
+ duk_to_object(thr, -1);
+ duk_hobject_enumerator_create(thr, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
+ duk_replace(thr, (duk_idx_t) b);
+ }
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_small_uint_t b;
+ duk_small_uint_t c;
+ duk_small_uint_t pc_skip = 0;
+
+ /*
+ * NEXTENUM checks whether the enumerator still has unenumerated
+ * keys. If so, the next key is loaded to the target register
+ * and the next instruction is skipped. Otherwise the next instruction
+ * will be executed, jumping out of the enumeration loop.
+ */
+
+ /* B -> target register for next key
+ * C -> enum register
+ */
+ b = DUK_DEC_B(ins);
+ c = DUK_DEC_C(ins);
+
+ DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
+ (duk_tval *) duk_get_tval(thr, (duk_idx_t) b),
+ (duk_tval *) duk_get_tval(thr, (duk_idx_t) c)));
+
+ if (duk_is_object(thr, (duk_idx_t) c)) {
+ /* XXX: assert 'c' is an enumerator */
+ duk_dup(thr, (duk_idx_t) c);
+ if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) {
+ /* [ ... enum ] -> [ ... next_key ] */
+ DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
+ (duk_tval *) duk_get_tval(thr, -1)));
+ pc_skip = 1;
+ } else {
+ /* [ ... enum ] -> [ ... ] */
+ DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
+ thr->valstack_top++;
+ }
+ duk_replace(thr, (duk_idx_t) b);
+ } else {
+ /* 'null' enumerator case -> behave as with an empty enumerator */
+ DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c));
+ DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
+ }
+
+ return pc_skip;
+}
+
+/*
+ * Call handling helpers.
+ */
+
+DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, duk_idx_t nargs, duk_small_uint_t call_flags) {
+ duk_bool_t rc;
+
+ duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
+
+ /* Attempt an Ecma-to-Ecma call setup. If the call
+ * target is (directly or indirectly) Reflect.construct(),
+ * the call may change into a constructor call on the fly.
+ */
+ rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags);
+ if (rc != 0) {
+ /* Ecma-to-ecma call possible, may or may not
+ * be a tail call. Avoid C recursion by
+ * reusing current executor instance.
+ */
+ DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
+ /* curr_pc synced by duk_handle_call_unprotected() */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ return rc;
+ } else {
+ /* Call was handled inline. */
+ }
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
+ return rc;
+}
+
+/*
* Ecmascript bytecode executor.
*
* Resume execution for the current thread from its current activation.
@@ -67341,34 +74563,76 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#if defined(DUK_USE_EXEC_FUN_LOCAL)
#define DUK__FUN() fun
#else
-#define DUK__FUN() ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1))
+#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr))
#endif
-#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
+
+/* Strict flag. */
+#define DUK__STRICT() ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
/* Reg/const access macros: these are very footprint and performance sensitive
- * so modify with care.
+ * so modify with care. Arguments are sometimes evaluated multiple times which
+ * is not ideal.
*/
#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
#define DUK__REGP(x) (thr->valstack_bottom + (x))
#define DUK__CONST(x) (*(consts + (x)))
#define DUK__CONSTP(x) (consts + (x))
-#if 0
-#define DUK__REGCONST(x) ((x) < DUK_BC_REGLIMIT ? DUK__REG((x)) : DUK__CONST((x) - DUK_BC_REGLIMIT))
-#define DUK__REGCONSTP(x) ((x) < DUK_BC_REGLIMIT ? DUK__REGP((x)) : DUK__CONSTP((x) - DUK_BC_REGLIMIT))
-#define DUK__REGCONST(x) *((((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x)))
-#define DUK__REGCONSTP(x) (((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x))
-#endif
-/* This macro works when a regconst field is 9 bits, [0,0x1ff]. Adding
- * DUK_LIKELY/DUK_UNLIKELY increases code footprint and doesn't seem to
- * improve performance on x64 (and actually harms performance in some tests).
- */
-#define DUK__RCISREG(x) (((x) & 0x100) == 0)
-#define DUK__REGCONST(x) (*((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x)))
-#define DUK__REGCONSTP(x) ((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x))
-#ifdef DUK_USE_VERBOSE_EXECUTOR_ERRORS
+/* Reg/const access macros which take the 32-bit instruction and avoid an
+ * explicit field decoding step by using shifts and masks. These must be
+ * kept in sync with duk_js_bytecode.h. The shift/mask values are chosen
+ * so that 'ins' can be shifted and masked and used as a -byte- offset
+ * instead of a duk_tval offset which needs further shifting (which is an
+ * issue on some, but not all, CPUs).
+ */
+#define DUK__RCBIT_B DUK_BC_REGCONST_B
+#define DUK__RCBIT_C DUK_BC_REGCONST_C
+#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
+#if defined(DUK_USE_PACKED_TVAL)
+#define DUK__TVAL_SHIFT 3 /* sizeof(duk_tval) == 8 */
+#else
+#define DUK__TVAL_SHIFT 4 /* sizeof(duk_tval) == 16; not always the case so also asserted for */
+#endif
+#define DUK__SHIFT_A (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT)
+#define DUK__SHIFT_B (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT)
+#define DUK__SHIFT_C (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT)
+#define DUK__SHIFT_BC (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT)
+#define DUK__MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT)
+#define DUK__MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT)
+#define DUK__MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT)
+#define DUK__MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT)
+#define DUK__BYTEOFF_A(ins) (((ins) >> DUK__SHIFT_A) & DUK__MASK_A)
+#define DUK__BYTEOFF_B(ins) (((ins) >> DUK__SHIFT_B) & DUK__MASK_B)
+#define DUK__BYTEOFF_C(ins) (((ins) >> DUK__SHIFT_C) & DUK__MASK_C)
+#define DUK__BYTEOFF_BC(ins) (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC)
+
+#define DUK__REGP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins))))
+#define DUK__REGP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins))))
+#define DUK__REGP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins))))
+#define DUK__REGP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins))))
+#define DUK__CONSTP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins))))
+#define DUK__CONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins))))
+#define DUK__CONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins))))
+#define DUK__CONSTP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins))))
+#define DUK__REGCONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins))))
+#define DUK__REGCONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins))))
+#else /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
+/* Safe alternatives, no assumption about duk_tval size. */
+#define DUK__REGP_A(ins) DUK__REGP(DUK_DEC_A((ins)))
+#define DUK__REGP_B(ins) DUK__REGP(DUK_DEC_B((ins)))
+#define DUK__REGP_C(ins) DUK__REGP(DUK_DEC_C((ins)))
+#define DUK__REGP_BC(ins) DUK__REGP(DUK_DEC_BC((ins)))
+#define DUK__CONSTP_A(ins) DUK__CONSTP(DUK_DEC_A((ins)))
+#define DUK__CONSTP_B(ins) DUK__CONSTP(DUK_DEC_B((ins)))
+#define DUK__CONSTP_C(ins) DUK__CONSTP(DUK_DEC_C((ins)))
+#define DUK__CONSTP_BC(ins) DUK__CONSTP(DUK_DEC_BC((ins)))
+#define DUK__REGCONSTP_B(ins) ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins)))
+#define DUK__REGCONSTP_C(ins) ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins)))
+#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
+
+#if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
#define DUK__INTERNAL_ERROR(msg) do { \
- DUK_ERROR_INTERNAL(thr, (msg)); \
+ DUK_ERROR_ERROR(thr, (msg)); \
} while (0)
#else
#define DUK__INTERNAL_ERROR(msg) do { \
@@ -67377,20 +74641,40 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#endif
#define DUK__SYNC_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack + thr->callstack_top - 1; \
- act->curr_pc = curr_pc; \
+ duk_activation *duk__act; \
+ duk__act = thr->callstack_curr; \
+ duk__act->curr_pc = curr_pc; \
} while (0)
#define DUK__SYNC_AND_NULL_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack + thr->callstack_top - 1; \
- act->curr_pc = curr_pc; \
+ duk_activation *duk__act; \
+ duk__act = thr->callstack_curr; \
+ duk__act->curr_pc = curr_pc; \
thr->ptr_curr_pc = NULL; \
} while (0)
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+#define DUK__LOOKUP_INDIRECT(idx) do { \
+ (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \
+ } while (0)
+#elif defined(DUK_USE_FASTINT)
+#define DUK__LOOKUP_INDIRECT(idx) do { \
+ duk_tval *tv_ind; \
+ tv_ind = DUK__REGP((idx)); \
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind)); /* compiler guarantees */ \
+ (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \
+ } while (0)
+#else
+#define DUK__LOOKUP_INDIRECT(idx) do { \
+ duk_tval *tv_ind; \
+ tv_ind = DUK__REGP(idx); \
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
+ idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \
+ } while (0)
+#endif
+
DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top,
+ duk_activation *entry_act,
duk_int_t entry_call_recursion_depth,
duk_jmpbuf *entry_jmpbuf_ptr) {
duk_small_uint_t lj_ret;
@@ -67412,17 +74696,29 @@ DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
*/
heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
- lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
+ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act);
+
+ /* Error handling complete, remove side effect protections.
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ DUK_ASSERT(heap->error_not_allowed == 1);
+ heap->error_not_allowed = 0;
+#endif
+ DUK_ASSERT(heap->pf_prevent_count > 0);
+ heap->pf_prevent_count--;
+ DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count));
if (lj_ret == DUK__LONGJMP_RESTART) {
/* Restart bytecode execution, possibly with a changed thread. */
- ;
+ DUK_REFZERO_CHECK_SLOW(heap->curr_thread);
} else {
- /* Rethrow error to calling state. */
- DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
+ /* If an error is propagated, don't run refzero checks here.
+ * The next catcher will deal with that. Pf_prevent_count
+ * will be re-bumped by the longjmp.
+ */
- /* Longjmp handling has restored jmpbuf_ptr. */
- DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
+ DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */
+ DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */
/* Thread may have changed, e.g. YIELD converted to THROW. */
duk_err_longjmp(heap->curr_thread);
@@ -67434,7 +74730,7 @@ DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
/* Entry level info. */
duk_hthread *entry_thread;
- duk_size_t entry_callstack_top;
+ duk_activation *entry_act;
duk_int_t entry_call_recursion_depth;
duk_jmpbuf *entry_jmpbuf_ptr;
duk_jmpbuf our_jmpbuf;
@@ -67445,12 +74741,16 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
- DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1)));
+ DUK_ASSERT(exec_thr->callstack_curr != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr)));
+
+ DUK_GC_TORTURE(exec_thr->heap);
entry_thread = exec_thr;
heap = entry_thread->heap;
- entry_callstack_top = entry_thread->callstack_top;
+ entry_act = entry_thread->callstack_curr;
+ DUK_ASSERT(entry_act != NULL);
entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
@@ -67474,7 +74774,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
#endif
/* Execute bytecode until returned or longjmp(). */
- duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
+ duk__js_execute_bytecode_inner(entry_thread, entry_act);
/* Successful return: restore jmpbuf and return to caller. */
heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
@@ -67489,10 +74789,10 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_UNREF(exc);
#endif
DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
@@ -67503,29 +74803,29 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
what = "unknown";
}
DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
try {
DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
} catch (duk_internal_exception exc) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
DUK_UNREF(exc);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
} catch (...) {
DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
try {
DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ERROR_API(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
+ DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
} catch (duk_internal_exception exc) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
DUK_UNREF(exc);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
@@ -67537,7 +74837,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
}
/* Inner executor, performance critical. */
-DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
+DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) {
/* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
* Critical for performance. It would be safest to make this volatile,
* but that eliminates performance benefits; aliasing guarantees
@@ -67550,23 +74850,36 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
duk_hthread *thr; /* stable */
duk_tval *consts; /* stable */
- duk_tval *consts2; /* stable; precalculated for faster lookups */
duk_uint_fast32_t ins;
/* 'funcs' is quite rarely used, so no local for it */
#if defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
+ duk_hcompfunc *fun;
#else
/* 'fun' is quite rarely used, so no local for it */
#endif
-#ifdef DUK_USE_INTERRUPT_COUNTER
+#if defined(DUK_USE_INTERRUPT_COUNTER)
duk_int_t int_ctr;
#endif
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
#endif
+ /* Optimized reg/const access macros assume sizeof(duk_tval) to be
+ * either 8 or 16. Heap allocation checks this even without asserts
+ * enabled now because it can't be autodetected in duk_config.h.
+ */
+#if 1
+#if defined(DUK_USE_PACKED_TVAL)
+ DUK_ASSERT(sizeof(duk_tval) == 8);
+#else
+ DUK_ASSERT(sizeof(duk_tval) == 16);
+#endif
+#endif
+
+ DUK_GC_TORTURE(entry_thread->heap);
+
/*
* Restart execution by reloading thread state.
*
@@ -67602,7 +74915,6 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*
* The following are not assumed to have stable pointers at all:
* - the value stack (registers) of the current thread
- * - the catch stack of the current thread
*
* See execution.rst for discussion.
*/
@@ -67616,8 +74928,11 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
thr = entry_thread->heap->curr_thread;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
+
+ DUK_GC_TORTURE(thr->heap);
thr->ptr_curr_pc = &curr_pc;
@@ -67625,28 +74940,29 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
{
duk_activation *act;
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
+ duk_hcompfunc *fun;
#endif
/* Assume interrupt init/counter are properly initialized here. */
/* Assume that thr->valstack_bottom has been set-up before getting here. */
- act = thr->callstack + thr->callstack_top - 1;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
DUK_ASSERT(fun != NULL);
DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
- consts = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, fun);
+ consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun);
DUK_ASSERT(consts != NULL);
- consts2 = consts - DUK_BC_REGLIMIT;
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
+ if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) {
duk__executor_recheck_debugger(thr, act, fun);
- act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
#endif
@@ -67655,22 +74971,23 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
- "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
+ "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, "
"preventcount=%ld",
(void *) thr,
(long) (thr->callstack_top - 1),
(void *) DUK__FUN(),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
+ (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
+ (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
(long) (thr->callstack_top - 1),
(long) (thr->valstack_bottom - thr->valstack),
(long) (thr->valstack_top - thr->valstack),
- (long) thr->catchstack_top,
(long) thr->callstack_preventcount));
/* Dispatch loop. */
for (;;) {
+ duk_uint8_t op;
+
DUK_ASSERT(thr->callstack_top >= 1);
DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
@@ -67689,15 +75006,18 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
/* Trigger at zero or below */
duk_small_uint_t exec_int_ret;
+ DUK_STATS_INC(thr->heap, stats_exec_interrupt);
+
/* Write curr_pc back for the debugger. */
- DUK_ASSERT(thr->callstack_top > 0);
{
duk_activation *act;
- act = thr->callstack + thr->callstack_top - 1;
+ DUK_ASSERT(thr->callstack_top > 0);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
act->curr_pc = (duk_instr_t *) curr_pc;
}
- /* Force restart caused by a function return; must recheck
+ /* Forced restart caused by a function return; must recheck
* debugger breakpoints before checking line transitions,
* see GH-303. Restart and then handle interrupt_counter
* zero again.
@@ -67727,13 +75047,13 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
{
duk_activation *act;
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(curr_pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN()));
- DUK_ASSERT(curr_pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, DUK__FUN()));
+ act = thr->callstack_curr;
+ DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN()));
+ DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN()));
DUK_UNREF(act); /* if debugging disabled */
DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
- (long) (curr_pc - DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN())),
+ (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())),
(unsigned long) *curr_pc,
(long) DUK_DEC_OP(*curr_pc),
(long) (thr->valstack_top - thr->valstack),
@@ -67759,424 +75079,1030 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
#endif
ins = *curr_pc++;
+ DUK_STATS_INC(thr->heap, stats_exec_opcodes);
/* Typing: use duk_small_(u)int_fast_t when decoding small
- * opcode fields (op, A, B, C) and duk_(u)int_fast_t when
- * decoding larger fields (e.g. BC which is 18 bits). Use
- * unsigned variant by default, signed when the value is used
- * in signed arithmetic. Using variable names such as 'a', 'b',
- * 'c', 'bc', etc makes it easier to spot typing mismatches.
+ * opcode fields (op, A, B, C, BC) which fit into 16 bits
+ * and duk_(u)int_fast_t when decoding larger fields (e.g.
+ * ABC). Use unsigned variant by default, signed when the
+ * value is used in signed arithmetic. Using variable names
+ * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot
+ * typing mismatches.
*/
- /* XXX: the best typing needs to be validated by perf measurement:
- * e.g. using a small type which is the cast to a larger duk_idx_t
- * may be slower than declaring the variable as a duk_idx_t in the
- * first place.
+ /* Switch based on opcode. Cast to 8-bit unsigned value and
+ * use a fully populated case clauses so that the compiler
+ * will (at least usually) omit a bounds check.
*/
+ op = (duk_uint8_t) DUK_DEC_OP(ins);
+ switch (op) {
- /* XXX: use macros for the repetitive tval/refcount handling. */
+ /* Some useful macros. These access inner executor variables
+ * directly so they only apply within the executor.
+ */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+#define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; }
+#define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; }
+#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
+ duk_bool_t duk__bval; \
+ duk__bval = (bval); \
+ DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
+ duk_push_boolean(thr, duk__bval); \
+ DUK__REPLACE_TOP_A_BREAK(); \
+ }
+#else
+#define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; }
+#define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; }
+#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
+ duk_bool_t duk__bval; \
+ duk_tval *duk__tvdst; \
+ duk__bval = (bval); \
+ DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
+ duk__tvdst = DUK__REGP_A(ins); \
+ DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \
+ break; \
+ }
+#endif
- switch ((int) DUK_DEC_OP(ins)) {
- /* XXX: switch cast? */
+ /* XXX: 12 + 12 bit variant might make sense too, for both reg and
+ * const loads.
+ */
+ /* For LDREG, STREG, LDCONST footprint optimized variants would just
+ * duk_dup() + duk_replace(), but because they're used quite a lot
+ * they're currently intentionally not size optimized.
+ */
case DUK_OP_LDREG: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
duk_tval *tv1, *tv2;
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
+ tv1 = DUK__REGP_A(ins);
+ tv2 = DUK__REGP_BC(ins);
DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
break;
}
case DUK_OP_STREG: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
duk_tval *tv1, *tv2;
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
+ tv1 = DUK__REGP_A(ins);
+ tv2 = DUK__REGP_BC(ins);
DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
break;
}
case DUK_OP_LDCONST: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
duk_tval *tv1, *tv2;
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__CONSTP(bc);
+ tv1 = DUK__REGP_A(ins);
+ tv2 = DUK__CONSTP_BC(ins);
DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
break;
}
+ /* LDINT and LDINTX are intended to load an arbitrary signed
+ * 32-bit value. Only an LDINT+LDINTX sequence is supported.
+ * This also guarantees all values remain fastints.
+ */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_LDINT: {
+ duk_int32_t val;
+
+ val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
+ duk_push_int(thr, val);
+ DUK__REPLACE_TOP_A_BREAK();
+ }
+ case DUK_OP_LDINTX: {
+ duk_int32_t val;
+
+ val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins));
+ val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
+ duk_push_int(thr, val);
+ DUK__REPLACE_TOP_A_BREAK();
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
case DUK_OP_LDINT: {
- duk_small_uint_fast_t a;
- duk_int_fast_t bc;
duk_tval *tv1;
-#if defined(DUK_USE_FASTINT)
duk_int32_t val;
-#else
- duk_double_t val;
-#endif
-#if defined(DUK_USE_FASTINT)
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); val = (duk_int32_t) (bc - DUK_BC_LDINT_BIAS);
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv1, val); /* side effects */
-#else
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); val = (duk_double_t) (bc - DUK_BC_LDINT_BIAS);
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv1, val); /* side effects */
-#endif
+ val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
+ tv1 = DUK__REGP_A(ins);
+ DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
break;
}
-
case DUK_OP_LDINTX: {
- duk_small_uint_fast_t a;
duk_tval *tv1;
- duk_double_t val;
-
- /* LDINTX is not necessarily in FASTINT range, so
- * no fast path for now.
- *
- * XXX: perhaps restrict LDINTX to fastint range, wider
- * range very rarely needed.
- */
+ duk_int32_t val;
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
+ tv1 = DUK__REGP_A(ins);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- val = DUK_TVAL_GET_NUMBER(tv1) * ((duk_double_t) (1L << DUK_BC_LDINTX_SHIFT)) +
- (duk_double_t) DUK_DEC_BC(ins);
#if defined(DUK_USE_FASTINT)
- DUK_TVAL_SET_NUMBER_CHKFAST(tv1, val);
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ val = DUK_TVAL_GET_FASTINT_I32(tv1);
#else
- DUK_TVAL_SET_NUMBER(tv1, val);
+ /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */
+ val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1);
#endif
+ val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
+ DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
break;
}
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- case DUK_OP_MPUTOBJ:
- case DUK_OP_MPUTOBJI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a;
- duk_tval *tv1;
- duk_hobject *obj;
- duk_uint_fast_t idx;
- duk_small_uint_fast_t count;
-
- /* A -> register of target object
- * B -> first register of key/value pair list
- * C -> number of key/value pairs
- */
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- obj = DUK_TVAL_GET_OBJECT(tv1);
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
- count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (DUK_UNLIKELY(idx + count * 2 > (duk_uint_fast_t) duk_get_top(ctx))) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
- }
-#endif
-
- duk_push_hobject(ctx, obj);
-
- while (count > 0) {
- /* XXX: faster initialization (direct access or better primitives) */
-
- duk_push_tval(ctx, DUK__REGP(idx));
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_push_tval(ctx, DUK__REGP(idx + 1)); /* -> [... obj key value] */
- duk_xdef_prop_wec(ctx, -3); /* -> [... obj] */
-
- count--;
- idx += 2;
- }
-
- duk_pop(ctx); /* [... obj] -> [...] */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_LDTHIS: {
+ duk_push_this(thr);
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
+ case DUK_OP_LDUNDEF: {
+ duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins));
break;
}
+ case DUK_OP_LDNULL: {
+ duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins));
+ break;
+ }
+ case DUK_OP_LDTRUE: {
+ duk_push_true(thr);
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
+ case DUK_OP_LDFALSE: {
+ duk_push_false(thr);
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_LDTHIS: {
+ /* Note: 'this' may be bound to any value, not just an object */
+ duk_tval *tv1, *tv2;
- case DUK_OP_MPUTARR:
- case DUK_OP_MPUTARRI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a;
+ tv1 = DUK__REGP_BC(ins);
+ tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
+ DUK_ASSERT(tv2 >= thr->valstack);
+ DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
+ break;
+ }
+ case DUK_OP_LDUNDEF: {
duk_tval *tv1;
- duk_hobject *obj;
- duk_uint_fast_t idx;
- duk_small_uint_fast_t count;
- duk_uint32_t arr_idx;
-
- /* A -> register of target object
- * B -> first register of value data (start_index, value1, value2, ..., valueN)
- * C -> number of key/value pairs (N)
- */
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- obj = DUK_TVAL_GET_OBJECT(tv1);
- DUK_ASSERT(obj != NULL);
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
- count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + count + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("MPUTARR out of bounds");
- }
-#endif
-
- tv1 = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
- idx++;
- duk_push_hobject(ctx, obj);
-
- while (count > 0) {
- /* duk_xdef_prop() will define an own property without any array
- * special behaviors. We'll need to set the array length explicitly
- * in the end. For arrays with elisions, the compiler will emit an
- * explicit SETALEN which will update the length.
- */
+ tv1 = DUK__REGP_BC(ins);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ break;
+ }
+ case DUK_OP_LDNULL: {
+ duk_tval *tv1;
- /* XXX: because we're dealing with 'own' properties of a fresh array,
- * the array initializer should just ensure that the array has a large
- * enough array part and write the values directly into array part,
- * and finally set 'length' manually in the end (as already happens now).
- */
+ tv1 = DUK__REGP_BC(ins);
+ DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
+ break;
+ }
+ case DUK_OP_LDTRUE: {
+ duk_tval *tv1;
- duk_push_tval(ctx, DUK__REGP(idx)); /* -> [... obj value] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx); /* -> [... obj] */
+ tv1 = DUK__REGP_BC(ins);
+ DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1); /* side effects */
+ break;
+ }
+ case DUK_OP_LDFALSE: {
+ duk_tval *tv1;
- /* XXX: could use at least one fewer loop counters */
- count--;
- idx++;
- arr_idx++;
- }
+ tv1 = DUK__REGP_BC(ins);
+ DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0); /* side effects */
+ break;
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- /* XXX: E5.1 Section 11.1.4 coerces the final length through
- * ToUint32() which is odd but happens now as a side effect of
- * 'arr_idx' type.
- */
- duk_hobject_set_length(thr, obj, (duk_uint32_t) arr_idx);
+ case DUK_OP_BNOT: {
+ duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
+ break;
+ }
- duk_pop(ctx); /* [... obj] -> [...] */
+ case DUK_OP_LNOT: {
+ duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
break;
}
- case DUK_OP_NEW:
- case DUK_OP_NEWI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_small_uint_fast_t i;
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_UNM:
+ case DUK_OP_UNP: {
+ duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op);
+ break;
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_UNM: {
+ duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM);
+ break;
+ }
+ case DUK_OP_UNP: {
+ duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP);
+ break;
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- /* A -> unused (reserved for flags, for consistency with DUK_OP_CALL)
- * B -> target register and start reg: constructor, arg1, ..., argN
- * (for DUK_OP_NEWI, 'b' is indirect)
- * C -> num args (N)
- */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_TYPEOF: {
+ duk_small_uint_t stridx;
- /* duk_new() will call the constuctor using duk_handle_call().
- * A constructor call prevents a yield from inside the constructor,
- * even if the constructor is an Ecmascript function.
- */
+ stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins));
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ duk_push_hstring_stridx(thr, stridx);
+ DUK__REPLACE_TOP_A_BREAK();
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_TYPEOF: {
+ duk_tval *tv;
+ duk_small_uint_t stridx;
+ duk_hstring *h_str;
+
+ tv = DUK__REGP_BC(ins);
+ stridx = duk_js_typeof_stridx(tv);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
+ tv = DUK__REGP_A(ins);
+ DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
+ break;
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- /* Don't need to sync curr_pc here; duk_new() will do that
- * when it augments the created error.
- */
+ case DUK_OP_TYPEOFID: {
+ duk_small_uint_t stridx;
+#if !defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_hstring *h_str;
+#endif
+ duk_activation *act;
+ duk_hstring *name;
+ duk_tval *tv;
- /* XXX: unnecessary copying of values? Just set 'top' to
- * b + c, and let the return handling fix up the stack frame?
+ /* A -> target register
+ * BC -> constant index of identifier name
*/
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_NEWI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
+ tv = DUK__CONSTP_BC(ins);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
+ name = DUK_TVAL_GET_STRING(tv);
+ tv = NULL; /* lookup has side effects */
+ act = thr->callstack_curr;
+ if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
+ /* -> [... val this] */
+ tv = DUK_GET_TVAL_NEGIDX(thr, -2);
+ stridx = duk_js_typeof_stridx(tv);
+ tv = NULL; /* no longer needed */
+ duk_pop_2_unsafe(thr);
+ } else {
+ /* unresolvable, no stack changes */
+ stridx = DUK_STRIDX_LC_UNDEFINED;
+ }
+ DUK_ASSERT_STRIDX_VALID(stridx);
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_push_hstring_stridx(thr, stridx);
+ DUK__REPLACE_TOP_A_BREAK();
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
+ tv = DUK__REGP_A(ins);
+ DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
+ break;
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+ }
+
+ /* Equality: E5 Sections 11.9.1, 11.9.3 */
+
+#define DUK__EQ_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_equals(thr, (barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#define DUK__NEQ_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_equals(thr, (barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ tmp ^= 1; \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#define DUK__SEQ_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_strict_equals((barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#define DUK__SNEQ_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_strict_equals((barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ tmp ^= 1; \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_EQ_RR:
+ case DUK_OP_EQ_CR:
+ case DUK_OP_EQ_RC:
+ case DUK_OP_EQ_CC:
+ DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_NEQ_RR:
+ case DUK_OP_NEQ_CR:
+ case DUK_OP_NEQ_RC:
+ case DUK_OP_NEQ_CC:
+ DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_SEQ_RR:
+ case DUK_OP_SEQ_CR:
+ case DUK_OP_SEQ_RC:
+ case DUK_OP_SEQ_CC:
+ DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_SNEQ_RR:
+ case DUK_OP_SNEQ_CR:
+ case DUK_OP_SNEQ_RC:
+ case DUK_OP_SNEQ_CC:
+ DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_EQ_RR:
+ DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_EQ_CR:
+ DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_EQ_RC:
+ DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_EQ_CC:
+ DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_NEQ_RR:
+ DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_NEQ_CR:
+ DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_NEQ_RC:
+ DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_NEQ_CC:
+ DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_SEQ_RR:
+ DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_SEQ_CR:
+ DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_SEQ_RC:
+ DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_SEQ_CC:
+ DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_SNEQ_RR:
+ DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_SNEQ_CR:
+ DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_SNEQ_RC:
+ DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_SNEQ_CC:
+ DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+#define DUK__COMPARE_BODY(arg1,arg2,flags) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0)
+#define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
+#define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
+#define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE)
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_GT_RR:
+ case DUK_OP_GT_CR:
+ case DUK_OP_GT_RC:
+ case DUK_OP_GT_CC:
+ DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_GE_RR:
+ case DUK_OP_GE_CR:
+ case DUK_OP_GE_RC:
+ case DUK_OP_GE_CC:
+ DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_LT_RR:
+ case DUK_OP_LT_CR:
+ case DUK_OP_LT_RC:
+ case DUK_OP_LT_CC:
+ DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_LE_RR:
+ case DUK_OP_LE_CR:
+ case DUK_OP_LE_RC:
+ case DUK_OP_LE_CC:
+ DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_GT_RR:
+ DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GT_CR:
+ DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GT_RC:
+ DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GT_CC:
+ DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GE_RR:
+ DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GE_CR:
+ DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GE_RC:
+ DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GE_CC:
+ DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_LT_RR:
+ DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_LT_CR:
+ DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_LT_RC:
+ DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_LT_CC:
+ DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_LE_RR:
+ DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_LE_CR:
+ DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_LE_RC:
+ DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_LE_CC:
+ DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+ /* No size optimized variant at present for IF. */
+ case DUK_OP_IFTRUE_R: {
+ if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) {
+ curr_pc++;
}
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + c + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("NEW out of bounds");
+ break;
+ }
+ case DUK_OP_IFTRUE_C: {
+ if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) {
+ curr_pc++;
}
-#endif
-
- duk_require_stack(ctx, (duk_idx_t) c);
- duk_push_tval(ctx, DUK__REGP(idx));
- for (i = 0; i < c; i++) {
- duk_push_tval(ctx, DUK__REGP(idx + i + 1));
+ break;
+ }
+ case DUK_OP_IFFALSE_R: {
+ if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) {
+ curr_pc++;
+ }
+ break;
+ }
+ case DUK_OP_IFFALSE_C: {
+ if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) {
+ curr_pc++;
}
- duk_new(ctx, (duk_idx_t) c); /* [... constructor arg1 ... argN] -> [retval] */
- DUK_DDD(DUK_DDDPRINT("NEW -> %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, (duk_idx_t) idx);
-
- /* When debugger is enabled, we need to recheck the activation
- * status after returning. This is now handled by call handling
- * and heap->dbg_force_restart.
- */
break;
}
- case DUK_OP_REGEXP: {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /* A -> target register
- * B -> bytecode (also contains flags)
- * C -> escaped source
- */
-
- duk_push_tval(ctx, DUK__REGCONSTP(c));
- duk_push_tval(ctx, DUK__REGCONSTP(b)); /* -> [ ... escaped_source bytecode ] */
- duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
- DUK_DDD(DUK_DDDPRINT("regexp instance: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, (duk_idx_t) a);
-#else
- /* The compiler should never emit DUK_OP_REGEXP if there is no
- * regexp support.
- */
- DUK__INTERNAL_ERROR("no regexp support");
-#endif
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_ADD_RR:
+ case DUK_OP_ADD_CR:
+ case DUK_OP_ADD_RC:
+ case DUK_OP_ADD_CC: {
+ /* XXX: could leave value on stack top and goto replace_top_a; */
+ duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins));
+ break;
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_ADD_RR: {
+ duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
+ break;
+ }
+ case DUK_OP_ADD_CR: {
+ duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
+ break;
+ }
+ case DUK_OP_ADD_RC: {
+ duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
+ break;
+ }
+ case DUK_OP_ADD_CC: {
+ duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
+ break;
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_SUB_RR:
+ case DUK_OP_SUB_CR:
+ case DUK_OP_SUB_RC:
+ case DUK_OP_SUB_CC:
+ case DUK_OP_MUL_RR:
+ case DUK_OP_MUL_CR:
+ case DUK_OP_MUL_RC:
+ case DUK_OP_MUL_CC:
+ case DUK_OP_DIV_RR:
+ case DUK_OP_DIV_CR:
+ case DUK_OP_DIV_RC:
+ case DUK_OP_DIV_CC:
+ case DUK_OP_MOD_RR:
+ case DUK_OP_MOD_CR:
+ case DUK_OP_MOD_RC:
+ case DUK_OP_MOD_CC:
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_OP_EXP_RR:
+ case DUK_OP_EXP_CR:
+ case DUK_OP_EXP_RC:
+ case DUK_OP_EXP_CC:
+#endif /* DUK_USE_ES7_EXP_OPERATOR */
+ {
+ /* XXX: could leave value on stack top and goto replace_top_a; */
+ duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
+ break;
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_SUB_RR: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
+ break;
+ }
+ case DUK_OP_SUB_CR: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
+ break;
+ }
+ case DUK_OP_SUB_RC: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
+ break;
+ }
+ case DUK_OP_SUB_CC: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
+ break;
+ }
+ case DUK_OP_MUL_RR: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
+ break;
+ }
+ case DUK_OP_MUL_CR: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
+ break;
+ }
+ case DUK_OP_MUL_RC: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
+ break;
+ }
+ case DUK_OP_MUL_CC: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
+ break;
+ }
+ case DUK_OP_DIV_RR: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
+ break;
+ }
+ case DUK_OP_DIV_CR: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
+ break;
+ }
+ case DUK_OP_DIV_RC: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
+ break;
+ }
+ case DUK_OP_DIV_CC: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
+ break;
+ }
+ case DUK_OP_MOD_RR: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
+ break;
+ }
+ case DUK_OP_MOD_CR: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
+ break;
+ }
+ case DUK_OP_MOD_RC: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
+ break;
+ }
+ case DUK_OP_MOD_CC: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
+ break;
+ }
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_OP_EXP_RR: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
+ break;
+ }
+ case DUK_OP_EXP_CR: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
+ break;
+ }
+ case DUK_OP_EXP_RC: {
+ duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
+ break;
+ }
+ case DUK_OP_EXP_CC: {
+ duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
+ break;
+ }
+#endif /* DUK_USE_ES7_EXP_OPERATOR */
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_BAND_RR:
+ case DUK_OP_BAND_CR:
+ case DUK_OP_BAND_RC:
+ case DUK_OP_BAND_CC:
+ case DUK_OP_BOR_RR:
+ case DUK_OP_BOR_CR:
+ case DUK_OP_BOR_RC:
+ case DUK_OP_BOR_CC:
+ case DUK_OP_BXOR_RR:
+ case DUK_OP_BXOR_CR:
+ case DUK_OP_BXOR_RC:
+ case DUK_OP_BXOR_CC:
+ case DUK_OP_BASL_RR:
+ case DUK_OP_BASL_CR:
+ case DUK_OP_BASL_RC:
+ case DUK_OP_BASL_CC:
+ case DUK_OP_BLSR_RR:
+ case DUK_OP_BLSR_CR:
+ case DUK_OP_BLSR_RC:
+ case DUK_OP_BLSR_CC:
+ case DUK_OP_BASR_RR:
+ case DUK_OP_BASR_CR:
+ case DUK_OP_BASR_RC:
+ case DUK_OP_BASR_CC: {
+ /* XXX: could leave value on stack top and goto replace_top_a; */
+ duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
+ break;
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_BAND_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
+ break;
+ }
+ case DUK_OP_BAND_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
+ break;
+ }
+ case DUK_OP_BAND_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
+ break;
+ }
+ case DUK_OP_BAND_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
+ break;
+ }
+ case DUK_OP_BOR_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
+ break;
+ }
+ case DUK_OP_BOR_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
+ break;
+ }
+ case DUK_OP_BOR_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
+ break;
+ }
+ case DUK_OP_BOR_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
+ break;
+ }
+ case DUK_OP_BXOR_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
+ break;
+ }
+ case DUK_OP_BXOR_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
+ break;
+ }
+ case DUK_OP_BXOR_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
+ break;
+ }
+ case DUK_OP_BXOR_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
+ break;
+ }
+ case DUK_OP_BASL_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
+ break;
+ }
+ case DUK_OP_BASL_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
+ break;
+ }
+ case DUK_OP_BASL_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
+ break;
+ }
+ case DUK_OP_BASL_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
+ break;
+ }
+ case DUK_OP_BLSR_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
+ break;
+ }
+ case DUK_OP_BLSR_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
+ break;
+ }
+ case DUK_OP_BLSR_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
+ break;
+ }
+ case DUK_OP_BLSR_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
+ break;
+ }
+ case DUK_OP_BASR_RR: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
+ break;
+ }
+ case DUK_OP_BASR_CR: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
+ break;
+ }
+ case DUK_OP_BASR_RC: {
+ duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
+ break;
+ }
+ case DUK_OP_BASR_CC: {
+ duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
+ break;
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+ /* For INSTOF and IN, B is always a register. */
+#define DUK__INSTOF_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_instanceof(thr, (barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#define DUK__IN_BODY(barg,carg) { \
+ duk_bool_t tmp; \
+ tmp = duk_js_in(thr, (barg), (carg)); \
+ DUK_ASSERT(tmp == 0 || tmp == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(tmp); \
+ }
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_INSTOF_RR:
+ case DUK_OP_INSTOF_CR:
+ case DUK_OP_INSTOF_RC:
+ case DUK_OP_INSTOF_CC:
+ DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_IN_RR:
+ case DUK_OP_IN_CR:
+ case DUK_OP_IN_RC:
+ case DUK_OP_IN_CC:
+ DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_INSTOF_RR:
+ DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_INSTOF_CR:
+ DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_INSTOF_RC:
+ DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_INSTOF_CC:
+ DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_IN_RR:
+ DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_IN_CR:
+ DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_IN_RC:
+ DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_IN_CC:
+ DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+ /* Pre/post inc/dec for register variables, important for loops. */
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_PREINCR:
+ case DUK_OP_PREDECR:
+ case DUK_OP_POSTINCR:
+ case DUK_OP_POSTDECR: {
+ duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op);
+ break;
+ }
+ case DUK_OP_PREINCV:
+ case DUK_OP_PREDECV:
+ case DUK_OP_POSTINCV:
+ case DUK_OP_POSTDECV: {
+ duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT());
+ break;
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_PREINCR: {
+ duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR);
+ break;
+ }
+ case DUK_OP_PREDECR: {
+ duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR);
+ break;
+ }
+ case DUK_OP_POSTINCR: {
+ duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR);
+ break;
+ }
+ case DUK_OP_POSTDECR: {
+ duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR);
+ break;
+ }
+ case DUK_OP_PREINCV: {
+ duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT());
+ break;
+ }
+ case DUK_OP_PREDECV: {
+ duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT());
+ break;
+ }
+ case DUK_OP_POSTINCV: {
+ duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT());
+ break;
+ }
+ case DUK_OP_POSTDECV: {
+ duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT());
break;
}
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- case DUK_OP_CSREG:
- case DUK_OP_CSREGI: {
- /*
- * Assuming a register binds to a variable declared within this
- * function (a declarative binding), the 'this' for the call
- * setup is always 'undefined'. E5 Section 10.2.1.1.6.
- */
+ /* XXX: Move to separate helper, optimize for perf/size separately. */
+ /* Preinc/predec for object properties. */
+ case DUK_OP_PREINCP_RR:
+ case DUK_OP_PREINCP_CR:
+ case DUK_OP_PREINCP_RC:
+ case DUK_OP_PREINCP_CC:
+ case DUK_OP_PREDECP_RR:
+ case DUK_OP_PREDECP_CR:
+ case DUK_OP_PREDECP_RC:
+ case DUK_OP_PREDECP_CC:
+ case DUK_OP_POSTINCP_RR:
+ case DUK_OP_POSTINCP_CR:
+ case DUK_OP_POSTINCP_RC:
+ case DUK_OP_POSTINCP_CC:
+ case DUK_OP_POSTDECP_RR:
+ case DUK_OP_POSTDECP_CR:
+ case DUK_OP_POSTDECP_RC:
+ case DUK_OP_POSTDECP_CC: {
+ duk_tval *tv_obj;
+ duk_tval *tv_key;
+ duk_tval *tv_val;
+ duk_bool_t rc;
+ duk_double_t x, y, z;
+#if !defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_tval *tv_dst;
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins); /* restricted to regs */
- duk_uint_fast_t idx;
+ /* A -> target reg
+ * B -> object reg/const (may be const e.g. in "'foo'[1]")
+ * C -> key reg/const
+ */
- /* A -> target register (A, A+1) for call setup
- * (for DUK_OP_CSREGI, 'a' is indirect)
- * B -> register containing target function (not type checked here)
+ /* Opcode bits 0-1 are used to distinguish reg/const variants.
+ * Opcode bits 2-3 are used to distinguish inc/dec variants:
+ * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1).
*/
+ DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00);
+ DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04);
+ DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08);
+ DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c);
- /* XXX: direct manipulation, or duk_replace_tval() */
+ tv_obj = DUK__REGCONSTP_B(ins);
+ tv_key = DUK__REGCONSTP_C(ins);
+ rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
+ DUK_UNREF(rc); /* ignore */
+ tv_obj = NULL; /* invalidated */
+ tv_key = NULL; /* invalidated */
- /* Note: target registers a and a+1 may overlap with DUK__REGP(b).
- * Careful here.
+ /* XXX: Fastint fast path would be useful here. Also fastints
+ * now lose their fastint status in current handling which is
+ * not intuitive.
*/
- idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSREGI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSREG out of bounds");
+ x = duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ if (ins & DUK_BC_INCDECP_FLAG_DEC) {
+ y = x - 1.0;
+ } else {
+ y = x + 1.0;
}
-#endif
- duk_push_tval(ctx, DUK__REGP(b));
- duk_replace(ctx, (duk_idx_t) idx);
- duk_push_undefined(ctx);
- duk_replace(ctx, (duk_idx_t) (idx + 1));
- break;
- }
-
- case DUK_OP_GETVAR: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_hstring *name;
-
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- DUK_DDD(DUK_DDDPRINT("GETVAR: '%!O'", (duk_heaphdr *) name));
- act = thr->callstack + thr->callstack_top - 1;
- (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
+ duk_push_number(thr, y);
+ tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
+ DUK_ASSERT(tv_val != NULL);
+ tv_obj = DUK__REGCONSTP_B(ins);
+ tv_key = DUK__REGCONSTP_C(ins);
+ rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
+ DUK_UNREF(rc); /* ignore */
+ tv_obj = NULL; /* invalidated */
+ tv_key = NULL; /* invalidated */
+ duk_pop_unsafe(thr);
- duk_pop(ctx); /* 'this' binding is not needed here */
- duk_replace(ctx, (duk_idx_t) a);
+ z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y;
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ duk_push_number(thr, z);
+ DUK__REPLACE_TOP_A_BREAK();
+#else
+ tv_dst = DUK__REGP_A(ins);
+ DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z);
break;
+#endif
}
- case DUK_OP_PUTVAR: {
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_hstring *name;
-
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
-
- /* XXX: putvar takes a duk_tval pointer, which is awkward and
- * should be reworked.
- */
-
- tv1 = DUK__REGP(a); /* val */
- act = thr->callstack + thr->callstack_top - 1;
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
- break;
- }
+ /* XXX: GETPROP where object is 'this', GETPROPT?
+ * Occurs relatively often in object oriented code.
+ */
- case DUK_OP_DECLVAR: {
+#define DUK__GETPROP_BODY(barg,carg) { \
+ /* A -> target reg \
+ * B -> object reg/const (may be const e.g. in "'foo'[1]") \
+ * C -> key reg/const \
+ */ \
+ (void) duk_hobject_getprop(thr, (barg), (carg)); \
+ DUK__REPLACE_TOP_A_BREAK(); \
+ }
+#define DUK__GETPROPC_BODY(barg,carg) { \
+ /* Same as GETPROP but callability check for property-based calls. */ \
+ duk_tval *tv__targ; \
+ (void) duk_hobject_getprop(thr, (barg), (carg)); \
+ DUK_GC_TORTURE(thr->heap); \
+ tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \
+ if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \
+ /* Here we intentionally re-evaluate the macro \
+ * arguments to deal with potentially changed \
+ * valstack base pointer! \
+ */ \
+ duk_call_setup_propcall_error(thr, tv__targ, (barg), (carg)); \
+ } \
+ DUK__REPLACE_TOP_A_BREAK(); \
+ }
+#define DUK__PUTPROP_BODY(aarg,barg,carg) { \
+ /* A -> object reg \
+ * B -> key reg/const \
+ * C -> value reg/const \
+ * \
+ * Note: intentional difference to register arrangement \
+ * of e.g. GETPROP; 'A' must contain a register-only value. \
+ */ \
+ (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \
+ break; \
+ }
+#define DUK__DELPROP_BODY(barg,carg) { \
+ /* A -> result reg \
+ * B -> object reg \
+ * C -> key reg/const \
+ */ \
+ duk_bool_t rc; \
+ rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \
+ DUK_ASSERT(rc == 0 || rc == 1); \
+ DUK__REPLACE_BOOL_A_BREAK(rc); \
+ }
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_GETPROP_RR:
+ case DUK_OP_GETPROP_CR:
+ case DUK_OP_GETPROP_RC:
+ case DUK_OP_GETPROP_CC:
+ DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ case DUK_OP_GETPROPC_CR:
+ case DUK_OP_GETPROPC_RC:
+ case DUK_OP_GETPROPC_CC:
+ DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#endif
+ case DUK_OP_PUTPROP_RR:
+ case DUK_OP_PUTPROP_CR:
+ case DUK_OP_PUTPROP_RC:
+ case DUK_OP_PUTPROP_CC:
+ DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+ case DUK_OP_DELPROP_RR:
+ case DUK_OP_DELPROP_RC: /* B is always reg */
+ DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins));
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_GETPROP_RR:
+ DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROP_CR:
+ DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROP_RC:
+ DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GETPROP_CC:
+ DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROPC_CR:
+ DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROPC_RC:
+ DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GETPROPC_CC:
+ DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#endif
+ case DUK_OP_PUTPROP_RR:
+ DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_PUTPROP_CR:
+ DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_PUTPROP_RC:
+ DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_PUTPROP_CC:
+ DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_DELPROP_RR: /* B is always reg */
+ DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_DELPROP_RC:
+ DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+
+ /* No fast path for DECLVAR now, it's quite a rare instruction. */
+ case DUK_OP_DECLVAR_RR:
+ case DUK_OP_DECLVAR_CR:
+ case DUK_OP_DECLVAR_RC:
+ case DUK_OP_DECLVAR_CC: {
duk_activation *act;
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
duk_tval *tv1;
duk_hstring *name;
duk_small_uint_t prop_flags;
duk_bool_t is_func_decl;
- duk_bool_t is_undef_value;
- tv1 = DUK__REGCONSTP(b);
+ tv1 = DUK__REGCONSTP_B(ins);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
name = DUK_TVAL_GET_STRING(tv1);
DUK_ASSERT(name != NULL);
- is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0);
is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
/* XXX: declvar takes an duk_tval pointer, which is awkward and
@@ -68188,101 +76114,92 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
- if (is_undef_value) {
- duk_push_undefined(ctx);
+ if (is_func_decl) {
+ duk_push_tval(thr, DUK__REGCONSTP_C(ins));
} else {
- duk_push_tval(ctx, DUK__REGCONSTP(c));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
+ thr->valstack_top++;
}
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
- act = thr->callstack + thr->callstack_top - 1;
+ act = thr->callstack_curr;
if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
- /* already declared, must update binding value */
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
+ if (is_func_decl) {
+ /* Already declared, update value. */
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
+ duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
+ } else {
+ /* Already declared but no initializer value
+ * (e.g. 'var xyz;'), no-op.
+ */
+ }
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
break;
}
- case DUK_OP_DELVAR: {
- duk_activation *act;
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_tval *tv1;
- duk_hstring *name;
- duk_bool_t rc;
-
- tv1 = DUK__REGCONSTP(b);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- DUK_DDD(DUK_DDDPRINT("DELVAR '%!O'", (duk_heaphdr *) name));
- act = thr->callstack + thr->callstack_top - 1;
- rc = duk_js_delvar_activation(thr, act, name);
+#if defined(DUK_USE_REGEXP_SUPPORT)
+ /* The compiler should never emit DUK_OP_REGEXP if there is no
+ * regexp support.
+ */
+ case DUK_OP_REGEXP_RR:
+ case DUK_OP_REGEXP_CR:
+ case DUK_OP_REGEXP_RC:
+ case DUK_OP_REGEXP_CC: {
+ /* A -> target register
+ * B -> bytecode (also contains flags)
+ * C -> escaped source
+ */
- duk_push_boolean(ctx, rc);
- duk_replace(ctx, (duk_idx_t) a);
- break;
+ duk_push_tval(thr, DUK__REGCONSTP_C(ins));
+ duk_push_tval(thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */
+ duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
+ DUK__REPLACE_TOP_A_BREAK();
}
+#endif /* DUK_USE_REGEXP_SUPPORT */
- case DUK_OP_CSVAR:
- case DUK_OP_CSVARI: {
- /* 'this' value:
- * E5 Section 6.b.i
+ /* XXX: 'c' is unused, use whole BC, etc. */
+ case DUK_OP_CSVAR_RR:
+ case DUK_OP_CSVAR_CR:
+ case DUK_OP_CSVAR_RC:
+ case DUK_OP_CSVAR_CC: {
+ /* The speciality of calling through a variable binding is that the
+ * 'this' value may be provided by the variable lookup: E5 Section 6.b.i.
*
* The only (standard) case where the 'this' binding is non-null is when
* (1) the variable is found in an object environment record, and
* (2) that object environment record is a 'with' block.
- *
*/
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
duk_uint_fast_t idx;
duk_tval *tv1;
duk_hstring *name;
- tv1 = DUK__REGCONSTP(b);
+ /* A -> target registers (A, A + 1) for call setup
+ * B -> identifier name, usually constant but can be a register due to shuffling
+ */
+
+ tv1 = DUK__REGCONSTP_B(ins);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
name = DUK_TVAL_GET_STRING(tv1);
DUK_ASSERT(name != NULL);
- act = thr->callstack + thr->callstack_top - 1;
+ act = thr->callstack_curr;
(void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
- /* Note: target registers a and a+1 may overlap with DUK__REGCONSTP(b)
- * and DUK__REGCONSTP(c). Careful here.
- */
-
idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSVARI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSVAR out of bounds");
- }
-#endif
-
- duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
- duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
+ /* Could add direct value stack handling. */
+ duk_replace(thr, (duk_idx_t) (idx + 1)); /* 'this' binding */
+ duk_replace(thr, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
break;
}
case DUK_OP_CLOSURE: {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
- duk_hcompiledfunction *fun;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
+ duk_hcompfunc *fun_act;
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
duk_hobject *fun_temp;
/* A -> target reg
@@ -68290,16 +76207,16 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
- (long) a, (long) bc, (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
+ (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
+ DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
- act = thr->callstack + thr->callstack_top - 1;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- fun_temp = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun)[bc];
+ act = thr->callstack_curr;
+ fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
+ fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc];
DUK_ASSERT(fun_temp != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(fun_temp));
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp));
DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
(void *) fun_temp, (duk_heaphdr *) fun_temp));
@@ -68307,6 +76224,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
if (act->lex_env == NULL) {
DUK_ASSERT(act->var_env == NULL);
duk_js_init_activation_environment_records_delayed(thr, act);
+ act = thr->callstack_curr;
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
@@ -68316,1615 +76234,885 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
* matters here.
*/
duk_js_push_closure(thr,
- (duk_hcompiledfunction *) fun_temp,
+ (duk_hcompfunc *) fun_temp,
act->var_env,
act->lex_env,
1 /*add_auto_proto*/);
- duk_replace(ctx, (duk_idx_t) a);
-
- break;
+ DUK__REPLACE_TOP_A_BREAK();
}
- case DUK_OP_GETPROP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- /* A -> target reg
- * B -> object reg/const (may be const e.g. in "'foo'[1]")
- * C -> key reg/const
- */
-
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- DUK_DDD(DUK_DDDPRINT("GETPROP: a=%ld obj=%!T, key=%!T",
- (long) a,
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* ignore */
- DUK_DDD(DUK_DDDPRINT("GETPROP --> %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
+ case DUK_OP_GETVAR: {
+ duk_activation *act;
+ duk_tval *tv1;
+ duk_hstring *name;
- duk_replace(ctx, (duk_idx_t) a); /* val */
- break;
+ tv1 = DUK__CONSTP_BC(ins);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+ name = DUK_TVAL_GET_STRING(tv1);
+ DUK_ASSERT(name != NULL);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
+ duk_pop_unsafe(thr); /* 'this' binding is not needed here */
+ DUK__REPLACE_TOP_A_BREAK();
}
- case DUK_OP_PUTPROP: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_tval *tv_val;
- duk_bool_t rc;
+ case DUK_OP_PUTVAR: {
+ duk_activation *act;
+ duk_tval *tv1;
+ duk_hstring *name;
- /* A -> object reg
- * B -> key reg/const
- * C -> value reg/const
- *
- * Note: intentional difference to register arrangement
- * of e.g. GETPROP; 'A' must contain a register-only value.
- */
+ tv1 = DUK__CONSTP_BC(ins);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+ name = DUK_TVAL_GET_STRING(tv1);
+ DUK_ASSERT(name != NULL);
- tv_obj = DUK__REGP(a);
- tv_key = DUK__REGCONSTP(b);
- tv_val = DUK__REGCONSTP(c);
- DUK_DDD(DUK_DDDPRINT("PUTPROP: obj=%!T, key=%!T, val=%!T",
- (duk_tval *) DUK__REGP(a),
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
- DUK_UNREF(rc); /* ignore */
- DUK_DDD(DUK_DDDPRINT("PUTPROP --> obj=%!T, key=%!T, val=%!T",
- (duk_tval *) DUK__REGP(a),
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
- tv_val = NULL; /* invalidated */
+ /* XXX: putvar takes a duk_tval pointer, which is awkward and
+ * should be reworked.
+ */
+ tv1 = DUK__REGP_A(ins); /* val */
+ act = thr->callstack_curr;
+ duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
break;
}
- case DUK_OP_DELPROP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
+ case DUK_OP_DELVAR: {
+ duk_activation *act;
+ duk_tval *tv1;
+ duk_hstring *name;
duk_bool_t rc;
- /* A -> result reg
- * B -> object reg
- * C -> key reg/const
- */
-
- tv_obj = DUK__REGP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_delprop(thr, tv_obj, tv_key, DUK__STRICT());
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
+ tv1 = DUK__CONSTP_BC(ins);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+ name = DUK_TVAL_GET_STRING(tv1);
+ DUK_ASSERT(name != NULL);
+ act = thr->callstack_curr;
+ rc = duk_js_delvar_activation(thr, act, name);
+ DUK__REPLACE_BOOL_A_BREAK(rc);
+ }
- duk_push_boolean(ctx, rc);
- duk_replace(ctx, (duk_idx_t) a); /* result */
+ case DUK_OP_JUMP: {
+ /* Note: without explicit cast to signed, MSVC will
+ * apparently generate a large positive jump when the
+ * bias-corrected value would normally be negative.
+ */
+ curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS;
break;
}
- case DUK_OP_CSPROP:
- case DUK_OP_CSPROPI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
+#define DUK__RETURN_SHARED() do { \
+ duk_small_uint_t ret_result; \
+ /* duk__handle_return() is guaranteed never to throw, except \
+ * for potential out-of-memory situations which will then \
+ * propagate out of the executor longjmp handler. \
+ */ \
+ DUK_ASSERT(thr->ptr_curr_pc == NULL); \
+ ret_result = duk__handle_return(thr, entry_act); \
+ if (ret_result == DUK__RETHAND_RESTART) { \
+ goto restart_execution; \
+ } \
+ DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \
+ return; \
+ } while (0)
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_RETREG:
+ case DUK_OP_RETCONST:
+ case DUK_OP_RETCONSTN:
+ case DUK_OP_RETUNDEF: {
+ /* BC -> return value reg/const */
- /* E5 Section 11.2.3, step 6.a.i */
- /* E5 Section 10.4.3 */
+ DUK__SYNC_AND_NULL_CURR_PC();
- /* XXX: allow object to be a const, e.g. in 'foo'.toString()?
- * On the other hand, DUK_REGCONSTP() is slower and generates
- * more code.
- */
+ if (op == DUK_OP_RETREG) {
+ duk_push_tval(thr, DUK__REGP_BC(ins));
+ } else if (op == DUK_OP_RETUNDEF) {
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
+ thr->valstack_top++;
+ } else {
+ DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN);
+ duk_push_tval(thr, DUK__CONSTP_BC(ins));
+ }
- tv_obj = DUK__REGP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* unused */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
+ DUK__RETURN_SHARED();
+ }
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ case DUK_OP_RETREG: {
+ duk_tval *tv;
- /* Note: target registers a and a+1 may overlap with DUK__REGP(b)
- * and DUK__REGCONSTP(c). Careful here.
- */
+ DUK__SYNC_AND_NULL_CURR_PC();
+ tv = DUK__REGP_BC(ins);
+ DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
+ DUK_TVAL_INCREF(thr, tv);
+ thr->valstack_top++;
+ DUK__RETURN_SHARED();
+ }
+ /* This will be unused without refcounting. */
+ case DUK_OP_RETCONST: {
+ duk_tval *tv;
- idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSPROPI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
+ DUK__SYNC_AND_NULL_CURR_PC();
+ tv = DUK__CONSTP_BC(ins);
+ DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
+ DUK_TVAL_INCREF(thr, tv);
+ thr->valstack_top++;
+ DUK__RETURN_SHARED();
+ }
+ case DUK_OP_RETCONSTN: {
+ duk_tval *tv;
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSPROP out of bounds");
- }
+ DUK__SYNC_AND_NULL_CURR_PC();
+ tv = DUK__CONSTP_BC(ins);
+ DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Without refcounting only RETCONSTN is used. */
+ DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */
#endif
-
- duk_push_tval(ctx, DUK__REGP(b)); /* [ ... val obj ] */
- duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
- duk_replace(ctx, (duk_idx_t) idx); /* val */
- break;
+ thr->valstack_top++;
+ DUK__RETURN_SHARED();
}
+ case DUK_OP_RETUNDEF: {
+ DUK__SYNC_AND_NULL_CURR_PC();
+ thr->valstack_top++; /* value at valstack top is already undefined by valstack policy */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
+ DUK__RETURN_SHARED();
+ }
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
- case DUK_OP_ADD:
- case DUK_OP_SUB:
- case DUK_OP_MUL:
- case DUK_OP_DIV:
- case DUK_OP_MOD: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_small_uint_fast_t op = DUK_DEC_OP(ins);
+ case DUK_OP_LABEL: {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- if (op == DUK_OP_ADD) {
- /*
- * Handling DUK_OP_ADD this way is more compact (experimentally)
- * than a separate case with separate argument decoding.
- */
- duk__vm_arith_add(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a);
- } else {
- duk__vm_arith_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
- }
- break;
- }
+ /* Allocate catcher and populate it (must be atomic). */
- case DUK_OP_BAND:
- case DUK_OP_BOR:
- case DUK_OP_BXOR:
- case DUK_OP_BASL:
- case DUK_OP_BLSR:
- case DUK_OP_BASR: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_small_uint_fast_t op = DUK_DEC_OP(ins);
+ cat = duk_hthread_catcher_alloc(thr);
+ DUK_ASSERT(cat != NULL);
- duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
- break;
- }
+ cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT));
+ cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
+ cat->idx_base = 0; /* unused for label */
+ cat->h_varname = NULL;
- case DUK_OP_EQ:
- case DUK_OP_NEQ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat->parent = act->cat;
+ act->cat = cat;
- /* E5 Sections 11.9.1, 11.9.3 */
- tmp = duk_js_equals(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
- if (DUK_DEC_OP(ins) == DUK_OP_NEQ) {
- tmp = !tmp;
- }
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
+ DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, "
+ "idx_base=%ld, h_varname=%!O, label_id=%ld",
+ (long) cat->flags, (long) cat->pc_base,
+ (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
+
+ curr_pc += 2; /* skip jump slots */
break;
}
- case DUK_OP_SEQ:
- case DUK_OP_SNEQ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
+ case DUK_OP_ENDLABEL: {
+ duk_activation *act;
+#if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS)
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
+#endif
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
+ DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
+#endif
- /* E5 Sections 11.9.1, 11.9.3 */
- tmp = duk_js_strict_equals(DUK__REGCONSTP(b), DUK__REGCONSTP(c));
- if (DUK_DEC_OP(ins) == DUK_OP_SNEQ) {
- tmp = !tmp;
- }
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL);
+ DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc);
+ duk_hthread_catcher_unwind_nolexenv_norz(thr, act);
+
+ /* no need to unwind callstack */
break;
}
- /* Note: combining comparison ops must be done carefully because
- * of uncomparable values (NaN): it's not necessarily true that
- * (x >= y) === !(x < y). Also, evaluation order matters, and
- * although it would only seem to affect the compiler this is
- * actually not the case, because there are also run-time coercions
- * of the arguments (with potential side effects).
- *
- * XXX: can be combined; check code size.
- */
+ case DUK_OP_BREAK: {
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- case DUK_OP_GT: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x > y --> y < x */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(c), /* y */
- DUK__REGCONSTP(b), /* x */
- 0); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
+ DUK__SYNC_AND_NULL_CURR_PC();
+ duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
+ goto restart_execution;
}
- case DUK_OP_GE: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x >= y --> not (x < y) */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(b), /* x */
- DUK__REGCONSTP(c), /* y */
- DUK_COMPARE_FLAG_EVAL_LEFT_FIRST |
- DUK_COMPARE_FLAG_NEGATE); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
+ case DUK_OP_CONTINUE: {
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- case DUK_OP_LT: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x < y */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(b), /* x */
- DUK__REGCONSTP(c), /* y */
- DUK_COMPARE_FLAG_EVAL_LEFT_FIRST); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
+ DUK__SYNC_AND_NULL_CURR_PC();
+ duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
+ goto restart_execution;
}
- case DUK_OP_LE: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x <= y --> not (x > y) --> not (y < x) */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(c), /* y */
- DUK__REGCONSTP(b), /* x */
- DUK_COMPARE_FLAG_NEGATE); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
+ /* XXX: move to helper, too large to be inline here */
+ case DUK_OP_TRYCATCH: {
+ duk__handle_op_trycatch(thr, ins, curr_pc);
+ curr_pc += 2; /* skip jump slots */
break;
}
- case DUK_OP_IF: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_toboolean(DUK__REGCONSTP(b));
- if (tmp == (duk_bool_t) a) {
- /* if boolean matches A, skip next inst */
- curr_pc++;
- } else {
- ;
- }
+ case DUK_OP_ENDTRY: {
+ curr_pc = duk__handle_op_endtry(thr, ins);
break;
}
- case DUK_OP_JUMP: {
- duk_int_fast_t abc = DUK_DEC_ABC(ins);
-
- curr_pc += abc - DUK_BC_JUMP_BIAS;
+ case DUK_OP_ENDCATCH: {
+ duk__handle_op_endcatch(thr, ins);
break;
}
- case DUK_OP_RETURN: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- /* duk_small_uint_fast_t c = DUK_DEC_C(ins); */
- duk_small_uint_t ret_result;
-
- /* A -> flags
- * B -> return value reg/const
- * C -> currently unused
- */
-
+ case DUK_OP_ENDFIN: {
+ /* Sync and NULL early. */
DUK__SYNC_AND_NULL_CURR_PC();
- /* duk__handle_return() is guaranteed never to throw, except
- * for potential out-of-memory situations which will then
- * propagate out of the executor longjmp handler.
- */
-
- if (a & DUK_BC_RETURN_FLAG_HAVE_RETVAL) {
- duk_push_tval(ctx, DUK__REGCONSTP(b));
- } else {
- duk_push_undefined(ctx);
- }
- ret_result = duk__handle_return(thr,
- entry_thread,
- entry_callstack_top);
- if (ret_result == DUK__RETHAND_RESTART) {
- goto restart_execution;
+ if (duk__handle_op_endfin(thr, ins, entry_act) != 0) {
+ return;
}
- DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
- DUK_DDD(DUK_DDDPRINT("exiting executor after RETURN handling"));
- return;
+ /* Must restart because we NULLed out curr_pc. */
+ goto restart_execution;
}
- case DUK_OP_CALL:
- case DUK_OP_CALLI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_small_uint_t call_flags;
- duk_small_uint_t flag_tailcall;
- duk_small_uint_t flag_evalcall;
- duk_tval *tv_func;
- duk_hobject *obj_func;
- duk_bool_t setup_rc;
- duk_idx_t num_stack_args;
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
-#endif
+ case DUK_OP_THROW: {
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- /* A -> flags
- * B -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
- * (for DUK_OP_CALLI, 'b' is indirect)
- * C -> nargs
+ /* Note: errors are augmented when they are created, not
+ * when they are thrown. So, don't augment here, it would
+ * break re-throwing for instance.
*/
- /* these are not necessarily 0 or 1 (may be other non-zero), that's ok */
- flag_tailcall = (a & DUK_BC_CALL_FLAG_TAILCALL);
- flag_evalcall = (a & DUK_BC_CALL_FLAG_EVALCALL);
+ /* Sync so that augmentation sees up-to-date activations, NULL
+ * thr->ptr_curr_pc so that it's not used if side effects occur
+ * in augmentation or longjmp handling.
+ */
+ DUK__SYNC_AND_NULL_CURR_PC();
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CALLI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
+ duk_dup(thr, (duk_idx_t) bc);
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
+ (duk_tval *) duk_get_tval(thr, -1)));
+#if defined(DUK_USE_AUGMENT_ERROR_THROW)
+ duk_err_augment_error_throw(thr);
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
+ (duk_tval *) duk_get_tval(thr, -1)));
+#endif
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (!duk_is_valid_index(ctx, (duk_idx_t) idx)) {
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CALL out of bounds");
- }
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_err_check_debugger_integration(thr);
#endif
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+ duk_err_longjmp(thr);
+ DUK_UNREACHABLE();
+ break;
+ }
+
+ case DUK_OP_CSREG: {
/*
- * To determine whether to use an optimized Ecmascript-to-Ecmascript
- * call, we need to know whether the final, non-bound function is an
- * Ecmascript function.
- *
- * This is now implemented so that we start to do an ecma-to-ecma call
- * setup which will resolve the bound chain as the first thing. If the
- * final function is not eligible, the return value indicates that the
- * ecma-to-ecma call is not possible. The setup will overwrite the call
- * target at DUK__REGP(idx) with the final, non-bound function (which
- * may be a lightfunc), and fudge arguments if necessary.
- *
- * XXX: If an ecma-to-ecma call is not possible, this initial call
- * setup will do bound function chain resolution but won't do the
- * "effective this binding" resolution which is quite confusing.
- * Perhaps add a helper for doing bound function and effective this
- * binding resolution - and call that explicitly? Ecma-to-ecma call
- * setup and normal function handling can then assume this prestep has
- * been done by the caller.
+ * Assuming a register binds to a variable declared within this
+ * function (a declarative binding), the 'this' for the call
+ * setup is always 'undefined'. E5 Section 10.2.1.1.6.
*/
- duk_set_top(ctx, (duk_idx_t) (idx + c + 2)); /* [ ... func this arg1 ... argN ] */
-
- call_flags = 0;
- if (flag_tailcall) {
- /* We request a tail call, but in some corner cases
- * call handling can decide that a tail call is
- * actually not possible.
- * See: test-bug-tailcall-preventyield-assert.c.
- */
- call_flags |= DUK_CALL_FLAG_IS_TAILCALL;
- }
+ duk_small_uint_fast_t a = DUK_DEC_A(ins);
+ duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- /* Compared to duk_handle_call():
- * - protected call: never
- * - ignore recursion limit: never
+ /* A -> register containing target function (not type checked here)
+ * BC -> target registers (BC, BC + 1) for call setup
*/
- num_stack_args = c;
- setup_rc = duk_handle_ecma_call_setup(thr,
- num_stack_args,
- call_flags);
-
- if (setup_rc) {
- /* Ecma-to-ecma call possible, may or may not be a tail call.
- * Avoid C recursion by being clever.
- */
- DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
- /* curr_pc synced by duk_handle_ecma_call_setup() */
- goto restart_execution;
- }
- DUK_ASSERT(thr->ptr_curr_pc != NULL); /* restored if ecma-to-ecma setup fails */
- DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call not possible, target is native (may be lightfunc)"));
-
- /* Recompute argument count: bound function handling may have shifted. */
- num_stack_args = duk_get_top(ctx) - (idx + 2);
- DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_dup(thr, (duk_idx_t) a);
+ duk_replace(thr, (duk_idx_t) bc);
+ duk_to_undefined(thr, (duk_idx_t) (bc + 1));
+#else
+ duk_tval *tv1;
+ duk_tval *tv2;
+ duk_tval *tv3;
+ duk_tval tv_tmp1;
+ duk_tval tv_tmp2;
- tv_func = DUK__REGP(idx); /* Relookup if relocated */
- if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ tv1 = DUK__REGP(bc);
+ tv2 = tv1 + 1;
+ DUK_TVAL_SET_TVAL(&tv_tmp1, tv1);
+ DUK_TVAL_SET_TVAL(&tv_tmp2, tv2);
+ tv3 = DUK__REGP(a);
+ DUK_TVAL_SET_TVAL(tv1, tv3);
+ DUK_TVAL_INCREF(thr, tv1); /* no side effects */
+ DUK_TVAL_SET_UNDEFINED(tv2); /* no need for incref */
+ DUK_TVAL_DECREF(thr, &tv_tmp1);
+ DUK_TVAL_DECREF(thr, &tv_tmp2);
+#endif
+ break;
+ }
- call_flags = 0; /* not protected, respect reclimit, not constructor */
- /* There is no eval() special handling here: eval() is never
- * automatically converted to a lightfunc.
- */
- DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
+ /* XXX: in some cases it's faster NOT to reuse the value
+ * stack but rather copy the arguments on top of the stack
+ * (mainly when the calling value stack is large and the value
+ * stack resize would be large).
+ */
- duk_handle_call_unprotected(thr,
- num_stack_args,
- call_flags);
+ case DUK_OP_CALL0:
+ case DUK_OP_CALL1:
+ case DUK_OP_CALL2:
+ case DUK_OP_CALL3:
+ case DUK_OP_CALL4:
+ case DUK_OP_CALL5:
+ case DUK_OP_CALL6:
+ case DUK_OP_CALL7: {
+ /* Opcode packs 4 flag bits: 1 for indirect, 3 map
+ * 1:1 to three lowest call handling flags.
+ *
+ * A -> nargs or register with nargs (indirect)
+ * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
+ */
- /* duk_js_call.c is required to restore the stack reserve
- * so we only need to reset the top.
- */
+ duk_idx_t nargs;
+ duk_idx_t idx;
+ duk_small_uint_t call_flags;
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- fun = DUK__FUN();
+ duk_hcompfunc *fun;
#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
- /* No need to reinit setjmp() catchpoint, as call handling
- * will store and restore our state.
- */
- } else {
- /* Call setup checks callability. */
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_func));
- obj_func = DUK_TVAL_GET_OBJECT(tv_func);
- DUK_ASSERT(obj_func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(obj_func));
+ DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
+ DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0);
- /*
- * Other cases, use C recursion.
- *
- * If a tail call was requested we ignore it and execute a normal call.
- * Since Duktape 0.11.0 the compiler emits a RETURN opcode even after
- * a tail call to avoid test-bug-tailcall-thread-yield-resume.js.
- *
- * Direct eval call: (1) call target (before following bound function
- * chain) is the built-in eval() function, and (2) call was made with
- * the identifier 'eval'.
- */
+ nargs = (duk_idx_t) DUK_DEC_A(ins);
+ call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
+ idx = (duk_idx_t) DUK_DEC_BC(ins);
- call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj_func) &&
- ((duk_hnativefunction *) obj_func)->func == duk_bi_global_object_eval) {
- if (flag_evalcall) {
- DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
- } else {
- DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was not 'eval' -> indirect eval"));
- }
- }
-
- duk_handle_call_unprotected(thr,
- num_stack_args,
- call_flags);
+ if (duk__executor_handle_call(thr, idx, nargs, call_flags)) {
+ /* curr_pc synced by duk_handle_call_unprotected() */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ goto restart_execution;
+ }
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
- /* duk_js_call.c is required to restore the stack reserve
- * so we only need to reset the top.
- */
+ /* duk_js_call.c is required to restore the stack reserve
+ * so we only need to reset the top.
+ */
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- fun = DUK__FUN();
+ fun = DUK__FUN();
#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
-
- /* No need to reinit setjmp() catchpoint, as call handling
- * will store and restore our state.
- */
- }
+ duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
- /* When debugger is enabled, we need to recheck the activation
+ /* No need to reinit setjmp() catchpoint, as call handling
+ * will store and restore our state.
+ *
+ * When debugger is enabled, we need to recheck the activation
* status after returning. This is now handled by call handling
* and heap->dbg_force_restart.
*/
break;
}
- case DUK_OP_TRYCATCH: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
-
- /* A -> flags
- * BC -> reg_catch; base register for two registers used both during
- * trycatch setup and when catch is triggered
- *
- * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
- * reg_catch + 0: catch binding variable name (string).
- * Automatic declarative environment is established for
- * the duration of the 'catch' clause.
- *
- * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
- * reg_catch + 0: with 'target value', which is coerced to
- * an object and then used as a bindind object for an
- * environment record. The binding is initialized here, for
- * the 'try' clause.
- *
- * Note that a TRYCATCH generated for a 'with' statement has no
- * catch or finally parts.
- */
-
- /* XXX: TRYCATCH handling should be reworked to avoid creating
- * an explicit scope unless it is actually needed (e.g. function
- * instances or eval is executed inside the catch block). This
- * rework is not trivial because the compiler doesn't have an
- * intermediate representation. When the rework is done, the
- * opcode format can also be made more straightforward.
- */
-
- /* XXX: side effect handling is quite awkward here */
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
- "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
- (long) DUK_DEC_BC(ins),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
- (unsigned long) DUK_DEC_A(ins)));
-
- a = DUK_DEC_A(ins);
- bc = DUK_DEC_BC(ins);
-
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(thr->callstack_top >= 1);
-
- /* 'with' target must be created first, in case we run out of memory */
- /* XXX: refactor out? */
-
- if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
- DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object"));
-
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
- DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
-
- /* must relookup act in case of side effects */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top - 1;
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype, updated below */
-
- duk_push_tval(ctx, DUK__REGP(bc));
- duk_to_object(ctx, -1);
- duk_dup(ctx, -1);
-
- /* [ ... env target ] */
- /* [ ... env target target ] */
-
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
-
- /* [ ... env ] */
-
- DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT",
- (duk_tval *) duk_get_tval(ctx, -1)));
- }
-
- /* allocate catcher and populate it (should be atomic) */
-
- duk_hthread_catchstack_grow(thr);
- cat = thr->catchstack + thr->catchstack_top;
- DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
- thr->catchstack_top++;
+ case DUK_OP_CALL8:
+ case DUK_OP_CALL9:
+ case DUK_OP_CALL10:
+ case DUK_OP_CALL11:
+ case DUK_OP_CALL12:
+ case DUK_OP_CALL13:
+ case DUK_OP_CALL14:
+ case DUK_OP_CALL15: {
+ /* Indirect variant. */
+ duk_uint_fast_t nargs;
+ duk_idx_t idx;
+ duk_small_uint_t call_flags;
+#if !defined(DUK_USE_EXEC_FUN_LOCAL)
+ duk_hcompfunc *fun;
+#endif
- cat->flags = DUK_CAT_TYPE_TCF;
- cat->h_varname = NULL;
+ DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
+ DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0);
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
- cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
- cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
- DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
- cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
- tv1 = DUK__REGP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+ nargs = (duk_uint_fast_t) DUK_DEC_A(ins);
+ DUK__LOOKUP_INDIRECT(nargs);
+ call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
+ idx = (duk_idx_t) DUK_DEC_BC(ins);
- /* borrowed reference; although 'tv1' comes from a register,
- * its value was loaded using LDCONST so the constant will
- * also exist and be reachable.
- */
- cat->h_varname = DUK_TVAL_GET_STRING(tv1);
- } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
- /* env created above to stack top */
- duk_hobject *new_env;
-
- DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher"));
- cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
-
- DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
- (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ASSERT(act->lex_env != NULL);
- new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
- DUK_ASSERT(new_env != NULL);
-
- act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */
-
- act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
- act->lex_env = new_env;
- DUK_HOBJECT_INCREF(thr, new_env);
- duk_pop(ctx);
- } else {
- ;
+ if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) {
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ goto restart_execution;
}
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
- /* Registers 'bc' and 'bc + 1' are written in longjmp handling
- * and if their previous values (which are temporaries) become
- * unreachable -and- have a finalizer, there'll be a function
- * call during error handling which is not supported now (GH-287).
- * Ensure that both 'bc' and 'bc + 1' have primitive values to
- * guarantee no finalizer calls in error handling. Scrubbing also
- * ensures finalizers for the previous values run here rather than
- * later. Error handling related values are also written to 'bc'
- * and 'bc + 1' but those values never become unreachable during
- * error handling, so there's no side effect problem even if the
- * error value has a finalizer.
- */
- duk_to_undefined(ctx, bc);
- duk_to_undefined(ctx, bc + 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */
- cat->callstack_index = thr->callstack_top - 1;
- cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
- cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
- "idx_base=%ld, h_varname=%!O",
- (unsigned long) cat->flags, (long) cat->callstack_index,
- (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
-
- curr_pc += 2; /* skip jump slots */
+#if !defined(DUK_USE_EXEC_FUN_LOCAL)
+ fun = DUK__FUN();
+#endif
+ duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
break;
}
- /* Pre/post inc/dec for register variables, important for loops. */
- case DUK_OP_PREINCR:
- case DUK_OP_PREDECR:
- case DUK_OP_POSTINCR:
- case DUK_OP_POSTDECR: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1, *tv2;
- duk_double_t x, y, z;
-
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
- */
- DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
-
- tv1 = DUK__REGP(bc);
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv1)) {
- duk_int64_t x_fi, y_fi, z_fi;
- x_fi = DUK_TVAL_GET_FASTINT(tv1);
- if (ins & DUK_ENC_OP(0x01)) {
- if (x_fi == DUK_FASTINT_MIN) {
- goto skip_fastint;
- }
- y_fi = x_fi - 1;
- } else {
- if (x_fi == DUK_FASTINT_MAX) {
- goto skip_fastint;
- }
- y_fi = x_fi + 1;
- }
-
- DUK_TVAL_SET_FASTINT(tv1, y_fi); /* no need for refcount update */
-
- tv2 = DUK__REGP(a);
- z_fi = (ins & DUK_ENC_OP(0x02)) ? x_fi : y_fi;
- DUK_TVAL_SET_FASTINT_UPDREF(thr, tv2, z_fi); /* side effects */
- break;
+ case DUK_OP_NEWOBJ: {
+ duk_push_object(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_hobject *h;
+ h = duk_require_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
}
- skip_fastint:
#endif
- if (DUK_TVAL_IS_NUMBER(tv1)) {
- /* Fast path for the case where the register
- * is a number (e.g. loop counter).
- */
-
- x = DUK_TVAL_GET_NUMBER(tv1);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
-
- DUK_TVAL_SET_NUMBER(tv1, y); /* no need for refcount update */
- } else {
- x = duk_to_number(ctx, bc);
-
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* XXX: could do a direct props realloc, but need hash size */
+ duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
+#endif
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
- duk_push_number(ctx, y);
- duk_replace(ctx, bc);
+ case DUK_OP_NEWARR: {
+ duk_push_array(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_hobject *h;
+ h = duk_require_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h));
}
-
- tv2 = DUK__REGP(a);
- z = (ins & DUK_ENC_OP(0x02)) ? x : y;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv2, z); /* side effects */
- break;
+#endif
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_hobject_realloc_props(thr,
+ duk_known_hobject(thr, -1),
+ 0 /*new_e_size*/,
+ DUK_DEC_A(ins) /*new_a_size*/,
+ 0 /*new_h_size*/,
+ 0 /*abandon_array*/);
+#if 0
+ duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
+#endif
+#endif
+ DUK__REPLACE_TOP_BC_BREAK();
}
- /* Preinc/predec for var-by-name, slow path. */
- case DUK_OP_PREINCV:
- case DUK_OP_PREDECV:
- case DUK_OP_POSTINCV:
- case DUK_OP_POSTDECV: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_double_t x, y;
- duk_tval *tv1;
- duk_hstring *name;
+ case DUK_OP_MPUTOBJ:
+ case DUK_OP_MPUTOBJI: {
+ duk_idx_t obj_idx;
+ duk_uint_fast_t idx, idx_end;
+ duk_small_uint_fast_t count;
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
+ /* A -> register of target object
+ * B -> first register of key/value pair list
+ * or register containing first register number if indirect
+ * C -> number of key/value pairs * 2
+ * (= number of value stack indices used starting from 'B')
*/
- DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- act = thr->callstack + thr->callstack_top - 1;
- (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
-
- /* XXX: fastint fast path would be very useful here */
+ obj_idx = DUK_DEC_A(ins);
+ DUK_ASSERT(duk_is_object(thr, obj_idx));
- x = duk_to_number(ctx, -2);
- duk_pop_2(ctx);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
+ idx = (duk_uint_fast_t) DUK_DEC_B(ins);
+ if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
+ DUK__LOOKUP_INDIRECT(idx);
}
- duk_push_number(ctx, y);
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv1 != NULL);
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
- duk_pop(ctx);
-
- duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- /* Preinc/predec for object properties. */
- case DUK_OP_PREINCP:
- case DUK_OP_PREDECP:
- case DUK_OP_POSTINCP:
- case DUK_OP_POSTDECP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_tval *tv_val;
- duk_bool_t rc;
- duk_double_t x, y;
-
- /* A -> target reg
- * B -> object reg/const (may be const e.g. in "'foo'[1]")
- * C -> key reg/const
- */
-
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
- */
- DUK_ASSERT((DUK_OP_PREINCP & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECP & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCP & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECP & 0x03) == 0x03);
-
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* ignore */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
+ count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
+ DUK_ASSERT(count > 0); /* compiler guarantees */
+ idx_end = idx + count;
- x = duk_to_number(ctx, -1);
- duk_pop(ctx);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
+#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
+ if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) {
+ /* XXX: use duk_is_valid_index() instead? */
+ /* XXX: improve check; check against nregs, not against top */
+ DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
}
+#endif
- duk_push_number(ctx, y);
- tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv_val != NULL);
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
- DUK_UNREF(rc); /* ignore */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
- duk_pop(ctx);
-
- duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
- duk_replace(ctx, (duk_idx_t) a);
+ /* Use 'force' flag to duk_def_prop() to ensure that any
+ * inherited properties don't prevent the operation.
+ * With ES2015 duplicate properties are allowed, so that we
+ * must overwrite any previous data or accessor property.
+ *
+ * With ES2015 computed property names the literal keys
+ * may be arbitrary values and need to be ToPropertyKey()
+ * coerced at runtime.
+ */
+ do {
+ /* XXX: faster initialization (direct access or better primitives) */
+ duk_dup(thr, (duk_idx_t) idx);
+ duk_dup(thr, (duk_idx_t) (idx + 1));
+ duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE |
+ DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_SET_WRITABLE |
+ DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE);
+ idx += 2;
+ } while (idx < idx_end);
break;
}
- case DUK_OP_EXTRA: {
- /* XXX: shared decoding of 'b' and 'c'? */
-
- duk_small_uint_fast_t extraop = DUK_DEC_A(ins);
- switch ((int) extraop) {
- /* XXX: switch cast? */
-
- case DUK_EXTRAOP_NOP: {
- /* nop */
- break;
- }
-
- case DUK_EXTRAOP_INVALID: {
- DUK_ERROR_FMT1(thr, DUK_ERR_INTERNAL_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_BC(ins));
- break;
- }
-
- case DUK_EXTRAOP_LDTHIS: {
- /* Note: 'this' may be bound to any value, not just an object */
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1, *tv2;
-
- tv1 = DUK__REGP(bc);
- tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
- DUK_ASSERT(tv2 >= thr->valstack);
-
- DUK_DDD(DUK_DDDPRINT("LDTHIS: %!T to r%ld", (duk_tval *) tv2, (long) bc));
-
- DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDUNDEF: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDNULL: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDTRUE:
- case DUK_EXTRAOP_LDFALSE: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_small_uint_fast_t bval = (extraop == DUK_EXTRAOP_LDTRUE ? 1 : 0);
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, bval); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_NEWOBJ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
-
- duk_push_object(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_NEWARR: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
-
- duk_push_array(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_SETALEN: {
- duk_small_uint_fast_t b;
- duk_small_uint_fast_t c;
- duk_tval *tv1;
- duk_hobject *h;
- duk_uint32_t len;
-
- b = DUK_DEC_B(ins); tv1 = DUK__REGP(b);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- h = DUK_TVAL_GET_OBJECT(tv1);
-
- c = DUK_DEC_C(ins); tv1 = DUK__REGP(c);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
-
- duk_hobject_set_length(thr, h, len);
-
- break;
- }
-
- case DUK_EXTRAOP_TYPEOF: {
- duk_context *ctx = (duk_context *) thr;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_push_hstring(ctx, duk_js_typeof(thr, DUK__REGP(bc)));
- duk_replace(ctx, (duk_idx_t) bc);
- break;
- }
-
- case DUK_EXTRAOP_TYPEOFID: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_hstring *name;
- duk_tval *tv;
-
- /* B -> target register
- * C -> constant index of identifier name
- */
-
- tv = DUK__REGCONSTP(c); /* XXX: this could be a DUK__CONSTP instead */
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
- name = DUK_TVAL_GET_STRING(tv);
- act = thr->callstack + thr->callstack_top - 1;
- if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
- /* -> [... val this] */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
- duk_push_hstring(ctx, duk_js_typeof(thr, tv));
- duk_replace(ctx, (duk_idx_t) b);
- duk_pop_2(ctx);
- } else {
- /* unresolvable, no stack changes */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_replace(ctx, (duk_idx_t) b);
- }
-
- break;
- }
-
- case DUK_EXTRAOP_INITENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /*
- * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
- * If called with 'null' or 'undefined', this opcode returns 'null' as
- * the enumerator, which is special cased in NEXTENUM. This simplifies
- * the compiler part
- */
-
- /* B -> register for writing enumerator object
- * C -> value to be enumerated (register)
- */
-
- if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
- duk_push_null(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- duk_dup(ctx, (duk_idx_t) c);
- duk_to_object(ctx, -1);
- duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
- duk_replace(ctx, (duk_idx_t) b);
- }
- break;
- }
+ case DUK_OP_INITSET:
+ case DUK_OP_INITGET: {
+ duk__handle_op_initset_initget(thr, ins);
+ break;
+ }
- case DUK_EXTRAOP_NEXTENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
+ case DUK_OP_MPUTARR:
+ case DUK_OP_MPUTARRI: {
+ duk_idx_t obj_idx;
+ duk_uint_fast_t idx, idx_end;
+ duk_small_uint_fast_t count;
+ duk_tval *tv1;
+ duk_uint32_t arr_idx;
- /*
- * NEXTENUM checks whether the enumerator still has unenumerated
- * keys. If so, the next key is loaded to the target register
- * and the next instruction is skipped. Otherwise the next instruction
- * will be executed, jumping out of the enumeration loop.
- */
+ /* A -> register of target object
+ * B -> first register of value data (start_index, value1, value2, ..., valueN)
+ * or register containing first register number if indirect
+ * C -> number of key/value pairs (N)
+ */
- /* B -> target register for next key
- * C -> enum register
- */
+ obj_idx = DUK_DEC_A(ins);
+ DUK_ASSERT(duk_is_object(thr, obj_idx));
- DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
-
- if (duk_is_object(ctx, (duk_idx_t) c)) {
- /* XXX: assert 'c' is an enumerator */
- duk_dup(ctx, (duk_idx_t) c);
- if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
- /* [ ... enum ] -> [ ... next_key ] */
- DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
- (duk_tval *) duk_get_tval(ctx, -1)));
- curr_pc++;
- } else {
- /* [ ... enum ] -> [ ... ] */
- DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
- duk_push_undefined(ctx);
- }
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- /* 'null' enumerator case -> behave as with an empty enumerator */
- DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
- DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
- }
- break;
+ idx = (duk_uint_fast_t) DUK_DEC_B(ins);
+ if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
+ DUK__LOOKUP_INDIRECT(idx);
}
- case DUK_EXTRAOP_INITSET:
- case DUK_EXTRAOP_INITSETI:
- case DUK_EXTRAOP_INITGET:
- case DUK_EXTRAOP_INITGETI: {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t is_set = (extraop == DUK_EXTRAOP_INITSET || extraop == DUK_EXTRAOP_INITSETI);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_uint_fast_t idx;
-
- /* B -> object register
- * C -> C+0 contains key, C+1 closure (value)
- */
-
- /*
- * INITSET/INITGET are only used to initialize object literal keys.
- * The compiler ensures that there cannot be a previous data property
- * of the same name. It also ensures that setter and getter can only
- * be initialized once (or not at all).
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_C(ins);
- if (extraop == DUK_EXTRAOP_INITSETI || extraop == DUK_EXTRAOP_INITGETI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
+ count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
+ DUK_ASSERT(count > 0 + 1); /* compiler guarantees */
+ idx_end = idx + count;
#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("INITSET/INITGET out of bounds");
- }
-#endif
-
- /* XXX: this is now a very unoptimal implementation -- this can be
- * made very simple by direct manipulation of the object internals,
- * given the guarantees above.
- */
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_OBJECT_CONSTRUCTOR);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_DEFINE_PROPERTY);
- duk_push_undefined(ctx);
- duk_dup(ctx, (duk_idx_t) b);
- duk_dup(ctx, (duk_idx_t) (idx + 0));
- duk_push_object(ctx); /* -> [ Object defineProperty undefined obj key desc ] */
-
- duk_push_true(ctx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
- duk_push_true(ctx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
- duk_dup(ctx, (duk_idx_t) (idx + 1));
- duk_put_prop_stridx(ctx, -2, (is_set ? DUK_STRIDX_SET : DUK_STRIDX_GET));
-
- DUK_DDD(DUK_DDDPRINT("INITGET/INITSET: obj=%!T, key=%!T, desc=%!T",
- (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_call_method(ctx, 3); /* -> [ Object res ] */
- duk_pop_2(ctx);
-
- DUK_DDD(DUK_DDDPRINT("INITGET/INITSET AFTER: obj=%!T",
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b)));
- break;
- }
-
- case DUK_EXTRAOP_ENDTRY: {
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
- DUK_CAT_CLEAR_CATCH_ENABLED(cat);
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
- break;
- }
-
- case DUK_EXTRAOP_ENDCATCH: {
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
-
- act = thr->callstack + thr->callstack_top - 1;
-
- if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
- duk_hobject *prev_env;
-
- /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
- DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
- DUK_ASSERT(act->lex_env != NULL);
-
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
-
- prev_env = act->lex_env;
- DUK_ASSERT(prev_env != NULL);
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
- DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
- DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
- }
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
- break;
+ if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) {
+ /* XXX: use duk_is_valid_index() instead? */
+ /* XXX: improve check; check against nregs, not against top */
+ DUK__INTERNAL_ERROR("MPUTARR out of bounds");
}
-
- case DUK_EXTRAOP_ENDFIN: {
- duk_context *ctx = (duk_context *) thr;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_t cont_type;
- duk_small_uint_t ret_result;
-
- /* Sync and NULL early. */
- DUK__SYNC_AND_NULL_CURR_PC();
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- /* CATCH flag may be enabled or disabled here; it may be enabled if
- * the statement has a catch block but the try block does not throw
- * an error.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
- /* XXX: assert idx_base */
-
- DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
- (duk_tval *) (thr->valstack + cat->idx_base + 0),
- (duk_tval *) (thr->valstack + cat->idx_base + 1)));
-
- tv1 = thr->valstack + cat->idx_base + 1; /* type */
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
-
- switch (cont_type) {
- case DUK_LJ_TYPE_NORMAL: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
- "dismantle catcher, resume execution after ENDFIN"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- goto restart_execution;
- }
- case DUK_LJ_TYPE_RETURN: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
- "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
-
- /* Not necessary to unwind catchstack: return handling will
- * do it. The finally flag of 'cat' is no longer set. The
- * catch flag may be set, but it's not checked by return handling.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
#endif
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
- ret_result = duk__handle_return(thr,
- entry_thread,
- entry_callstack_top);
- if (ret_result == DUK__RETHAND_RESTART) {
- goto restart_execution;
- }
- DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
-
- DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
- return;
- }
- case DUK_LJ_TYPE_BREAK:
- case DUK_LJ_TYPE_CONTINUE: {
- duk_uint_t label_id;
- duk_small_uint_t lj_type;
-
- /* Not necessary to unwind catchstack: break/continue
- * handling will do it. The finally flag of 'cat' is
- * no longer set. The catch flag may be set, but it's
- * not checked by break/continue handling.
- */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
-#endif
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+ tv1 = DUK__REGP(idx);
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
- label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
#else
- label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
+ arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
#endif
- lj_type = cont_type;
- duk__handle_break_or_continue(thr, label_id, lj_type);
- goto restart_execution;
- }
- default: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
- "dismantle catcher, re-throw error",
- (long) cont_type));
-
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
-
- duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
- }
-
- /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
- DUK_UNREACHABLE();
- break;
- }
-
- case DUK_EXTRAOP_THROW: {
- duk_context *ctx = (duk_context *) thr;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
+ idx++;
- /* Note: errors are augmented when they are created, not
- * when they are thrown. So, don't augment here, it would
- * break re-throwing for instance.
+ do {
+ /* duk_xdef_prop() will define an own property without any array
+ * special behaviors. We'll need to set the array length explicitly
+ * in the end. For arrays with elisions, the compiler will emit an
+ * explicit SETALEN which will update the length.
*/
- /* Sync so that augmentation sees up-to-date activations, NULL
- * thr->ptr_curr_pc so that it's not used if side effects occur
- * in augmentation or longjmp handling.
+ /* XXX: because we're dealing with 'own' properties of a fresh array,
+ * the array initializer should just ensure that the array has a large
+ * enough array part and write the values directly into array part,
+ * and finally set 'length' manually in the end (as already happens now).
*/
- DUK__SYNC_AND_NULL_CURR_PC();
-
- duk_dup(ctx, (duk_idx_t) bc);
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- duk_err_augment_error_throw(thr);
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
-#endif
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+ duk_dup(thr, (duk_idx_t) idx);
+ duk_xdef_prop_index_wec(thr, obj_idx, arr_idx);
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- break;
- }
+ idx++;
+ arr_idx++;
+ } while (idx < idx_end);
- case DUK_EXTRAOP_INVLHS: {
- DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "invalid lvalue");
+ /* XXX: E5.1 Section 11.1.4 coerces the final length through
+ * ToUint32() which is odd but happens now as a side effect of
+ * 'arr_idx' type.
+ */
+ duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx);
+ break;
+ }
- DUK_UNREACHABLE();
- break;
- }
+ case DUK_OP_SETALEN: {
+ duk_tval *tv1;
+ duk_hobject *h;
+ duk_uint32_t len;
- case DUK_EXTRAOP_UNM:
- case DUK_EXTRAOP_UNP: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk__vm_arith_unary_op(thr, DUK__REGP(bc), bc, extraop);
- break;
- }
+ tv1 = DUK__REGP_A(ins);
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
+ h = DUK_TVAL_GET_OBJECT(tv1);
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h));
- case DUK_EXTRAOP_DEBUGGER: {
- /* Opcode only emitted by compiler when debugger
- * support is enabled. Ignore it silently without
- * debugger support, in case it has been loaded
- * from precompiled bytecode.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
- DUK__SYNC_AND_NULL_CURR_PC();
- duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
- DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
- goto restart_execution;
- } else {
- DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
- }
+ tv1 = DUK__REGP_BC(ins);
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
#else
- DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
+ len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
#endif
- break;
- }
-
- case DUK_EXTRAOP_BREAK: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- DUK_DDD(DUK_DDDPRINT("BREAK: %ld", (long) bc));
+ ((duk_harray *) h)->length = len;
+ break;
+ }
- DUK__SYNC_AND_NULL_CURR_PC();
- duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
- goto restart_execution;
- }
+ case DUK_OP_INITENUM: {
+ duk__handle_op_initenum(thr, ins);
+ break;
+ }
- case DUK_EXTRAOP_CONTINUE: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
+ case DUK_OP_NEXTENUM: {
+ curr_pc += duk__handle_op_nextenum(thr, ins);
+ break;
+ }
- DUK_DDD(DUK_DDDPRINT("CONTINUE: %ld", (long) bc));
+ case DUK_OP_INVLHS: {
+ DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE);
+ DUK_UNREACHABLE();
+ break;
+ }
+ case DUK_OP_DEBUGGER: {
+ /* Opcode only emitted by compiler when debugger
+ * support is enabled. Ignore it silently without
+ * debugger support, in case it has been loaded
+ * from precompiled bytecode.
+ */
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ if (duk_debug_is_attached(thr->heap)) {
+ DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
DUK__SYNC_AND_NULL_CURR_PC();
- duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
+ duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
+ DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
goto restart_execution;
+ } else {
+ DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
}
-
- case DUK_EXTRAOP_BNOT: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- duk__vm_bitwise_not(thr, DUK__REGP(bc), bc);
- break;
- }
-
- case DUK_EXTRAOP_LNOT: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- duk__vm_logical_not(thr, tv1, tv1);
- break;
- }
-
- case DUK_EXTRAOP_INSTOF: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_instanceof(thr, DUK__REGP(b), DUK__REGCONSTP(c));
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_IN: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_in(thr, DUK__REGP(b), DUK__REGCONSTP(c));
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_LABEL: {
- duk_catcher *cat;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- /* allocate catcher and populate it (should be atomic) */
-
- duk_hthread_catchstack_grow(thr);
- cat = thr->catchstack + thr->catchstack_top;
- thr->catchstack_top++;
-
- cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
- cat->callstack_index = thr->callstack_top - 1;
- cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
- cat->idx_base = 0; /* unused for label */
- cat->h_varname = NULL;
-
- DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
- "idx_base=%ld, h_varname=%!O, label_id=%ld",
- (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
- (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
-
- curr_pc += 2; /* skip jump slots */
- break;
- }
-
- case DUK_EXTRAOP_ENDLABEL: {
- duk_catcher *cat;
-#if defined(DUK_USE_DDDPRINT) || defined(DUK_USE_ASSERTIONS)
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-#endif
-#if defined(DUK_USE_DDDPRINT)
- DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
+#else
+ DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
#endif
+ break;
+ }
- DUK_ASSERT(thr->catchstack_top >= 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_UNREF(cat);
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
- DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
-
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- break;
- }
-
- default: {
- DUK__INTERNAL_ERROR("invalid extra opcode");
- }
-
- } /* end switch */
+ case DUK_OP_NOP: {
+ /* Nop, ignored, but ABC fields may carry a value e.g.
+ * for indirect opcode handling.
+ */
+ break;
+ }
+ case DUK_OP_INVALID: {
+ DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins));
break;
}
- default: {
- /* this should never be possible, because the switch-case is
- * comprehensive
+#if defined(DUK_USE_ES6)
+ case DUK_OP_NEWTARGET: {
+ /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation
+ * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
+ *
+ * No newTarget support now, so as a first approximation
+ * use the resolved (non-bound) target function.
+ */
+ /* XXX: C API: push_new_target()? */
+ duk_activation *act;
+
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+
+ /* Check CONSTRUCT flag from current function, or if running
+ * direct eval, from a non-direct-eval parent (with possibly
+ * more than one nested direct eval). An alternative to this
+ * would be to store [[NewTarget]] as a hidden symbol of the
+ * lexical scope, and then just look up that variable.
*/
+ for (;;) {
+ if (act == NULL) {
+ duk_push_undefined(thr);
+ break;
+ }
+ if (act->flags & DUK_ACT_FLAG_CONSTRUCT) {
+ duk_push_tval(thr, &act->tv_func);
+ break;
+ } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ act = act->parent;
+ } else {
+ duk_push_undefined(thr);
+ break;
+ }
+ }
+
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
+#endif /* DUK_USE_ES6 */
+
+#if !defined(DUK_USE_EXEC_PREFER_SIZE)
+#if !defined(DUK_USE_ES7_EXP_OPERATOR)
+ case DUK_OP_EXP_RR:
+ case DUK_OP_EXP_CR:
+ case DUK_OP_EXP_RC:
+ case DUK_OP_EXP_CC:
+#endif
+#if !defined(DUK_USE_ES6)
+ case DUK_OP_NEWTARGET:
+#endif
+#if !defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ case DUK_OP_GETPROPC_CR:
+ case DUK_OP_GETPROPC_RC:
+ case DUK_OP_GETPROPC_CC:
+#endif
+ case DUK_OP_UNUSED207:
+ case DUK_OP_UNUSED212:
+ case DUK_OP_UNUSED213:
+ case DUK_OP_UNUSED214:
+ case DUK_OP_UNUSED215:
+ case DUK_OP_UNUSED216:
+ case DUK_OP_UNUSED217:
+ case DUK_OP_UNUSED218:
+ case DUK_OP_UNUSED219:
+ case DUK_OP_UNUSED220:
+ case DUK_OP_UNUSED221:
+ case DUK_OP_UNUSED222:
+ case DUK_OP_UNUSED223:
+ case DUK_OP_UNUSED224:
+ case DUK_OP_UNUSED225:
+ case DUK_OP_UNUSED226:
+ case DUK_OP_UNUSED227:
+ case DUK_OP_UNUSED228:
+ case DUK_OP_UNUSED229:
+ case DUK_OP_UNUSED230:
+ case DUK_OP_UNUSED231:
+ case DUK_OP_UNUSED232:
+ case DUK_OP_UNUSED233:
+ case DUK_OP_UNUSED234:
+ case DUK_OP_UNUSED235:
+ case DUK_OP_UNUSED236:
+ case DUK_OP_UNUSED237:
+ case DUK_OP_UNUSED238:
+ case DUK_OP_UNUSED239:
+ case DUK_OP_UNUSED240:
+ case DUK_OP_UNUSED241:
+ case DUK_OP_UNUSED242:
+ case DUK_OP_UNUSED243:
+ case DUK_OP_UNUSED244:
+ case DUK_OP_UNUSED245:
+ case DUK_OP_UNUSED246:
+ case DUK_OP_UNUSED247:
+ case DUK_OP_UNUSED248:
+ case DUK_OP_UNUSED249:
+ case DUK_OP_UNUSED250:
+ case DUK_OP_UNUSED251:
+ case DUK_OP_UNUSED252:
+ case DUK_OP_UNUSED253:
+ case DUK_OP_UNUSED254:
+ case DUK_OP_UNUSED255:
+ /* Force all case clauses to map to an actual handler
+ * so that the compiler can emit a jump without a bounds
+ * check: the switch argument is a duk_uint8_t so that
+ * the compiler may be able to figure it out. This is
+ * a small detail and obviously compiler dependent.
+ */
+ /* default: clause omitted on purpose */
+#else /* DUK_USE_EXEC_PREFER_SIZE */
+ default:
+#endif /* DUK_USE_EXEC_PREFER_SIZE */
+ {
+ /* Default case catches invalid/unsupported opcodes. */
+ DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins));
DUK__INTERNAL_ERROR("invalid opcode");
break;
}
} /* end switch */
+
+ continue;
+
+ /* Some shared exit paths for opcode handling below. These
+ * are mostly useful to reduce code footprint when multiple
+ * opcodes have a similar epilogue (like replacing stack top
+ * with index 'a').
+ */
+
+#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ replace_top_a:
+ DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins));
+ continue;
+ replace_top_bc:
+ DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins));
+ continue;
+#endif
}
DUK_UNREACHABLE();
-#ifndef DUK_USE_VERBOSE_EXECUTOR_ERRORS
+#if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
internal_error:
- DUK_ERROR_INTERNAL(thr, "internal error in bytecode executor");
+ DUK_ERROR_INTERNAL(thr);
#endif
}
+/* automatic undefs */
+#undef DUK__BYTEOFF_A
+#undef DUK__BYTEOFF_B
+#undef DUK__BYTEOFF_BC
+#undef DUK__BYTEOFF_C
+#undef DUK__COMPARE_BODY
+#undef DUK__CONST
+#undef DUK__CONSTP
+#undef DUK__CONSTP_A
+#undef DUK__CONSTP_B
+#undef DUK__CONSTP_BC
+#undef DUK__CONSTP_C
+#undef DUK__DELPROP_BODY
+#undef DUK__EQ_BODY
+#undef DUK__FUN
+#undef DUK__GETPROPC_BODY
+#undef DUK__GETPROP_BODY
+#undef DUK__GE_BODY
+#undef DUK__GT_BODY
+#undef DUK__INLINE_PERF
+#undef DUK__INSTOF_BODY
+#undef DUK__INTERNAL_ERROR
+#undef DUK__INT_NOACTION
+#undef DUK__INT_RESTART
+#undef DUK__IN_BODY
+#undef DUK__LE_BODY
#undef DUK__LONGJMP_RESTART
-#undef DUK__LONGJMP_FINISHED
#undef DUK__LONGJMP_RETHROW
-
-#undef DUK__RETHAND_RESTART
-#undef DUK__RETHAND_FINISHED
-
-#undef DUK__FUN
-#undef DUK__STRICT
+#undef DUK__LOOKUP_INDIRECT
+#undef DUK__LT_BODY
+#undef DUK__MASK_A
+#undef DUK__MASK_B
+#undef DUK__MASK_BC
+#undef DUK__MASK_C
+#undef DUK__NEQ_BODY
+#undef DUK__NOINLINE_PERF
+#undef DUK__PUTPROP_BODY
+#undef DUK__RCBIT_B
+#undef DUK__RCBIT_C
#undef DUK__REG
+#undef DUK__REGCONSTP_B
+#undef DUK__REGCONSTP_C
#undef DUK__REGP
-#undef DUK__CONST
-#undef DUK__CONSTP
-#undef DUK__RCISREG
-#undef DUK__REGCONST
-#undef DUK__REGCONSTP
-
-#undef DUK__INTERNAL_ERROR
-#undef DUK__SYNC_CURR_PC
+#undef DUK__REGP_A
+#undef DUK__REGP_B
+#undef DUK__REGP_BC
+#undef DUK__REGP_C
+#undef DUK__REPLACE_BOOL_A_BREAK
+#undef DUK__REPLACE_TOP_A_BREAK
+#undef DUK__REPLACE_TOP_BC_BREAK
+#undef DUK__REPLACE_TO_TVPTR
+#undef DUK__RETHAND_FINISHED
+#undef DUK__RETHAND_RESTART
+#undef DUK__RETURN_SHARED
+#undef DUK__SEQ_BODY
+#undef DUK__SHIFT_A
+#undef DUK__SHIFT_B
+#undef DUK__SHIFT_BC
+#undef DUK__SHIFT_C
+#undef DUK__SNEQ_BODY
+#undef DUK__STRICT
#undef DUK__SYNC_AND_NULL_CURR_PC
-#line 1 "duk_js_ops.c"
+#undef DUK__SYNC_CURR_PC
+#undef DUK__TVAL_SHIFT
/*
* Ecmascript specification algorithm and conversion helpers.
*
- * These helpers encapsulate the primitive Ecmascript operation
- * semantics, and are used by the bytecode executor and the API
- * (among other places). Note that some primitives are only
- * implemented as part of the API and have no "internal" helper.
- * (This is the case when an internal helper would not really be
- * useful; e.g. the operation is rare, uses value stack heavily,
- * etc.)
+ * These helpers encapsulate the primitive Ecmascript operation semantics,
+ * and are used by the bytecode executor and the API (among other places).
+ * Some primitives are only implemented as part of the API and have no
+ * "internal" helper. This is the case when an internal helper would not
+ * really be useful; e.g. the operation is rare, uses value stack heavily,
+ * etc.
*
* The operation arguments depend on what is required to implement
* the operation:
@@ -69961,13 +77149,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
* in-place coercion is OK for the bytecode executor and the API.
*/
-/* include removed: duk_internal.h */
-
-/*
- * [[DefaultValue]] (E5 Section 8.12.8)
- *
- * ==> implemented in the API.
- */
+/* #include duk_internal.h -> already included */
/*
* ToPrimitive() (E5 Section 9.1)
@@ -69985,8 +77167,13 @@ DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
case DUK_TAG_NULL:
return 0;
case DUK_TAG_BOOLEAN:
+ DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1);
return DUK_TVAL_GET_BOOLEAN(tv);
case DUK_TAG_STRING: {
+ /* Symbols ToBoolean() coerce to true, regardless of their
+ * description. This happens with no explicit check because
+ * of the symbol representation byte prefix.
+ */
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
@@ -69995,10 +77182,10 @@ DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
return 1;
}
case DUK_TAG_BUFFER: {
- /* mimic semantics for strings */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
+ /* Mimic Uint8Array semantics: objects coerce true, regardless
+ * of buffer length (zero or not) or context.
+ */
+ return 1;
}
case DUK_TAG_POINTER: {
void *p = DUK_TVAL_GET_POINTER(tv);
@@ -70018,16 +77205,23 @@ DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
default: {
/* number */
duk_double_t d;
+#if defined(DUK_USE_PREFER_SIZE)
int c;
+#endif
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
d = DUK_TVAL_GET_DOUBLE(tv);
+#if defined(DUK_USE_PREFER_SIZE)
c = DUK_FPCLASSIFY((double) d);
if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
return 0;
} else {
return 1;
}
+#else
+ DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1);
+ return duk_double_is_nan_or_zero(d) ^ 1;
+#endif
}
}
DUK_UNREACHABLE();
@@ -70063,10 +77257,11 @@ DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
/* E5 Section 9.3.1 */
DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t s2n_flags;
duk_double_t d;
+ DUK_ASSERT(duk_is_string(thr, -1));
+
/* Quite lenient, e.g. allow empty as zero, but don't allow trailing
* garbage.
*/
@@ -70080,18 +77275,28 @@ DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
- DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
+ DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT |
+ DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT |
+ DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT;
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- d = duk_get_number(ctx, -1);
- duk_pop(ctx);
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
+
+#if defined(DUK_USE_PREFER_SIZE)
+ d = duk_get_number(thr, -1);
+ duk_pop_unsafe(thr);
+#else
+ thr->valstack_top--;
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top));
+ DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top)); /* no fastint conversion in numconv now */
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top));
+ d = DUK_TVAL_GET_DOUBLE(thr->valstack_top); /* assumes not a fastint */
+ DUK_TVAL_SET_UNDEFINED(thr->valstack_top);
+#endif
return d;
}
DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
- duk_context *ctx = (duk_hthread *) thr;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv != NULL);
@@ -70114,35 +77319,29 @@ DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
return 0.0;
}
case DUK_TAG_STRING: {
+ /* For Symbols ToNumber() is always a TypeError. */
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- duk_push_hstring(ctx, h);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL);
+ }
+ duk_push_hstring(thr, h);
return duk__tonumber_string_raw(thr);
}
+ case DUK_TAG_BUFFER: /* plain buffer treated like object */
case DUK_TAG_OBJECT: {
- /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
- * so use [[DefaultValue]] directly.
- */
duk_double_t d;
- duk_push_tval(ctx, tv);
- duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
+ duk_push_tval(thr, tv);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
/* recursive call for a primitive value (guaranteed not to cause second
* recursion).
*/
- d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
+ DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
+ d = duk_js_tonumber(thr, duk_get_tval(thr, -1));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
return d;
}
- case DUK_TAG_BUFFER: {
- /* Coerce like a string. This makes sense because addition also treats
- * buffers like strings.
- */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- duk_push_hbuffer(ctx, h);
- duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */
- return duk__tonumber_string_raw(thr);
- }
case DUK_TAG_POINTER: {
/* Coerce like boolean */
void *p = DUK_TVAL_GET_POINTER(tv);
@@ -70173,23 +77372,33 @@ DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
/* exposed, used by e.g. duk_bi_date.c */
DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
+#if defined(DUK_USE_PREFER_SIZE)
duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
- if (c == DUK_FP_NAN) {
+ if (DUK_UNLIKELY(c == DUK_FP_NAN)) {
return 0.0;
- } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
- /* XXX: FP_ZERO check can be removed, the else clause handles it
- * correctly (preserving sign).
- */
+ } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) {
return x;
} else {
- duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x);
- x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
- if (s) {
- x = -x;
+ /* Finite, including neg/pos zero. Neg zero sign must be
+ * preserved.
+ */
+ return duk_double_trunc_towards_zero(x);
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ /* NaN and Infinity have the same exponent so it's a cheap
+ * initial check for the rare path.
+ */
+ if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) {
+ if (duk_double_is_nan(x)) {
+ return 0.0;
+ } else {
+ return x;
}
- return x;
+ } else {
+ return duk_double_trunc_towards_zero(x);
}
+#endif /* DUK_USE_PREFER_SIZE */
}
DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
@@ -70204,20 +77413,23 @@ DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
/* combined algorithm matching E5 Sections 9.5 and 9.6 */
DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
- duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
- duk_small_int_t s;
+#if defined (DUK_USE_PREFER_SIZE)
+ duk_small_int_t c;
+#endif
+#if defined (DUK_USE_PREFER_SIZE)
+ c = (duk_small_int_t) DUK_FPCLASSIFY(x);
if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
return 0.0;
}
-
+#else
+ if (duk_double_is_nan_zero_inf(x)) {
+ return 0.0;
+ }
+#endif
/* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
- s = (duk_small_int_t) DUK_SIGNBIT(x);
- x = DUK_FLOOR(DUK_FABS(x));
- if (s) {
- x = -x;
- }
+ x = duk_double_trunc_towards_zero(x);
/* NOTE: fmod(x) result sign is same as sign of x, which
* differs from what Javascript wants (see Section 9.6).
@@ -70228,7 +77440,7 @@ DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t i
if (x < 0.0) {
x += DUK_DOUBLE_2TO32;
}
- /* -> x in [0, 2**32[ */
+ DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32); /* -> x in [0, 2**32[ */
if (is_toint32) {
if (x >= DUK_DOUBLE_2TO31) {
@@ -70284,58 +77496,13 @@ DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
/*
* ToString() (E5 Section 9.8)
- *
- * ==> implemented in the API.
- */
-
-/*
* ToObject() (E5 Section 9.9)
- *
- * ==> implemented in the API.
- */
-
-/*
* CheckObjectCoercible() (E5 Section 9.10)
- *
- * Note: no API equivalent now.
- */
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
- duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);
-
- /* Note: this must match ToObject() behavior */
-
- if (tag == DUK_TAG_UNDEFINED ||
- tag == DUK_TAG_NULL ||
- tag == DUK_TAG_POINTER ||
- tag == DUK_TAG_BUFFER) {
- DUK_ERROR_TYPE(thr, "not object coercible");
- }
-}
-#endif
-
-/*
* IsCallable() (E5 Section 9.11)
*
- * XXX: API equivalent is a separate implementation now, and this has
- * currently no callers.
+ * ==> implemented in the API.
*/
-#if 0 /* unused */
-DUK_INTERNAL duk_bool_t duk_js_iscallable(duk_tval *tv_x) {
- duk_hobject *obj;
-
- if (!DUK_TVAL_IS_OBJECT(tv_x)) {
- return 0;
- }
- obj = DUK_TVAL_GET_OBJECT(tv_x);
- DUK_ASSERT(obj != NULL);
-
- return DUK_HOBJECT_IS_CALLABLE(obj);
-}
-#endif
-
/*
* Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
* 9.12). These have much in common so they can share some helpers.
@@ -70407,8 +77574,8 @@ DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
*
* signbit(x) == signbit(y)
*/
- duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
- duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
+ duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0;
+ duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0;
return (sx == sy);
}
@@ -70435,14 +77602,12 @@ DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
*
* signbit(x) == signbit(y)
*/
- duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
- duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
- return (sx == sy);
+ return duk_double_same_sign(x, y);
}
return 1;
} else {
/* IEEE requires that zeros compare the same regardless
- * of their signed, so if both x and y are zeroes, they
+ * of their sign, so if both x and y are zeroes, they
* are caught above.
*/
DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
@@ -70459,9 +77624,9 @@ DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
#endif /* DUK_USE_PARANOID_MATH */
}
-DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_tmp;
+DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
+ duk_uint_t type_mask_x;
+ duk_uint_t type_mask_y;
/* If flags != 0 (strict or SameValue), thr can be NULL. For loose
* equals comparison it must be != NULL.
@@ -70486,15 +77651,19 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
else
#endif
if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- /* Catches both doubles and cases where only one argument is a fastint */
+ duk_double_t d1, d2;
+
+ /* Catches both doubles and cases where only one argument is
+ * a fastint so can't assume a double.
+ */
+ d1 = DUK_TVAL_GET_NUMBER(tv_x);
+ d2 = DUK_TVAL_GET_NUMBER(tv_y);
if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
/* SameValue */
- return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
- DUK_TVAL_GET_NUMBER(tv_y));
+ return duk__js_samevalue_number(d1, d2);
} else {
/* equals and strict equals */
- return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
- DUK_TVAL_GET_NUMBER(tv_y));
+ return duk__js_equals_number(d1, d2);
}
} else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
switch (DUK_TVAL_GET_TAG(tv_x)) {
@@ -70510,34 +77679,19 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
}
case DUK_TAG_STRING:
case DUK_TAG_OBJECT: {
- /* heap pointer comparison suffices */
+ /* Heap pointer comparison suffices for strings and objects.
+ * Symbols compare equal if they have the same internal
+ * representation; again heap pointer comparison suffices.
+ */
return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
}
case DUK_TAG_BUFFER: {
- if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
- /* heap pointer comparison suffices */
- return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
- } else {
- /* non-strict equality for buffers compares contents */
- duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
- duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
- duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
- duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
- void *buf_x;
- void *buf_y;
- if (len_x != len_y) {
- return 0;
- }
- buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
- buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
- /* if len_x == len_y == 0, buf_x and/or buf_y may
- * be NULL, but that's OK.
- */
- DUK_ASSERT(len_x == len_y);
- DUK_ASSERT(len_x == 0 || buf_x != NULL);
- DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
- }
+ /* In Duktape 2.x plain buffers mimic Uint8Array objects
+ * so always compare by heap pointer. In Duktape 1.x
+ * strict comparison would compare heap pointers and
+ * non-strict would compare contents.
+ */
+ return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
}
case DUK_TAG_LIGHTFUNC: {
/* At least 'magic' has a significant impact on function
@@ -70579,105 +77733,85 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
* code size.
*/
+ type_mask_x = duk_get_type_mask_tval(tv_x);
+ type_mask_y = duk_get_type_mask_tval(tv_y);
+
/* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
- if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
- (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
+ if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) &&
+ (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) {
return 1;
}
- /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
- if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
- /* the next 'if' is guaranteed to match after swap */
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
+ /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
+ if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) {
+ if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) {
+ duk_double_t d1, d2;
+ d1 = DUK_TVAL_GET_NUMBER(tv_x);
+ d2 = duk_to_number_tval(thr, tv_y);
+ return duk__js_equals_number(d1, d2);
+ }
}
- if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
- /* XXX: this is possible without resorting to the value stack */
- duk_double_t d1, d2;
- d2 = DUK_TVAL_GET_NUMBER(tv_y);
- duk_push_tval(ctx, tv_x);
- duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
- duk_to_number(ctx, -1);
- d1 = duk_require_number(ctx, -1);
- duk_pop(ctx);
- return duk__js_equals_number(d1, d2);
- }
-
- /* Buffer/string -> compare contents. */
- if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
- }
- if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
- duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
- duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
- duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
- duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
- const void *buf_x;
- const void *buf_y;
- if (len_x != len_y) {
- return 0;
+ if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) {
+ if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) {
+ duk_double_t d1, d2;
+ d1 = DUK_TVAL_GET_NUMBER(tv_y);
+ d2 = duk_to_number_tval(thr, tv_x);
+ return duk__js_equals_number(d1, d2);
}
- buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
- buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
- /* if len_x == len_y == 0, buf_x and/or buf_y may
- * be NULL, but that's OK.
- */
- DUK_ASSERT(len_x == len_y);
- DUK_ASSERT(len_x == 0 || buf_x != NULL);
- DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
}
/* Boolean/any -> coerce boolean to number and try again. If boolean is
* compared to a pointer, the final comparison after coercion now always
* yields false (as pointer vs. number compares to false), but this is
* not special cased.
+ *
+ * ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1.
*/
- if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
+ if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) {
+ DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1);
+ duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x));
+ duk_push_tval(thr, tv_y);
+ goto recursive_call;
}
- if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
- /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
- duk_bool_t rc;
+ if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) {
DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
- duk_push_tval(ctx, tv_x);
- duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
- rc = duk_js_equals_helper(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- 0 /*flags:nonstrict*/);
- duk_pop_2(ctx);
- return rc;
+ duk_push_tval(thr, tv_x);
+ duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y));
+ goto recursive_call;
}
- /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
- if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
- DUK_TVAL_IS_OBJECT(tv_y)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
+ /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */
+ if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) &&
+ (type_mask_y & DUK_TYPE_MASK_OBJECT)) {
+ /* No symbol check needed because symbols and strings are accepted. */
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -1, DUK_HINT_NONE); /* apparently no hint? */
+ goto recursive_call;
+ }
+ if ((type_mask_x & DUK_TYPE_MASK_OBJECT) &&
+ (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) {
+ /* No symbol check needed because symbols and strings are accepted. */
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -2, DUK_HINT_NONE); /* apparently no hint? */
+ goto recursive_call;
}
- if (DUK_TVAL_IS_OBJECT(tv_x) &&
- (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
+
+ /* Nothing worked -> not equal. */
+ return 0;
+
+ recursive_call:
+ /* Shared code path to call the helper again with arguments on stack top. */
+ {
duk_bool_t rc;
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
rc = duk_js_equals_helper(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
+ DUK_GET_TVAL_NEGIDX(thr, -2),
+ DUK_GET_TVAL_NEGIDX(thr, -1),
0 /*flags:nonstrict*/);
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return rc;
}
-
- /* Nothing worked -> not equal. */
- return 0;
}
/*
@@ -70759,75 +77893,157 @@ DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *
}
#endif
-DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
+#if defined(DUK_USE_FASTINT)
+DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) {
+ DUK_ASSERT(retval == 0 || retval == 1);
+ if (v1 < v2) {
+ return retval ^ 1;
+ } else {
+ return retval;
+ }
+}
+#endif
+
+#if defined(DUK_USE_PARANOID_MATH)
+DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
+ duk_small_int_t c1, s1, c2, s2;
+
+ DUK_ASSERT(retval == 0 || retval == 1);
+ c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
+ s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
+ c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
+ s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
+
+ if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
+ return 0; /* Always false, regardless of negation. */
+ }
+
+ if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
+ /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
+ * steps e, f, and g.
+ */
+ return retval; /* false */
+ }
+
+ if (d1 == d2) {
+ return retval; /* false */
+ }
+
+ if (c1 == DUK_FP_INFINITE && s1 == 0) {
+ /* x == +Infinity */
+ return retval; /* false */
+ }
+
+ if (c2 == DUK_FP_INFINITE && s2 == 0) {
+ /* y == +Infinity */
+ return retval ^ 1; /* true */
+ }
+
+ if (c2 == DUK_FP_INFINITE && s2 != 0) {
+ /* y == -Infinity */
+ return retval; /* false */
+ }
+
+ if (c1 == DUK_FP_INFINITE && s1 != 0) {
+ /* x == -Infinity */
+ return retval ^ 1; /* true */
+ }
+
+ if (d1 < d2) {
+ return retval ^ 1; /* true */
+ }
+
+ return retval; /* false */
+}
+#else /* DUK_USE_PARANOID_MATH */
+DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
+ /* This comparison tree relies doesn't match the exact steps in
+ * E5 Section 11.8.5 but should produce the same results. The
+ * steps rely on exact IEEE semantics for NaNs, etc.
+ */
+
+ DUK_ASSERT(retval == 0 || retval == 1);
+ if (d1 < d2) {
+ /* In no case should both (d1 < d2) and (d2 < d1) be true.
+ * It's possible that neither is true though, and that's
+ * handled below.
+ */
+ DUK_ASSERT(!(d2 < d1));
+
+ /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN)
+ * - d2 is +Infinity, d1 != +Infinity and NaN
+ * - d1 is -Infinity, d2 != -Infinity and NaN
+ */
+ return retval ^ 1;
+ } else {
+ if (d2 < d1) {
+ /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN)
+ * - d1 is +Infinity, d2 != +Infinity and NaN
+ * - d2 is -Infinity, d1 != -Infinity and NaN
+ */
+ return retval;
+ } else {
+ /* - d1 and/or d2 is NaN
+ * - d1 and d2 are both +/- 0
+ * - d1 == d2 (including infinities)
+ */
+ if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) {
+ /* Note: undefined from Section 11.8.5 always
+ * results in false return (see e.g. Section
+ * 11.8.3) - hence special treatment here.
+ */
+ return 0; /* zero regardless of negation */
+ } else {
+ return retval;
+ }
+ }
+ }
+}
+#endif /* DUK_USE_PARANOID_MATH */
+
+DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
duk_double_t d1, d2;
- duk_small_int_t c1, c2;
- duk_small_int_t s1, s2;
duk_small_int_t rc;
duk_bool_t retval;
+ DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1); /* Rely on this flag being lowest. */
+ retval = flags & DUK_COMPARE_FLAG_NEGATE;
+ DUK_ASSERT(retval == 0 || retval == 1);
+
/* Fast path for fastints */
#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
- duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
- if (v1 < v2) {
- /* 'lt is true' */
- retval = 1;
- } else {
- retval = 0;
- }
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval ^= 1;
- }
- return retval;
+ if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) {
+ return duk__compare_fastint(retval,
+ DUK_TVAL_GET_FASTINT(tv_x),
+ DUK_TVAL_GET_FASTINT(tv_y));
}
#endif /* DUK_USE_FASTINT */
/* Fast path for numbers (one of which may be a fastint) */
-#if 1 /* XXX: make fast paths optional for size minimization? */
- if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- d1 = DUK_TVAL_GET_NUMBER(tv_x);
- d2 = DUK_TVAL_GET_NUMBER(tv_y);
- c1 = DUK_FPCLASSIFY(d1);
- c2 = DUK_FPCLASSIFY(d2);
-
- if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
- /* XXX: this is a very narrow check, and doesn't cover
- * zeroes, subnormals, infinities, which compare normally.
- */
-
- if (d1 < d2) {
- /* 'lt is true' */
- retval = 1;
- } else {
- retval = 0;
- }
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval ^= 1;
- }
- return retval;
- }
+#if !defined(DUK_USE_PREFER_SIZE)
+ if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) {
+ return duk__compare_number(retval,
+ DUK_TVAL_GET_NUMBER(tv_x),
+ DUK_TVAL_GET_NUMBER(tv_y));
}
#endif
/* Slow path */
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
} else {
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
}
/* Note: reuse variables */
- tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
- tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_x = DUK_GET_TVAL_NEGIDX(thr, -2);
+ tv_y = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
@@ -70835,102 +78051,51 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
DUK_ASSERT(h1 != NULL);
DUK_ASSERT(h2 != NULL);
- rc = duk_js_string_compare(h1, h2);
- if (rc < 0) {
- goto lt_true;
- } else {
- goto lt_false;
- }
- } else {
- /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
- * preserve it just in case.
- */
-
- if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- d1 = duk_to_number(ctx, -2);
- d2 = duk_to_number(ctx, -1);
- } else {
- d2 = duk_to_number(ctx, -1);
- d1 = duk_to_number(ctx, -2);
- }
-
- c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
- s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
- c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
- s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
-
- if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
- goto lt_undefined;
- }
-
- if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
- /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
- * steps e, f, and g.
- */
- goto lt_false;
- }
-
- if (d1 == d2) {
- goto lt_false;
- }
-
- if (c1 == DUK_FP_INFINITE && s1 == 0) {
- /* x == +Infinity */
- goto lt_false;
- }
-
- if (c2 == DUK_FP_INFINITE && s2 == 0) {
- /* y == +Infinity */
- goto lt_true;
- }
-
- if (c2 == DUK_FP_INFINITE && s2 != 0) {
- /* y == -Infinity */
- goto lt_false;
- }
-
- if (c1 == DUK_FP_INFINITE && s1 != 0) {
- /* x == -Infinity */
- goto lt_true;
- }
-
- if (d1 < d2) {
- goto lt_true;
+ if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) {
+ rc = duk_js_string_compare(h1, h2);
+ duk_pop_2_unsafe(thr);
+ if (rc < 0) {
+ return retval ^ 1;
+ } else {
+ return retval;
+ }
}
- goto lt_false;
+ /* One or both are Symbols: fall through to handle in the
+ * generic path. Concretely, ToNumber() will fail.
+ */
}
- lt_undefined:
- /* Note: undefined from Section 11.8.5 always results in false
- * return (see e.g. Section 11.8.3) - hence special treatment here.
- */
- retval = 0;
- goto cleanup;
-
- lt_true:
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval = 0;
- goto cleanup;
+ /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */
+#if 0
+ if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
} else {
- retval = 1;
- goto cleanup;
+ d2 = duk_to_number_m1(thr);
+ d1 = duk_to_number_m2(thr);
}
- /* never here */
+#endif
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
- lt_false:
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval = 1;
- goto cleanup;
- } else {
- retval = 0;
- goto cleanup;
- }
- /* never here */
+ /* We want to duk_pop_2_unsafe(thr); because the values are numbers
+ * no decref check is needed.
+ */
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_pop_2_nodecref_unsafe(thr);
+#else
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2)));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1)));
+ DUK_ASSERT(duk_get_top(thr) >= 2);
+ thr->valstack_top -= 2;
+ tv_x = thr->valstack_top;
+ tv_y = tv_x + 1;
+ DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */
+ DUK_TVAL_SET_UNDEFINED(tv_y);
+#endif
- cleanup:
- duk_pop_2(ctx);
- return retval;
+ return duk__compare_number(retval, d1, d2);
}
/*
@@ -70954,10 +78119,11 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
*/
DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *func;
duk_hobject *val;
duk_hobject *proto;
+ duk_tval *tv;
+ duk_bool_t skip_first;
duk_uint_t sanity;
/*
@@ -70970,52 +78136,41 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* Using duk_require_hobject() is thus correct (except for error msg).
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- func = duk_require_hobject(ctx, -1);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ func = duk_require_hobject(thr, -1);
+ DUK_ASSERT(func != NULL);
/*
* For bound objects, [[HasInstance]] just calls the target function
* [[HasInstance]]. If that is again a bound object, repeat until
* we find a non-bound Function object.
+ *
+ * The bound function chain is now "collapsed" so there can be only
+ * one bound function in the chain.
*/
- /* XXX: this bound function resolution also happens elsewhere,
- * move into a shared helper.
- */
-
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- /* check func supports [[HasInstance]] (this is checked for every function
- * in the bound chain, including the final one)
+ if (!DUK_HOBJECT_IS_CALLABLE(func)) {
+ /*
+ * Note: of native Ecmascript objects, only Function instances
+ * have a [[HasInstance]] internal property. Custom objects might
+ * also have it, but not in current implementation.
+ *
+ * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
*/
+ goto error_invalid_rval;
+ }
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- /*
- * Note: of native Ecmascript objects, only Function instances
- * have a [[HasInstance]] internal property. Custom objects might
- * also have it, but not in current implementation.
- *
- * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
- */
- DUK_ERROR_TYPE(thr, "invalid instanceof rval");
- }
-
- if (!DUK_HOBJECT_HAS_BOUND(func)) {
- break;
- }
-
- /* [ ... lval rval ] */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
- duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
- func = duk_require_hobject(ctx, -1);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
+ duk_push_tval(thr, &((duk_hboundfunc *) func)->target);
+ duk_replace(thr, -2);
+ func = duk_require_hobject(thr, -1); /* lightfunc throws */
- /* func support for [[HasInstance]] checked in the beginning of the loop */
- } while (--sanity > 0);
-
- if (sanity == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
+ /* Rely on Function.prototype.bind() never creating bound
+ * functions whose target is not proper.
+ */
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
}
/*
@@ -71024,27 +78179,51 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* to execute E5 Section 15.3.5.3.
*/
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
/* [ ... lval rval(func) ] */
- /* Handle lightfuncs through object coercion for now. */
- /* XXX: direct implementation */
- val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
- if (!val) {
- goto pop_and_false;
+ /* For lightfuncs, buffers, and pointers start the comparison directly
+ * from the virtual prototype object.
+ */
+ skip_first = 0;
+ tv = DUK_GET_TVAL_NEGIDX(thr, -2);
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_LIGHTFUNC:
+ val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ DUK_ASSERT(val != NULL);
+ break;
+ case DUK_TAG_BUFFER:
+ val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
+ DUK_ASSERT(val != NULL);
+ break;
+ case DUK_TAG_POINTER:
+ val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
+ DUK_ASSERT(val != NULL);
+ break;
+ case DUK_TAG_OBJECT:
+ skip_first = 1; /* Ignore object itself on first round. */
+ val = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(val != NULL);
+ break;
+ default:
+ goto pop2_and_false;
}
+ DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
- proto = duk_require_hobject(ctx, -1);
- duk_pop(ctx); /* -> [ ... lval rval ] */
-
- DUK_ASSERT(val != NULL);
-
-#if defined(DUK_USE_ES6_PROXY)
- val = duk_hobject_resolve_proxy_target(thr, val);
- DUK_ASSERT(val != NULL);
+ /* Look up .prototype of rval. Leave it on the value stack in case it
+ * has been virtualized (e.g. getter, Proxy trap).
+ */
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ proto = duk_get_hobject(thr, -1);
+ if (proto == NULL) {
+ goto error_invalid_rval_noproto;
+ }
+#else
+ proto = duk_require_hobject(thr, -1);
#endif
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
@@ -71067,37 +78246,51 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* also the built-in Function prototype, the result is true.
*/
- DUK_ASSERT(val != NULL);
- val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
-
if (!val) {
- goto pop_and_false;
+ goto pop3_and_false;
}
DUK_ASSERT(val != NULL);
#if defined(DUK_USE_ES6_PROXY)
- val = duk_hobject_resolve_proxy_target(thr, val);
+ val = duk_hobject_resolve_proxy_target(val);
#endif
- if (val == proto) {
- goto pop_and_true;
+ if (skip_first) {
+ skip_first = 0;
+ } else if (val == proto) {
+ goto pop3_and_true;
}
- /* follow prototype chain */
+ DUK_ASSERT(val != NULL);
+ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
} while (--sanity > 0);
- if (sanity == 0) {
+ if (DUK_UNLIKELY(sanity == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
}
DUK_UNREACHABLE();
- pop_and_false:
- duk_pop_2(ctx);
+ pop2_and_false:
+ duk_pop_2_unsafe(thr);
+ return 0;
+
+ pop3_and_false:
+ duk_pop_3_unsafe(thr);
return 0;
- pop_and_true:
- duk_pop_2(ctx);
+ pop3_and_true:
+ duk_pop_3_unsafe(thr);
return 1;
+
+ error_invalid_rval:
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL);
+ return 0;
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ error_invalid_rval_noproto:
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO);
+ return 0;
+#endif
}
/*
@@ -71111,7 +78304,6 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
*/
DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
duk_bool_t retval;
/*
@@ -71123,24 +78315,25 @@ DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv
/* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
* must be string coerced before the internal HasProperty() algorithm is
* invoked. A fast path skipping coercion could be safely implemented for
- * numbers (as number-to-string coercion has no side effects). For ES6
+ * numbers (as number-to-string coercion has no side effects). For ES2015
* proxy behavior, the trap 'key' argument must be in a string coerced
* form (which is a shame).
*/
- /* TypeError if rval is not an object (or lightfunc which should behave
- * like a Function instance).
+ /* TypeError if rval is not an object or object like (e.g. lightfunc
+ * or plain buffer).
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
- duk_to_string(ctx, -2); /* coerce lval with ToString() */
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+
+ (void) duk_to_property_key_hstring(thr, -2);
retval = duk_hobject_hasprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- DUK_GET_TVAL_NEGIDX(ctx, -2));
+ DUK_GET_TVAL_NEGIDX(thr, -1),
+ DUK_GET_TVAL_NEGIDX(thr, -2));
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return retval;
}
@@ -71158,10 +78351,8 @@ DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv
* lowercase variants now.
*/
-DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
- duk_small_int_t stridx = 0;
-
- DUK_UNREF(thr);
+DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) {
+ duk_small_uint_t stridx = 0;
switch (DUK_TVAL_GET_TAG(tv_x)) {
case DUK_TAG_UNDEFINED: {
@@ -71169,7 +78360,7 @@ DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
break;
}
case DUK_TAG_NULL: {
- /* Note: not a typo, "object" is returned for a null value */
+ /* Note: not a typo, "object" is returned for a null value. */
stridx = DUK_STRIDX_LC_OBJECT;
break;
}
@@ -71178,12 +78369,21 @@ DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
break;
}
case DUK_TAG_POINTER: {
- /* implementation specific */
+ /* Implementation specific. */
stridx = DUK_STRIDX_LC_POINTER;
break;
}
case DUK_TAG_STRING: {
- stridx = DUK_STRIDX_LC_STRING;
+ duk_hstring *str;
+
+ /* All internal keys are identified as Symbols. */
+ str = DUK_TVAL_GET_STRING(tv_x);
+ DUK_ASSERT(str != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) {
+ stridx = DUK_STRIDX_LC_SYMBOL;
+ } else {
+ stridx = DUK_STRIDX_LC_STRING;
+ }
break;
}
case DUK_TAG_OBJECT: {
@@ -71197,8 +78397,11 @@ DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
break;
}
case DUK_TAG_BUFFER: {
- /* implementation specific */
- stridx = DUK_STRIDX_LC_BUFFER;
+ /* Implementation specific. In Duktape 1.x this would be
+ * 'buffer', in Duktape 2.x changed to 'object' because plain
+ * buffers now mimic Uint8Array objects.
+ */
+ stridx = DUK_STRIDX_LC_OBJECT;
break;
}
case DUK_TAG_LIGHTFUNC: {
@@ -71217,8 +78420,8 @@ DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
}
}
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- return DUK_HTHREAD_GET_STRING(thr, stridx);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ return stridx;
}
/*
@@ -71226,66 +78429,112 @@ DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
*
* Array index: E5 Section 15.4
* Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
- *
- * The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
- * call duk_js_to_arrayindex_string_helper().
*/
-DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) {
- duk_uarridx_t res, new_res;
-
- if (blen == 0 || blen > 10) {
- goto parse_fail;
- }
- if (str[0] == (duk_uint8_t) '0' && blen > 1) {
- goto parse_fail;
- }
+/* Compure array index from string context, or return a "not array index"
+ * indicator.
+ */
+DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) {
+ duk_uarridx_t res;
- /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
- * Leading zeroes are not accepted (zero index "0" is an exception
- * handled above).
+ /* Only strings with byte length 1-10 can be 32-bit array indices.
+ * Leading zeroes (except '0' alone), plus/minus signs are not allowed.
+ * We could do a lot of prechecks here, but since most strings won't
+ * start with any digits, it's simpler to just parse the number and
+ * fail quickly.
*/
res = 0;
- while (blen-- > 0) {
- duk_uint8_t c = *str++;
- if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
- new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');
- if (new_res < res) {
- /* overflow, more than 32 bits -> not an array index */
- goto parse_fail;
+ if (blen == 0) {
+ goto parse_fail;
+ }
+ do {
+ duk_uarridx_t dig;
+ dig = (duk_uarridx_t) (*str++) - DUK_ASC_0;
+
+ if (dig <= 9U) {
+ /* Careful overflow handling. When multiplying by 10:
+ * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding
+ * 0...9 is safe.
+ * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding
+ * 0...5 is safe, 6...9 overflows.
+ * - 0x1999999a x 10 = 0x100000004: always overflow.
+ */
+ if (DUK_UNLIKELY(res >= 0x19999999UL)) {
+ if (res >= 0x1999999aUL) {
+ /* Always overflow. */
+ goto parse_fail;
+ }
+ DUK_ASSERT(res == 0x19999999UL);
+ if (dig >= 6U) {
+ goto parse_fail;
+ }
+ res = 0xfffffffaUL + dig;
+ DUK_ASSERT(res >= 0xfffffffaUL);
+ DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */
+ } else {
+ res = res * 10U + dig;
+ if (DUK_UNLIKELY(res == 0)) {
+ /* If 'res' is 0, previous 'res' must
+ * have been 0 and we scanned in a zero.
+ * This is only allowed if blen == 1,
+ * i.e. the exact string '0'.
+ */
+ if (blen == (duk_uint32_t) 1) {
+ return 0;
+ }
+ goto parse_fail;
+ }
}
- res = new_res;
} else {
+ /* Because 'dig' is unsigned, catches both values
+ * above '9' and below '0'.
+ */
goto parse_fail;
}
- }
+ } while (--blen > 0);
- *out_idx = res;
- return 1;
+ return res;
parse_fail:
- *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
- return 0;
+ return DUK_HSTRING_NO_ARRAY_INDEX;
}
-/* Called by duk_hstring.h macros */
-DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
+#if !defined(DUK_USE_HSTRING_ARRIDX)
+/* Get array index for a string which is known to be an array index. This helper
+ * is needed when duk_hstring doesn't concretely store the array index, but strings
+ * are flagged as array indices at intern time.
+ */
+DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) {
+ const duk_uint8_t *p;
duk_uarridx_t res;
- duk_small_int_t rc;
+ duk_uint8_t t;
+
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h));
+
+ p = DUK_HSTRING_GET_DATA(h);
+ res = 0;
+ for (;;) {
+ t = *p++;
+ if (DUK_UNLIKELY(t == 0)) {
+ /* Scanning to NUL is always safe for interned strings. */
+ break;
+ }
+ DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9);
+ res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0;
+ }
+ return res;
+}
+DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) {
+ DUK_ASSERT(h != NULL);
if (!DUK_HSTRING_HAS_ARRIDX(h)) {
return DUK_HSTRING_NO_ARRAY_INDEX;
}
-
- rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
- DUK_HSTRING_GET_BYTELEN(h),
- &res);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- return res;
+ return duk_js_to_arrayindex_hstring_fast_known(h);
}
-#line 1 "duk_js_var.c"
+#endif /* DUK_USE_HSTRING_ARRIDX */
/*
* Identifier access and function closure handling.
*
@@ -71318,18 +78567,18 @@ DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
* if "raw" own property helpers are added.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Local result type for duk__get_identifier_reference() lookup.
*/
typedef struct {
+ duk_hobject *env;
duk_hobject *holder; /* for object-bound identifiers */
duk_tval *value; /* for register-bound and declarative env identifiers */
- duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
- duk_tval *this_binding;
- duk_hobject *env;
+ duk_uint_t attrs; /* property attributes for identifier (relevant if value != NULL) */
+ duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */
} duk__id_lookup_result;
/*
@@ -71358,27 +78607,28 @@ typedef struct {
* even if the closure object remains reachable.
*/
-DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f) {
+DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) {
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
+ DUK_UNREF(thr);
+
/* If function creation fails due to out-of-memory, the data buffer
* pointer may be NULL in some cases. That's actually possible for
* GC code, but shouldn't be possible here because the incomplete
* function will be unwound from the value stack and never instantiated.
*/
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL);
- DUK_UNREF(thr);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL);
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f);
+ tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f);
while (tv < tv_end) {
DUK_TVAL_INCREF(thr, tv);
tv++;
}
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
+ funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f);
+ funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f);
while (funcs < funcs_end) {
DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
funcs++;
@@ -71396,51 +78646,56 @@ DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
/* order: most frequent to least frequent */
DUK_STRIDX_INT_VARMAP,
DUK_STRIDX_INT_FORMALS,
- DUK_STRIDX_NAME,
+#if defined(DUK_USE_PC2LINE)
DUK_STRIDX_INT_PC2LINE,
+#endif
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
DUK_STRIDX_FILE_NAME,
+#endif
+#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
DUK_STRIDX_INT_SOURCE
+#endif
};
DUK_INTERNAL
void duk_js_push_closure(duk_hthread *thr,
- duk_hcompiledfunction *fun_temp,
+ duk_hcompfunc *fun_temp,
duk_hobject *outer_var_env,
duk_hobject *outer_lex_env,
duk_bool_t add_auto_proto) {
- duk_context *ctx = (duk_context *) thr;
- duk_hcompiledfunction *fun_clos;
+ duk_hcompfunc *fun_clos;
duk_small_uint_t i;
duk_uint_t len_value;
DUK_ASSERT(fun_temp != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL);
DUK_ASSERT(outer_var_env != NULL);
DUK_ASSERT(outer_lex_env != NULL);
DUK_UNREF(len_value);
- duk_push_compiledfunction(ctx);
- duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
-
- fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
+ fun_clos = duk_push_hcompfunc(thr);
DUK_ASSERT(fun_clos != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun_clos));
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) == NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+
+ duk_push_hobject(thr, &fun_temp->obj); /* -> [ ... closure template ] */
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp));
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp));
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp));
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos));
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL);
+
+ DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp));
+ DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp));
+ DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp));
/* Note: all references inside 'data' need to get their refcounts
* upped too. This is the case because refcounts are decreased
* through every function referencing 'data' independently.
*/
- DUK_HBUFFER_INCREF(thr, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos));
+ DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos));
duk__inc_data_inner_refcounts(thr, fun_temp);
fun_clos->nregs = fun_temp->nregs;
@@ -71450,51 +78705,50 @@ void duk_js_push_closure(duk_hthread *thr,
fun_clos->end_line = fun_temp->end_line;
#endif
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL);
- /* XXX: could also copy from template, but there's no way to have any
+ /* XXX: Could also copy from template, but there's no way to have any
* other value here now (used code has no access to the template).
+ * Prototype is set by duk_push_hcompfunc().
*/
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#endif
- /*
- * Init/assert flags, copying them where appropriate. Some flags
- * (like NEWENV) are processed separately below.
+ /* Copy duk_hobject flags as is from the template using a mask.
+ * Leave out duk_heaphdr owned flags just in case (e.g. if there's
+ * some GC flag or similar). Some flags can then be adjusted
+ * separately if necessary.
*/
- /* XXX: copy flags using a mask */
+ /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */
+ DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp));
+ DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx",
+ (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp),
+ (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos)));
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
- DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
- DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj));
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj));
/* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
- if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
- DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
- }
- if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
- DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
- }
/* DUK_HOBJECT_FLAG_NEWENV: handled below */
- if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
- /* Although NAMEBINDING is not directly needed for using
- * function instances, it's needed by bytecode dump/load
- * so copy it too.
- */
- DUK_HOBJECT_SET_NAMEBINDING(&fun_clos->obj);
- }
- if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
- DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
- }
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
+ if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) {
+ /* If the template is not constructable don't add an automatic
+ * .prototype property. This is the case for e.g. ES2015 object
+ * literal getters/setters and method definitions.
+ */
+ add_auto_proto = 0;
+ }
+
/*
* Setup environment record properties based on the template and
* its flags.
@@ -71511,11 +78765,11 @@ void duk_js_push_closure(duk_hthread *thr,
* This is relatively complex, see doc/identifier-handling.rst.
*/
- if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
- DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
-
- if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
+ if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) {
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) {
duk_hobject *proto;
+ duk_hdecenv *new_env;
/*
* Named function expression, name needs to be bound
@@ -71526,8 +78780,6 @@ void duk_js_push_closure(duk_hthread *thr,
* b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
*/
- DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
-
if (outer_lex_env) {
proto = outer_lex_env;
} else {
@@ -71535,40 +78787,57 @@ void duk_js_push_closure(duk_hthread *thr,
}
/* -> [ ... closure template env ] */
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- proto);
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
+ DUK_ASSERT(new_env != NULL);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
+
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto);
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto);
+
+ DUK_ASSERT(new_env->thread == NULL); /* Closed. */
+ DUK_ASSERT(new_env->varmap == NULL);
/* It's important that duk_xdef_prop() is a 'raw define' so that any
* properties in an ancestor are never an issue (they should never be
* e.g. non-writable, but just in case).
+ *
+ * Because template objects are not visible to user code, the case
+ * where .name is missing shouldn't happen in practice. It it does,
+ * the name 'undefined' gets bound and maps to the closure (which is
+ * a bit odd, but safe).
*/
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
- duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
+ (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
+ /* -> [ ... closure template env funcname ] */
+ duk_dup_m4(thr); /* -> [ ... closure template env funcname closure ] */
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
/* env[funcname] = closure */
/* [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
+ DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env);
+ DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env);
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
+ duk_pop_unsafe(thr);
/* [ ... closure template ] */
- } else {
+ }
+ else
+#endif /* DUK_USE_FUNC_NAME_PROPERTY */
+ {
/*
* Other cases (function declaration, anonymous function expression,
* strict direct eval code). The "outer" environment will be whatever
* the caller gave us.
*/
- duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
+ DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
+ DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env);
+ DUK_HOBJECT_INCREF(thr, outer_lex_env);
+ DUK_HOBJECT_INCREF(thr, outer_lex_env);
/* [ ... closure template ] */
}
@@ -71583,73 +78852,68 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
- duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
-
- if (outer_var_env != outer_lex_env) {
- duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_WC);
- }
+ DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
+ DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env);
+ DUK_HOBJECT_INCREF(thr, outer_lex_env); /* NULLs not allowed; asserted on entry */
+ DUK_HOBJECT_INCREF(thr, outer_var_env);
}
-#ifdef DUK_USE_DDDPRINT
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARENV);
- duk_get_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV);
- DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
-#endif
+ DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO",
+ (duk_heaphdr *) fun_clos->var_env,
+ (duk_heaphdr *) fun_clos->lex_env));
+
+ /* Call handling assumes this for all callable closures. */
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL);
/*
* Copy some internal properties directly
*
- * The properties will be writable and configurable, but not enumerable.
+ * The properties will be non-writable and non-enumerable, but
+ * configurable.
*/
/* [ ... closure template ] */
DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
- if (duk_get_prop_stridx(ctx, -1, stridx)) {
+ if (duk_get_prop_stridx_short(thr, -1, stridx)) {
/* [ ... closure template val ] */
DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
- duk_xdef_prop_stridx(ctx, -3, stridx, DUK_PROPDESC_FLAGS_WC);
+ duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C);
} else {
DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
}
/*
* "length" maps to number of formals (E5 Section 13.2) for function
* declarations/expressions (non-bound functions). Note that 'nargs'
- * is NOT necessarily equal to the number of arguments.
+ * is NOT necessarily equal to the number of arguments. Use length
+ * of _Formals; if missing, assume nargs matches .length.
*/
/* [ ... closure template ] */
- len_value = 0;
-
- /* XXX: use helper for size optimization */
- if (duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS)) {
+ /* XXX: these lookups should be just own property lookups instead of
+ * looking up the inheritance chain.
+ */
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS)) {
/* [ ... closure template formals ] */
- DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH));
- DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
- len_value = (duk_uint_t) duk_get_length(ctx, -1);
+ len_value = (duk_uint_t) duk_get_length(thr, -1); /* could access duk_harray directly, not important */
+ DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value));
} else {
- /* XXX: what to do if _Formals is not empty but compiler has
- * optimized it away -- read length from an explicit property
- * then?
- */
+ len_value = fun_temp->nargs;
+ DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
- duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_uint(thr, len_value); /* [ ... closure template len_value ] */
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
/*
* "prototype" is, by default, a fresh object with the "constructor"
@@ -71668,11 +78932,11 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
if (add_auto_proto) {
- duk_push_object(ctx); /* -> [ ... closure template newobj ] */
- duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
- duk_compact(ctx, -1); /* compact the prototype */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
+ duk_push_object(thr); /* -> [ ... closure template newobj ] */
+ duk_dup_m3(thr); /* -> [ ... closure template newobj closure ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
+ duk_compact(thr, -1); /* compact the prototype */
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
}
/*
@@ -71686,40 +78950,43 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS);
} else {
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
- duk_push_null(ctx);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_null(thr);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
#else
DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
#endif
}
/*
- * "name" is a non-standard property found in at least V8, Rhino, smjs.
- * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
- * for V8 it is writable, non-enumerable, non-configurable. It is also defined
- * for an anonymous function expression in which case the value is an empty string.
- * We could also leave name 'undefined' for anonymous functions but that would
- * differ from behavior of other engines, so use an empty string.
- *
- * XXX: make optional? costs something per function.
+ * "name" used to be non-standard but is now defined by ES2015.
+ * In ES2015/ES2016 the .name property is configurable.
*/
/* [ ... closure template ] */
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ /* XXX: Look for own property only; doesn't matter much because
+ * templates are bare objects.
+ */
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) {
/* [ ... closure template name ] */
- DUK_ASSERT(duk_is_string(ctx, -1));
+ DUK_ASSERT(duk_is_string(thr, -1));
+ DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(thr, -1)));
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */
} else {
- /* [ ... closure template undefined ] */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ /* Anonymous functions don't have a .name in ES2015, so don't set
+ * it on the instance either. The instance will then inherit
+ * it from Function.prototype.name.
+ */
+ DUK_DD(DUK_DDPRINT("not setting function instance .name"));
+ duk_pop_unsafe(thr);
}
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
+#endif
/*
* Compact the closure, in most cases no properties will be added later.
@@ -71730,7 +78997,7 @@ void duk_js_push_closure(duk_hthread *thr,
* through the API).
*/
- duk_compact(ctx, -2);
+ duk_compact(thr, -2);
/*
* Some assertions (E5 Section 13.2).
@@ -71739,13 +79006,13 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
- DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
- DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
- DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
+ DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0);
+ DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0);
+ /* May be missing .name */
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
+ duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0);
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
+ duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
/*
* Finish
@@ -71754,10 +79021,10 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
- (duk_tval *) duk_get_tval(ctx, -1),
- (duk_tval *) duk_get_tval(ctx, -2)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (duk_tval *) duk_get_tval(thr, -2)));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
/* [ ... closure ] */
}
@@ -71773,56 +79040,70 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_INTERNAL
duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
duk_hobject *func,
- duk_size_t idx_bottom) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *env;
+ duk_size_t bottom_byteoff) {
+ duk_hdecenv *env;
duk_hobject *parent;
- duk_tval *tv;
+ duk_hcompfunc *f;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- parent = DUK_TVAL_GET_OBJECT(tv);
- } else {
+ f = (duk_hcompfunc *) func;
+ parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
+ if (!parent) {
parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- -1); /* no prototype, updated below */
- env = duk_require_hobject(ctx, -1);
+ env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(env != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
+ duk_push_hobject(thr, (duk_hobject *) env);
+
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent);
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */
/* open scope information, for compiled functions only */
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- duk_push_hthread(ctx, thr);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_THREAD);
- duk_push_hobject(ctx, func);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_CALLEE);
- duk_push_size_t(ctx, idx_bottom);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_REGBASE);
+ DUK_ASSERT(env->thread == NULL);
+ DUK_ASSERT(env->varmap == NULL);
+ DUK_ASSERT(env->regbase_byteoff == 0);
+ if (DUK_HOBJECT_IS_COMPFUNC(func)) {
+ duk_hobject *varmap;
+ duk_tval *tv;
+
+ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
+ if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
+ varmap = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(varmap != NULL);
+ env->varmap = varmap;
+ DUK_HOBJECT_INCREF(thr, varmap);
+ env->thread = thr;
+ DUK_HTHREAD_INCREF(thr, thr);
+ env->regbase_byteoff = bottom_byteoff;
+ } else {
+ /* If function has no _Varmap, leave the environment closed. */
+ DUK_ASSERT(env->thread == NULL);
+ DUK_ASSERT(env->varmap == NULL);
+ DUK_ASSERT(env->regbase_byteoff == 0);
+ }
}
- return env;
+ return (duk_hobject *) env;
}
DUK_INTERNAL
void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
duk_activation *act) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *func;
duk_hobject *env;
+ DUK_ASSERT(thr != NULL);
func = DUK_ACT_GET_FUNC(act);
DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */
/*
* Delayed initialization only occurs for 'NEWENV' functions.
@@ -71832,11 +79113,12 @@ void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
DUK_ASSERT(act->lex_env == NULL);
DUK_ASSERT(act->var_env == NULL);
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
DUK_ASSERT(env != NULL);
+ /* 'act' is a stable pointer, so still OK. */
DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
{
duk_hobject *p = env;
while (p) {
@@ -71851,163 +79133,109 @@ void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
DUK_HOBJECT_INCREF(thr, env);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/*
* Closing environment records.
*
* The environment record MUST be closed with the thread where its activation
- * is. In other words (if 'env' is open):
- *
- * - 'thr' must match _env.thread
- * - 'func' must match _env.callee
- * - 'regbase' must match _env.regbase
- *
- * These are not looked up from the env to minimize code size.
- *
- * XXX: should access the own properties directly instead of using the API
+ * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase
+ * and varmap must still be valid. On entry, 'env' must be reachable.
*/
-DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) {
duk_uint_fast32_t i;
+ duk_hobject *varmap;
+ duk_hstring *key;
+ duk_tval *tv;
+ duk_uint_t regnum;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(env != NULL);
- /* func is NULL for lightfuncs */
- if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
- DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
- "or already closed: %!iO",
- (duk_heaphdr *) env));
+ if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) {
+ DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env));
return;
}
- DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
- (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
-
- duk_push_hobject(ctx, env);
-
- /* assertions: env must be closed in the same thread as where it runs */
-#ifdef DUK_USE_ASSERTIONS
- {
- /* [... env] */
+ varmap = ((duk_hdecenv *) env)->varmap;
+ if (varmap == NULL) {
+ DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env));
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
- DUK_ASSERT(duk_is_object(ctx, -1));
- DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD)) {
- DUK_ASSERT(duk_is_object(ctx, -1));
- DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
- }
- duk_pop(ctx);
-
- /* [... env] */
+ return;
}
-#endif
-
- if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- duk_hobject *varmap;
- duk_hstring *key;
- duk_tval *tv;
- duk_uint_t regnum;
-
- /* XXX: additional conditions when to close variables? we don't want to do it
- * unless the environment may have "escaped" (referenced in a function closure).
- * With delayed environments, the existence is probably good enough of a check.
- */
+ DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL);
+ DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
- /* XXX: any way to detect faster whether something needs to be closed?
- * We now look up _Callee and then skip the rest.
- */
+ DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env));
+ DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
- /* Note: we rely on the _Varmap having a bunch of nice properties, like:
- * - being compacted and unmodified during this process
- * - not containing an array part
- * - having correct value types
- */
-
- /* [... env] */
-
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
- DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
- duk_pop(ctx);
- goto skip_varmap;
- }
-
- /* [... env callee] */
-
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
- DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
- duk_pop_2(ctx);
- goto skip_varmap;
- }
- varmap = duk_require_hobject(ctx, -1);
- DUK_ASSERT(varmap != NULL);
+ /* Env must be closed in the same thread as where it runs. */
+ DUK_ASSERT(((duk_hdecenv *) env)->thread == thr);
- DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
-
- /* [... env callee varmap] */
-
- DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
+ /* XXX: additional conditions when to close variables? we don't want to do it
+ * unless the environment may have "escaped" (referenced in a function closure).
+ * With delayed environments, the existence is probably good enough of a check.
+ */
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
- DUK_ASSERT(key != NULL); /* assume keys are compacted */
+ /* Note: we rely on the _Varmap having a bunch of nice properties, like:
+ * - being compacted and unmodified during this process
+ * - not containing an array part
+ * - having correct value types
+ */
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
+ DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
- regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
- DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
- DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
- DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
- DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
+ /* Copy over current variable values from value stack to the
+ * environment record. The scope object is empty but may
+ * inherit from another scope which has conflicting names.
+ */
- /* XXX: slightly awkward */
- duk_push_hstring(ctx, key);
- duk_push_tval(ctx, thr->valstack + regbase + regnum);
- DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
- (const char *) duk_require_string(ctx, -2),
- (long) regnum,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ /* XXX: Do this using a once allocated entry area, no side effects.
+ * Hash part would need special treatment however (maybe copy, and
+ * then realloc with hash part if large enough).
+ */
+ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
+ duk_size_t regbase_byteoff;
- /* [... env callee varmap key val] */
+ key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
+ DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */
+ DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
- /* if property already exists, overwrites silently */
- duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
- }
+ tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
+ regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv);
+#else
+ regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
+#endif
- duk_pop_2(ctx);
+ regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff;
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top);
- /* [... env] */
+ /* If property already exists, overwrites silently.
+ * Property is writable, but not deletable (not configurable
+ * in terms of property attributes).
+ */
+ duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum));
+ DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T",
+ (duk_heaphdr *) key,
+ (long) regnum,
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE);
}
- skip_varmap:
-
- /* [... env] */
-
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE);
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD);
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE);
-
- duk_pop(ctx);
+ /* NULL atomically to avoid inconsistent state + side effects. */
+ DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread);
+ DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap);
+ ((duk_hdecenv *) env)->thread = NULL;
+ ((duk_hdecenv *) env)->varmap = NULL;
- DUK_HOBJECT_SET_ENVRECCLOSED(env);
-
- DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
- (duk_heaphdr *) env));
+ DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env));
}
/*
@@ -72037,84 +79265,48 @@ DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject
DUK_LOCAL
duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
duk_hstring *name,
- duk_hobject *env,
+ duk_hdecenv *env,
duk__id_lookup_result *out) {
- duk_hthread *env_thr;
- duk_hobject *env_func;
- duk_size_t env_regbase;
- duk_hobject *varmap;
duk_tval *tv;
duk_size_t reg_rel;
- duk_size_t idx;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(name != NULL);
DUK_ASSERT(env != NULL);
DUK_ASSERT(out != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
+ DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env));
+ DUK_ASSERT_HDECENV_VALID(env);
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
- if (!tv) {
- /* env is closed, should be missing _Callee, _Thread, _Regbase */
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
+ if (env->thread == NULL) {
+ /* already closed */
return 0;
}
+ DUK_ASSERT(env->varmap != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(tv)));
- env_func = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(env_func != NULL);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
- if (!tv) {
+ tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name);
+ if (DUK_UNLIKELY(tv == NULL)) {
return 0;
}
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- varmap = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(varmap != NULL);
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
- if (!tv) {
- return 0;
- }
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
+ reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv);
+#else
reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
+#endif
DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
- DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
- env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(env_thr != NULL);
-
- /* Note: env_thr != thr is quite possible and normal, so careful
- * with what thread is used for valstack lookup.
- */
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
-
- idx = env_regbase + reg_rel;
- tv = env_thr->valstack + idx;
- DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel);
+ DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */
out->value = tv;
out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
- out->env = env;
+ out->env = (duk_hobject *) env;
out->holder = NULL;
-
+ out->has_this = 0;
return 1;
}
@@ -72128,7 +79320,6 @@ duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
duk_hobject *func;
duk_hobject *varmap;
duk_size_t reg_rel;
- duk_size_t idx;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(name != NULL);
@@ -72139,10 +79330,11 @@ duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
DUK_ASSERT(func != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+ if (!DUK_HOBJECT_IS_COMPFUNC(func)) {
return 0;
}
+ /* XXX: move varmap to duk_hcompfunc struct field. */
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
if (!tv) {
return 0;
@@ -72158,20 +79350,16 @@ duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
DUK_ASSERT_DISABLE(reg_rel >= 0);
- DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) func)->nregs);
+ DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs);
- idx = act->idx_bottom + reg_rel;
- DUK_ASSERT(idx >= act->idx_bottom);
- tv = thr->valstack + idx;
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ tv += reg_rel;
out->value = tv;
out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
out->env = NULL;
out->holder = NULL;
-
+ out->has_this = 0;
return 1;
}
@@ -72183,8 +79371,6 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
duk_bool_t parents,
duk__id_lookup_result *out) {
duk_tval *tv;
- duk_tval *tv_target;
- duk_tval tv_name;
duk_uint_t sanity;
DUK_ASSERT(thr != NULL);
@@ -72213,6 +79399,7 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
if (env == NULL && act != NULL) {
duk_hobject *func;
+ duk_hcompfunc *f;
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
"delayed env case, look up activation regs first"));
@@ -72223,10 +79410,10 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
if (duk__getid_activation_regs(thr, name, act, out)) {
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
+ "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
"(found from register bindings when env=NULL)",
(duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
+ (long) out->attrs, (long) out->has_this,
(duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
return 1;
}
@@ -72257,13 +79444,10 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
func = DUK_ACT_GET_FUNC(act);
DUK_ASSERT(func != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
+ f = (duk_hcompfunc *) func;
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- env = DUK_TVAL_GET_OBJECT(tv);
- } else {
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr)) == NULL);
+ env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
+ if (!env) {
env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
@@ -72279,8 +79463,8 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
while (env != NULL) {
- duk_small_int_t cl;
- duk_int_t attrs;
+ duk_small_uint_t cl;
+ duk_uint_t attrs;
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
(duk_heaphdr *) name,
@@ -72306,37 +79490,30 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
* register-bound variables.
*/
- if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
- /* already closed */
- goto skip_regs;
- }
-
- if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
+ DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
+ if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) {
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
+ "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
"(declarative environment record, scope open, found in regs)",
(duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
+ (long) out->attrs, (long) out->has_this,
(duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
return 1;
}
- skip_regs:
tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
if (tv) {
out->value = tv;
out->attrs = attrs;
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
out->env = env;
out->holder = env;
+ out->has_this = 0;
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
+ "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
"(declarative environment record, found in properties)",
(duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
+ (long) out->attrs, (long) out->has_this,
(duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
return 1;
}
@@ -72359,11 +79536,9 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
duk_bool_t found;
DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
+ DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env);
- tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
- DUK_ASSERT(tv_target != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
- target = DUK_TVAL_GET_OBJECT(tv_target);
+ target = ((duk_hobjenv *) env)->target;
DUK_ASSERT(target != NULL);
/* Target may be a Proxy or property may be an accessor, so we must
@@ -72373,12 +79548,19 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
* property is found, but rather the object binding target object.
*/
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) {
+ duk_tval tv_name;
+ duk_tval tv_target_tmp;
+
DUK_ASSERT(name != NULL);
DUK_TVAL_SET_STRING(&tv_name, name);
+ DUK_TVAL_SET_OBJECT(&tv_target_tmp, target);
- found = duk_hobject_hasprop(thr, tv_target, &tv_name);
- } else {
+ found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name);
+ } else
+#endif /* DUK_USE_ES6_PROXY */
+ {
/* XXX: duk_hobject_hasprop() would be correct for
* non-Proxy objects too, but it is about ~20-25%
* slower at present so separate code paths for
@@ -72390,16 +79572,15 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
if (found) {
out->value = NULL; /* can't get value, may be accessor */
out->attrs = 0; /* irrelevant when out->value == NULL */
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr));
- out->this_binding = tv; /* may be NULL */
out->env = env;
out->holder = target;
+ out->has_this = ((duk_hobjenv *) env)->has_this;
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
+ "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
"(object environment record)",
(duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
+ (long) out->attrs, (long) out->has_this,
(duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
return 1;
}
@@ -72411,11 +79592,11 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
goto fail_not_found;
}
- if (sanity-- == 0) {
+ if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
}
env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
- };
+ }
/*
* Not found (even in global object)
@@ -72501,7 +79682,6 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr,
duk_activation *act,
duk_hstring *name,
duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk__id_lookup_result ref;
duk_tval tv_tmp_obj;
duk_tval tv_tmp_key;
@@ -72516,35 +79696,35 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr,
DUK_ASSERT(name != NULL);
/* env and act may be NULL */
+ DUK_STATS_INC(thr->heap, stats_getvar_all);
+
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
parents = 1; /* follow parent chain */
if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
if (ref.value) {
- DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
- duk_push_tval(ctx, ref.value);
- duk_push_undefined(ctx);
+ duk_push_tval(thr, ref.value);
+ duk_push_undefined(thr);
} else {
DUK_ASSERT(ref.holder != NULL);
- /* Note: getprop may invoke any getter and invalidate any
- * duk_tval pointers, so this must be done first.
+ /* ref.holder is safe across the getprop call (even
+ * with side effects) because 'env' is reachable and
+ * ref.holder is a direct heap pointer.
*/
- if (ref.this_binding) {
- duk_push_tval(ctx, ref.this_binding);
- } else {
- duk_push_undefined(ctx);
- }
-
DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
DUK_TVAL_SET_STRING(&tv_tmp_key, name);
- (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
+ (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */
- /* ref.value, ref.this.binding invalidated here by getprop call */
+ if (ref.has_this) {
+ duk_push_hobject(thr, ref.holder);
+ } else {
+ duk_push_undefined(thr);
+ }
- duk_insert(ctx, -2); /* [this value] -> [value this] */
+ /* [value this] */
}
return 1;
@@ -72603,6 +79783,8 @@ void duk__putvar_helper(duk_hthread *thr,
duk_tval tv_tmp_key;
duk_bool_t parents;
+ DUK_STATS_INC(thr->heap, stats_putvar_all);
+
DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
"(env -> %!dO, val -> %!T)",
(void *) thr, (void *) env, (void *) act,
@@ -72647,13 +79829,11 @@ void duk__putvar_helper(duk_hthread *thr,
*/
duk_tval *tv_val;
- DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
-
tv_val = ref.value;
DUK_ASSERT(tv_val != NULL);
DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
- /* ref.value and ref.this_binding invalidated here */
+ /* ref.value invalidated here */
} else {
DUK_ASSERT(ref.holder != NULL);
@@ -72661,7 +79841,7 @@ void duk__putvar_helper(duk_hthread *thr,
DUK_TVAL_SET_STRING(&tv_tmp_key, name);
(void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
- /* ref.value and ref.this_binding invalidated here */
+ /* ref.value invalidated here */
}
return;
@@ -72674,7 +79854,9 @@ void duk__putvar_helper(duk_hthread *thr,
if (strict) {
DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
- DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
+ DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
+ "identifier '%s' undefined",
+ (const char *) DUK_HSTRING_GET_DATA(name));
}
DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
@@ -72845,9 +80027,8 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
duk_hobject *env,
duk_hstring *name,
duk_tval *val,
- duk_small_int_t prop_flags,
+ duk_small_uint_t prop_flags,
duk_bool_t is_func_decl) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *holder;
duk_bool_t parents;
duk__id_lookup_result ref;
@@ -72888,7 +80069,7 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
duk_int_t e_idx;
duk_int_t h_idx;
- duk_small_int_t flags;
+ duk_small_uint_t flags;
/*
* Variable already declared, ignore re-declaration.
@@ -72935,8 +80116,8 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
/* must be found: was found earlier, and cannot be inherited */
for (;;) {
DUK_ASSERT(holder != NULL);
- duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
- if (e_idx >= 0) {
+ if (duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
break;
}
/* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
@@ -73015,7 +80196,7 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
- duk_push_tval(ctx, val);
+ duk_push_tval(thr, val);
duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
}
@@ -73032,14 +80213,11 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
*/
if (DUK_HOBJECT_IS_DECENV(env)) {
+ DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
holder = env;
} else {
- DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- holder = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env);
+ holder = ((duk_hobjenv *) env)->target;
DUK_ASSERT(holder != NULL);
}
@@ -73058,11 +80236,11 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
goto fail_not_extensible;
}
- duk_push_hobject(ctx, holder);
- duk_push_hstring(ctx, name);
- duk_push_tval(ctx, val);
- duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
- duk_pop(ctx);
+ duk_push_hobject(thr, holder);
+ duk_push_hstring(thr, name);
+ duk_push_tval(thr, val);
+ duk_xdef_prop(thr, -3, prop_flags); /* [holder name val] -> [holder] */
+ duk_pop_unsafe(thr);
return 0;
@@ -73077,11 +80255,13 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
duk_activation *act,
duk_hstring *name,
duk_tval *val,
- duk_small_int_t prop_flags,
+ duk_small_uint_t prop_flags,
duk_bool_t is_func_decl) {
duk_hobject *env;
duk_tval tv_val_copy;
+ DUK_ASSERT(act != NULL);
+
/*
* Make a value copy of the input val. This ensures that
* side effects cannot invalidate the pointer.
@@ -73097,6 +80277,7 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
if (!act->var_env) {
DUK_ASSERT(act->lex_env == NULL);
duk_js_init_activation_environment_records_delayed(thr, act);
+ /* 'act' is a stable pointer, so still OK. */
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
@@ -73107,7 +80288,6 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
}
-#line 1 "duk_lexer.c"
/*
* Lexer for source files, ToNumber() string conversions, RegExp expressions,
* and JSON.
@@ -73180,7 +80360,7 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
* least potentially) slow.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Various defines and file specific helper macros
@@ -73197,11 +80377,12 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
/* lexer character window helpers */
-#define DUK__LOOKUP(lex_ctx,index) ((lex_ctx)->window[(index)].codepoint)
-#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_bytes((lex_ctx), (count) * sizeof(duk_lexer_codepoint))
-#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
-#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
-#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
+#define DUK__LOOKUP(lex_ctx,idx) ((lex_ctx)->window[(idx)].codepoint)
+#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_chars((lex_ctx), (count))
+#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
+#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
+#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
+#define DUK__APPENDBUFFER_ASCII(lex_ctx,x) duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x))
/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
@@ -73421,7 +80602,7 @@ DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t s
lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
lex_ctx->input_line = input_line;
- DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
}
DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
@@ -73581,7 +80762,7 @@ DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
error_clipped: /* clipped codepoint */
error_encoding: /* invalid codepoint encoding or codepoint */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
return 0;
}
@@ -73614,6 +80795,10 @@ DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
}
#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
+DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) {
+ duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint));
+}
+
/*
* (Re)initialize the temporary byte buffer. May be called extra times
* with little impact.
@@ -73646,24 +80831,31 @@ DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
* escapes ("\udead\ubeef") so all 16-but unsigned values can be
* present, even when the source file itself is strict UTF-8.
*/
-
- DUK_ASSERT(x >= 0 && x <= 0x10ffff);
+ DUK_ASSERT(x >= 0 && x <= 0x10ffffL);
DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
}
+DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
+ /* ASCII characters can be emitted as a single byte without encoding
+ * which matters for some fast paths.
+ */
+ DUK_ASSERT(x >= 0 && x <= 0x7f);
+
+ DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x);
+}
+
/*
* Intern the temporary byte buffer into a valstack slot
* (in practice, slot1 or slot2).
*/
-DUK_LOCAL void duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
- duk_context *ctx = (duk_context *) lex_ctx->thr;
-
+DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
- duk_replace(ctx, valstack_idx);
+ duk_replace(lex_ctx->thr, valstack_idx);
+ return duk_known_hstring(lex_ctx->thr, valstack_idx);
}
/*
@@ -73688,7 +80880,10 @@ DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
* Set lexer input position and reinitialize lookup window.
*/
-/* NB: duk_lexer_getpoint() is a macro only */
+DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
+ pt->offset = lex_ctx->window[0].offset;
+ pt->line = lex_ctx->window[0].line;
+}
DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
@@ -73702,8 +80897,10 @@ DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt
* Lexing helpers
*/
-/* numeric value of a hex digit (also covers octal and decimal digits) */
-DUK_LOCAL duk_codepoint_t duk__hexval(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
+/* Numeric value of a hex digit (also covers octal and decimal digits) or
+ * -1 if not a valid hex digit.
+ */
+DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) {
duk_small_int_t t;
/* Here 'x' is a Unicode codepoint */
@@ -73714,11 +80911,21 @@ DUK_LOCAL duk_codepoint_t duk__hexval(duk_lexer_ctx *lex_ctx, duk_codepoint_t x)
}
}
- /* Throwing an error this deep makes the error rather vague, but
- * saves hundreds of bytes of code.
- */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "decode error");
- return 0;
+ return -1;
+}
+
+/* Just a wrapper for call sites where 'x' is known to be valid so
+ * we assert for it before decoding.
+ */
+DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) {
+ duk_codepoint_t ret;
+
+ DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
+ (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) ||
+ (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F));
+ ret = duk__hexval_validate(x);
+ DUK_ASSERT(ret >= 0 && ret <= 15);
+ return ret;
}
/* having this as a separate function provided a size benefit */
@@ -73729,18 +80936,314 @@ DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
return 0;
}
-DUK_LOCAL duk_codepoint_t duk__decode_hexesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
- /* validation performed by duk__hexval */
- return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 4) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint));
+/* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}. Shared by
+ * source and RegExp parsing.
+ */
+DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) {
+ duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */
+ duk_codepoint_t escval;
+ duk_codepoint_t x;
+ duk_small_uint_t adv;
+
+ DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */
+ DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U);
+ DUK_UNREF(allow_es6);
+
+ adv = 2;
+ digits = 2;
+ if (DUK__L1() == DUK_ASC_LC_U) {
+ digits = 4;
+#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
+ if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) {
+ digits = 0;
+ adv = 3;
+ }
+#endif
+ }
+ DUK__ADVANCECHARS(lex_ctx, adv);
+
+ escval = 0;
+ for (;;) {
+ /* One of the escape forms: \xHH, \uHHHH, \u{H+}.
+ * The 'digits' variable tracks parsing state and is
+ * initialized to:
+ *
+ * \xHH 2
+ * \uHH 4
+ * \u{H+} 0 first time, updated to -1 to indicate
+ * at least one digit has been parsed
+ *
+ * Octal parsing is handled separately because it can be
+ * done with fixed lookahead and also has validation
+ * rules which depend on the escape length (which is
+ * variable).
+ *
+ * We don't need a specific check for x < 0 (end of
+ * input) or duk_unicode_is_line_terminator(x)
+ * because the 'dig' decode will fail and lead to a
+ * SyntaxError.
+ */
+ duk_codepoint_t dig;
+
+ x = DUK__L0();
+ DUK__ADVANCECHARS(lex_ctx, 1);
+
+ dig = duk__hexval_validate(x);
+ if (digits > 0) {
+ digits--;
+ if (dig < 0) {
+ goto fail_escape;
+ }
+ DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
+ escval = (escval << 4) + dig;
+ if (digits == 0) {
+ DUK_ASSERT(escval >= 0 && escval <= 0xffffL);
+ break;
+ }
+ } else {
+#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
+ DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */);
+ if (dig >= 0) {
+ DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
+ escval = (escval << 4) + dig;
+ if (escval > 0x10ffffL) {
+ goto fail_escape;
+ }
+ } else if (x == DUK_ASC_RCURLY) {
+ if (digits == 0) {
+ /* Empty escape, \u{}. */
+ goto fail_escape;
+ }
+ DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL);
+ break;
+ } else {
+ goto fail_escape;
+ }
+ digits = -1; /* Indicate we have at least one digit. */
+#else /* DUK_USE_ES6_UNICODE_ESCAPE */
+ DUK_ASSERT(0); /* Never happens if \u{H+} support disabled. */
+#endif /* DUK_USE_ES6_UNICODE_ESCAPE */
+ }
+ }
+
+ return escval;
+
+ fail_escape:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
+}
+
+/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum
+ * allowed value is \0377 (U+00FF), longest match is used. Used for both string
+ * RegExp octal escape parsing. Window[0] must be the slash '\' and the first
+ * digit must already be validated to be in [0-9] by the caller.
+ */
+DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_uint_t *out_adv, duk_bool_t reject_annex_b) {
+ duk_codepoint_t cp;
+ duk_small_uint_t lookup_idx;
+ duk_small_uint_t adv;
+ duk_codepoint_t tmp;
+
+ DUK_ASSERT(out_adv != NULL);
+ DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH);
+ DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9);
+
+ cp = 0;
+ tmp = 0;
+ for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) {
+ DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
+ tmp = DUK__LOOKUP(lex_ctx, lookup_idx);
+ if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) {
+ /* No more valid digits. */
+ break;
+ }
+ tmp = (cp << 3) + (tmp - DUK_ASC_0);
+ if (tmp > 0xff) {
+ /* Three digit octal escapes above \377 (= 0xff)
+ * are not allowed.
+ */
+ break;
+ }
+ cp = tmp;
+ }
+ DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
+
+ adv = lookup_idx;
+ if (lookup_idx == 1) {
+ DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too"));
+ DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9);
+ cp = tmp;
+ adv++; /* correction to above, eat offending character */
+ } else if (lookup_idx == 2 && cp == 0) {
+ /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not.
+ * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError.
+ */
+ DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too"));
+ } else {
+ /* This clause also handles non-shortest zero, e.g. \00. */
+ if (reject_annex_b) {
+ DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp));
+ cp = -1;
+ } else {
+ DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp));
+ DUK_ASSERT(cp >= 0 && cp <= 0xff);
+ }
+ }
+
+ *out_adv = adv;
+
+ DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b));
+ return cp;
+}
+
+/* XXX: move strict mode to lex_ctx? */
+DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) {
+ duk_small_uint_t adv;
+
+ for (adv = 1 /* initial quote */ ;;) {
+ duk_codepoint_t x;
+
+ DUK__ADVANCECHARS(lex_ctx, adv); /* eat opening quote on first loop */
+ x = DUK__L0();
+
+ adv = 1;
+ if (x == quote) {
+ DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
+ break;
+ } else if (x == '\\') {
+ /* DUK__L0 -> '\' char
+ * DUK__L1 ... DUK__L5 -> more lookup
+ */
+ duk_small_int_t emitcp = -1;
+
+ x = DUK__L1();
+
+ /* How much to advance before next loop. */
+ adv = 2; /* note: long live range */
+
+ switch (x) {
+ case '\'':
+ emitcp = 0x0027;
+ break;
+ case '"':
+ emitcp = 0x0022;
+ break;
+ case '\\':
+ emitcp = 0x005c;
+ break;
+ case 'b':
+ emitcp = 0x0008;
+ break;
+ case 'f':
+ emitcp = 0x000c;
+ break;
+ case 'n':
+ emitcp = 0x000a;
+ break;
+ case 'r':
+ emitcp = 0x000d;
+ break;
+ case 't':
+ emitcp = 0x0009;
+ break;
+ case 'v':
+ emitcp = 0x000b;
+ break;
+ case 'x':
+ case 'u': {
+ duk_codepoint_t esc_cp;
+ esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
+ DUK__APPENDBUFFER(lex_ctx, esc_cp);
+ adv = 0;
+ break;
+ }
+ default: {
+ if (duk_unicode_is_line_terminator(x)) {
+ /* line continuation */
+ if (x == 0x000d && DUK__L2() == 0x000a) {
+ /* CR LF again a special case */
+ adv = 3; /* line terminator, CR, LF */
+ }
+ } else if (DUK__ISDIGIT(x)) {
+ /*
+ * Octal escape or zero escape:
+ * \0 (lookahead not OctalDigit)
+ * \1 ... \7 (lookahead not OctalDigit)
+ * \ZeroToThree OctalDigit (lookahead not OctalDigit)
+ * \FourToSeven OctalDigit (no lookahead restrictions)
+ * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
+ *
+ * Zero escape is part of the standard syntax. Octal escapes are
+ * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
+ * Any other productions starting with a decimal digit are invalid
+ * but are in practice treated like identity escapes.
+ *
+ * Parse octal (up to 3 digits) from the lookup window.
+ */
+
+ emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/);
+ if (emitcp < 0) {
+ goto fail_escape;
+ }
+ } else if (x < 0) {
+ goto fail_unterminated;
+ } else {
+ /* escaped NonEscapeCharacter */
+ DUK__APPENDBUFFER(lex_ctx, x);
+ }
+ } /* end default clause */
+ } /* end switch */
+
+ /* Shared handling for single codepoint escapes. */
+ if (emitcp >= 0) {
+ DUK__APPENDBUFFER(lex_ctx, emitcp);
+ }
+
+ /* Track number of escapes; count not really needed but directive
+ * prologues need to detect whether there were any escapes or line
+ * continuations or not.
+ */
+ out_token->num_escapes++;
+ } else if (x >= 0x20 && x <= 0x7f) {
+ /* Fast path for ASCII case, avoids line terminator
+ * check and CESU-8 encoding.
+ */
+ DUK_ASSERT(x >= 0);
+ DUK_ASSERT(!duk_unicode_is_line_terminator(x));
+ DUK_ASSERT(x != quote);
+ DUK_ASSERT(x != DUK_ASC_BACKSLASH);
+ DUK__APPENDBUFFER_ASCII(lex_ctx, x);
+ } else if (x < 0 || duk_unicode_is_line_terminator(x)) {
+ goto fail_unterminated;
+ } else {
+ /* Character which is part of the string but wasn't handled
+ * by the fast path.
+ */
+ DUK__APPENDBUFFER(lex_ctx, x);
+ }
+ } /* string parse loop */
+
+ return;
+
+ fail_escape:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
+ return;
+
+ fail_unterminated:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING);
+ return;
}
-DUK_LOCAL duk_codepoint_t duk__decode_uniesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
- /* validation performed by duk__hexval */
- return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 12) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint) << 8) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 2].codepoint) << 4) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 3].codepoint));
+/* Skip to end-of-line (or end-of-file), used for single line comments. */
+DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) {
+ for (;;) {
+ duk_codepoint_t x;
+
+ x = DUK__L0();
+ if (x < 0 || duk_unicode_is_line_terminator(x)) {
+ break;
+ }
+ DUK__ADVANCECHARS(lex_ctx, 1);
+ }
}
/*
@@ -73819,12 +81322,11 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
if (++lex_ctx->token_count >= lex_ctx->token_limit) {
- DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
- return; /* unreachable */
+ goto fail_token_limit;
}
out_token->t = DUK_TOK_EOF;
- out_token->t_nores = -1; /* marker: copy t if not changed */
+ out_token->t_nores = DUK_TOK_INVALID; /* marker: copy t if not changed */
#if 0 /* not necessary to init, disabled for faster parsing */
out_token->num = DUK_DOUBLE_NAN;
out_token->str1 = NULL;
@@ -73839,8 +81341,8 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
* freed normally.
*/
#if 0
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
+ duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx);
+ duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx);
#endif
/* 'advtok' indicates how much to advance and which token id to assign
@@ -73882,23 +81384,28 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__ADVANCECHARS(lex_ctx, 1);
got_lineterm = 1;
goto restart_lineupdate;
+#if defined(DUK_USE_SHEBANG_COMMENTS)
+ case DUK_ASC_HASH: /* '#' */
+ if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 &&
+ (lex_ctx->flags & DUK_COMPILE_SHEBANG)) {
+ /* "Shebang" comment ('#! ...') on first line. */
+ /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
+ duk__lexer_skip_to_endofline(lex_ctx);
+ goto restart; /* line terminator will be handled on next round */
+ }
+ goto fail_token;
+#endif /* DUK_USE_SHEBANG_COMMENTS */
case DUK_ASC_SLASH: /* '/' */
- if (DUK__L1() == '/') {
+ if (DUK__L1() == DUK_ASC_SLASH) {
/*
* E5 Section 7.4, allow SourceCharacter (which is any 16-bit
* code point).
*/
- /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */
- for (;;) {
- x = DUK__L0();
- if (x < 0 || duk_unicode_is_line_terminator(x)) {
- break;
- }
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
+ /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
+ duk__lexer_skip_to_endofline(lex_ctx);
goto restart; /* line terminator will be handled on next round */
- } else if (DUK__L1() == '*') {
+ } else if (DUK__L1() == DUK_ASC_STAR) {
/*
* E5 Section 7.4. If the multi-line comment contains a newline,
* it is treated like a single line terminator for automatic
@@ -73910,16 +81417,16 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
for (;;) {
x = DUK__L0();
if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in multiline comment");
+ goto fail_unterm_comment;
}
DUK__ADVANCECHARS(lex_ctx, 1);
- if (last_asterisk && x == '/') {
+ if (last_asterisk && x == DUK_ASC_SLASH) {
break;
}
if (duk_unicode_is_line_terminator(x)) {
got_lineterm = 1;
}
- last_asterisk = (x == '*');
+ last_asterisk = (x == DUK_ASC_STAR);
}
goto restart_lineupdate;
} else if (regexp_mode) {
@@ -73988,24 +81495,24 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
x = DUK__L0();
if (x < 0 || duk_unicode_is_line_terminator(x)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in regexp");
+ goto fail_unterm_regexp;
}
x = DUK__L0(); /* re-read to avoid spill / fetch */
if (state == 0) {
- if (x == '/') {
+ if (x == DUK_ASC_SLASH) {
DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
break;
- } else if (x == '\\') {
+ } else if (x == DUK_ASC_BACKSLASH) {
state = 1;
- } else if (x == '[') {
+ } else if (x == DUK_ASC_LBRACKET) {
state = 2;
}
} else if (state == 1) {
state = 0;
} else if (state == 2) {
- if (x == ']') {
+ if (x == DUK_ASC_RBRACKET) {
state = 0;
- } else if (x == '\\') {
+ } else if (x == DUK_ASC_BACKSLASH) {
state = 3;
}
} else { /* state == 3 */
@@ -74013,8 +81520,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
}
DUK__APPENDBUFFER(lex_ctx, x);
}
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
+ out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
/* second, parse flags */
@@ -74028,18 +81534,17 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__APPENDBUFFER(lex_ctx, x);
DUK__ADVANCECHARS(lex_ctx, 1);
}
- duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
- out_token->str2 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
+ out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
DUK__INITBUFFER(lex_ctx); /* free some memory */
/* validation of the regexp is caller's responsibility */
advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
-#else
- DUK_ERROR_SYNTAX(lex_ctx->thr, "regexp support disabled");
-#endif
- } else if (DUK__L1() == '=') {
+#else /* DUK_USE_REGEXP_SUPPORT */
+ goto fail_regexp_support;
+#endif /* DUK_USE_REGEXP_SUPPORT */
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
/* "/=" and not in regexp mode */
advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
} else {
@@ -74083,101 +81588,139 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
break;
case DUK_ASC_LANGLE: /* '<' */
- if (DUK__L1() == '<' && DUK__L2() == '=') {
+#if defined(DUK_USE_HTML_COMMENTS)
+ if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) {
+ /*
+ * ES2015: B.1.3, handle "<!--" SingleLineHTMLOpenComment
+ */
+
+ /* DUK__ADVANCECHARS(lex_ctx, 4) would be correct here, but not necessary */
+ duk__lexer_skip_to_endofline(lex_ctx);
+ goto restart; /* line terminator will be handled on next round */
+ }
+ else
+#endif /* DUK_USE_HTML_COMMENTS */
+ if (DUK__L1() == DUK_ASC_LANGLE && DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_LE);
- } else if (DUK__L1() == '<') {
+ } else if (DUK__L1() == DUK_ASC_LANGLE) {
advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_LT);
}
break;
case DUK_ASC_RANGLE: /* '>' */
- if (DUK__L1() == '>' && DUK__L2() == '>' && DUK__L3() == '=') {
+ if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE && DUK__L3() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
- } else if (DUK__L1() == '>' && DUK__L2() == '>') {
+ } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE) {
advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
- } else if (DUK__L1() == '>' && DUK__L2() == '=') {
+ } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_GE);
- } else if (DUK__L1() == '>') {
+ } else if (DUK__L1() == DUK_ASC_RANGLE) {
advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_GT);
}
break;
case DUK_ASC_EQUALS: /* '=' */
- if (DUK__L1() == '=' && DUK__L2() == '=') {
+ if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
}
break;
case DUK_ASC_EXCLAMATION: /* '!' */
- if (DUK__L1() == '=' && DUK__L2() == '=') {
+ if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
}
break;
case DUK_ASC_PLUS: /* '+' */
- if (DUK__L1() == '+') {
+ if (DUK__L1() == DUK_ASC_PLUS) {
advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
}
break;
case DUK_ASC_MINUS: /* '-' */
- if (DUK__L1() == '-') {
+#if defined(DUK_USE_HTML_COMMENTS)
+ if (got_lineterm && DUK__L1() == DUK_ASC_MINUS && DUK__L2() == DUK_ASC_RANGLE) {
+ /*
+ * ES2015: B.1.3, handle "-->" SingleLineHTMLCloseComment
+ * Only allowed:
+ * - on new line
+ * - preceded only by whitespace
+ * - preceded by end of multiline comment and optional whitespace
+ *
+ * Since whitespace generates no tokens, and multiline comments
+ * are treated as a line ending, consulting `got_lineterm` is
+ * sufficient to test for these three options.
+ */
+
+ /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */
+ duk__lexer_skip_to_endofline(lex_ctx);
+ goto restart; /* line terminator will be handled on next round */
+ } else
+#endif /* DUK_USE_HTML_COMMENTS */
+ if (DUK__L1() == DUK_ASC_MINUS) {
advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
}
break;
case DUK_ASC_STAR: /* '*' */
- if (DUK__L1() == '=') {
+#if defined(DUK_USE_ES7_EXP_OPERATOR)
+ if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) {
+ advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ);
+ } else if (DUK__L1() == DUK_ASC_STAR) {
+ advtok = DUK__ADVTOK(2, DUK_TOK_EXP);
+ } else
+#endif
+ if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
}
break;
case DUK_ASC_PERCENT: /* '%' */
- if (DUK__L1() == '=') {
+ if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
}
break;
case DUK_ASC_AMP: /* '&' */
- if (DUK__L1() == '&') {
+ if (DUK__L1() == DUK_ASC_AMP) {
advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
}
break;
case DUK_ASC_PIPE: /* '|' */
- if (DUK__L1() == '|') {
+ if (DUK__L1() == DUK_ASC_PIPE) {
advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
- } else if (DUK__L1() == '=') {
+ } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
}
break;
case DUK_ASC_CARET: /* '^' */
- if (DUK__L1() == '=') {
+ if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
} else {
advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
@@ -74194,140 +81737,10 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
break;
case DUK_ASC_DOUBLEQUOTE: /* '"' */
case DUK_ASC_SINGLEQUOTE: { /* '\'' */
- duk_small_int_t quote = x; /* Note: duk_uint8_t type yields larger code */
- duk_small_int_t adv;
-
DUK__INITBUFFER(lex_ctx);
- for (;;) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat opening quote on first loop */
- x = DUK__L0();
- if (x < 0 || duk_unicode_is_line_terminator(x)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
- }
- if (x == quote) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
- break;
- }
- if (x == '\\') {
- /* DUK__L0 -> '\' char
- * DUK__L1 ... DUK__L5 -> more lookup
- */
-
- x = DUK__L1();
-
- /* How much to advance before next loop; note that next loop
- * will advance by 1 anyway, so -1 from the total escape
- * length (e.g. len('\uXXXX') - 1 = 6 - 1). As a default,
- * 1 is good.
- */
- adv = 2 - 1; /* note: long live range */
-
- if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
- }
- if (duk_unicode_is_line_terminator(x)) {
- /* line continuation */
- if (x == 0x000d && DUK__L2() == 0x000a) {
- /* CR LF again a special case */
- adv = 3 - 1;
- }
- } else if (x == '\'') {
- DUK__APPENDBUFFER(lex_ctx, 0x0027);
- } else if (x == '"') {
- DUK__APPENDBUFFER(lex_ctx, 0x0022);
- } else if (x == '\\') {
- DUK__APPENDBUFFER(lex_ctx, 0x005c);
- } else if (x == 'b') {
- DUK__APPENDBUFFER(lex_ctx, 0x0008);
- } else if (x == 'f') {
- DUK__APPENDBUFFER(lex_ctx, 0x000c);
- } else if (x == 'n') {
- DUK__APPENDBUFFER(lex_ctx, 0x000a);
- } else if (x == 'r') {
- DUK__APPENDBUFFER(lex_ctx, 0x000d);
- } else if (x == 't') {
- DUK__APPENDBUFFER(lex_ctx, 0x0009);
- } else if (x == 'v') {
- DUK__APPENDBUFFER(lex_ctx, 0x000b);
- } else if (x == 'x') {
- adv = 4 - 1;
- DUK__APPENDBUFFER(lex_ctx, duk__decode_hexesc_from_window(lex_ctx, 2));
- } else if (x == 'u') {
- adv = 6 - 1;
- DUK__APPENDBUFFER(lex_ctx, duk__decode_uniesc_from_window(lex_ctx, 2));
- } else if (DUK__ISDIGIT(x)) {
- duk_codepoint_t ch = 0; /* initialized to avoid warnings of unused var */
-
- /*
- * Octal escape or zero escape:
- * \0 (lookahead not DecimalDigit)
- * \1 ... \7 (lookahead not DecimalDigit)
- * \ZeroToThree OctalDigit (lookahead not DecimalDigit)
- * \FourToSeven OctalDigit (no lookahead restrictions)
- * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
- *
- * Zero escape is part of the standard syntax. Octal escapes are
- * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
- * Any other productions starting with a decimal digit are invalid.
- */
-
- if (x == '0' && !DUK__ISDIGIT(DUK__L2())) {
- /* Zero escape (also allowed in non-strict mode) */
- ch = 0;
- /* adv = 2 - 1 default OK */
-#if defined(DUK_USE_OCTAL_SUPPORT)
- } else if (strict_mode) {
- /* No other escape beginning with a digit in strict mode */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
- } else if (DUK__ISDIGIT03(x) && DUK__ISOCTDIGIT(DUK__L2()) && DUK__ISOCTDIGIT(DUK__L3())) {
- /* Three digit octal escape, digits validated. */
- adv = 4 - 1;
- ch = (duk__hexval(lex_ctx, x) << 6) +
- (duk__hexval(lex_ctx, DUK__L2()) << 3) +
- duk__hexval(lex_ctx, DUK__L3());
- } else if (((DUK__ISDIGIT03(x) && !DUK__ISDIGIT(DUK__L3())) || DUK__ISDIGIT47(x)) &&
- DUK__ISOCTDIGIT(DUK__L2())) {
- /* Two digit octal escape, digits validated.
- *
- * The if-condition is a bit tricky. We could catch e.g.
- * '\039' in the three-digit escape and fail it there (by
- * validating the digits), but we want to avoid extra
- * additional validation code.
- */
- adv = 3 - 1;
- ch = (duk__hexval(lex_ctx, x) << 3) +
- duk__hexval(lex_ctx, DUK__L2());
- } else if (DUK__ISDIGIT(x) && !DUK__ISDIGIT(DUK__L2())) {
- /* One digit octal escape, digit validated. */
- /* adv = 2 default OK */
- ch = duk__hexval(lex_ctx, x);
-#else
- /* fall through to error */
-#endif
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
- }
-
- DUK__APPENDBUFFER(lex_ctx, ch);
- } else {
- /* escaped NonEscapeCharacter */
- DUK__APPENDBUFFER(lex_ctx, x);
- }
- DUK__ADVANCECHARS(lex_ctx, adv);
-
- /* Track number of escapes; count not really needed but directive
- * prologues need to detect whether there were any escapes or line
- * continuations or not.
- */
- out_token->num_escapes++;
- } else {
- /* part of string */
- DUK__APPENDBUFFER(lex_ctx, x);
- }
- }
-
+ duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode);
duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
+ out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx);
DUK__INITBUFFER(lex_ctx); /* free some memory */
@@ -74354,7 +81767,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
}
got_lineterm = 1;
goto restart_lineupdate;
- } else if (duk_unicode_is_identifier_start(x) || x == '\\') {
+ } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) {
/*
* Parse an identifier and then check whether it is:
* - reserved word (keyword or other reserved word)
@@ -74386,29 +81799,27 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
* parsing the identifier. This has little practical impact.
*/
- duk_small_int_t i, i_end;
+ duk_small_uint_t i, i_end;
duk_bool_t first = 1;
duk_hstring *str;
DUK__INITBUFFER(lex_ctx);
for (;;) {
/* re-lookup first char on first loop */
- if (DUK__L0() == '\\') {
- duk_codepoint_t ch;
- if (DUK__L1() != 'u') {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
+ if (DUK__L0() == DUK_ASC_BACKSLASH) {
+ duk_codepoint_t esc_cp;
+ if (DUK__L1() != DUK_ASC_LC_U) {
+ goto fail_escape;
}
-
- ch = duk__decode_uniesc_from_window(lex_ctx, 2);
+ esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
+ DUK__APPENDBUFFER(lex_ctx, esc_cp);
/* IdentifierStart is stricter than IdentifierPart, so if the first
* character is escaped, must have a stricter check here.
*/
- if (!(first ? duk_unicode_is_identifier_start(ch) : duk_unicode_is_identifier_part(ch))) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
+ if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) {
+ goto fail_escape;
}
- DUK__APPENDBUFFER(lex_ctx, ch);
- DUK__ADVANCECHARS(lex_ctx, 6);
/* Track number of escapes: necessary for proper keyword
* detection.
@@ -74429,10 +81840,8 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
first = 0;
}
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
+ out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
str = out_token->str1;
- DUK_ASSERT(str != NULL);
out_token->t_nores = DUK_TOK_IDENTIFIER;
DUK__INITBUFFER(lex_ctx); /* free some memory */
@@ -74462,30 +81871,31 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
if (out_token->num_escapes == 0) {
for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
- DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
+ DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS);
if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
break;
}
}
}
- } else if (DUK__ISDIGIT(x) || (x == '.')) {
+ } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) {
/* Note: decimal number may start with a period, but must be followed by a digit */
/*
- * DecimalLiteral, HexIntegerLiteral, OctalIntegerLiteral
- * "pre-parsing", followed by an actual, accurate parser step.
+ * Pre-parsing for decimal, hex, octal (both legacy and ES2015),
+ * and binary literals, followed by an actual parser step
+ * provided by numconv.
*
* Note: the leading sign character ('+' or '-') is -not- part of
* the production in E5 grammar, and that the a DecimalLiteral
- * starting with a '0' must be followed by a non-digit. Leading
- * zeroes are syntax errors and must be checked for.
+ * starting with a '0' must be followed by a non-digit.
*
* XXX: the two step parsing process is quite awkward, it would
* be more straightforward to allow numconv to parse the longest
* valid prefix (it already does that, it only needs to indicate
* where the input ended). However, the lexer decodes characters
- * using a lookup window, so this is not a trivial change.
+ * using a limited lookup window, so this is not a trivial change.
*/
/* XXX: because of the final check below (that the literal is not
@@ -74495,39 +81905,58 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
*/
duk_double_t val;
- duk_bool_t int_only = 0;
- duk_bool_t allow_hex = 0;
+ duk_bool_t legacy_oct = 0;
duk_small_int_t state; /* 0=before period/exp,
* 1=after period, before exp
* 2=after exp, allow '+' or '-'
* 3=after exp and exp sign
*/
duk_small_uint_t s2n_flags;
- duk_codepoint_t y;
+ duk_codepoint_t y, z;
+ duk_small_int_t s2n_radix = 10;
+ duk_small_uint_t pre_adv = 0;
DUK__INITBUFFER(lex_ctx);
y = DUK__L1();
- if (x == '0' && (y == 'x' || y == 'X')) {
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__APPENDBUFFER(lex_ctx, y);
- DUK__ADVANCECHARS(lex_ctx, 2);
- int_only = 1;
- allow_hex = 1;
-#if defined(DUK_USE_OCTAL_SUPPORT)
- } else if (!strict_mode && x == '0' && DUK__ISDIGIT(y)) {
- /* Note: if DecimalLiteral starts with a '0', it can only be
- * followed by a period or an exponent indicator which starts
- * with 'e' or 'E'. Hence the if-check above ensures that
- * OctalIntegerLiteral is the only valid NumericLiteral
- * alternative at this point (even if y is, say, '9').
- */
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__ADVANCECHARS(lex_ctx, 1);
- int_only = 1;
-#endif
+ if (x == DUK_ASC_0) {
+ z = DUK_LOWERCASE_CHAR_ASCII(y);
+
+ pre_adv = 2; /* default for 0xNNN, 0oNNN, 0bNNN. */
+ if (z == DUK_ASC_LC_X) {
+ s2n_radix = 16;
+ } else if (z == DUK_ASC_LC_O) {
+ s2n_radix = 8;
+ } else if (z == DUK_ASC_LC_B) {
+ s2n_radix = 2;
+ } else {
+ pre_adv = 0;
+ if (DUK__ISDIGIT(y)) {
+ if (strict_mode) {
+ /* Reject octal like \07 but also octal-lookalike
+ * decimal like \08 in strict mode.
+ */
+ goto fail_number_literal;
+ } else {
+ /* Legacy OctalIntegerLiteral or octal-lookalice
+ * decimal. Deciding between the two happens below
+ * in digit scanning.
+ */
+ DUK__APPENDBUFFER(lex_ctx, x);
+ pre_adv = 1;
+ legacy_oct = 1;
+ s2n_radix = 8; /* tentative unless conflicting digits found */
+ }
+ }
+ }
}
+ DUK__ADVANCECHARS(lex_ctx, pre_adv);
+
+ /* XXX: we could parse integers here directly, and fall back
+ * to numconv only when encountering a fractional expression
+ * or when an octal literal turned out to be decimal (0778 etc).
+ */
state = 0;
for (;;) {
x = DUK__L0(); /* re-lookup curr char on first round */
@@ -74535,25 +81964,35 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
/* Note: intentionally allow leading zeroes here, as the
* actual parser will check for them.
*/
+ if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) {
+ /* Started out as an octal-lookalike
+ * but interpreted as decimal, e.g.
+ * '0779' -> 779. This also means
+ * that fractions are allowed, e.g.
+ * '0779.123' is allowed but '0777.123'
+ * is not!
+ */
+ s2n_radix = 10;
+ }
if (state == 2) {
state = 3;
}
- } else if (allow_hex && DUK__ISHEXDIGIT(x)) {
+ } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) {
/* Note: 'e' and 'E' are also accepted here. */
;
- } else if (x == '.') {
- if (state >= 1 || int_only) {
+ } else if (x == DUK_ASC_PERIOD) {
+ if (state >= 1 || s2n_radix != 10) {
break;
} else {
state = 1;
}
- } else if (x == 'e' || x == 'E') {
- if (state >= 2 || int_only) {
+ } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) {
+ if (state >= 2 || s2n_radix != 10) {
break;
} else {
state = 2;
}
- } else if (x == '-' || x == '+') {
+ } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) {
if (state != 2) {
break;
} else {
@@ -74567,24 +82006,26 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
}
/* XXX: better coercion */
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
+ (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
- DUK_S2N_FLAG_ALLOW_FRAC |
- DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
- DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
-#if defined(DUK_USE_OCTAL_SUPPORT)
- (strict_mode ? 0 : DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) |
-#endif
- DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
+ if (s2n_radix != 10) {
+ /* For bases other than 10, integer only. */
+ s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
+ } else {
+ s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
+ DUK_S2N_FLAG_ALLOW_FRAC |
+ DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
+ DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
+ DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
+ }
- duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_numconv_parse((duk_context *) lex_ctx->thr, 10 /*radix*/, s2n_flags);
- val = duk_to_number((duk_context *) lex_ctx->thr, -1);
+ duk_dup(lex_ctx->thr, lex_ctx->slot1_idx);
+ duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags);
+ val = duk_to_number_m1(lex_ctx->thr);
if (DUK_ISNAN(val)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
+ goto fail_number_literal;
}
- duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
+ duk_replace(lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
DUK__INITBUFFER(lex_ctx); /* free some memory */
@@ -74593,7 +82034,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
*/
if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
+ goto fail_number_literal;
}
out_token->num = val;
@@ -74604,7 +82045,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
} else if (x < 0) {
advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid token");
+ goto fail_token;
}
skip_slow_path:
@@ -74614,7 +82055,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
out_token->t = advtok & 0xff;
- if (out_token->t_nores < 0) {
+ if (out_token->t_nores == DUK_TOK_INVALID) {
out_token->t_nores = out_token->t;
}
out_token->lineterm = got_lineterm;
@@ -74628,6 +82069,38 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
} else {
out_token->allow_auto_semi = 0;
}
+
+ return;
+
+ fail_token_limit:
+ DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
+ return;
+
+ fail_token:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN);
+ return;
+
+ fail_number_literal:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL);
+ return;
+
+ fail_escape:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
+ return;
+
+ fail_unterm_regexp:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP);
+ return;
+
+ fail_unterm_comment:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT);
+ return;
+
+#if !defined(DUK_USE_REGEXP_SUPPORT)
+ fail_regexp_support:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED);
+ return;
+#endif
}
#if defined(DUK_USE_REGEXP_SUPPORT)
@@ -74642,12 +82115,11 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
*/
DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
- duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
+ duk_small_uint_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
duk_codepoint_t x, y;
if (++lex_ctx->token_count >= lex_ctx->token_limit) {
- DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
- return; /* unreachable */
+ goto fail_token_limit;
}
DUK_MEMZERO(out_token, sizeof(*out_token));
@@ -74658,22 +82130,22 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
switch (x) {
- case '|': {
+ case DUK_ASC_PIPE: {
advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
break;
}
- case '^': {
+ case DUK_ASC_CARET: {
advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
break;
}
- case '$': {
+ case DUK_ASC_DOLLAR: {
advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
break;
}
- case '?': {
+ case DUK_ASC_QUESTION: {
out_token->qmin = 0;
out_token->qmax = 1;
- if (y == '?') {
+ if (y == DUK_ASC_QUESTION) {
advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
out_token->greedy = 0;
} else {
@@ -74682,10 +82154,10 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
}
break;
}
- case '*': {
+ case DUK_ASC_STAR: {
out_token->qmin = 0;
out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
- if (y == '?') {
+ if (y == DUK_ASC_QUESTION) {
advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
out_token->greedy = 0;
} else {
@@ -74694,10 +82166,10 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
}
break;
}
- case '+': {
+ case DUK_ASC_PLUS: {
out_token->qmin = 1;
out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
- if (y == '?') {
+ if (y == DUK_ASC_QUESTION) {
advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
out_token->greedy = 0;
} else {
@@ -74706,16 +82178,16 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
}
break;
}
- case '{': {
+ case DUK_ASC_LCURLY: {
/* Production allows 'DecimalDigits', including leading zeroes */
- duk_uint_fast32_t val1 = 0;
- duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
+ duk_uint32_t val1 = 0;
+ duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
duk_small_int_t digits = 0;
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
duk_lexer_point lex_pt;
#endif
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
/* Store lexer position, restoring if quantifier is invalid. */
DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
#endif
@@ -74725,15 +82197,15 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
x = DUK__L0();
if (DUK__ISDIGIT(x)) {
digits++;
- val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
- } else if (x == ',') {
+ val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x);
+ } else if (x == DUK_ASC_COMMA) {
if (digits > DUK__MAX_RE_QUANT_DIGITS) {
goto invalid_quantifier;
}
if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
goto invalid_quantifier;
}
- if (DUK__L1() == '}') {
+ if (DUK__L1() == DUK_ASC_RCURLY) {
/* form: { DecimalDigits , }, val1 = min count */
if (digits == 0) {
goto invalid_quantifier;
@@ -74746,7 +82218,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
val2 = val1;
val1 = 0;
digits = 0; /* not strictly necessary because of lookahead '}' above */
- } else if (x == '}') {
+ } else if (x == DUK_ASC_RCURLY) {
if (digits > DUK__MAX_RE_QUANT_DIGITS) {
goto invalid_quantifier;
}
@@ -74768,7 +82240,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
goto invalid_quantifier;
}
}
- if (DUK__L0() == '?') {
+ if (DUK__L0() == DUK_ASC_QUESTION) {
out_token->greedy = 0;
DUK__ADVANCECHARS(lex_ctx, 1);
} else {
@@ -74777,129 +82249,143 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
break;
invalid_quantifier:
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
/* Failed to match the quantifier, restore lexer and parse
* opening brace as a literal.
*/
DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
- out_token->num = '{';
+ out_token->num = DUK_ASC_LCURLY;
#else
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp quantifier");
+ goto fail_quantifier;
#endif
break;
}
- case '.': {
+ case DUK_ASC_PERIOD: {
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
break;
}
- case '\\': {
+ case DUK_ASC_BACKSLASH: {
/* The E5.1 specification does not seem to allow IdentifierPart characters
* to be used as identity escapes. Unfortunately this includes '$', which
* cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
* Many other implementations (including V8 and Rhino, for instance) do
- * accept '\$' as a valid identity escape, which is quite pragmatic.
- * See: test-regexp-identity-escape-dollar.js.
+ * accept '\$' as a valid identity escape, which is quite pragmatic, and
+ * ES2015 Annex B relaxes the rules to allow these (and other) real world forms.
*/
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
- if (y == 'b') {
+ if (y == DUK_ASC_LC_B) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
- } else if (y == 'B') {
+ } else if (y == DUK_ASC_UC_B) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
- } else if (y == 'f') {
+ } else if (y == DUK_ASC_LC_F) {
out_token->num = 0x000c;
- } else if (y == 'n') {
+ } else if (y == DUK_ASC_LC_N) {
out_token->num = 0x000a;
- } else if (y == 't') {
+ } else if (y == DUK_ASC_LC_T) {
out_token->num = 0x0009;
- } else if (y == 'r') {
+ } else if (y == DUK_ASC_LC_R) {
out_token->num = 0x000d;
- } else if (y == 'v') {
+ } else if (y == DUK_ASC_LC_V) {
out_token->num = 0x000b;
- } else if (y == 'c') {
+ } else if (y == DUK_ASC_LC_C) {
x = DUK__L2();
- if ((x >= 'a' && x <= 'z') ||
- (x >= 'A' && x <= 'Z')) {
- out_token->num = (x % 32);
+ if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
+ (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
+ out_token->num = (duk_uint32_t) (x % 32);
advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- } else if (y == 'x') {
- out_token->num = duk__decode_hexesc_from_window(lex_ctx, 2);
- advtok = DUK__ADVTOK(4, DUK_RETOK_ATOM_CHAR);
- } else if (y == 'u') {
- out_token->num = duk__decode_uniesc_from_window(lex_ctx, 2);
- advtok = DUK__ADVTOK(6, DUK_RETOK_ATOM_CHAR);
- } else if (y == 'd') {
+ goto fail_escape;
+ }
+ } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) {
+ /* The token value is the Unicode codepoint without
+ * it being decode into surrogate pair characters
+ * here. The \u{H+} is only allowed in Unicode mode
+ * which we don't support yet.
+ */
+ out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
+ advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR);
+ } else if (y == DUK_ASC_LC_D) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
- } else if (y == 'D') {
+ } else if (y == DUK_ASC_UC_D) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
- } else if (y == 's') {
+ } else if (y == DUK_ASC_LC_S) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
- } else if (y == 'S') {
+ } else if (y == DUK_ASC_UC_S) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
- } else if (y == 'w') {
+ } else if (y == DUK_ASC_LC_W) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
- } else if (y == 'W') {
+ } else if (y == DUK_ASC_UC_W) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
} else if (DUK__ISDIGIT(y)) {
/* E5 Section 15.10.2.11 */
- if (y == '0') {
+ if (y == DUK_ASC_0) {
if (DUK__ISDIGIT(DUK__L2())) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
+ goto fail_escape;
}
out_token->num = 0x0000;
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
} else {
/* XXX: shared parsing? */
- duk_uint_fast32_t val = 0;
+ duk_uint32_t val = 0;
duk_small_int_t i;
for (i = 0; ; i++) {
if (i >= DUK__MAX_RE_DECESC_DIGITS) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
+ goto fail_escape;
}
DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
x = DUK__L0();
if (!DUK__ISDIGIT(x)) {
break;
}
- val = val * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
+ val = val * 10 + (duk_uint32_t) duk__hexval(x);
}
/* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
out_token->num = val;
}
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
+ } else if (y >= 0) {
+ /* For ES2015 Annex B, accept any source character as identity
+ * escape except 'c' which is used for control characters.
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns
+ * Careful not to match end-of-buffer (<0) here.
+ * This is not yet full ES2015 Annex B because cases above
+ * (like hex escape) won't backtrack.
+ */
+ DUK_ASSERT(y != DUK_ASC_LC_C); /* covered above */
+#else /* DUK_USE_ES6_REGEXP_SYNTAX */
} else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
-#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
- y == '$' ||
-#endif
y == DUK_UNICODE_CP_ZWNJ ||
y == DUK_UNICODE_CP_ZWJ) {
- /* IdentityEscape, with dollar added as a valid additional
- * non-standard escape (see test-regexp-identity-escape-dollar.js).
- * Careful not to match end-of-buffer (<0) here.
+ /* For ES5.1 identity escapes are not allowed for identifier
+ * parts. This conflicts with a lot of real world code as this
+ * doesn't e.g. allow escaping a dollar sign as /\$/, see
+ * test-regexp-identity-escape-dollar.js.
*/
- out_token->num = y;
+#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
+ out_token->num = (duk_uint32_t) y;
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
+ goto fail_escape;
}
break;
}
- case '(': {
+ case DUK_ASC_LPAREN: {
/* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
- if (y == '?') {
- if (DUK__L2() == '=') {
+ if (y == DUK_ASC_QUESTION) {
+ if (DUK__L2() == DUK_ASC_EQUALS) {
/* (?= */
advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
- } else if (DUK__L2() == '!') {
+ } else if (DUK__L2() == DUK_ASC_EXCLAMATION) {
/* (?! */
advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
- } else if (DUK__L2() == ':') {
+ } else if (DUK__L2() == DUK_ASC_COLON) {
/* (?: */
advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
+ } else {
+ goto fail_group;
}
} else {
/* ( */
@@ -74907,32 +82393,37 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
}
break;
}
- case ')': {
+ case DUK_ASC_RPAREN: {
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
break;
}
- case '[': {
+ case DUK_ASC_LBRACKET: {
/*
* To avoid creating a heavy intermediate value for the list of ranges,
* only the start token ('[' or '[^') is parsed here. The regexp
* compiler parses the ranges itself.
*/
+
+ /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket
+ * literal too, but it's not easy to parse without backtracking.
+ */
+
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
- if (y == '^') {
+ if (y == DUK_ASC_CARET) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
}
break;
}
-#if !defined(DUK_USE_ES6_REGEXP_BRACES)
- case '}':
-#endif
- case ']': {
+#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
+ case DUK_ASC_RCURLY:
+ case DUK_ASC_RBRACKET: {
/* Although these could be parsed as PatternCharacters unambiguously (here),
* E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
*/
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp character");
+ goto fail_invalid_char;
break;
}
+#endif
case -1: {
/* EOF */
advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
@@ -74941,7 +82432,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
default: {
/* PatternCharacter, all excluded characters are matched by cases above */
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
- out_token->num = x;
+ out_token->num = (duk_uint32_t) x;
break;
}
}
@@ -74952,6 +82443,29 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
out_token->t = advtok & 0xff;
+ return;
+
+ fail_token_limit:
+ DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
+ return;
+
+ fail_escape:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
+ return;
+
+ fail_group:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP);
+ return;
+
+#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
+ fail_invalid_char:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER);
+ return;
+
+ fail_quantifier:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER);
+ return;
+#endif
}
/*
@@ -74997,26 +82511,29 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
duk_codepoint_t ch;
duk_codepoint_t x;
duk_bool_t dash = 0;
+ duk_small_uint_t adv = 0;
DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
for (;;) {
+ DUK__ADVANCECHARS(lex_ctx, adv);
+ adv = 1;
+
x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
DUK_UNREF(ch);
if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in character class");
- } else if (x == ']') {
- DUK_ASSERT(!dash); /* lookup should prevent this */
+ goto fail_unterm_charclass;
+ } else if (x == DUK_ASC_RBRACKET) {
if (start >= 0) {
gen_range(userdata, start, start, 0);
}
+ DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */
break;
- } else if (x == '-') {
- if (start >= 0 && !dash && DUK__L0() != ']') {
+ } else if (x == DUK_ASC_MINUS) {
+ if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) {
/* '-' as a range indicator */
dash = 1;
continue;
@@ -75024,7 +82541,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
/* '-' verbatim */
ch = x;
}
- } else if (x == '\\') {
+ } else if (x == DUK_ASC_BACKSLASH) {
/*
* The escapes are same as outside a character class, except that \b has a
* different meaning, and \B and backreferences are prohibited (see E5
@@ -75033,79 +82550,79 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
* range for it.
*/
- x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
+ /* XXX: ES2015 surrogate pair handling. */
+
+ x = DUK__L1();
+
+ adv = 2;
- if (x == 'b') {
+ if (x == DUK_ASC_LC_B) {
/* Note: '\b' in char class is different than outside (assertion),
* '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
* check below.
*/
ch = 0x0008;
- } else if (x == 'f') {
+ } else if (x == DUK_ASC_LC_F) {
ch = 0x000c;
- } else if (x == 'n') {
+ } else if (x == DUK_ASC_LC_N) {
ch = 0x000a;
- } else if (x == 't') {
+ } else if (x == DUK_ASC_LC_T) {
ch = 0x0009;
- } else if (x == 'r') {
+ } else if (x == DUK_ASC_LC_R) {
ch = 0x000d;
- } else if (x == 'v') {
+ } else if (x == DUK_ASC_LC_V) {
ch = 0x000b;
- } else if (x == 'c') {
- x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
- if ((x >= 'a' && x <= 'z') ||
- (x >= 'A' && x <= 'Z')) {
+ } else if (x == DUK_ASC_LC_C) {
+ x = DUK__L2();
+ adv = 3;
+ if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
+ (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
ch = (x % 32);
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- return; /* never reached, but avoids warnings of
- * potentially unused variables.
- */
+ goto fail_escape;
}
- } else if (x == 'x') {
- ch = duk__decode_hexesc_from_window(lex_ctx, 0);
- DUK__ADVANCECHARS(lex_ctx, 2);
- } else if (x == 'u') {
- ch = duk__decode_uniesc_from_window(lex_ctx, 0);
- DUK__ADVANCECHARS(lex_ctx, 4);
- } else if (x == 'd') {
+ } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) {
+ /* The \u{H+} form is only allowed in Unicode mode which
+ * we don't support yet.
+ */
+ ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
+ adv = 0;
+ } else if (x == DUK_ASC_LC_D) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
duk_unicode_re_ranges_digit,
sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
ch = -1;
- } else if (x == 'D') {
+ } else if (x == DUK_ASC_UC_D) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
duk_unicode_re_ranges_not_digit,
sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
ch = -1;
- } else if (x == 's') {
+ } else if (x == DUK_ASC_LC_S) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
duk_unicode_re_ranges_white,
sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
ch = -1;
- } else if (x == 'S') {
+ } else if (x == DUK_ASC_UC_S) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
duk_unicode_re_ranges_not_white,
sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
ch = -1;
- } else if (x == 'w') {
+ } else if (x == DUK_ASC_LC_W) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
duk_unicode_re_ranges_wordchar,
sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
ch = -1;
- } else if (x == 'W') {
+ } else if (x == DUK_ASC_UC_W) {
duk__emit_u16_direct_ranges(lex_ctx,
gen_range,
userdata,
@@ -75113,21 +82630,42 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
ch = -1;
} else if (DUK__ISDIGIT(x)) {
- /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
- if (x == '0' && !DUK__ISDIGIT(DUK__L0())) {
+ /* DecimalEscape, only \0 is allowed, no leading
+ * zeroes are allowed.
+ *
+ * ES2015 Annex B also allows (maximal match) legacy
+ * octal escapes up to \377 and \8 and \9 are
+ * accepted as literal '8' and '9', also in strict mode.
+ */
+
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
+ ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/);
+ DUK_ASSERT(ch >= 0); /* no rejections */
+#else
+ if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) {
ch = 0x0000;
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
+ goto fail_escape;
}
- } else if (!duk_unicode_is_identifier_part(x)
-#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
- || x == '$'
#endif
- ) {
- /* IdentityEscape */
+#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
+ } else if (x >= 0) {
+ /* IdentityEscape: ES2015 Annex B allows almost all
+ * source characters here. Match anything except
+ * EOF here.
+ */
ch = x;
+#else /* DUK_USE_ES6_REGEXP_SYNTAX */
+ } else if (!duk_unicode_is_identifier_part(x)) {
+ /* IdentityEscape: ES5.1 doesn't allow identity escape
+ * for identifier part characters, which conflicts with
+ * some real world code. For example, it doesn't allow
+ * /[\$]/ which is awkward.
+ */
+ ch = x;
+#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
} else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
+ goto fail_escape;
}
} else {
/* character represents itself */
@@ -75144,7 +82682,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
*/
if (start >= 0) {
if (dash) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
+ goto fail_range;
} else {
gen_range(userdata, start, start, 0);
start = -1;
@@ -75155,7 +82693,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
if (start >= 0) {
if (dash) {
if (start > ch) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
+ goto fail_range;
}
gen_range(userdata, start, ch, 0);
start = -1;
@@ -75172,10 +82710,43 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
}
return;
+
+ fail_escape:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
+ return;
+
+ fail_range:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE);
+ return;
+
+ fail_unterm_charclass:
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS);
+ return;
}
#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_numconv.c"
+
+/* automatic undefs */
+#undef DUK__ADVANCEBYTES
+#undef DUK__ADVANCECHARS
+#undef DUK__ADVTOK
+#undef DUK__APPENDBUFFER
+#undef DUK__APPENDBUFFER_ASCII
+#undef DUK__INITBUFFER
+#undef DUK__ISDIGIT
+#undef DUK__ISDIGIT03
+#undef DUK__ISDIGIT47
+#undef DUK__ISHEXDIGIT
+#undef DUK__ISOCTDIGIT
+#undef DUK__L0
+#undef DUK__L1
+#undef DUK__L2
+#undef DUK__L3
+#undef DUK__L4
+#undef DUK__L5
+#undef DUK__LOOKUP
+#undef DUK__MAX_RE_DECESC_DIGITS
+#undef DUK__MAX_RE_QUANT_DIGITS
/*
* Number-to-string and string-to-number conversions.
*
@@ -75188,7 +82759,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
* See: doc/number-conversion.rst.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
@@ -75196,7 +82767,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
/*
- * Tables generated with src/gennumdigits.py.
+ * Tables generated with util/gennumdigits.py.
*
* duk__str2num_digits_for_radix indicates, for each radix, how many input
* digits should be considered significant for string-to-number conversion.
@@ -75251,7 +82822,7 @@ DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
*/
#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
#else
#define DUK__BI_PRINT(name,x)
@@ -75263,7 +82834,7 @@ typedef struct {
duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
} duk__bigint;
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
/* Overestimate required size; debug code so not critical to be tight. */
char buf[DUK__BI_MAX_PARTS * 9 + 64];
@@ -75283,7 +82854,7 @@ DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
}
#endif
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
return (duk_small_int_t)
( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
@@ -75314,7 +82885,7 @@ DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
if (n == 0) {
return;
}
- DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
+ DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n));
}
DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
@@ -75368,7 +82939,7 @@ DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
}
/* x <- y + z */
-#ifdef DUK_USE_64BIT_OPS
+#if defined(DUK_USE_64BIT_OPS)
DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
duk_uint64_t tmp;
duk_small_int_t i, ny, nz;
@@ -75478,7 +83049,7 @@ DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t)
#endif
/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
-#ifdef DUK_USE_64BIT_OPS
+#if defined(DUK_USE_64BIT_OPS)
DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
duk_small_int_t i, ny, nz;
duk_uint32_t ty, tz;
@@ -75499,7 +83070,7 @@ DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
tz = 0;
}
tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
- x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
+ x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL);
tmp = tmp >> 32; /* 0 or -1 */
}
DUK_ASSERT(tmp == 0);
@@ -75590,12 +83161,12 @@ DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
return;
}
- DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
+ DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx));
x->n = nx;
nz = z->n;
for (i = 0; i < y->n; i++) {
-#ifdef DUK_USE_64BIT_OPS
+#if defined(DUK_USE_64BIT_OPS)
duk_uint64_t tmp = 0U;
for (j = 0; j < nz; j++) {
tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
@@ -75740,7 +83311,7 @@ DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
n = (y / 32) + 1;
DUK_ASSERT(n > 0);
r = y % 32;
- DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
+ DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * (size_t) n);
x->n = n;
x->v[n - 1] = (((duk_uint32_t) 1) << r);
}
@@ -75763,7 +83334,7 @@ DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_in
DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
duk__bi_set_small(x, 1);
- duk__bi_set_small(t1, b);
+ duk__bi_set_small(t1, (duk_uint32_t) b);
for (;;) {
/* Loop structure ensures that we don't compute t1^2 unnecessarily
* on the final round, as that might create a bignum exceeding the
@@ -75804,10 +83375,10 @@ DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_in
*/
/* Maximum number of digits generated. */
-#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
+#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */
/* Maximum number of characters in formatted value. */
-#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
+#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */
/* Number and (minimum) size of bigints in the nc_ctx structure. */
#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
@@ -75852,7 +83423,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
duk_uint8_t *p;
duk_size_t len;
duk_small_int_t dig;
- duk_small_int_t t;
+ duk_uint32_t t;
DUK_ASSERT(radix >= 2 && radix <= 36);
@@ -75863,8 +83434,8 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
p = buf + 32;
for (;;) {
- t = x / radix;
- dig = x - t * radix;
+ t = x / (duk_uint32_t) radix;
+ dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix);
x = t;
DUK_ASSERT(dig >= 0 && dig < 36);
@@ -75944,10 +83515,10 @@ DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
"unequal gaps"));
duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
- duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
+ duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b); /* mp <- b^(e+1) */
duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
- duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
- duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
+ duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
+ duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2)); /* s <- 2 * b */
nc_ctx->unequal_gaps = 1;
} else {
/* (>= e 0) AND (not (= f (expt b (- p 1))))
@@ -75993,7 +83564,7 @@ DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
"lowest mantissa for this exponent -> "
"unequal gaps"));
- duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
+ duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2)); /* r <- (2 * b) * f */
duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, 1 - nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
duk__bi_set_small(&nc_ctx->mp, 2);
@@ -76072,7 +83643,7 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
* k <- (+ k 1)
*/
- duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
k++;
} else {
break;
@@ -76092,7 +83663,7 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
DUK__BI_PRINT("m-", &nc_ctx->mm);
duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
- duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
+ duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B); /* t2 = (* (+ r m+) B) */
if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
DUK_DDD(DUK_DDDPRINT("k is too high"));
/* r <- (* r B)
@@ -76101,11 +83672,11 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
* m- <- (* m- B)
* k <- (- k 1)
*/
- duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
if (nc_ctx->unequal_gaps) {
DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
}
k--;
} else {
@@ -76161,7 +83732,7 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
DUK__BI_PRINT("m-", &nc_ctx->mm);
/* (quotient-remainder (* r B) s) using a dummy subtraction loop */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
+ duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B); /* t1 <- (* r B) */
d = 0;
for (;;) {
if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
@@ -76175,8 +83746,8 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
DUK__BI_PRINT("r(rem)", &nc_ctx->r);
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
+ duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
+ duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
@@ -76275,7 +83846,7 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
DUK_DDD(DUK_DDDPRINT("generate finished"));
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
{
duk_uint8_t buf[2048];
duk_small_int_t i, t;
@@ -76346,7 +83917,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
(const void *) (&nc_ctx->digits[0]),
- (size_t) (sizeof(char) * nc_ctx->count));
+ (size_t) (sizeof(char) * (size_t) nc_ctx->count));
nc_ctx->digits[0] = 1; /* don't increase 'count' */
nc_ctx->k++; /* position of highest digit changed */
nc_ctx->count++; /* number of digits changed */
@@ -76375,11 +83946,11 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
- duk_context *ctx,
- duk_small_int_t radix,
- duk_small_int_t digits,
- duk_small_uint_t flags,
- duk_small_int_t neg) {
+ duk_hthread *thr,
+ duk_small_int_t radix,
+ duk_small_int_t digits,
+ duk_small_uint_t flags,
+ duk_small_int_t neg) {
duk_small_int_t k;
duk_small_int_t pos, pos_end;
duk_small_int_t expt;
@@ -76515,7 +84086,7 @@ DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
q += len;
}
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
+ duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf));
}
/*
@@ -76694,7 +84265,7 @@ DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, du
(unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
- t += expt << 20;
+ t += ((duk_uint32_t) expt) << 20;
#if 0 /* caller handles sign change */
if (negative) {
t |= 0x80000000U;
@@ -76716,7 +84287,7 @@ DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, du
* Output: [ string ]
*/
-DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
+DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
duk_double_t x;
duk_small_int_t c;
duk_small_int_t neg;
@@ -76724,8 +84295,8 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
- x = (duk_double_t) duk_require_number(ctx, -1);
- duk_pop(ctx);
+ x = (duk_double_t) duk_require_number(thr, -1);
+ duk_pop(thr);
/*
* Handle special cases (NaN, infinity, zero).
@@ -76743,15 +84314,15 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
if (c == DUK_FP_NAN) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_NAN);
return;
} else if (c == DUK_FP_INFINITE) {
if (neg) {
/* -Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY);
} else {
/* Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY);
}
return;
} else if (c == DUK_FP_ZERO) {
@@ -76785,7 +84356,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
*p++ = (duk_uint8_t) '-';
}
p += duk__dragon4_format_uint32(p, uval, radix);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
return;
}
@@ -76844,7 +84415,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
}
DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
DUK_ASSERT(count >= 1);
- DUK_MEMZERO((void *) nc_ctx->digits, count);
+ DUK_MEMZERO((void *) nc_ctx->digits, (size_t) count);
nc_ctx->count = count;
nc_ctx->k = 1; /* 0.000... */
neg = 0;
@@ -76906,7 +84477,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
*/
}
- duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
+ duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg);
}
/*
@@ -76919,8 +84490,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
* fails due to an internal error, an InternalError is thrown.
*/
-DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) {
duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
duk_double_t res;
@@ -76939,26 +84509,8 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
const duk_uint8_t *p;
duk_small_int_t ch;
- /* This seems to waste a lot of stack frame entries, but good compilers
- * will compute these as needed below. Some of these initial flags are
- * also modified in the code below, so they can't all be removed.
- */
- duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
- duk_small_int_t allow_expt = (flags & DUK_S2N_FLAG_ALLOW_EXP);
- duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
- duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
- duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
- duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
- duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
- duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
- duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
- duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
- duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
- duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
- duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
-
DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) radix, (unsigned long) flags));
DUK_ASSERT(radix >= 2 && radix <= 36);
@@ -76979,29 +84531,33 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* Automatic hex number detection (leading '0x' or '0X') and octal
* number detection (leading '0' followed by at least one octal digit)
* is done here too.
+ *
+ * Symbols are not explicitly rejected here (that's up to the caller).
+ * If a symbol were passed here, it should ultimately safely fail
+ * parsing due to a syntax error.
*/
- if (trim_white) {
+ if (flags & DUK_S2N_FLAG_TRIM_WHITE) {
/* Leading / trailing whitespace is sometimes accepted and
* sometimes not. After white space trimming, all valid input
* characters are pure ASCII.
*/
- duk_trim(ctx, -1);
+ duk_trim(thr, -1);
}
- h_str = duk_require_hstring(ctx, -1);
+ h_str = duk_require_hstring(thr, -1);
DUK_ASSERT(h_str != NULL);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
neg = 0;
ch = *p;
if (ch == (duk_small_int_t) '+') {
- if (!allow_plus) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
goto parse_fail;
}
p++;
} else if (ch == (duk_small_int_t) '-') {
- if (!allow_minus) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
goto parse_fail;
}
@@ -77009,8 +84565,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
neg = 1;
}
- ch = *p;
- if (allow_infinity && ch == (duk_small_int_t) 'I') {
+ if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity", 8) == 0) {
/* Don't check for Infinity unless the context allows it.
* 'Infinity' is a valid integer literal in e.g. base-36:
*
@@ -77018,41 +84573,49 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* 1461559270678
*/
- const duk_uint8_t *q;
-
- /* borrow literal Infinity from builtin string */
- q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
- if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
- if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
- DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
- goto parse_fail;
- } else {
- res = DUK_DOUBLE_INFINITY;
- goto negcheck_and_ret;
- }
+ if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) {
+ DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
+ goto parse_fail;
+ } else {
+ res = DUK_DOUBLE_INFINITY;
+ goto negcheck_and_ret;
}
}
+ ch = *p;
if (ch == (duk_small_int_t) '0') {
duk_small_int_t detect_radix = 0;
- ch = p[1];
- if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
+ ch = DUK_LOWERCASE_CHAR_ASCII(p[1]); /* 'x' or 'X' -> 'x' */
+ if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) {
DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
detect_radix = 16;
- allow_empty = 0; /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
- p += 2;
- } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
+#if 0
+ } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) &&
+ (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
detect_radix = 8;
- allow_empty = 1; /* interpret e.g. '09' as '0', not NaN */
+
+ /* NOTE: if this legacy octal case is added back, it has
+ * different flags and 'p' advance so this needs to be
+ * reworked.
+ */
+ flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO; /* interpret e.g. '09' as '0', not NaN */
p += 1;
+#endif
+ } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) {
+ DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent"));
+ detect_radix = 8;
+ } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) {
+ DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent"));
+ detect_radix = 2;
}
if (detect_radix > 0) {
radix = detect_radix;
- allow_expt = 0;
- allow_frac = 0;
- allow_naked_frac = 0;
- allow_empty_frac = 0;
- allow_leading_zero = 1; /* allow e.g. '0x0009' and '00077' */
+ /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
+ flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
+ DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
+ DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
+ flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO; /* allow e.g. '0x0009' and '0b00010001' */
+ p += 2;
}
}
@@ -77123,14 +84686,14 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
/* Most common cases first. */
if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
- dig = (int) ch - '0' + 0;
+ dig = (duk_small_int_t) ch - '0' + 0;
} else if (ch == (duk_small_int_t) '.') {
/* A leading digit is not required in some cases, e.g. accept ".123".
* In other cases (JSON.parse()) a leading digit is required. This
* is checked for after the loop.
*/
if (dig_frac >= 0 || dig_expt >= 0) {
- if (allow_garbage) {
+ if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
break;
} else {
@@ -77139,11 +84702,11 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
}
}
- if (!allow_frac) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) {
/* Some contexts don't allow fractions at all; this can't be a
* post-check because the state ('f' and expt) would be incorrect.
*/
- if (allow_garbage) {
+ if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
break;
} else {
@@ -77157,7 +84720,8 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
} else if (ch == (duk_small_int_t) 0) {
DUK_DDD(DUK_DDDPRINT("NUL termination"));
break;
- } else if (allow_expt && dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
+ } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) &&
+ dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
/* Note: we don't parse back exponent notation for anything else
* than radix 10, so this is not an ambiguous check (e.g. hex
* exponent values may have 'e' either as a significand digit
@@ -77192,7 +84756,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
if (dig >= radix) {
- if (allow_garbage) {
+ if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
DUK_DDD(DUK_DDDPRINT("garbage termination"));
break;
} else {
@@ -77219,8 +84783,8 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
/* XXX: join these ops (multiply-accumulate), but only if
* code footprint decreases.
*/
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
- duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
+ duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix);
+ duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig);
dig_prec++;
}
} else {
@@ -77254,7 +84818,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
/* Leading zero. */
if (dig_lzero > 0 && dig_whole > 1) {
- if (!allow_leading_zero) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
goto parse_fail;
}
@@ -77269,14 +84833,14 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
goto parse_fail;
} else if (dig_frac > 0) {
/* ".123" */
- if (!allow_naked_frac) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
"leading integer digit(s)"));
goto parse_fail;
}
} else {
/* empty ("") is allowed in some formats (e.g. Number(''), as zero */
- if (!allow_empty) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
goto parse_fail;
}
@@ -77284,7 +84848,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
} else {
if (dig_frac == 0) {
/* "123." is allowed in some formats */
- if (!allow_empty_frac) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
goto parse_fail;
}
@@ -77302,7 +84866,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
*/
if (dig_expt == 0) {
- if (!allow_garbage) {
+ if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) {
DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
goto parse_fail;
}
@@ -77342,7 +84906,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* have enough (apparent) precision to work with.
*/
DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
- duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1);
DUK__BI_PRINT("f", &nc_ctx->f);
expt--;
dig_prec++;
@@ -77417,6 +84981,10 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
/*
* Convert binary digits into an IEEE double. Need to handle
* denormals and rounding correctly.
+ *
+ * Some call sites currently assume the result is always a
+ * non-fastint double. If this is changed, check all call
+ * sites.
*/
duk__dragon4_ctx_to_double(nc_ctx, &res);
@@ -77426,15 +84994,15 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
if (neg) {
res = -res;
}
- duk_pop(ctx);
- duk_push_number(ctx, (double) res);
- DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ duk_pop(thr);
+ duk_push_number(thr, (double) res);
+ DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
return;
parse_fail:
DUK_DDD(DUK_DDDPRINT("parse failed"));
- duk_pop(ctx);
- duk_push_nan(ctx);
+ duk_pop(thr);
+ duk_push_nan(thr);
return;
parse_explimit_error:
@@ -77442,7 +85010,19 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
DUK_ERROR_RANGE(thr, "exponent too large");
return;
}
-#line 1 "duk_regexp_compiler.c"
+
+/* automatic undefs */
+#undef DUK__BI_MAX_PARTS
+#undef DUK__BI_PRINT
+#undef DUK__DIGITCHAR
+#undef DUK__DRAGON4_OUTPUT_PREINC
+#undef DUK__IEEE_DOUBLE_EXP_BIAS
+#undef DUK__IEEE_DOUBLE_EXP_MIN
+#undef DUK__MAX_FORMATTED_LENGTH
+#undef DUK__MAX_OUTPUT_DIGITS
+#undef DUK__NO_EXP
+#undef DUK__NUMCONV_CTX_BIGINTS_SIZE
+#undef DUK__NUMCONV_CTX_NUM_BIGINTS
/*
* Regexp compilation.
*
@@ -77463,9 +85043,9 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* size when emitting bytecode (slower).
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
/*
* Helper macros
@@ -77473,7 +85053,6 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
#define DUK__RE_INITIAL_BUFSIZE 64
-#undef DUK__RE_BUFLEN
#define DUK__RE_BUFLEN(re_ctx) \
DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
@@ -77532,35 +85111,50 @@ DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t
duk_small_int_t len;
len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
- DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
+ DUK_ASSERT(len >= 0);
+ DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len);
return (duk_uint32_t) len;
}
-DUK_LOCAL duk_uint32_t duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
- duk_small_int_t len;
+DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
+ DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x);
+}
- len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
- DUK_BW_WRITE_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, buf, len);
- return (duk_uint32_t) len;
+DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk__append_u32(re_ctx, x);
+#else
+ DUK_ASSERT(x <= 0x7fU);
+ DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x);
+#endif
}
+#if 0
+DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) {
+ DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y);
+}
+#endif
+
DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
}
+DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) {
+ DUK_ASSERT(reop <= 0x7fU);
+ (void) duk__append_7bit(re_ctx, reop);
+}
+
#if 0 /* unused */
-DUK_LOCAL duk_uint32_t duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
- return duk__append_u32(re_ctx, duk__encode_i32(x));
+DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
+ duk__append_u32(re_ctx, duk__encode_i32(x));
}
#endif
/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
/* Call sites don't need the result length so it's not accumulated. */
- while (count > 0) {
- (void) duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
- count--;
+ while (count-- > 0) {
+ duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
}
}
@@ -77590,17 +85184,66 @@ DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_
* variable length UTF-8 encoding. See doc/regexp.rst for discussion.
*/
DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
- duk_small_int_t len;
-
- /* XXX: solve into closed form (smaller code) */
-
+#if 0
+ /* Iterative solution. */
if (skip < 0) {
+ duk_small_int_t len;
/* two encoding attempts suffices */
len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
skip -= (duk_int32_t) len;
}
+#endif
+
+#if defined(DUK_USE_PREFER_SIZE)
+ /* Closed form solution, this produces smallest code.
+ * See re_neg_jump_offset (closed2).
+ */
+ if (skip < 0) {
+ skip--;
+ if (skip < -0x3fL) {
+ skip--;
+ }
+ if (skip < -0x3ffL) {
+ skip--;
+ }
+ if (skip < -0x7fffL) {
+ skip--;
+ }
+ if (skip < -0xfffffL) {
+ skip--;
+ }
+ if (skip < -0x1ffffffL) {
+ skip--;
+ }
+ if (skip < -0x3fffffffL) {
+ skip--;
+ }
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ /* Closed form solution, this produces fastest code.
+ * See re_neg_jump_offset (closed1).
+ */
+ if (skip < 0) {
+ if (skip >= -0x3eL) {
+ skip -= 1;
+ } else if (skip >= -0x3fdL) {
+ skip -= 2;
+ } else if (skip >= -0x7ffcL) {
+ skip -= 3;
+ } else if (skip >= -0xffffbL) {
+ skip -= 4;
+ } else if (skip >= -0x1fffffaL) {
+ skip -= 5;
+ } else if (skip >= -0x3ffffff9L) {
+ skip -= 6;
+ } else {
+ skip -= 7;
+ }
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+
return duk__insert_i32(re_ctx, offset, skip);
}
@@ -77611,71 +85254,213 @@ DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_
/*
* duk_re_range_callback for generating character class ranges.
*
- * When ignoreCase is false, the range is simply emitted as is.
- * We don't, for instance, eliminate duplicates or overlapping
- * ranges in a character class.
- *
- * When ignoreCase is true, the range needs to be normalized through
- * canonicalization. Unfortunately a canonicalized version of a
- * continuous range is not necessarily continuous (e.g. [x-{] is
- * continuous but [X-{] is not). The current algorithm creates the
- * canonicalized range(s) space efficiently at the cost of compile
- * time execution time (see doc/regexp.rst for discussion).
- *
- * Note that the ctx->nranges is a context-wide temporary value
- * (this is OK because there cannot be multiple character classes
- * being parsed simultaneously).
- */
+ * When ignoreCase is false, the range is simply emitted as is. We don't,
+ * for instance, eliminate duplicates or overlapping ranges in a character
+ * class.
+ *
+ * When ignoreCase is true but the 'direct' flag is set, the caller knows
+ * that the range canonicalizes to itself for case insensitive matching,
+ * so the range is emitted as is. This is mainly useful for built-in ranges
+ * like \W.
+ *
+ * Otherwise, when ignoreCase is true, the range needs to be normalized
+ * through canonicalization. Unfortunately a canonicalized version of a
+ * continuous range is not necessarily continuous (e.g. [x-{] is continuous
+ * but [X-{] is not). As a result, a single input range may expand to a lot
+ * of output ranges. The current algorithm creates the canonicalized ranges
+ * footprint efficiently at the cost of compile time execution time; see
+ * doc/regexp.rst for discussion, and some more details below.
+ *
+ * Note that the ctx->nranges is a context-wide temporary value. This is OK
+ * because there cannot be multiple character classes being parsed
+ * simultaneously.
+ *
+ * More detail on canonicalization:
+ *
+ * Conceptually, a range is canonicalized by scanning the entire range,
+ * normalizing each codepoint by converting it to uppercase, and generating
+ * a set of result ranges.
+ *
+ * Ideally a minimal set of output ranges would be emitted by merging all
+ * possible ranges even if they're emitted out of sequence. Because the
+ * input string is also case normalized during matching, some codepoints
+ * never occur at runtime; these "don't care" codepoints can be included or
+ * excluded from ranges when merging/optimizing ranges.
+ *
+ * The current algorithm does not do optimal range merging. Rather, output
+ * codepoints are generated in sequence, and when the output codepoints are
+ * continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a
+ * range as possible. A small canonicalization bitmap is used to reduce
+ * actual codepoint canonicalizations which are quite slow at present. The
+ * bitmap provides a "codepoint block is continuous with respect to
+ * canonicalization" for N-codepoint blocks. This allows blocks to be
+ * skipped quickly.
+ *
+ * There are a number of shortcomings and future work here:
+ *
+ * - Individual codepoint normalizations are slow because they involve
+ * walking bit-packed rules without a lookup index.
+ *
+ * - The conceptual algorithm needs to canonicalize every codepoint in the
+ * input range to figure out the output range(s). Even with the small
+ * canonicalization bitmap the algorithm runs quite slowly for worst case
+ * inputs. There are many data structure alternatives to improve this.
+ *
+ * - While the current algorithm generates maximal output ranges when the
+ * output codepoints are emitted linearly, output ranges are not sorted or
+ * merged otherwise. In the worst case a lot of ranges are emitted when
+ * most of the ranges could be merged. In this process one could take
+ * advantage of "don't care" codepoints, which are never matched against at
+ * runtime due to canonicalization of input codepoints before comparison,
+ * to merge otherwise discontinuous output ranges.
+ *
+ * - The runtime data structure is just a linear list of ranges to match
+ * against. This can be quite slow if there are a lot of output ranges.
+ * There are various ways to make matching against the ranges faster,
+ * e.g. sorting the ranges and using a binary search; skip lists; tree
+ * based representations; full or approximate codepoint bitmaps, etc.
+ *
+ * - Only BMP is supported, codepoints above BMP are assumed to canonicalize
+ * to themselves. For now this is one place where we don't want to
+ * support chars outside the BMP, because the exhaustive search would be
+ * massively larger. It would be possible to support non-BMP with a
+ * different algorithm, or perhaps doing case normalization only at match
+ * time.
+ */
+
+DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) {
+ DUK_ASSERT(r2 >= r1);
+ duk__append_u32(re_ctx, (duk_uint32_t) r1);
+ duk__append_u32(re_ctx, (duk_uint32_t) r2);
+ re_ctx->nranges++;
+}
+
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/* Find next canonicalization discontinuity (conservative estimate) starting
+ * from 'start', not exceeding 'end'. If continuity is fine up to 'end'
+ * inclusive, returns end. Minimum possible return value is start.
+ */
+DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
+ duk_uint_t start_blk;
+ duk_uint_t end_blk;
+ duk_uint_t blk;
+ duk_uint_t offset;
+ duk_uint8_t mask;
+
+ /* Inclusive block range. */
+ DUK_ASSERT(start >= 0);
+ DUK_ASSERT(end >= 0);
+ DUK_ASSERT(end >= start);
+ start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT);
+ end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT);
+
+ for (blk = start_blk; blk <= end_blk; blk++) {
+ offset = blk >> 3;
+ mask = 1U << (blk & 0x07);
+ if (offset >= sizeof(duk_unicode_re_canon_bitmap)) {
+ /* Reached non-BMP range which is assumed continuous. */
+ return end;
+ }
+ DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap));
+ if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) {
+ /* Block is discontinuous, continuity is guaranteed
+ * only up to end of previous block (+1 for exclusive
+ * return value => start of current block). Start
+ * block requires special handling.
+ */
+ if (blk > start_blk) {
+ return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT);
+ } else {
+ return start;
+ }
+ }
+ }
+ DUK_ASSERT(blk == end_blk + 1); /* Reached end block which is continuous. */
+ return end;
+}
+#else /* DUK_USE_REGEXP_CANON_BITMAP */
+DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
+ DUK_ASSERT(start >= 0);
+ DUK_ASSERT(end >= 0);
+ DUK_ASSERT(end >= start);
+ if (start >= 0x10000) {
+ /* Even without the bitmap, treat non-BMP as continuous. */
+ return end;
+ }
+ return start;
+}
+#endif /* DUK_USE_REGEXP_CANON_BITMAP */
-DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
+DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
+ duk_codepoint_t r_start;
+ duk_codepoint_t r_end;
+ duk_codepoint_t i;
+ duk_codepoint_t t;
+ duk_codepoint_t r_disc;
- DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
+ DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
(void *) re_ctx, (long) r1, (long) r2, (long) direct));
- if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
- /*
- * Canonicalize a range, generating result ranges as necessary.
- * Needs to exhaustively scan the entire range (at most 65536
- * code points). If 'direct' is set, caller (lexer) has ensured
- * that the range is already canonicalization compatible (this
- * is used to avoid unnecessary canonicalization of built-in
- * ranges like \W, which are not affected by canonicalization).
- *
- * NOTE: here is one place where we don't want to support chars
- * outside the BMP, because the exhaustive search would be
- * massively larger.
- */
+ DUK_ASSERT(r2 >= r1); /* SyntaxError for out of order range. */
+
+ if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) {
+ DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]", (long) r1, (long) r2));
+ duk__regexp_emit_range(re_ctx, r1, r2);
+ return;
+ }
- duk_codepoint_t i;
- duk_codepoint_t t;
- duk_codepoint_t r_start, r_end;
+ DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]", (long) r1, (long) r2));
- r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
- r_end = r_start;
- for (i = r1 + 1; i <= r2; i++) {
- t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
- if (t == r_end + 1) {
- r_end = t;
- } else {
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- r_start = t;
- r_end = t;
- }
- }
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- } else {
- DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
- duk__append_u32(re_ctx, (duk_uint32_t) r1);
- duk__append_u32(re_ctx, (duk_uint32_t) r2);
- re_ctx->nranges++;
+ r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
+ r_end = r_start;
+
+ for (i = r1 + 1; i <= r2;) {
+ /* Input codepoint space processed up to i-1, and
+ * current range in r_{start,end} is up-to-date
+ * (inclusive) and may either break or continue.
+ */
+ r_disc = duk__re_canon_next_discontinuity(i, r2);
+ DUK_ASSERT(r_disc >= i);
+ DUK_ASSERT(r_disc <= r2);
+
+ r_end += r_disc - i; /* May be zero. */
+ t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc);
+ if (t == r_end + 1) {
+ /* Not actually a discontinuity, continue range
+ * to r_disc and recheck.
+ */
+ r_end = t;
+ } else {
+ duk__regexp_emit_range(re_ctx, r_start, r_end);
+ r_start = t;
+ r_end = t;
+ }
+ i = r_disc + 1; /* Guarantees progress. */
}
+ duk__regexp_emit_range(re_ctx, r_start, r_end);
+
+#if 0 /* Exhaustive search, very slow. */
+ r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
+ r_end = r_start;
+ for (i = r1 + 1; i <= r2; i++) {
+ t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
+ if (t == r_end + 1) {
+ r_end = t;
+ } else {
+ DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
+ duk__append_u32(re_ctx, (duk_uint32_t) r_start);
+ duk__append_u32(re_ctx, (duk_uint32_t) r_end);
+ re_ctx->nranges++;
+ r_start = t;
+ r_end = t;
+ }
+ }
+ DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
+ duk__append_u32(re_ctx, (duk_uint32_t) r_start);
+ duk__append_u32(re_ctx, (duk_uint32_t) r_end);
+ re_ctx->nranges++;
+#endif
}
/*
@@ -77728,6 +85513,28 @@ DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_code
* as complex though.
*/
+DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = {
+ duk_unicode_re_ranges_digit,
+ duk_unicode_re_ranges_white,
+ duk_unicode_re_ranges_wordchar
+};
+DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = {
+ sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)),
+ sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)),
+ sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t))
+};
+
+DUK_LOCAL void duk__append_range_atom_matcher(duk_re_compiler_ctx *re_ctx, duk_small_uint_t re_op, const duk_uint16_t *ranges, duk_small_uint_t count) {
+#if 0
+ DUK_ASSERT(re_op <= 0x7fUL);
+ DUK_ASSERT(count <= 0x7fUL);
+ duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count);
+#endif
+ duk__append_reop(re_ctx, re_op);
+ duk__append_7bit(re_ctx, count);
+ duk__append_u16_list(re_ctx, ranges, count * 2);
+}
+
DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
duk_int32_t atom_char_length = 0; /* negative -> complex atom */
@@ -77788,24 +85595,24 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
duk_uint32_t offset;
DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
+ offset = (duk_uint32_t) unpatched_disjunction_jump;
offset += duk__insert_jump_offset(re_ctx,
offset,
(duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
/* offset is now target of the pending split (right after jump) */
duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
+ (duk_uint32_t) unpatched_disjunction_split,
+ (duk_int32_t) offset - unpatched_disjunction_split);
}
/* add a new pending split to the beginning of the entire disjunction */
(void) duk__insert_u32(re_ctx,
entry_offset,
DUK_REOP_SPLIT1); /* prefer direct execution */
- unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
+ unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1); /* +1 for opcode */
/* add a new pending match jump for latest finished alternative */
- duk__append_u32(re_ctx, DUK_REOP_JUMP);
+ duk__append_reop(re_ctx, DUK_REOP_JUMP);
unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
/* 'taint' result as complex */
@@ -77848,15 +85655,15 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
}
}
- duk__append_u32(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
- atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
+ duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
+ atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset);
- offset = atom_start_offset;
+ offset = (duk_uint32_t) atom_start_offset;
if (re_ctx->curr_token.greedy) {
offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
offset += duk__insert_u32(re_ctx, offset, qmin);
offset += duk__insert_u32(re_ctx, offset, qmax);
- offset += duk__insert_u32(re_ctx, offset, atom_char_length);
+ offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length);
offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
} else {
offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
@@ -77896,9 +85703,9 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
(long) atom_start_captures, (long) re_ctx->captures));
/* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
- duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE);
} else {
DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
(long) atom_start_captures));
@@ -77910,7 +85717,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
tmp_qmin = re_ctx->curr_token.qmin;
tmp_qmax = re_ctx->curr_token.qmax;
while (tmp_qmin > 0) {
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
tmp_qmin--;
if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
tmp_qmax--;
@@ -77926,14 +85733,14 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
/* Special case: original qmin was zero so there is nothing
* to repeat. Emit an atom copy but jump over it here.
*/
- duk__append_u32(re_ctx, DUK_REOP_JUMP);
+ duk__append_reop(re_ctx, DUK_REOP_JUMP);
duk__append_jump_offset(re_ctx, atom_code_length);
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
}
if (re_ctx->curr_token.greedy) {
- duk__append_u32(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
+ duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
} else {
- duk__append_u32(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
+ duk__append_reop(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
}
duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
} else {
@@ -77955,7 +85762,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
*/
duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
while (tmp_qmax > 0) {
- duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
+ duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
if (re_ctx->curr_token.greedy) {
duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
} else {
@@ -77969,7 +85776,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
}
/* remove the original 'template' atom */
- duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
}
/* 'taint' result as complex */
@@ -77977,19 +85784,19 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
break;
}
case DUK_RETOK_ASSERT_START: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_START);
+ duk__append_reop(re_ctx, DUK_REOP_ASSERT_START);
break;
}
case DUK_RETOK_ASSERT_END: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_END);
+ duk__append_reop(re_ctx, DUK_REOP_ASSERT_END);
break;
}
case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
+ duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
break;
}
case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
+ duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
break;
}
case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
@@ -78000,7 +85807,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
duk__parse_disjunction(re_ctx, 0, &tmp_disj);
- duk__append_u32(re_ctx, DUK_REOP_MATCH);
+ duk__append_reop(re_ctx, DUK_REOP_MATCH);
(void) duk__insert_u32(re_ctx, offset, opcode);
(void) duk__insert_jump_offset(re_ctx,
@@ -78016,57 +85823,58 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
case DUK_RETOK_ATOM_PERIOD: {
new_atom_char_length = 1;
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_PERIOD);
+ duk__append_reop(re_ctx, DUK_REOP_PERIOD);
break;
}
case DUK_RETOK_ATOM_CHAR: {
/* Note: successive characters could be joined into string matches
* but this is not trivial (consider e.g. '/xyz+/); see docs for
* more discussion.
+ *
+ * No support for \u{H+} yet. While only BMP Unicode escapes are
+ * supported for RegExps at present, 'ch' may still be a non-BMP
+ * codepoint if it is decoded straight from source text UTF-8.
+ * There's no non-BMP support yet so this is handled simply by
+ * matching the non-BMP character (which is custom behavior).
*/
duk_uint32_t ch;
new_atom_char_length = 1;
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_CHAR);
+ duk__append_reop(re_ctx, DUK_REOP_CHAR);
ch = re_ctx->curr_token.num;
if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
- ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
+ ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch);
}
duk__append_u32(re_ctx, ch);
break;
}
case DUK_RETOK_ATOM_DIGIT:
- case DUK_RETOK_ATOM_NOT_DIGIT: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_DIGIT) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_digit, sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
- break;
- }
+ case DUK_RETOK_ATOM_NOT_DIGIT:
case DUK_RETOK_ATOM_WHITE:
- case DUK_RETOK_ATOM_NOT_WHITE: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_WHITE) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_white, sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
- break;
- }
+ case DUK_RETOK_ATOM_NOT_WHITE:
case DUK_RETOK_ATOM_WORD_CHAR:
case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
+ duk_small_uint_t re_op;
+ duk_small_uint_t idx;
+
new_atom_char_length = 1;
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_WORD_CHAR) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_wordchar, sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
+
+ DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0);
+ DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0);
+ DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0);
+ DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0);
+ DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0);
+ DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0);
+ re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES;
+
+ DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2);
+ DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4);
+ idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U);
+ DUK_ASSERT(idx <= 2U); /* Assume continuous token numbers; also checks negative underflow. */
+
+ duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]);
break;
}
case DUK_RETOK_ATOM_BACKREFERENCE: {
@@ -78076,7 +85884,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
}
new_atom_char_length = -1; /* mark as complex */
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_BACKREFERENCE);
+ duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE);
duk__append_u32(re_ctx, backref);
break;
}
@@ -78086,10 +85894,10 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
new_atom_char_length = -1; /* mark as complex (capture handling) */
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
cap = ++re_ctx->captures;
- duk__append_u32(re_ctx, DUK_REOP_SAVE);
+ duk__append_reop(re_ctx, DUK_REOP_SAVE);
duk__append_u32(re_ctx, cap * 2);
duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
- duk__append_u32(re_ctx, DUK_REOP_SAVE);
+ duk__append_reop(re_ctx, DUK_REOP_SAVE);
duk__append_u32(re_ctx, cap * 2 + 1);
break;
}
@@ -78132,14 +85940,14 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
/* insert ranges instruction, range count patched in later */
new_atom_char_length = 1;
new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
+ duk__append_reop(re_ctx,
+ (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
+ DUK_REOP_RANGES : DUK_REOP_INVRANGES);
offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
/* parse ranges until character class ends */
re_ctx->nranges = 0; /* note: ctx-wide temporary */
- duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
+ duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx);
/* insert range count */
duk__insert_u32(re_ctx, offset, re_ctx->nranges);
@@ -78185,14 +85993,14 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
duk_uint32_t offset;
DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
+ offset = (duk_uint32_t) unpatched_disjunction_jump;
offset += duk__insert_jump_offset(re_ctx,
offset,
(duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
/* offset is now target of the pending split (right after jump) */
duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
+ (duk_uint32_t) unpatched_disjunction_split,
+ (duk_int32_t) offset - unpatched_disjunction_split);
}
#if 0
@@ -78221,37 +86029,37 @@ DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h)
while (p < p_end) {
duk_uint8_t c = *p++;
- switch ((int) c) {
- case (int) 'g': {
+ switch (c) {
+ case (duk_uint8_t) 'g': {
if (flags & DUK_RE_FLAG_GLOBAL) {
- goto error;
+ goto flags_error;
}
flags |= DUK_RE_FLAG_GLOBAL;
break;
}
- case (int) 'i': {
+ case (duk_uint8_t) 'i': {
if (flags & DUK_RE_FLAG_IGNORE_CASE) {
- goto error;
+ goto flags_error;
}
flags |= DUK_RE_FLAG_IGNORE_CASE;
break;
}
- case (int) 'm': {
+ case (duk_uint8_t) 'm': {
if (flags & DUK_RE_FLAG_MULTILINE) {
- goto error;
+ goto flags_error;
}
flags |= DUK_RE_FLAG_MULTILINE;
break;
}
default: {
- goto error;
+ goto flags_error;
}
}
}
return flags;
- error:
+ flags_error:
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
return 0; /* never here */
}
@@ -78277,7 +86085,6 @@ DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h)
*/
DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h;
const duk_uint8_t *p;
duk_bufwriter_ctx bw_alloc;
@@ -78286,14 +86093,12 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
duk_size_t i, n;
duk_uint_fast8_t c_prev, c;
- h = duk_get_hstring(ctx, idx_pattern);
- DUK_ASSERT(h != NULL);
+ h = duk_known_hstring(thr, idx_pattern);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
if (n == 0) {
- /* return '(?:)' */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP);
+ duk_push_string(thr, "(?:)");
return;
}
@@ -78320,7 +86125,9 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
}
DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
- duk_to_string(ctx, -1); /* -> [ ... escaped_source ] */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
+
+ /* [ ... escaped_source ] */
}
/*
@@ -78339,7 +86146,6 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
*/
DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_re_compiler_ctx re_ctx;
duk_lexer_point lex_point;
duk_hstring *h_pattern;
@@ -78347,15 +86153,14 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
duk__re_disjunction_info ign_disj;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
/*
* Args validation
*/
/* TypeError if fails */
- h_pattern = duk_require_hstring(ctx, -2);
- h_flags = duk_require_hstring(ctx, -1);
+ h_pattern = duk_require_hstring_notsymbol(thr, -2);
+ h_flags = duk_require_hstring_notsymbol(thr, -1);
/*
* Create normalized 'source' property (E5 Section 15.10.3).
@@ -78402,12 +86207,12 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("starting regexp compilation"));
- duk__append_u32(&re_ctx, DUK_REOP_SAVE);
- duk__append_u32(&re_ctx, 0);
+ duk__append_reop(&re_ctx, DUK_REOP_SAVE);
+ duk__append_7bit(&re_ctx, 0);
duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
- duk__append_u32(&re_ctx, DUK_REOP_SAVE);
- duk__append_u32(&re_ctx, 1);
- duk__append_u32(&re_ctx, DUK_REOP_MATCH);
+ duk__append_reop(&re_ctx, DUK_REOP_SAVE);
+ duk__append_7bit(&re_ctx, 1);
+ duk__append_reop(&re_ctx, DUK_REOP_MATCH);
/*
* Check for invalid backreferences; note that it is NOT an error
@@ -78433,7 +86238,7 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
/* [ ... pattern flags escaped_source buffer ] */
DUK_BW_COMPACT(thr, &re_ctx.bw);
- duk_to_string(ctx, -1); /* coerce to string */
+ (void) duk_buffer_to_string(thr, -1); /* Safe because flags is at most 7 bit. */
/* [ ... pattern flags escaped_source bytecode ] */
@@ -78441,11 +86246,11 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
* Finalize stack
*/
- duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
- duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
+ duk_remove(thr, -4); /* -> [ ... flags escaped_source bytecode ] */
+ duk_remove(thr, -3); /* -> [ ... escaped_source bytecode ] */
DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
- (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
+ (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2)));
}
/*
@@ -78459,63 +86264,47 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
*/
DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h;
- duk_hstring *h_bc;
- duk_small_int_t re_flags;
-
- /* [ ... escape_source bytecode ] */
-
- h_bc = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_bc != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1); /* always at least the header */
- DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
- DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80); /* flags always encodes to 1 byte */
- re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
/* [ ... escaped_source bytecode ] */
- duk_push_object(ctx);
- h = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
- duk_insert(ctx, -3);
+ duk_push_object(thr);
+ h = duk_known_hobject(thr, -1);
+ duk_insert(thr, -3);
/* [ ... regexp_object escaped_source bytecode ] */
DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
/* [ ... regexp_object escaped_source ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ ... regexp_object ] */
-
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE);
+ /* In ES2015 .source, and the .global, .multiline, etc flags are
+ * inherited getters. Store the escaped source as an internal
+ * property for the getter.
+ */
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE);
+ /* [ ... regexp_object ] */
- duk_push_int(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
+ duk_push_int(thr, 0);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
/* [ ... regexp_object ] */
}
-#undef DUK__RE_BUFLEN
-
#else /* DUK_USE_REGEXP_SUPPORT */
/* regexp support disabled */
#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_regexp_executor.c"
+
+/* automatic undefs */
+#undef DUK__RE_BUFLEN
+#undef DUK__RE_INITIAL_BUFSIZE
/*
* Regexp executor.
*
@@ -78532,9 +86321,9 @@ DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
* This also requires a regexp bytecode change.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
/*
* Helpers for UTF-8 handling
@@ -78585,7 +86374,7 @@ DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uin
return p;
fail:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
return NULL; /* never here */
}
@@ -78616,7 +86405,7 @@ DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8
return p;
fail:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_ERROR_INTERNAL(thr);
return NULL; /* never here */
}
@@ -78626,10 +86415,15 @@ DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8
/* Get a (possibly canonicalized) input character from current sp. The input
* itself is never modified, and captures always record non-canonicalized
- * characters even in case-insensitive matching.
+ * characters even in case-insensitive matching. Return <0 if out of input.
*/
DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
- duk_codepoint_t res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
+ duk_codepoint_t res;
+
+ if (*sp >= re_ctx->input_end) {
+ return -1;
+ }
+ res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
}
@@ -78672,7 +86466,15 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
}
re_ctx->steps_count++;
+ /* Opcodes are at most 7 bits now so they encode to one byte. If this
+ * were not the case or 'pc' is invalid here (due to a bug etc) we'll
+ * still fail safely through the switch default case.
+ */
+ DUK_ASSERT(pc[0] <= 0x7fU);
+#if 0
op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
+#endif
+ op = *pc++;
DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
(long) re_ctx->recursion_depth,
@@ -78704,10 +86506,17 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
- if (sp >= re_ctx->input_end) {
+ c2 = duk__inp_get_cp(re_ctx, &sp);
+ /* No need to check for c2 < 0 (end of input): because c1 >= 0, it
+ * will fail the match below automatically and cause goto fail.
+ */
+#if 0
+ if (c2 < 0) {
goto fail;
}
- c2 = duk__inp_get_cp(re_ctx, &sp);
+#endif
+ DUK_ASSERT(c1 >= 0);
+
DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
if (c1 != c2) {
goto fail;
@@ -78717,11 +86526,8 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
case DUK_REOP_PERIOD: {
duk_codepoint_t c;
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
c = duk__inp_get_cp(re_ctx, &sp);
- if (duk_unicode_is_line_terminator(c)) {
+ if (c < 0 || duk_unicode_is_line_terminator(c)) {
/* E5 Sections 15.10.2.8, 7.3 */
goto fail;
}
@@ -78734,10 +86540,10 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
duk_small_int_t match;
n = duk__bc_get_u32(re_ctx, &pc);
- if (sp >= re_ctx->input_end) {
+ c = duk__inp_get_cp(re_ctx, &sp);
+ if (c < 0) {
goto fail;
}
- c = duk__inp_get_cp(re_ctx, &sp);
match = 0;
while (n) {
@@ -78788,14 +86594,14 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
duk_codepoint_t c;
const duk_uint8_t *tmp_sp;
- if (sp >= re_ctx->input_end) {
+ tmp_sp = sp;
+ c = duk__inp_get_cp(re_ctx, &tmp_sp);
+ if (c < 0) {
break;
}
if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
goto fail;
}
- tmp_sp = sp;
- c = duk__inp_get_cp(re_ctx, &tmp_sp);
if (duk_unicode_is_line_terminator(c)) {
/* E5 Sections 15.10.2.8, 7.3 */
break;
@@ -78978,7 +86784,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
* slightly higher code footprint.
*/
duk_uint32_t idx_start, idx_count;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
duk_uint32_t idx_end, idx;
#endif
duk_uint8_t **range_save;
@@ -78998,12 +86804,12 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
}
DUK_ASSERT(idx_count > 0);
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- range_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
- sizeof(duk_uint8_t *) * idx_count);
+ duk_require_stack(re_ctx->thr, 1);
+ range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
+ sizeof(duk_uint8_t *) * idx_count);
DUK_ASSERT(range_save != NULL);
DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
idx_end = idx_start + idx_count;
for (idx = idx_start; idx < idx_end; idx++) {
re_ctx->saved[idx] = NULL;
@@ -79018,7 +86824,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
(long) idx_start, (long) (idx_start + idx_count - 1),
(long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
sp = sub_sp;
goto match;
}
@@ -79030,7 +86836,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
(const void *) range_save,
sizeof(duk_uint8_t *) * idx_count);
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
goto fail;
}
case DUK_REOP_LOOKPOS:
@@ -79045,7 +86851,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
* The temporary save buffer is pushed on to the valstack to handle
* errors correctly. Each lookahead causes a C recursion and pushes
* more stuff on the value stack. If the C recursion limit is less
- * than the value stack spare, there is no need to check the stack.
+ * than the value stack slack, there is no need to check the stack.
* We do so regardless, just in case.
*/
@@ -79055,9 +86861,9 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_ASSERT(re_ctx->nsaved > 0);
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- full_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
- sizeof(duk_uint8_t *) * re_ctx->nsaved);
+ duk_require_stack(re_ctx->thr, 1);
+ full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
+ sizeof(duk_uint8_t *) * re_ctx->nsaved);
DUK_ASSERT(full_save != NULL);
DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
@@ -79075,7 +86881,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
if (sub_sp) {
/* match: keep saves */
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
sp = sub_sp;
goto match;
}
@@ -79087,7 +86893,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_MEMCPY((void *) re_ctx->saved,
(const void *) full_save,
sizeof(duk_uint8_t *) * re_ctx->nsaved);
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
goto fail;
}
case DUK_REOP_BACKREFERENCE: {
@@ -79132,11 +86938,17 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
* valid compiled regexps cannot write a saved[] entry
* which points to outside the string.
*/
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
c1 = duk__inp_get_cp(re_ctx, &p);
+ DUK_ASSERT(c1 >= 0);
c2 = duk__inp_get_cp(re_ctx, &sp);
+ /* No need for an explicit c2 < 0 check: because c1 >= 0,
+ * the comparison will always fail if c2 < 0.
+ */
+#if 0
+ if (c2 < 0) {
+ goto fail;
+ }
+#endif
if (c1 != c2) {
goto fail;
}
@@ -79159,7 +86971,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
return NULL;
internal_error:
- DUK_ERROR_INTERNAL_DEFMSG(re_ctx->thr);
+ DUK_ERROR_INTERNAL(re_ctx->thr);
return NULL; /* never here */
}
@@ -79176,7 +86988,6 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
*/
DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
- duk_context *ctx = (duk_context *) thr;
duk_re_matcher_ctx re_ctx;
duk_hobject *h_regexp;
duk_hstring *h_bytecode;
@@ -79191,11 +87002,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
duk_uint32_t char_offset;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Regexp instance check, bytecode check, input coercion.
@@ -79204,17 +87014,16 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
*/
/* TypeError if wrong; class check, see E5 Section 15.10.6 */
- h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
+ h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP);
DUK_ASSERT(h_regexp != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
DUK_UNREF(h_regexp);
- duk_to_string(ctx, -1);
- h_input = duk_get_hstring(ctx, -1);
+ h_input = duk_to_hstring(thr, -1);
DUK_ASSERT(h_input != NULL);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
- h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
+ h_bytecode = duk_require_hstring(thr, -1); /* no regexp instance should exist without a non-configurable bytecode property */
DUK_ASSERT(h_bytecode != NULL);
/*
@@ -79247,14 +87056,14 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
re_ctx.bytecode = pc;
DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
- global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
+ global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
DUK_ASSERT(re_ctx.nsaved >= 2);
DUK_ASSERT((re_ctx.nsaved % 2) == 0);
- p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
+ p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */
DUK_UNREF(p_buf);
- re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
+ re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL);
DUK_ASSERT(re_ctx.saved != NULL);
/* [ ... re_obj input bc saved_buf ] */
@@ -79292,10 +87101,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
/* [ ... re_obj input bc saved_buf ] */
- duk_get_prop_stridx(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
- (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
- d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
+ (void) duk_to_int(thr, -1); /* ToInteger(lastIndex) */
+ d = duk_get_number(thr, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
+ duk_pop_nodecref_unsafe(thr);
if (global) {
if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
@@ -79314,6 +87123,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
char_offset = (duk_uint32_t) 0;
}
+ DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
/*
@@ -79331,7 +87141,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_ASSERT_DISABLE(char_offset >= 0);
DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
- /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
+ /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */
DUK_ASSERT(re_ctx.recursion_depth == 0);
DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
@@ -79346,7 +87156,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
*
* - Clearing saved[] is not necessary because backtracking does it
*
- * - Backtracking also rewinds ctx.recursion back to zero, unless an
+ * - Backtracking also rewinds re_ctx.recursion back to zero, unless an
* internal/limit error occurs (which causes a longjmp())
*
* - If we supported anchored matches, we would break out here
@@ -79402,7 +87212,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
/* [ ... re_obj input bc saved_buf ] */
if (match) {
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
duk_hobject *h_res;
#endif
duk_uint32_t char_end_offset = 0;
@@ -79417,10 +87227,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
* objects are usually short lived.
*/
- duk_push_array(ctx);
+ duk_push_array(thr);
-#ifdef DUK_USE_ASSERTIONS
- h_res = duk_require_hobject(ctx, -1);
+#if defined(DUK_USE_ASSERTIONS)
+ h_res = duk_require_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
@@ -79428,40 +87238,35 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_push_u32(ctx, char_offset);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INDEX);
+ duk_push_u32(thr, char_offset);
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX);
- duk_dup(ctx, -4);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INPUT);
+ duk_dup_m4(thr);
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT);
for (i = 0; i < re_ctx.nsaved; i += 2) {
/* Captures which are undefined have NULL pointers and are returned
* as 'undefined'. The same is done when saved[] pointers are insane
* (this should, of course, never happen in practice).
*/
- if (re_ctx.saved[i] && re_ctx.saved[i+1] && re_ctx.saved[i+1] >= re_ctx.saved[i]) {
- duk_hstring *h_saved;
-
- duk_push_lstring(ctx,
+ if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
+ duk_push_lstring(thr,
(const char *) re_ctx.saved[i],
(duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
- h_saved = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_saved != NULL);
-
if (i == 0) {
/* Assumes that saved[0] and saved[1] are always
* set by regexp bytecode (if not, char_end_offset
* will be zero). Also assumes clen reflects the
* correct char length.
*/
- char_end_offset = char_offset + DUK_HSTRING_GET_CHARLEN(h_saved);
+ char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1); /* add charlen */
}
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* [ ... re_obj input bc saved_buf res_obj val ] */
- duk_put_prop_index(ctx, -2, i / 2);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) (i / 2));
}
/* [ ... re_obj input bc saved_buf res_obj ] */
@@ -79470,8 +87275,8 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
if (global) {
/* global regexp: lastIndex updated on match */
- duk_push_u32(ctx, char_end_offset);
- duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
+ duk_push_u32(thr, char_end_offset);
+ duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
} else {
/* non-global regexp: lastIndex never updated on match */
;
@@ -79485,21 +87290,21 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_DDD(DUK_DDDPRINT("regexp does not match"));
- duk_push_null(ctx);
+ duk_push_null(thr);
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
}
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_insert(ctx, -5);
+ duk_insert(thr, -5);
/* [ ... res_obj re_obj input bc saved_buf ] */
- duk_pop_n(ctx, 4);
+ duk_pop_n_unsafe(thr, 4);
/* [ ... res_obj ] */
@@ -79524,13 +87329,12 @@ DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
/* regexp support disabled */
#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_selftest.c"
/*
* Self tests to ensure execution environment is sane. Intended to catch
* compiler/platform problems which cannot be detected at compile time.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_SELF_TESTS)
@@ -79540,43 +87344,93 @@ DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
typedef union {
double d;
- duk_uint8_t c[8];
+ duk_uint8_t x[8];
} duk__test_double_union;
+/* Self test failed. Expects a local variable 'error_count' to exist. */
+#define DUK__FAILED(msg) do { \
+ DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \
+ error_count++; \
+ } while (0)
+
#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
+ DUK__FAILED("double union compares false (expected true)"); \
} \
} while (0)
#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
+ DUK__FAILED("double union compares true (expected false)"); \
} \
} while (0)
typedef union {
duk_uint32_t i;
- duk_uint8_t c[8];
+ duk_uint8_t x[8];
} duk__test_u32_union;
+#if defined(DUK_USE_INTEGER_LE)
+#define DUK__U32_INIT(u, a, b, c, d) do { \
+ (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
+ } while (0)
+#elif defined(DUK_USE_INTEGER_ME)
+#error integer mixed endian not supported now
+#elif defined(DUK_USE_INTEGER_BE)
+#define DUK__U32_INIT(u, a, b, c, d) do { \
+ (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
+ } while (0)
+#else
+#error unknown integer endianness
+#endif
+
+#if defined(DUK_USE_DOUBLE_LE)
+#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
+ (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \
+ (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \
+ } while (0)
+#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
+ ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \
+ (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a))
+#elif defined(DUK_USE_DOUBLE_ME)
+#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
+ (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
+ (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \
+ } while (0)
+#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
+ ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \
+ (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e))
+#elif defined(DUK_USE_DOUBLE_BE)
+#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
+ (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
+ (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \
+ } while (0)
+#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
+ ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \
+ (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h))
+#else
+#error unknown double endianness
+#endif
+
/*
* Various sanity checks for typing
*/
-DUK_LOCAL void duk__selftest_types(void) {
+DUK_LOCAL duk_uint_t duk__selftest_types(void) {
+ duk_uint_t error_count = 0;
+
if (!(sizeof(duk_int8_t) == 1 &&
sizeof(duk_uint8_t) == 1 &&
sizeof(duk_int16_t) == 2 &&
sizeof(duk_uint16_t) == 2 &&
sizeof(duk_int32_t) == 4 &&
sizeof(duk_uint32_t) == 4)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size");
+ DUK__FAILED("duk_(u)int{8,16,32}_t size");
}
#if defined(DUK_USE_64BIT_OPS)
if (!(sizeof(duk_int64_t) == 8 &&
sizeof(duk_uint64_t) == 8)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size");
+ DUK__FAILED("duk_(u)int64_t size");
}
#endif
@@ -79584,30 +87438,37 @@ DUK_LOCAL void duk__selftest_types(void) {
/* Some internal code now assumes that all duk_uint_t values
* can be expressed with a duk_size_t.
*/
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t");
+ DUK__FAILED("duk_size_t is smaller than duk_uint_t");
}
if (!(sizeof(duk_int_t) >= 4)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits");
+ DUK__FAILED("duk_int_t is not 32 bits");
}
+
+ return error_count;
}
/*
* Packed tval sanity
*/
-DUK_LOCAL void duk__selftest_packed_tval(void) {
+DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) {
+ duk_uint_t error_count = 0;
+
#if defined(DUK_USE_PACKED_TVAL)
if (sizeof(void *) > 4) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4");
+ DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4");
}
#endif
+
+ return error_count;
}
/*
* Two's complement arithmetic.
*/
-DUK_LOCAL void duk__selftest_twos_complement(void) {
+DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) {
+ duk_uint_t error_count = 0;
volatile int test;
test = -1;
@@ -79615,8 +87476,10 @@ DUK_LOCAL void duk__selftest_twos_complement(void) {
* 'test' will be 0xFF for two's complement.
*/
if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
+ DUK__FAILED("two's complement arithmetic");
}
+
+ return error_count;
}
/*
@@ -79625,7 +87488,8 @@ DUK_LOCAL void duk__selftest_twos_complement(void) {
* defines.
*/
-DUK_LOCAL void duk__selftest_byte_order(void) {
+DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) {
+ duk_uint_t error_count = 0;
duk__test_u32_union u1;
duk__test_double_union u2;
@@ -79633,43 +87497,27 @@ DUK_LOCAL void duk__selftest_byte_order(void) {
* >>> struct.pack('>d', 102030405060).encode('hex')
* '4237c17c6dc40000'
*/
-#if defined(DUK_USE_INTEGER_LE)
- u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
-#elif defined(DUK_USE_INTEGER_ME)
-#error integer mixed endian not supported now
-#elif defined(DUK_USE_INTEGER_BE)
- u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
-#else
-#error unknown integer endianness
-#endif
-#if defined(DUK_USE_DOUBLE_LE)
- u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
- u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
-#elif defined(DUK_USE_DOUBLE_ME)
- u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
- u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
-#elif defined(DUK_USE_DOUBLE_BE)
- u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
- u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
-#else
-#error unknown double endianness
-#endif
+ DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef);
+ DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00);
if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
+ DUK__FAILED("duk_uint32_t byte order");
}
if (u2.d != (double) 102030405060.0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
+ DUK__FAILED("double byte order");
}
+
+ return error_count;
}
/*
* DUK_BSWAP macros
*/
-DUK_LOCAL void duk__selftest_bswap_macros(void) {
+DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) {
+ duk_uint_t error_count = 0;
duk_uint32_t x32;
duk_uint16_t x16;
duk_double_union du;
@@ -79678,13 +87526,13 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) {
x16 = 0xbeefUL;
x16 = DUK_BSWAP16(x16);
if (x16 != (duk_uint16_t) 0xefbeUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16");
+ DUK__FAILED("DUK_BSWAP16");
}
x32 = 0xdeadbeefUL;
x32 = DUK_BSWAP32(x32);
if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32");
+ DUK__FAILED("DUK_BSWAP32");
}
/* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
@@ -79696,7 +87544,7 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) {
DUK_DBLUNION_DOUBLE_NTOH(&du);
du_diff = du.d - 2.008366013071895;
#if 0
- DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
+ DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff));
#endif
if (du_diff > 1e-15) {
/* Allow very small lenience because some compilers won't parse
@@ -79704,74 +87552,216 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) {
* Linux gcc-4.8 -m32 at least).
*/
#if 0
- DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
(unsigned int) du.uc[0], (unsigned int) du.uc[1],
(unsigned int) du.uc[2], (unsigned int) du.uc[3],
(unsigned int) du.uc[4], (unsigned int) du.uc[5],
- (unsigned int) du.uc[6], (unsigned int) du.uc[7]);
+ (unsigned int) du.uc[6], (unsigned int) du.uc[7]));
#endif
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH");
+ DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH");
}
+
+ return error_count;
}
/*
* Basic double / byte union memory layout.
*/
-DUK_LOCAL void duk__selftest_double_union_size(void) {
+DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) {
+ duk_uint_t error_count = 0;
+
if (sizeof(duk__test_double_union) != 8) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
+ DUK__FAILED("invalid union size");
}
+
+ return error_count;
}
/*
* Union aliasing, see misc/clang_aliasing.c.
*/
-DUK_LOCAL void duk__selftest_double_aliasing(void) {
- duk__test_double_union a, b;
-
+DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) {
/* This testcase fails when Emscripten-generated code runs on Firefox.
* It's not an issue because the failure should only affect packed
* duk_tval representation, which is not used with Emscripten.
*/
-#if !defined(DUK_USE_PACKED_TVAL)
- DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
- return;
-#endif
+#if defined(DUK_USE_PACKED_TVAL)
+ duk_uint_t error_count = 0;
+ duk__test_double_union a, b;
/* Test signaling NaN and alias assignment in all endianness combinations.
*/
/* little endian */
- a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
- a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
+ a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44;
+ a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff;
b = a;
DUK__DBLUNION_CMP_TRUE(&a, &b);
/* big endian */
- a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
- a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
+ a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00;
+ a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11;
b = a;
DUK__DBLUNION_CMP_TRUE(&a, &b);
/* mixed endian */
- a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
- a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
+ a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff;
+ a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44;
b = a;
DUK__DBLUNION_CMP_TRUE(&a, &b);
+
+ return error_count;
+#else
+ DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
+ return 0;
+#endif
}
/*
* Zero sign, see misc/tcc_zerosign2.c.
*/
-DUK_LOCAL void duk__selftest_double_zero_sign(void) {
+DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) {
+ duk_uint_t error_count = 0;
duk__test_double_union a, b;
a.d = 0.0;
b.d = -a.d;
DUK__DBLUNION_CMP_FALSE(&a, &b);
+
+ return error_count;
+}
+
+/*
+ * Rounding mode: Duktape assumes round-to-nearest, check that this is true.
+ * If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST,
+ * but we don't want to rely on that header; and even if we did, it's good
+ * to ensure the rounding actually works.
+ */
+
+DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) {
+ duk_uint_t error_count = 0;
+ duk__test_double_union a, b, c;
+
+#if 0
+ /* Include <fenv.h> and test manually; these trigger failures: */
+ fesetround(FE_UPWARD);
+ fesetround(FE_DOWNWARD);
+ fesetround(FE_TOWARDZERO);
+
+ /* This is the default and passes. */
+ fesetround(FE_TONEAREST);
+#endif
+
+ /* Rounding tests check that none of the other modes (round to
+ * +Inf, round to -Inf, round to zero) can be active:
+ * http://www.gnu.org/software/libc/manual/html_node/Rounding.html
+ */
+
+ /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp.
+ * Round to nearest: 1.0
+ * Round to +Inf: 1.0 + ulp
+ * Round to -Inf: 1.0
+ * Round to zero: 1.0
+ * => Correct result eliminates round to +Inf.
+ */
+ DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ DUK_MEMSET((void *) &c, 0, sizeof(c));
+ c.d = a.d + b.d;
+ if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) {
+ DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
+ (unsigned int) c.x[0], (unsigned int) c.x[1],
+ (unsigned int) c.x[2], (unsigned int) c.x[3],
+ (unsigned int) c.x[4], (unsigned int) c.x[5],
+ (unsigned int) c.x[6], (unsigned int) c.x[7]));
+ DUK__FAILED("invalid result from 1.0 + 0.5ulp");
+ }
+
+ /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp.
+ * Round to nearest: 1.0 + 2*ulp (round to even mantissa)
+ * Round to +Inf: 1.0 + 2*ulp
+ * Round to -Inf: 1.0 + ulp
+ * Round to zero: 1.0 + ulp
+ * => Correct result eliminates round to -Inf and round to zero.
+ */
+ DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
+ DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ DUK_MEMSET((void *) &c, 0, sizeof(c));
+ c.d = a.d + b.d;
+ if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) {
+ DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
+ (unsigned int) c.x[0], (unsigned int) c.x[1],
+ (unsigned int) c.x[2], (unsigned int) c.x[3],
+ (unsigned int) c.x[4], (unsigned int) c.x[5],
+ (unsigned int) c.x[6], (unsigned int) c.x[7]));
+ DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp");
+ }
+
+ /* Could do negative number testing too, but the tests above should
+ * differentiate between IEEE 754 rounding modes.
+ */
+ return error_count;
+}
+
+/*
+ * fmod(): often a portability issue in embedded or bare platform targets.
+ * Check for at least minimally correct behavior. Unlike some other math
+ * functions (like cos()) Duktape relies on fmod() internally too.
+ */
+
+DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
+ duk_uint_t error_count = 0;
+ duk__test_double_union u1, u2;
+ volatile duk_double_t t1, t2, t3;
+
+ /* fmod() with integer argument and exponent 2^32 is used by e.g.
+ * ToUint32() and some Duktape internals.
+ */
+ u1.d = DUK_FMOD(10.0, 4294967296.0);
+ u2.d = 10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ u1.d = DUK_FMOD(4294967306.0, 4294967296.0);
+ u2.d = 10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ u1.d = DUK_FMOD(73014444042.0, 4294967296.0);
+ u2.d = 10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ /* 52-bit integer split into two parts:
+ * >>> 0x1fedcba9876543
+ * 8987183256397123
+ * >>> float(0x1fedcba9876543) / float(2**53)
+ * 0.9977777777777778
+ */
+ u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0);
+ u2.d = (duk_double_t) 0xa9876543UL;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+ t1 = 8987183256397123.0;
+ t2 = 4294967296.0;
+ t3 = t1 / t2;
+ u1.d = DUK_FLOOR(t3);
+ u2.d = (duk_double_t) 0x1fedcbUL;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ /* C99 behavior is for fmod() result sign to mathc argument sign. */
+ u1.d = DUK_FMOD(-10.0, 4294967296.0);
+ u2.d = -10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ u1.d = DUK_FMOD(-4294967306.0, 4294967296.0);
+ u2.d = -10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ u1.d = DUK_FMOD(-73014444042.0, 4294967296.0);
+ u2.d = -10.0;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
+ return error_count;
}
/*
@@ -79781,20 +87771,23 @@ DUK_LOCAL void duk__selftest_double_zero_sign(void) {
* selftest ensures they're correctly detected and used.
*/
-DUK_LOCAL void duk__selftest_struct_align(void) {
+DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) {
+ duk_uint_t error_count = 0;
+
#if (DUK_USE_ALIGN_BY == 4)
if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
+ DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4");
}
#elif (DUK_USE_ALIGN_BY == 8)
if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
+ DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8");
}
#elif (DUK_USE_ALIGN_BY == 1)
/* no check */
#else
#error invalid DUK_USE_ALIGN_BY
#endif
+ return error_count;
}
/*
@@ -79804,7 +87797,8 @@ DUK_LOCAL void duk__selftest_struct_align(void) {
* but don't work correctly. Test for known cases.
*/
-DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
+DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) {
+ duk_uint_t error_count = 0;
#if defined(DUK_USE_64BIT_OPS)
volatile duk_int64_t i;
volatile duk_double_t d;
@@ -79812,23 +87806,26 @@ DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
/* Catch a double-to-int64 cast issue encountered in practice. */
d = 2147483648.0;
i = (duk_int64_t) d;
- if (i != 0x80000000LL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed");
+ if (i != DUK_I64_CONSTANT(0x80000000)) {
+ DUK__FAILED("casting 2147483648.0 to duk_int64_t failed");
}
#else
/* nop */
#endif
+ return error_count;
}
/*
* Casting
*/
-DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
+DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) {
/*
* https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
*/
+ duk_uint_t error_count = 0;
+
duk_double_t d1, d2;
duk_small_uint_t u;
@@ -79842,7 +87839,7 @@ DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
d2 = (duk_double_t) u;
if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
+ DUK__FAILED("double to duk_small_uint_t cast failed");
}
/* Same test with volatiles */
@@ -79852,11 +87849,13 @@ DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
d2v = (duk_double_t) uv;
if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
+ DUK__FAILED("double to duk_small_uint_t cast failed");
}
+
+ return error_count;
}
-DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
+DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) {
/*
* This test fails on an exotic ARM target; double-to-uint
* cast is incorrectly clamped to -signed- int highest value.
@@ -79864,6 +87863,7 @@ DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
* https://github.com/svaarala/duktape/issues/336
*/
+ duk_uint_t error_count = 0;
duk_double_t dv;
duk_uint32_t uv;
@@ -79871,35 +87871,109 @@ DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
uv = (duk_uint32_t) dv;
if (uv != 0xdeadbeefUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed");
+ DUK__FAILED("double to duk_uint32_t cast failed");
}
+
+ return error_count;
}
/*
- * Self test main
+ * Minimal test of user supplied allocation functions
+ *
+ * - Basic alloc + realloc + free cycle
+ *
+ * - Realloc to significantly larger size to (hopefully) trigger a
+ * relocation and check that relocation copying works
*/
-DUK_INTERNAL void duk_selftest_run_tests(void) {
- duk__selftest_types();
- duk__selftest_packed_tval();
- duk__selftest_twos_complement();
- duk__selftest_byte_order();
- duk__selftest_bswap_macros();
- duk__selftest_double_union_size();
- duk__selftest_double_aliasing();
- duk__selftest_double_zero_sign();
- duk__selftest_struct_align();
- duk__selftest_64bit_arithmetic();
- duk__selftest_cast_double_to_small_uint();
- duk__selftest_cast_double_to_uint32();
+DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *udata) {
+ duk_uint_t error_count = 0;
+ void *ptr;
+ void *new_ptr;
+ duk_small_int_t i, j;
+ unsigned char x;
+
+ if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) {
+ return 0;
+ }
+
+ for (i = 1; i <= 256; i++) {
+ ptr = alloc_func(udata, (duk_size_t) i);
+ if (ptr == NULL) {
+ DUK_D(DUK_DPRINT("alloc failed, ignore"));
+ continue; /* alloc failed, ignore */
+ }
+ for (j = 0; j < i; j++) {
+ ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j);
+ }
+ new_ptr = realloc_func(udata, ptr, 1024);
+ if (new_ptr == NULL) {
+ DUK_D(DUK_DPRINT("realloc failed, ignore"));
+ free_func(udata, ptr);
+ continue; /* realloc failed, ignore */
+ }
+ ptr = new_ptr;
+ for (j = 0; j < i; j++) {
+ x = ((unsigned char *) ptr)[j];
+ if (x != (unsigned char) (0x80 + j)) {
+ DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx",
+ (long) j, (unsigned long) x));
+ DUK__FAILED("byte compare after realloc");
+ break;
+ }
+ }
+ free_func(udata, ptr);
+ }
+
+ return error_count;
}
-#undef DUK__DBLUNION_CMP_TRUE
-#undef DUK__DBLUNION_CMP_FALSE
+/*
+ * Self test main
+ */
+
+DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *udata) {
+ duk_uint_t error_count = 0;
+
+ DUK_D(DUK_DPRINT("self test starting"));
+
+ error_count += duk__selftest_types();
+ error_count += duk__selftest_packed_tval();
+ error_count += duk__selftest_twos_complement();
+ error_count += duk__selftest_byte_order();
+ error_count += duk__selftest_bswap_macros();
+ error_count += duk__selftest_double_union_size();
+ error_count += duk__selftest_double_aliasing();
+ error_count += duk__selftest_double_zero_sign();
+ error_count += duk__selftest_double_rounding();
+ error_count += duk__selftest_fmod();
+ error_count += duk__selftest_struct_align();
+ error_count += duk__selftest_64bit_arithmetic();
+ error_count += duk__selftest_cast_double_to_small_uint();
+ error_count += duk__selftest_cast_double_to_uint32();
+ error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata);
+
+ DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count));
+
+ return error_count;
+}
#endif /* DUK_USE_SELF_TESTS */
-/* include removed: duk_internal.h */
-#line 2 "duk_tval.c"
+
+/* automatic undefs */
+#undef DUK__DBLUNION_CMP_FALSE
+#undef DUK__DBLUNION_CMP_TRUE
+#undef DUK__DOUBLE_COMPARE
+#undef DUK__DOUBLE_INIT
+#undef DUK__FAILED
+#undef DUK__U32_INIT
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_FASTINT)
@@ -79920,7 +87994,7 @@ DUK_INTERNAL void duk_selftest_run_tests(void) {
* See doc/fastint.rst for details.
*/
-DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) {
+DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) {
duk_double_union du;
duk_int64_t i;
duk_small_int_t expt;
@@ -79936,9 +88010,9 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, du
if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
duk_int64_t t;
- if (((0x000fffffffffffffLL >> shift) & i) == 0) {
- t = i | 0x0010000000000000LL; /* implicit leading one */
- t = t & 0x001fffffffffffffLL;
+ if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) {
+ t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */
+ t = t & DUK_I64_CONSTANT(0x001fffffffffffff);
t = t >> (52 - shift);
if (i < 0) {
t = -t;
@@ -79947,13 +88021,13 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, du
return;
}
} else if (shift == -1023) { /* exponent 0 */
- if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
+ if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
/* Note: reject negative zero. */
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
return;
}
} else if (shift == 47) { /* exponent 1070 */
- if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
+ if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
return;
}
@@ -79963,6 +88037,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, du
return;
}
+DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) {
+ duk_tval_set_number_chkfast_fast(tv, x);
+}
+
/*
* Manually optimized number-to-double conversion
*/
@@ -79975,15 +88053,15 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval
t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
if ((t >> 48) != DUK_TAG_FASTINT) {
return tv->d;
- } else if (t & 0x0000800000000000ULL) {
+ } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) {
t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
- t = t & 0x0000ffffffffffffULL; /* negative */
- t |= 0xc330000000000000ULL;
+ t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */
+ t |= DUK_U64_CONSTANT(0xc330000000000000);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
} else if (t != 0) {
- t &= 0x0000ffffffffffffULL; /* positive */
- t |= 0x4330000000000000ULL;
+ t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */
+ t |= DUK_U64_CONSTANT(0x4330000000000000);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
@@ -79998,15 +88076,15 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tva
duk_double_union du;
duk_uint64_t t;
- DUK_ASSERT(tv->t == DUK__TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
+ DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
if (tv->t == DUK_TAG_FASTINT) {
if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
+ t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
+ t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
}
@@ -80025,11 +88103,11 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint
DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
+ t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
+ t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
}
@@ -80037,12 +88115,11 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint
#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
#endif /* DUK_USE_FASTINT */
-#line 1 "duk_unicode_tables.c"
/*
* Unicode support tables automatically generated during build.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Unicode tables containing ranges of Unicode characters in a
@@ -80053,53 +88130,64 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint
* compactness is most important.
*
* The tables are matched using uni_range_match() and the format
- * is described in src/extract_chars.py.
+ * is described in tools/extract_chars.py.
*/
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/* IdentifierStart production with ASCII excluded */
/* duk_unicode_ids_noa[] */
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-const duk_uint8_t duk_unicode_ids_noa[791] = {
-249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
-240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
-18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
-101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
-52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
-240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
-2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
-114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
-240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
-26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
-205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
-35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
-180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
-146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
-79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
-251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
-92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
-240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
-122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
-74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
-255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
-47,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
-34,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
-240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
-240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
-24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
-171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,241,91,47,10,47,3,
-33,46,61,241,79,107,243,127,37,255,223,13,79,33,242,31,15,240,63,11,242,
-127,14,63,20,87,36,241,207,142,255,226,86,83,2,241,194,20,3,240,127,156,
-240,107,240,175,184,15,1,50,34,240,191,30,240,223,117,242,107,240,107,240,
-63,127,243,159,254,42,239,37,243,223,29,255,238,68,255,226,97,248,63,83,
-255,234,145,255,227,33,255,240,2,44,95,254,18,191,255,0,52,187,31,255,0,18,
-242,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,
-255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
-240,1,114,143,255,0,149,201,241,191,254,242,124,252,239,255,0,46,214,255,
-225,16,0,
+const duk_uint8_t duk_unicode_ids_noa[1036] = {
+249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
+2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
+21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
+101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19,
+240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,
+2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18,
+47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12,
+38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6,
+41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,
+34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,
+85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,
+63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,
+240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,
+15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,
+240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,
+43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,
+15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68,
+112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52,
+29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12,
+146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255,
+224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63,
+253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34,
+35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31,
+240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
+240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7,
+95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
+207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
+207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255,
+223,13,79,33,242,31,16,240,47,11,111,22,191,14,63,20,87,36,241,207,142,240,
+79,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20,
+3,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15,
+1,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240,107,240,
+62,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241,47,9,240,
+207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244,102,32,35,
+46,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37,240,67,242,
+127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223,27,244,127,
+10,255,224,122,243,15,17,15,254,11,79,41,255,152,47,21,240,48,242,63,14,
+255,226,100,255,226,140,245,143,95,240,63,180,255,233,176,255,227,33,255,
+238,197,255,225,57,255,240,1,10,223,254,18,184,240,255,99,240,239,4,242,15,
+2,63,17,240,86,240,63,254,38,79,53,192,243,76,243,32,241,31,255,0,6,223,
+240,95,254,30,95,255,0,20,1,31,254,175,47,91,108,72,137,255,240,0,101,175,
+69,47,55,33,48,49,51,43,32,38,47,49,35,55,38,47,12,35,36,32,70,47,254,4,99,
+240,146,240,146,240,242,240,146,240,242,240,146,240,242,240,146,240,242,
+240,146,127,254,242,143,181,242,223,52,255,227,176,50,240,178,18,3,2,146,
+50,2,7,5,2,2,2,34,18,3,2,2,2,2,2,18,3,50,98,50,50,2,146,240,22,34,66,240,
+31,255,0,0,56,255,240,9,92,159,27,255,239,39,207,206,63,255,0,5,116,255,
+240,1,133,47,254,17,0,
};
#else
/* IdentifierStart production with ASCII and non-BMP excluded */
@@ -80108,38 +88196,39 @@ const duk_uint8_t duk_unicode_ids_noa[791] = {
* Automatically generated by extract_chars.py, do not edit!
*/
-const duk_uint8_t duk_unicode_ids_noabmp[611] = {
-249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
-240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
-18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
-101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
-52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
-240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
-2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
-114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
-240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
-26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
-205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
-35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
-180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
-146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
-79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
-251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
-92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
-240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
-122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
-74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
-255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
-47,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
-34,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
-240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
-240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
-24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
-171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,0,
+const duk_uint8_t duk_unicode_ids_noabmp[625] = {
+249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
+2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
+21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
+101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19,
+240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,
+2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18,
+47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12,
+38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6,
+41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,
+34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,
+85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,
+63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,
+240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,
+15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,
+240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,
+43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,
+15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68,
+112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52,
+29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12,
+146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255,
+224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63,
+253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34,
+35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31,
+240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
+240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7,
+95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
+207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
+207,73,69,53,53,50,0,
};
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/* IdentifierStart production with Letter and ASCII excluded */
/* duk_unicode_ids_m_let_noa[] */
/*
@@ -80148,7 +88237,7 @@ const duk_uint8_t duk_unicode_ids_noabmp[611] = {
const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
-249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,48,
+249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240,
};
#else
/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
@@ -80163,33 +88252,39 @@ const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
};
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/* IdentifierPart production with IdentifierStart and ASCII excluded */
/* duk_unicode_idp_m_ids_noa[] */
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
+const duk_uint8_t duk_unicode_idp_m_ids_noa[530] = {
255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
-36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
-57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
-240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
-242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
-34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
-53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
-211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
-79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
-185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
-4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
-109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
-121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
-240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
-96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
-240,162,251,41,241,112,255,225,177,15,254,25,105,255,228,75,34,22,63,26,37,
-15,254,75,66,242,126,241,25,240,34,241,250,255,240,10,249,228,69,151,54,
-241,3,248,98,255,228,125,242,47,255,12,23,244,254,0,
+36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
+160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
+97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
+240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50,
+242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41,
+244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,
+111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,
+241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242,
+244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57,
+241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31,
+35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,
+255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242,
+79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29,
+208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
+225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64,
+248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,228,13,47,
+39,239,17,159,1,63,31,175,39,151,47,22,210,159,37,13,47,34,218,36,159,68,
+183,15,146,182,151,63,42,2,99,19,42,11,19,100,79,178,240,42,159,72,240,77,
+159,199,99,143,13,31,68,240,31,1,159,67,201,159,69,229,159,254,9,169,255,
+226,57,114,127,2,159,42,240,98,223,255,0,60,157,159,120,79,45,111,11,159,
+254,46,191,30,240,35,255,240,3,191,225,255,240,0,59,164,69,151,54,241,3,
+248,98,255,228,125,242,47,254,15,79,39,95,34,144,240,0,240,132,46,255,228,
+68,98,240,19,98,18,79,254,121,150,245,246,105,255,240,192,105,175,224,0,
};
#else
/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
@@ -80198,29 +88293,29 @@ const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
* Automatically generated by extract_chars.py, do not edit!
*/
-const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
+const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357] = {
255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
-36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
-57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
-240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
-242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
-34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
-53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
-211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
-79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
-185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
-4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
-109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
-121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
-240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
-96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
-240,162,251,41,241,112,0,
+36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
+160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
+97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
+240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50,
+242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41,
+244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,
+111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,
+241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242,
+244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57,
+241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31,
+35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,
+255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242,
+79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29,
+208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
+225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0,
};
#endif
/*
- * Case conversion tables generated using src/extract_caseconv.py.
+ * Case conversion tables generated using tools/extract_caseconv.py.
*/
/* duk_unicode_caseconv_uc[] */
@@ -80230,95 +88325,102 @@ const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
* Automatically generated by extract_caseconv.py, do not edit!
*/
-const duk_uint8_t duk_unicode_caseconv_uc[1288] = {
-132,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
+const duk_uint8_t duk_unicode_caseconv_uc[1386] = {
+144,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
-104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,15,128,15,132,8,31,16,
-31,24,12,62,64,62,80,32,124,192,124,224,64,250,0,250,64,97,246,1,246,129,3,
-238,3,247,64,135,220,135,242,2,15,187,15,237,2,31,120,31,248,4,62,244,63,
-212,8,125,240,127,232,16,253,128,253,192,33,253,1,253,128,67,252,3,253,0,
-136,92,8,88,8,18,104,18,91,26,44,48,44,0,94,90,0,33,64,155,253,7,252,132,
-212,0,32,32,32,6,0,76,192,76,129,128,157,0,156,136,1,75,1,74,46,2,244,2,
-242,12,6,12,6,8,16,13,8,13,0,48,27,64,27,48,64,57,192,57,162,0,119,192,119,
-132,128,252,128,252,20,2,35,2,34,18,4,142,4,140,20,13,196,13,192,16,30,200,
-30,192,192,70,16,70,2,32,145,96,145,70,193,48,129,48,67,130,104,130,104,44,
-30,1,30,0,150,61,66,61,64,192,125,68,125,100,33,99,65,99,56,50,200,18,200,
-6,69,157,133,157,96,169,144,105,144,11,211,64,211,64,12,167,35,167,34,15,
-78,103,78,100,126,157,234,157,228,21,59,253,59,240,90,122,26,122,0,163,128,
-214,128,214,2,1,197,1,196,6,3,140,3,136,12,7,200,7,196,16,20,0,13,48,32,63,
-128,63,112,69,142,101,142,64,130,1,136,1,135,4,3,114,3,112,8,26,120,202,
-120,176,65,1,30,1,29,130,2,105,1,150,5,255,96,22,160,115,128,31,224,47,0,
-38,32,9,32,47,224,10,96,48,0,72,96,50,64,50,32,50,160,62,192,51,32,51,0,51,
-64,71,160,51,192,68,0,53,0,52,224,55,224,62,224,59,160,49,192,62,96,62,32,
-74,5,141,224,74,37,141,160,74,69,142,0,74,96,48,32,74,128,48,192,75,32,49,
-224,75,96,50,0,76,0,50,96,76,96,50,128,76,180,241,160,77,0,50,224,77,101,
-140,64,78,37,141,192,78,64,51,160,78,160,51,224,79,165,140,128,81,0,53,192,
-81,32,72,128,81,128,72,160,82,64,54,224,104,160,115,32,110,224,110,192,117,
-128,112,192,120,64,116,96,121,128,113,128,122,0,114,64,122,32,115,0,122,
-160,116,192,122,192,116,0,122,224,121,224,126,0,115,64,126,32,116,32,126,
-64,127,32,126,160,114,160,153,224,152,3,175,52,239,163,175,165,140,99,211,
-99,204,3,247,192,115,35,252,163,253,132,41,196,38,68,48,132,48,101,140,37,
-140,5,140,160,71,69,140,192,71,217,128,55,224,5,48,5,48,20,152,10,240,1,56,
-7,194,0,74,3,12,3,144,192,230,64,194,0,192,64,236,48,58,80,48,128,48,16,88,
-120,20,212,21,72,122,90,0,72,3,49,30,151,128,21,0,194,7,166,32,5,112,48,
-161,233,152,1,100,12,40,122,106,0,65,2,190,31,80,128,233,64,196,199,212,
-176,58,80,49,48,48,1,245,76,14,148,12,76,12,4,125,91,3,165,3,19,3,66,31,
-128,135,194,0,230,71,224,97,240,144,57,145,248,40,124,40,14,100,126,14,31,
-11,3,153,31,132,135,195,0,230,71,225,97,240,208,57,145,248,104,124,56,14,
-100,126,30,31,15,3,153,31,136,135,194,0,230,71,226,97,240,144,57,145,248,
-168,124,40,14,100,126,46,31,11,3,153,31,140,135,195,0,230,71,227,97,240,
-208,57,145,248,232,124,56,14,100,126,62,31,15,3,153,31,144,135,202,0,230,
-71,228,97,242,144,57,145,249,40,124,168,14,100,126,78,31,43,3,153,31,148,
-135,203,0,230,71,229,97,242,208,57,145,249,104,124,184,14,100,126,94,31,47,
-3,153,31,152,135,202,0,230,71,230,97,242,144,57,145,249,168,124,168,14,100,
-126,110,31,43,3,153,31,156,135,203,0,230,71,231,97,242,208,57,145,249,232,
-124,184,14,100,126,126,31,47,3,153,31,160,135,218,0,230,71,232,97,246,144,
-57,145,250,40,125,168,14,100,126,142,31,107,3,153,31,164,135,219,0,230,71,
-233,97,246,208,57,145,250,104,125,184,14,100,126,158,31,111,3,153,31,168,
-135,218,0,230,71,234,97,246,144,57,145,250,168,125,168,14,100,126,174,31,
-107,3,153,31,172,135,219,0,230,71,235,97,246,208,57,145,250,232,125,184,14,
-100,126,190,31,111,3,153,31,178,135,238,128,230,71,236,224,57,16,57,145,
-251,72,14,24,14,100,126,218,3,145,3,66,31,183,192,228,64,208,128,230,71,
-239,32,57,16,57,145,252,40,127,40,14,100,127,14,3,151,3,153,31,196,128,226,
-64,230,71,241,160,57,112,52,33,252,124,14,92,13,8,14,100,127,50,3,151,3,
-153,31,210,192,230,64,194,0,192,7,244,240,57,144,48,128,48,17,253,104,14,
-100,13,8,127,95,3,153,3,8,3,66,31,226,192,233,64,194,0,192,7,248,240,58,80,
-48,128,48,17,254,72,14,132,12,76,127,154,3,165,3,66,31,231,192,233,64,194,
-0,208,135,252,161,255,160,57,145,255,56,14,164,14,100,127,210,3,143,3,153,
-31,246,128,234,64,208,135,253,240,58,144,52,32,57,145,255,200,14,164,14,
-103,236,2,0,70,0,70,251,1,128,17,128,18,126,192,160,4,96,4,207,176,60,1,24,
-1,24,1,39,236,19,0,70,0,70,0,76,251,5,128,20,192,21,62,193,160,5,48,5,79,
-177,56,21,16,21,27,236,82,5,68,5,53,251,21,129,81,1,78,254,197,160,84,224,
-84,111,177,120,21,16,20,244,
+104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,9,252,9,248,6,28,131,4,
+33,4,62,0,62,16,32,124,64,124,96,48,249,0,249,64,129,243,1,243,129,3,232,3,
+233,1,135,216,7,218,4,15,184,15,221,2,31,114,31,200,8,62,236,63,180,8,125,
+224,127,224,16,251,208,255,80,33,247,193,255,160,67,246,3,247,0,135,244,7,
+246,1,15,240,15,244,2,33,112,33,96,32,73,160,73,108,104,176,192,176,1,121,
+104,0,133,2,106,183,1,58,10,31,232,63,228,38,162,1,1,1,0,48,2,102,2,100,12,
+4,232,4,228,64,10,88,10,81,112,23,160,23,144,96,48,96,48,64,128,104,64,104,
+1,128,218,0,217,130,1,206,1,205,16,3,190,3,188,36,7,228,7,224,160,17,24,17,
+16,144,36,112,36,96,160,110,32,110,0,128,246,64,246,6,2,48,130,48,17,4,139,
+4,138,54,9,132,9,130,28,19,68,19,65,128,240,8,240,4,177,234,17,234,6,3,234,
+35,235,33,11,26,11,25,193,150,64,150,64,50,44,236,44,235,5,76,131,76,128,
+94,154,6,154,0,117,57,29,57,16,122,115,58,115,35,244,239,84,239,32,169,223,
+233,223,130,211,200,211,200,2,167,151,167,150,21,79,107,79,104,8,112,26,
+208,26,192,64,56,160,56,128,192,113,128,113,1,128,249,0,248,130,2,128,1,
+166,4,7,240,7,238,8,177,204,177,200,16,96,49,0,48,224,128,110,64,110,1,1,
+51,83,213,2,0,48,35,192,35,176,64,77,32,50,192,139,73,196,49,193,127,48,2,
+212,14,112,3,252,5,224,4,196,1,36,5,252,1,76,6,0,9,12,6,72,6,68,6,84,7,216,
+6,100,6,96,6,104,8,244,6,120,8,128,6,160,6,156,6,252,7,220,7,116,6,56,7,
+204,7,196,9,64,177,188,9,68,177,180,9,72,177,192,9,76,6,4,9,80,6,24,9,100,
+6,60,9,108,6,64,9,114,158,172,9,128,6,76,9,134,158,176,9,140,6,80,9,150,
+158,52,9,160,6,92,9,172,177,136,9,178,158,180,9,196,177,184,9,200,6,116,9,
+212,6,124,9,244,177,144,10,30,158,196,10,32,6,184,10,36,9,16,10,48,9,20,10,
+72,6,220,10,118,158,200,10,122,158,192,13,20,14,100,13,220,13,216,14,176,
+14,24,15,8,14,140,15,48,14,48,15,64,14,72,15,68,14,96,15,84,14,152,15,88,
+14,128,15,92,15,60,15,192,14,104,15,196,14,132,15,200,15,228,15,204,13,252,
+15,212,14,84,19,60,19,0,114,0,16,72,114,4,16,80,114,8,16,120,114,20,16,136,
+114,24,16,168,114,28,17,136,114,34,153,40,117,230,157,244,117,244,177,140,
+122,108,121,128,126,248,14,100,127,148,127,176,133,56,132,200,134,16,134,
+12,177,132,177,128,177,148,8,232,177,152,8,248,179,204,179,202,158,50,158,
+46,173,78,158,207,48,6,252,0,166,0,166,2,147,1,94,0,39,0,248,64,9,64,97,
+128,114,24,28,200,24,64,24,8,29,134,7,74,6,16,6,2,11,15,2,154,130,169,15,
+75,64,9,0,102,35,210,240,2,160,24,64,244,196,0,174,6,20,61,51,0,44,129,133,
+15,77,64,8,32,87,195,234,16,29,40,24,152,250,150,7,74,6,38,6,0,62,169,129,
+210,129,137,129,128,143,171,96,116,160,98,96,104,67,240,16,248,64,28,200,
+252,12,62,18,7,50,63,5,15,133,1,204,143,193,195,225,96,115,35,240,144,248,
+96,28,200,252,44,62,26,7,50,63,13,15,135,1,204,143,195,195,225,224,115,35,
+241,16,248,64,28,200,252,76,62,18,7,50,63,21,15,133,1,204,143,197,195,225,
+96,115,35,241,144,248,96,28,200,252,108,62,26,7,50,63,29,15,135,1,204,143,
+199,195,225,224,115,35,242,16,249,64,28,200,252,140,62,82,7,50,63,37,15,
+149,1,204,143,201,195,229,96,115,35,242,144,249,96,28,200,252,172,62,90,7,
+50,63,45,15,151,1,204,143,203,195,229,224,115,35,243,16,249,64,28,200,252,
+204,62,82,7,50,63,53,15,149,1,204,143,205,195,229,96,115,35,243,144,249,96,
+28,200,252,236,62,90,7,50,63,61,15,151,1,204,143,207,195,229,224,115,35,
+244,16,251,64,28,200,253,12,62,210,7,50,63,69,15,181,1,204,143,209,195,237,
+96,115,35,244,144,251,96,28,200,253,44,62,218,7,50,63,77,15,183,1,204,143,
+211,195,237,224,115,35,245,16,251,64,28,200,253,76,62,210,7,50,63,85,15,
+181,1,204,143,213,195,237,96,115,35,245,144,251,96,28,200,253,108,62,218,7,
+50,63,93,15,183,1,204,143,215,195,237,224,115,35,246,80,253,208,28,200,253,
+156,7,34,7,50,63,105,1,195,1,204,143,219,64,114,32,104,67,246,248,28,136,
+26,16,28,200,253,228,7,34,7,50,63,133,15,229,1,204,143,225,192,114,224,115,
+35,248,144,28,72,28,200,254,52,7,46,6,132,63,143,129,203,129,161,1,204,143,
+230,64,114,224,115,35,250,88,28,200,24,64,24,0,254,158,7,50,6,16,6,2,63,
+173,1,204,129,161,15,235,224,115,32,97,0,104,67,252,88,29,40,24,64,24,0,
+255,30,7,74,6,16,6,2,63,201,1,208,129,137,143,243,64,116,160,104,67,252,
+248,29,40,24,64,26,16,255,148,63,244,7,50,63,231,1,212,129,204,143,250,64,
+113,224,115,35,254,208,29,72,26,16,255,190,7,82,6,132,7,50,63,249,1,212,
+129,204,253,128,64,8,192,8,223,96,48,2,48,2,79,216,20,0,140,0,153,246,7,
+128,35,0,35,0,36,253,130,96,8,192,8,192,9,159,96,176,2,152,2,167,216,52,0,
+166,0,169,246,39,2,162,2,163,125,138,64,168,128,166,191,98,176,42,32,41,
+223,216,180,10,156,10,141,246,47,2,162,2,158,128,
};
-const duk_uint8_t duk_unicode_caseconv_lc[616] = {
-144,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
+const duk_uint8_t duk_unicode_caseconv_lc[680] = {
+152,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
-0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,15,132,15,128,8,31,24,
-31,16,12,62,80,62,64,32,124,224,124,192,64,250,64,250,0,97,246,129,246,1,3,
-241,3,240,2,7,230,7,228,4,15,212,15,208,8,31,184,31,176,4,63,116,62,224,8,
-127,32,125,200,32,254,192,254,128,33,253,161,247,96,67,253,3,252,0,135,250,
-135,222,129,15,252,15,188,2,31,250,31,124,4,66,192,66,224,64,146,216,147,
-64,209,96,1,97,130,242,199,224,35,240,95,228,63,232,38,161,1,0,1,1,48,2,
-100,2,102,12,4,228,4,232,64,10,80,10,89,112,23,144,23,160,96,48,64,48,96,
-128,104,0,104,65,128,217,128,218,2,1,203,1,204,18,3,188,3,190,36,7,200,7,
-204,16,15,192,15,201,64,34,32,34,49,32,72,192,72,225,64,220,0,220,65,1,236,
-1,236,140,4,96,4,97,34,9,20,9,22,108,19,4,19,8,56,38,128,38,138,193,224,1,
-224,25,99,212,3,212,44,7,214,71,212,66,22,51,150,52,3,44,128,44,129,100,89,
-214,89,216,10,153,2,153,4,189,52,5,52,8,202,114,42,114,48,244,230,84,230,
-103,233,222,105,222,129,83,191,83,191,133,167,160,167,161,10,48,13,48,20,0,
-32,26,192,26,208,64,56,128,56,192,192,113,64,113,129,1,251,129,252,2,44,
-114,44,115,4,16,12,56,12,64,32,27,128,27,144,64,211,197,211,198,2,8,6,88,9,
-164,16,17,216,17,224,47,245,1,120,0,255,1,129,2,83,1,134,2,84,1,142,1,221,
-1,143,2,89,1,144,2,91,1,145,1,146,1,147,2,96,1,148,2,99,1,151,2,104,1,152,
-1,153,1,157,2,114,1,159,2,117,1,167,1,168,1,174,2,136,1,183,2,146,1,241,1,
-243,1,246,1,149,1,247,1,191,2,32,1,158,2,58,44,101,2,61,1,154,2,62,44,102,
-2,67,1,128,2,68,2,137,2,69,2,140,3,118,3,119,3,134,3,172,3,140,3,204,3,207,
-3,215,3,244,3,184,3,249,3,242,4,192,4,207,30,158,0,223,31,188,31,179,31,
-204,31,195,31,236,31,229,31,252,31,243,33,38,3,201,33,42,0,107,33,43,0,229,
-33,50,33,78,33,131,33,132,44,96,44,97,44,98,2,107,44,99,29,125,44,100,2,
-125,44,109,2,81,44,110,2,113,44,111,2,80,44,112,2,82,167,125,29,121,167,
-141,2,101,2,2,97,0,52,129,131,128,
+0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19,
+240,19,248,12,62,16,62,0,32,124,96,124,64,48,249,64,249,0,129,243,129,243,
+1,3,233,3,232,1,135,218,7,216,4,15,196,15,192,8,31,152,31,144,16,63,80,63,
+64,32,126,224,126,192,16,253,208,251,128,33,252,129,247,32,131,251,3,250,0,
+135,246,135,221,129,15,244,15,240,2,31,234,31,122,4,63,240,62,240,8,127,
+232,125,240,17,11,1,11,129,2,75,98,77,3,69,128,5,134,11,203,31,128,143,193,
+127,144,255,160,154,140,4,0,4,4,192,9,144,9,152,48,19,144,19,161,0,41,64,
+41,101,192,94,64,94,129,128,193,0,193,130,1,160,1,161,6,3,102,3,104,8,7,44,
+7,48,72,14,240,14,248,144,31,32,31,48,64,63,0,63,37,0,136,128,136,196,129,
+35,1,35,133,3,112,3,113,4,7,176,7,178,48,17,128,17,132,136,36,80,36,89,176,
+76,16,76,32,224,154,0,154,44,7,128,7,128,101,143,80,15,80,176,31,89,31,81,
+8,88,206,88,208,12,178,0,178,5,145,103,89,103,96,42,100,10,100,18,244,208,
+20,208,35,169,200,169,200,195,211,153,83,153,159,167,121,167,122,5,78,253,
+78,254,22,158,66,158,68,21,60,181,60,184,170,123,74,123,80,67,0,211,1,64,2,
+1,172,1,173,4,3,136,3,140,12,7,20,7,24,16,31,184,31,192,34,199,34,199,48,
+65,128,195,128,196,2,1,184,1,185,5,79,84,4,204,8,0,192,101,128,154,65,1,29,
+129,30,2,16,199,45,39,5,251,240,23,128,15,240,24,16,37,48,24,96,37,64,24,
+224,29,208,24,240,37,144,25,0,37,176,25,16,25,32,25,48,38,0,25,64,38,48,25,
+112,38,128,25,128,25,144,25,208,39,32,25,240,39,80,26,112,26,128,26,224,40,
+128,27,112,41,32,31,16,31,48,31,96,25,80,31,112,27,240,34,0,25,224,35,162,
+198,80,35,208,25,160,35,226,198,96,36,48,24,0,36,64,40,144,36,80,40,192,55,
+96,55,112,55,240,63,48,56,96,58,192,56,192,60,192,60,240,61,112,63,64,59,
+128,63,144,63,32,76,0,76,241,233,224,13,241,251,193,251,49,252,193,252,49,
+254,193,254,81,255,193,255,50,18,96,60,146,18,160,6,178,18,176,14,82,19,34,
+20,226,24,50,24,66,198,2,198,18,198,32,38,178,198,49,215,210,198,64,39,210,
+198,208,37,18,198,224,39,18,198,240,37,2,199,0,37,34,207,34,207,58,119,209,
+215,154,120,186,120,202,120,208,38,90,122,176,37,202,122,192,38,26,122,208,
+38,202,123,0,41,234,123,16,40,122,123,32,41,218,123,58,181,48,32,38,16,3,
+72,24,56,
};
#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
@@ -80358,5817 +88460,5836 @@ const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
11391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
-11373,11376,385,390,597,393,394,600,399,602,400,604,605,606,607,403,609,
-610,404,612,42893L,614,615,407,406,618,11362,620,621,622,412,624,11374,413,
-627,628,415,630,631,632,633,634,635,636,11364,638,639,422,641,642,425,644,
-645,646,647,430,580,433,434,581,653,654,655,656,657,439,659,660,661,662,
-663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,
-681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,
-699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,
-717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,
-735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,
-753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,
-771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,
-789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,
-807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,
-825,826,827,828,829,830,831,832,833,834,835,836,921,838,839,840,841,842,
-843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,
-861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,
-879,880,880,882,882,884,885,886,886,888,889,890,1021,1022,1023,894,895,896,
-897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,
-915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,
-933,934,935,936,937,938,939,902,904,905,906,944,913,914,915,916,917,918,
-919,920,921,922,923,924,925,926,927,928,929,931,931,932,933,934,935,936,
-937,938,939,908,910,911,975,914,920,978,979,980,934,928,975,984,984,986,
-986,988,988,990,990,992,992,994,994,996,996,998,998,1000,1000,1002,1002,
-1004,1004,1006,1006,922,929,1017,1011,1012,917,1014,1015,1015,1017,1018,
-1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,
-1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,
-1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,
-1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,1043,1044,1045,1046,
-1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,
-1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,
-1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1120,1120,1122,1122,
-1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,1134,1136,1136,1138,
-1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,1150,1150,1152,1152,
-1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,1164,1166,1166,1168,
-1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,1180,1180,1182,1182,
-1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,1194,1196,1196,1198,
-1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,1210,1210,1212,1212,
-1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,1225,1225,1227,1227,
-1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,1240,1240,1242,1242,
-1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,1254,1256,1256,1258,
-1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,1270,1270,1272,1272,
-1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,1284,1286,1286,1288,
-1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,1300,1300,1302,1302,
-1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,1314,1316,1316,1318,
-1318,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,
-1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,
-1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,
-1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1329,1330,
-1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,
-1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,
-1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,1420,1421,1422,1423,
-1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,
-1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,
-1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,
-1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,
-1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,
-1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,
-1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,
-1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,
-1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,
-1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,
-1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,
-1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,
-1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,
-1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,
-1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,
-1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,
-1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,
-1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,
-1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,
-1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,
-1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,
-1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,
-1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,
-1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,
-1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,
-1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,
-1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,
-1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,
-1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,
-1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,
-1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,
-1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,
-1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,
-1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,
-1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,
-1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,
-1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,
-1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,
-1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
-2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,
-2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,
-2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,
-2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,
-2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,
-2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,
-2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,
-2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,
-2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,
-2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,
-2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,
-2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,
-2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,
-2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,
-2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,
-2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,
-2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,
-2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,
-2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,
-2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,
-2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,
-2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,
-2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,
-2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,
-2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,
-2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,
-2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,
-2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,
-2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,
-2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,
-2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,
-2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,
-2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,
-2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,
-2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,
-2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,
-2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,
-2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,
-2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,
-2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,
-2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,
-2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,
-2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,
-2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,
-2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,
-2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,
-2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,
-2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,
-2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,
-2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,
-2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,
-2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,
-2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,
-2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,
-2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,
-2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,
-2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,
-2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,
-2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,
-2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,
-2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,
-2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,
-2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,
-2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,
-2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,
-2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,
-2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,
-3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,
-3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,
-3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,
-3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,
-3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,
-3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,
-3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,
-3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,
-3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,
-3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,
-3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,
-3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,
-3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,
-3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,
-3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,
-3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,
-3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,
-3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,
-3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,
-3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,
-3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,
-3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,
-3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,
-3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,
-3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,
-3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,
-3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,
-3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,
-3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,
-3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,
-3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,
-3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,
-3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,
-3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,
-3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,
-3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,
-3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,
-3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,
-3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,
-3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,
-3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,
-3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,
-3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,
-3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,
-3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,
-3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,
-3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,
-3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,
-3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,
-3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,
-3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,
-3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,
-3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,
-3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,
-3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,
-3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,
-3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,
-3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,
-3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,
-3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,
-3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,
-3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,
-3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,
-3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,
-3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,
-3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,
-4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,
-4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,
-4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,
-4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,
-4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,
-4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,
-4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,
-4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,
-4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,
-4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,
-4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,
-4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,
-4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,
-4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,
-4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,
-4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,
-4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,
-4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,
-4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,
-4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,
-4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,
-4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,
-4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,
-4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,
-4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,
-4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,
-4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,
-4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,
-4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,
-4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,
-4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,
-4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,
-4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,
-4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,
-4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,
-4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,
-4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,
-4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,
-4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,
-4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,
-4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,
-4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,
-4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,
-4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,
-4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,
-4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,
-4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,
-4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,
-4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,
-4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,
-4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,
-4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,
-4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,
-4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,
-4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,
-4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,
-4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,
-4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,
-4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,
-4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,
-4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,
-4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,
-4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,
-4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,
-4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,
-4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,
-4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,
-5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,
-5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,
-5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,
-5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,
-5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,
-5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,
-5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,5113,
-5114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,
-5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,
-5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,
-5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,
-5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,
-5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,
-5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,
-5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,
-5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,
-5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,
-5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,
-5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,
-5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,
-5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,
-5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,
-5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,
-5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,
-5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,
-5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,
-5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,
-5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,
-5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,
-5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,
-5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,
-5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,
-5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,
-5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,
-5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,
-5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,
-5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,
-5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,
-5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,
-5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,
-5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,
-5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,
-5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,
-5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,
-5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,
-5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,
-5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,
-5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,
-5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,
-5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,
-5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,
-5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,
-5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,
-5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,
-5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,
-5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,
-5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,
-5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876,5877,5878,
-5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892,5893,
-5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908,
-5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,
-5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,
-5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,
-5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,
-5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,
-5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,
-5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,
-6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,
-6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,
-6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,
-6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6072,6073,
-6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,
-6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,
-6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118,
-6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,
-6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,
-6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,
-6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,
-6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,
-6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,
-6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,
-6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,
-6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,
-6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,
-6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,
-6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,
-6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,6310,6311,6312,6313,
-6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,
-6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,
-6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,
-6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,
-6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,6385,6386,6387,6388,
-6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,
-6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,6415,6416,6417,6418,
-6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,
-6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,6445,6446,6447,6448,
-6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6460,6461,6462,6463,
-6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,6475,6476,6477,6478,
-6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,
-6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,
-6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,6522,6523,
-6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,
-6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,
-6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,
-6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,
-6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,
-6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613,
-6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,
-6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,
-6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,
-6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,
-6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,
-6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,
-6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,
-6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,
-6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,6746,6747,6748,
-6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,
-6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,
-6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,
-6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,
-6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,
-6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,6837,6838,
-6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,
-6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,
-6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,
-6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,
-6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,
-6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,
-6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,
-6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,
-6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,
-6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,
-6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,
-7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,
-7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,7031,7032,7033,
-7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,
-7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,
-7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,
-7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,
-7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,
-7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,
-7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138,
-7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,
-7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,
-7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,
-7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,
-7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,
-7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,
-7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,
-7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,
-7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,
-7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,
-7289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7301,7302,7303,
-7304,7305,7306,7307,7308,7309,7310,7311,7312,7313,7314,7315,7316,7317,7318,
-7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,
-7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,
-7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359,7360,7361,7362,7363,
-7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,
-7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,
-7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407,7408,
-7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423,
-7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,
-7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,
-7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,
-7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,
-7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,
-7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,
-7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,
-7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7542,7543,
-7544,42877L,7546,7547,7548,11363,7550,7551,7552,7553,7554,7555,7556,7557,
-7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,7568,7569,7570,7571,7572,
-7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,
-7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,
-7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615,7616,7617,
-7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,
-7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,
-7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,
-7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,
-7678,7679,7680,7680,7682,7682,7684,7684,7686,7686,7688,7688,7690,7690,7692,
-7692,7694,7694,7696,7696,7698,7698,7700,7700,7702,7702,7704,7704,7706,7706,
-7708,7708,7710,7710,7712,7712,7714,7714,7716,7716,7718,7718,7720,7720,7722,
-7722,7724,7724,7726,7726,7728,7728,7730,7730,7732,7732,7734,7734,7736,7736,
-7738,7738,7740,7740,7742,7742,7744,7744,7746,7746,7748,7748,7750,7750,7752,
-7752,7754,7754,7756,7756,7758,7758,7760,7760,7762,7762,7764,7764,7766,7766,
-7768,7768,7770,7770,7772,7772,7774,7774,7776,7776,7778,7778,7780,7780,7782,
-7782,7784,7784,7786,7786,7788,7788,7790,7790,7792,7792,7794,7794,7796,7796,
-7798,7798,7800,7800,7802,7802,7804,7804,7806,7806,7808,7808,7810,7810,7812,
-7812,7814,7814,7816,7816,7818,7818,7820,7820,7822,7822,7824,7824,7826,7826,
-7828,7828,7830,7831,7832,7833,7834,7776,7836,7837,7838,7839,7840,7840,7842,
-7842,7844,7844,7846,7846,7848,7848,7850,7850,7852,7852,7854,7854,7856,7856,
-7858,7858,7860,7860,7862,7862,7864,7864,7866,7866,7868,7868,7870,7870,7872,
-7872,7874,7874,7876,7876,7878,7878,7880,7880,7882,7882,7884,7884,7886,7886,
-7888,7888,7890,7890,7892,7892,7894,7894,7896,7896,7898,7898,7900,7900,7902,
-7902,7904,7904,7906,7906,7908,7908,7910,7910,7912,7912,7914,7914,7916,7916,
-7918,7918,7920,7920,7922,7922,7924,7924,7926,7926,7928,7928,7930,7930,7932,
-7932,7934,7934,7944,7945,7946,7947,7948,7949,7950,7951,7944,7945,7946,7947,
-7948,7949,7950,7951,7960,7961,7962,7963,7964,7965,7958,7959,7960,7961,7962,
-7963,7964,7965,7966,7967,7976,7977,7978,7979,7980,7981,7982,7983,7976,7977,
-7978,7979,7980,7981,7982,7983,7992,7993,7994,7995,7996,7997,7998,7999,7992,
-7993,7994,7995,7996,7997,7998,7999,8008,8009,8010,8011,8012,8013,8006,8007,
-8008,8009,8010,8011,8012,8013,8014,8015,8016,8025,8018,8027,8020,8029,8022,
-8031,8024,8025,8026,8027,8028,8029,8030,8031,8040,8041,8042,8043,8044,8045,
-8046,8047,8040,8041,8042,8043,8044,8045,8046,8047,8122,8123,8136,8137,8138,
-8139,8154,8155,8184,8185,8170,8171,8186,8187,8062,8063,8064,8065,8066,8067,
-8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,8081,8082,
-8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,
-8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111,8120,
-8121,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,921,8127,
-8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,
-8143,8152,8153,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,
-8158,8159,8168,8169,8162,8163,8164,8172,8166,8167,8168,8169,8170,8171,8172,
-8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,
-8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,
-8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,
-8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,
-8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,
-8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261,8262,
-8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277,
-8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,
-8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,
-8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,
-8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,
-8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,
-8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,
-8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,
-8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,
-8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,
-8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,
-8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,
-8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,
-8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,
-8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485,8486,8487,
-8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,
-8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,
-8518,8519,8520,8521,8522,8523,8524,8525,8498,8527,8528,8529,8530,8531,8532,
-8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,
-8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8544,8545,8546,
-8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8576,8577,
-8578,8579,8579,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,
-8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,
-8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,
-8623,8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,
-8638,8639,8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,
-8653,8654,8655,8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,
-8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,
-8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,
-8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709,8710,8711,8712,
-8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725,8726,8727,
-8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,
-8743,8744,8745,8746,8747,8748,8749,8750,8751,8752,8753,8754,8755,8756,8757,
-8758,8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,
-8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783,8784,8785,8786,8787,
-8788,8789,8790,8791,8792,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802,
-8803,8804,8805,8806,8807,8808,8809,8810,8811,8812,8813,8814,8815,8816,8817,
-8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,8831,8832,
-8833,8834,8835,8836,8837,8838,8839,8840,8841,8842,8843,8844,8845,8846,8847,
-8848,8849,8850,8851,8852,8853,8854,8855,8856,8857,8858,8859,8860,8861,8862,
-8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,8874,8875,8876,8877,
-8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,
-8893,8894,8895,8896,8897,8898,8899,8900,8901,8902,8903,8904,8905,8906,8907,
-8908,8909,8910,8911,8912,8913,8914,8915,8916,8917,8918,8919,8920,8921,8922,
-8923,8924,8925,8926,8927,8928,8929,8930,8931,8932,8933,8934,8935,8936,8937,
-8938,8939,8940,8941,8942,8943,8944,8945,8946,8947,8948,8949,8950,8951,8952,
-8953,8954,8955,8956,8957,8958,8959,8960,8961,8962,8963,8964,8965,8966,8967,
-8968,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,
-8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,8993,8994,8995,8996,8997,
-8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,
-9013,9014,9015,9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,
-9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,
-9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,
-9058,9059,9060,9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,
-9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,9086,9087,
-9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101,9102,
-9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117,
-9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,
-9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9146,9147,
-9148,9149,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,
-9163,9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,9176,9177,
-9178,9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,
-9193,9194,9195,9196,9197,9198,9199,9200,9201,9202,9203,9204,9205,9206,9207,
-9208,9209,9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,
-9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,
-9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9248,9249,9250,9251,9252,
-9253,9254,9255,9256,9257,9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,
-9268,9269,9270,9271,9272,9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,
-9283,9284,9285,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,
-9298,9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,
-9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,
-9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,
-9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,
-9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,
-9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,
-9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,
-9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,
-9418,9419,9420,9421,9422,9423,9398,9399,9400,9401,9402,9403,9404,9405,9406,
-9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,
-9422,9423,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461,9462,
-9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9475,9476,9477,
-9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,
-9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,
-9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,
-9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,
-9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552,
-9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,
-9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,
-9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,
-9598,9599,9600,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,
-9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,
-9628,9629,9630,9631,9632,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,
-9643,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,
-9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,
-9673,9674,9675,9676,9677,9678,9679,9680,9681,9682,9683,9684,9685,9686,9687,
-9688,9689,9690,9691,9692,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,
-9703,9704,9705,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715,9716,9717,
-9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,
-9733,9734,9735,9736,9737,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,
-9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,9759,9760,9761,9762,
-9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,
-9778,9779,9780,9781,9782,9783,9784,9785,9786,9787,9788,9789,9790,9791,9792,
-9793,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,
-9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,
-9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,
-9838,9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,
-9853,9854,9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,
-9868,9869,9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,
-9883,9884,9885,9886,9887,9888,9889,9890,9891,9892,9893,9894,9895,9896,9897,
-9898,9899,9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,
-9913,9914,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,
-9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,
-9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,9956,9957,
-9958,9959,9960,9961,9962,9963,9964,9965,9966,9967,9968,9969,9970,9971,9972,
-9973,9974,9975,9976,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987,
-9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,
-10002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,
-10014,10015,10016,10017,10018,10019,10020,10021,10022,10023,10024,10025,
-10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037,
-10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,
-10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,
-10062,10063,10064,10065,10066,10067,10068,10069,10070,10071,10072,10073,
-10074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,
-10086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097,
-10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,
-10110,10111,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,
-10122,10123,10124,10125,10126,10127,10128,10129,10130,10131,10132,10133,
-10134,10135,10136,10137,10138,10139,10140,10141,10142,10143,10144,10145,
-10146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,
-10158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10169,
-10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,
-10182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,
-10194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,
-10206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,
-10218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,
-10230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,
-10242,10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,
-10254,10255,10256,10257,10258,10259,10260,10261,10262,10263,10264,10265,
-10266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10276,10277,
-10278,10279,10280,10281,10282,10283,10284,10285,10286,10287,10288,10289,
-10290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,
-10302,10303,10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,
-10314,10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,
-10326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,
-10338,10339,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,
-10350,10351,10352,10353,10354,10355,10356,10357,10358,10359,10360,10361,
-10362,10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,
-10374,10375,10376,10377,10378,10379,10380,10381,10382,10383,10384,10385,
-10386,10387,10388,10389,10390,10391,10392,10393,10394,10395,10396,10397,
-10398,10399,10400,10401,10402,10403,10404,10405,10406,10407,10408,10409,
-10410,10411,10412,10413,10414,10415,10416,10417,10418,10419,10420,10421,
-10422,10423,10424,10425,10426,10427,10428,10429,10430,10431,10432,10433,
-10434,10435,10436,10437,10438,10439,10440,10441,10442,10443,10444,10445,
-10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,
-10458,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,
-10470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,
-10482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,
-10494,10495,10496,10497,10498,10499,10500,10501,10502,10503,10504,10505,
-10506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,
-10518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,
-10530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,
-10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,
-10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,
-10566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,
-10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,
-10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,
-10602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,
-10614,10615,10616,10617,10618,10619,10620,10621,10622,10623,10624,10625,
-10626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,
-10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,
-10650,10651,10652,10653,10654,10655,10656,10657,10658,10659,10660,10661,
-10662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,
-10674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,
-10686,10687,10688,10689,10690,10691,10692,10693,10694,10695,10696,10697,
-10698,10699,10700,10701,10702,10703,10704,10705,10706,10707,10708,10709,
-10710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,
-10722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,
-10734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,
-10746,10747,10748,10749,10750,10751,10752,10753,10754,10755,10756,10757,
-10758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,
-10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,
-10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,
-10794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,
-10806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,
-10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828,10829,
-10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,
-10842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,
-10854,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,
-10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,
-10878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,
-10890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,
-10902,10903,10904,10905,10906,10907,10908,10909,10910,10911,10912,10913,
-10914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,
-10926,10927,10928,10929,10930,10931,10932,10933,10934,10935,10936,10937,
-10938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,
-10950,10951,10952,10953,10954,10955,10956,10957,10958,10959,10960,10961,
-10962,10963,10964,10965,10966,10967,10968,10969,10970,10971,10972,10973,
-10974,10975,10976,10977,10978,10979,10980,10981,10982,10983,10984,10985,
-10986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,
-10998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,
-11010,11011,11012,11013,11014,11015,11016,11017,11018,11019,11020,11021,
-11022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,
-11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,
-11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,
-11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,
-11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,
-11082,11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,
-11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,
-11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,
-11118,11119,11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,
-11130,11131,11132,11133,11134,11135,11136,11137,11138,11139,11140,11141,
-11142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,
-11154,11155,11156,11157,11158,11159,11160,11161,11162,11163,11164,11165,
-11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,
-11178,11179,11180,11181,11182,11183,11184,11185,11186,11187,11188,11189,
-11190,11191,11192,11193,11194,11195,11196,11197,11198,11199,11200,11201,
-11202,11203,11204,11205,11206,11207,11208,11209,11210,11211,11212,11213,
-11214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225,
-11226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,
-11238,11239,11240,11241,11242,11243,11244,11245,11246,11247,11248,11249,
-11250,11251,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,
-11262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
-11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
-11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
-11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
-11310,11311,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
-11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
-11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
-11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
-11310,11359,11360,11360,11362,11363,11364,570,574,11367,11367,11369,11369,
-11371,11371,11373,11374,11375,11376,11377,11378,11378,11380,11381,11381,
-11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11392,11394,
-11394,11396,11396,11398,11398,11400,11400,11402,11402,11404,11404,11406,
-11406,11408,11408,11410,11410,11412,11412,11414,11414,11416,11416,11418,
-11418,11420,11420,11422,11422,11424,11424,11426,11426,11428,11428,11430,
-11430,11432,11432,11434,11434,11436,11436,11438,11438,11440,11440,11442,
-11442,11444,11444,11446,11446,11448,11448,11450,11450,11452,11452,11454,
-11454,11456,11456,11458,11458,11460,11460,11462,11462,11464,11464,11466,
-11466,11468,11468,11470,11470,11472,11472,11474,11474,11476,11476,11478,
-11478,11480,11480,11482,11482,11484,11484,11486,11486,11488,11488,11490,
-11490,11492,11493,11494,11495,11496,11497,11498,11499,11499,11501,11501,
-11503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,
-11515,11516,11517,11518,11519,4256,4257,4258,4259,4260,4261,4262,4263,4264,
-4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,
-4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,
-11558,11559,11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,
-11570,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,
-11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,11592,11593,
-11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,
-11606,11607,11608,11609,11610,11611,11612,11613,11614,11615,11616,11617,
-11618,11619,11620,11621,11622,11623,11624,11625,11626,11627,11628,11629,
-11630,11631,11632,11633,11634,11635,11636,11637,11638,11639,11640,11641,
-11642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,
-11654,11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,
-11666,11667,11668,11669,11670,11671,11672,11673,11674,11675,11676,11677,
-11678,11679,11680,11681,11682,11683,11684,11685,11686,11687,11688,11689,
-11690,11691,11692,11693,11694,11695,11696,11697,11698,11699,11700,11701,
-11702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,
-11714,11715,11716,11717,11718,11719,11720,11721,11722,11723,11724,11725,
-11726,11727,11728,11729,11730,11731,11732,11733,11734,11735,11736,11737,
-11738,11739,11740,11741,11742,11743,11744,11745,11746,11747,11748,11749,
-11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,
-11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,
-11774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,
-11786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,
-11798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,
-11810,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821,
-11822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,
-11834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,
-11846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,
-11858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,
-11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,
-11882,11883,11884,11885,11886,11887,11888,11889,11890,11891,11892,11893,
-11894,11895,11896,11897,11898,11899,11900,11901,11902,11903,11904,11905,
-11906,11907,11908,11909,11910,11911,11912,11913,11914,11915,11916,11917,
-11918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,
-11930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,
-11942,11943,11944,11945,11946,11947,11948,11949,11950,11951,11952,11953,
-11954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,
-11966,11967,11968,11969,11970,11971,11972,11973,11974,11975,11976,11977,
-11978,11979,11980,11981,11982,11983,11984,11985,11986,11987,11988,11989,
-11990,11991,11992,11993,11994,11995,11996,11997,11998,11999,12000,12001,
-12002,12003,12004,12005,12006,12007,12008,12009,12010,12011,12012,12013,
-12014,12015,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,
-12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,
-12038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,
-12050,12051,12052,12053,12054,12055,12056,12057,12058,12059,12060,12061,
-12062,12063,12064,12065,12066,12067,12068,12069,12070,12071,12072,12073,
-12074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084,12085,
-12086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,
-12098,12099,12100,12101,12102,12103,12104,12105,12106,12107,12108,12109,
-12110,12111,12112,12113,12114,12115,12116,12117,12118,12119,12120,12121,
-12122,12123,12124,12125,12126,12127,12128,12129,12130,12131,12132,12133,
-12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,
-12146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,
-12158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168,12169,
-12170,12171,12172,12173,12174,12175,12176,12177,12178,12179,12180,12181,
-12182,12183,12184,12185,12186,12187,12188,12189,12190,12191,12192,12193,
-12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,
-12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,
-12218,12219,12220,12221,12222,12223,12224,12225,12226,12227,12228,12229,
-12230,12231,12232,12233,12234,12235,12236,12237,12238,12239,12240,12241,
-12242,12243,12244,12245,12246,12247,12248,12249,12250,12251,12252,12253,
-12254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264,12265,
-12266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,
-12278,12279,12280,12281,12282,12283,12284,12285,12286,12287,12288,12289,
-12290,12291,12292,12293,12294,12295,12296,12297,12298,12299,12300,12301,
-12302,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,
-12314,12315,12316,12317,12318,12319,12320,12321,12322,12323,12324,12325,
-12326,12327,12328,12329,12330,12331,12332,12333,12334,12335,12336,12337,
-12338,12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,
-12350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,
-12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,
-12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,
-12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,
-12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,
-12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,
-12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,
-12434,12435,12436,12437,12438,12439,12440,12441,12442,12443,12444,12445,
-12446,12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,
-12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,
-12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,
-12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,
-12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,
-12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,
-12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,
-12530,12531,12532,12533,12534,12535,12536,12537,12538,12539,12540,12541,
-12542,12543,12544,12545,12546,12547,12548,12549,12550,12551,12552,12553,
-12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,
-12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,
-12578,12579,12580,12581,12582,12583,12584,12585,12586,12587,12588,12589,
-12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,
-12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,
-12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,
-12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,
-12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,
-12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,
-12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,
-12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,
-12686,12687,12688,12689,12690,12691,12692,12693,12694,12695,12696,12697,
-12698,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,
-12710,12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,
-12722,12723,12724,12725,12726,12727,12728,12729,12730,12731,12732,12733,
-12734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,12745,
-12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,
-12758,12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,
-12770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,
-12782,12783,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,
-12794,12795,12796,12797,12798,12799,12800,12801,12802,12803,12804,12805,
-12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,
-12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,12828,12829,
-12830,12831,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,
-12842,12843,12844,12845,12846,12847,12848,12849,12850,12851,12852,12853,
-12854,12855,12856,12857,12858,12859,12860,12861,12862,12863,12864,12865,
-12866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,
-12878,12879,12880,12881,12882,12883,12884,12885,12886,12887,12888,12889,
-12890,12891,12892,12893,12894,12895,12896,12897,12898,12899,12900,12901,
-12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,
-12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,
-12926,12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,
-12938,12939,12940,12941,12942,12943,12944,12945,12946,12947,12948,12949,
-12950,12951,12952,12953,12954,12955,12956,12957,12958,12959,12960,12961,
-12962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973,
-12974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,
-12986,12987,12988,12989,12990,12991,12992,12993,12994,12995,12996,12997,
-12998,12999,13000,13001,13002,13003,13004,13005,13006,13007,13008,13009,
-13010,13011,13012,13013,13014,13015,13016,13017,13018,13019,13020,13021,
-13022,13023,13024,13025,13026,13027,13028,13029,13030,13031,13032,13033,
-13034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,
-13046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,
-13058,13059,13060,13061,13062,13063,13064,13065,13066,13067,13068,13069,
-13070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081,
-13082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,
-13094,13095,13096,13097,13098,13099,13100,13101,13102,13103,13104,13105,
-13106,13107,13108,13109,13110,13111,13112,13113,13114,13115,13116,13117,
-13118,13119,13120,13121,13122,13123,13124,13125,13126,13127,13128,13129,
-13130,13131,13132,13133,13134,13135,13136,13137,13138,13139,13140,13141,
-13142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,
-13154,13155,13156,13157,13158,13159,13160,13161,13162,13163,13164,13165,
-13166,13167,13168,13169,13170,13171,13172,13173,13174,13175,13176,13177,
-13178,13179,13180,13181,13182,13183,13184,13185,13186,13187,13188,13189,
-13190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201,
-13202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,
-13214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,
-13226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,
-13238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,
-13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,
-13262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,
-13274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,
-13286,13287,13288,13289,13290,13291,13292,13293,13294,13295,13296,13297,
-13298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,
-13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,
-13322,13323,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,
-13334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,
-13346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,
-13358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,
-13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,
-13382,13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,
-13394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,
-13406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,
-13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,
-13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,
-13442,13443,13444,13445,13446,13447,13448,13449,13450,13451,13452,13453,
-13454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,
-13466,13467,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,
-13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,
-13490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,
-13502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,
-13514,13515,13516,13517,13518,13519,13520,13521,13522,13523,13524,13525,
-13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,
-13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,
-13550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,
-13562,13563,13564,13565,13566,13567,13568,13569,13570,13571,13572,13573,
-13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,
-13586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,
-13598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,
-13610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,
-13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,
-13634,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,
-13646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,
-13658,13659,13660,13661,13662,13663,13664,13665,13666,13667,13668,13669,
-13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680,13681,
-13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,
-13694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,
-13706,13707,13708,13709,13710,13711,13712,13713,13714,13715,13716,13717,
-13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,
-13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,
-13742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,
-13754,13755,13756,13757,13758,13759,13760,13761,13762,13763,13764,13765,
-13766,13767,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,
-13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,
-13790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,
-13802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,
-13814,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,
-13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,
-13838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,
-13850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,
-13862,13863,13864,13865,13866,13867,13868,13869,13870,13871,13872,13873,
-13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,
-13886,13887,13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,
-13898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,
-13910,13911,13912,13913,13914,13915,13916,13917,13918,13919,13920,13921,
-13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,
-13934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,
-13946,13947,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,
-13958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,
-13970,13971,13972,13973,13974,13975,13976,13977,13978,13979,13980,13981,
-13982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,
-13994,13995,13996,13997,13998,13999,14000,14001,14002,14003,14004,14005,
-14006,14007,14008,14009,14010,14011,14012,14013,14014,14015,14016,14017,
-14018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,
-14030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,
-14042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,
-14054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,
-14066,14067,14068,14069,14070,14071,14072,14073,14074,14075,14076,14077,
-14078,14079,14080,14081,14082,14083,14084,14085,14086,14087,14088,14089,
-14090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,
-14102,14103,14104,14105,14106,14107,14108,14109,14110,14111,14112,14113,
-14114,14115,14116,14117,14118,14119,14120,14121,14122,14123,14124,14125,
-14126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,
-14138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,
-14150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,
-14162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,
-14174,14175,14176,14177,14178,14179,14180,14181,14182,14183,14184,14185,
-14186,14187,14188,14189,14190,14191,14192,14193,14194,14195,14196,14197,
-14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,
-14210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,
-14222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,
-14234,14235,14236,14237,14238,14239,14240,14241,14242,14243,14244,14245,
-14246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,
-14258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,
-14270,14271,14272,14273,14274,14275,14276,14277,14278,14279,14280,14281,
-14282,14283,14284,14285,14286,14287,14288,14289,14290,14291,14292,14293,
-14294,14295,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,
-14306,14307,14308,14309,14310,14311,14312,14313,14314,14315,14316,14317,
-14318,14319,14320,14321,14322,14323,14324,14325,14326,14327,14328,14329,
-14330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,
-14342,14343,14344,14345,14346,14347,14348,14349,14350,14351,14352,14353,
-14354,14355,14356,14357,14358,14359,14360,14361,14362,14363,14364,14365,
-14366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,
-14378,14379,14380,14381,14382,14383,14384,14385,14386,14387,14388,14389,
-14390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,
-14402,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,
-14414,14415,14416,14417,14418,14419,14420,14421,14422,14423,14424,14425,
-14426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,
-14438,14439,14440,14441,14442,14443,14444,14445,14446,14447,14448,14449,
-14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,
-14462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,
-14474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14485,
-14486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,
-14498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,
-14510,14511,14512,14513,14514,14515,14516,14517,14518,14519,14520,14521,
-14522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,
-14534,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,
-14546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,
-14558,14559,14560,14561,14562,14563,14564,14565,14566,14567,14568,14569,
-14570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,
-14582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,
-14594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,
-14606,14607,14608,14609,14610,14611,14612,14613,14614,14615,14616,14617,
-14618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,
-14630,14631,14632,14633,14634,14635,14636,14637,14638,14639,14640,14641,
-14642,14643,14644,14645,14646,14647,14648,14649,14650,14651,14652,14653,
-14654,14655,14656,14657,14658,14659,14660,14661,14662,14663,14664,14665,
-14666,14667,14668,14669,14670,14671,14672,14673,14674,14675,14676,14677,
-14678,14679,14680,14681,14682,14683,14684,14685,14686,14687,14688,14689,
-14690,14691,14692,14693,14694,14695,14696,14697,14698,14699,14700,14701,
-14702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,
-14714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,
-14726,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,
-14738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14749,
-14750,14751,14752,14753,14754,14755,14756,14757,14758,14759,14760,14761,
-14762,14763,14764,14765,14766,14767,14768,14769,14770,14771,14772,14773,
-14774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,
-14786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,
-14798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,
-14810,14811,14812,14813,14814,14815,14816,14817,14818,14819,14820,14821,
-14822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,
-14834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,
-14846,14847,14848,14849,14850,14851,14852,14853,14854,14855,14856,14857,
-14858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,14869,
-14870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,
-14882,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,
-14894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,
-14906,14907,14908,14909,14910,14911,14912,14913,14914,14915,14916,14917,
-14918,14919,14920,14921,14922,14923,14924,14925,14926,14927,14928,14929,
-14930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,
-14942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,
-14954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14964,14965,
-14966,14967,14968,14969,14970,14971,14972,14973,14974,14975,14976,14977,
-14978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,
-14990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,
-15002,15003,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,
-15014,15015,15016,15017,15018,15019,15020,15021,15022,15023,15024,15025,
-15026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,
-15038,15039,15040,15041,15042,15043,15044,15045,15046,15047,15048,15049,
-15050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,
-15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,
-15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,
-15086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,
-15098,15099,15100,15101,15102,15103,15104,15105,15106,15107,15108,15109,
-15110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,
-15122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,
-15134,15135,15136,15137,15138,15139,15140,15141,15142,15143,15144,15145,
-15146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,
-15158,15159,15160,15161,15162,15163,15164,15165,15166,15167,15168,15169,
-15170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,
-15182,15183,15184,15185,15186,15187,15188,15189,15190,15191,15192,15193,
-15194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,
-15206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,
-15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,
-15230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,
-15242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,
-15254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,
-15266,15267,15268,15269,15270,15271,15272,15273,15274,15275,15276,15277,
-15278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,
-15290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,
-15302,15303,15304,15305,15306,15307,15308,15309,15310,15311,15312,15313,
-15314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,
-15326,15327,15328,15329,15330,15331,15332,15333,15334,15335,15336,15337,
-15338,15339,15340,15341,15342,15343,15344,15345,15346,15347,15348,15349,
-15350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,
-15362,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,
-15374,15375,15376,15377,15378,15379,15380,15381,15382,15383,15384,15385,
-15386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,
-15398,15399,15400,15401,15402,15403,15404,15405,15406,15407,15408,15409,
-15410,15411,15412,15413,15414,15415,15416,15417,15418,15419,15420,15421,
-15422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,
-15434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,
-15446,15447,15448,15449,15450,15451,15452,15453,15454,15455,15456,15457,
-15458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,
-15470,15471,15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,
-15482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,
-15494,15495,15496,15497,15498,15499,15500,15501,15502,15503,15504,15505,
-15506,15507,15508,15509,15510,15511,15512,15513,15514,15515,15516,15517,
-15518,15519,15520,15521,15522,15523,15524,15525,15526,15527,15528,15529,
-15530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,
-15542,15543,15544,15545,15546,15547,15548,15549,15550,15551,15552,15553,
-15554,15555,15556,15557,15558,15559,15560,15561,15562,15563,15564,15565,
-15566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15577,
-15578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,
-15590,15591,15592,15593,15594,15595,15596,15597,15598,15599,15600,15601,
-15602,15603,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,
-15614,15615,15616,15617,15618,15619,15620,15621,15622,15623,15624,15625,
-15626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,
-15638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,
-15650,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,
-15662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,
-15674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15685,
-15686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,
-15698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,
-15710,15711,15712,15713,15714,15715,15716,15717,15718,15719,15720,15721,
-15722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,
-15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,
-15746,15747,15748,15749,15750,15751,15752,15753,15754,15755,15756,15757,
-15758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,
-15770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,
-15782,15783,15784,15785,15786,15787,15788,15789,15790,15791,15792,15793,
-15794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15805,
-15806,15807,15808,15809,15810,15811,15812,15813,15814,15815,15816,15817,
-15818,15819,15820,15821,15822,15823,15824,15825,15826,15827,15828,15829,
-15830,15831,15832,15833,15834,15835,15836,15837,15838,15839,15840,15841,
-15842,15843,15844,15845,15846,15847,15848,15849,15850,15851,15852,15853,
-15854,15855,15856,15857,15858,15859,15860,15861,15862,15863,15864,15865,
-15866,15867,15868,15869,15870,15871,15872,15873,15874,15875,15876,15877,
-15878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,
-15890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15901,
-15902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,
-15914,15915,15916,15917,15918,15919,15920,15921,15922,15923,15924,15925,
-15926,15927,15928,15929,15930,15931,15932,15933,15934,15935,15936,15937,
-15938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,
-15950,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,
-15962,15963,15964,15965,15966,15967,15968,15969,15970,15971,15972,15973,
-15974,15975,15976,15977,15978,15979,15980,15981,15982,15983,15984,15985,
-15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,
-15998,15999,16000,16001,16002,16003,16004,16005,16006,16007,16008,16009,
-16010,16011,16012,16013,16014,16015,16016,16017,16018,16019,16020,16021,
-16022,16023,16024,16025,16026,16027,16028,16029,16030,16031,16032,16033,
-16034,16035,16036,16037,16038,16039,16040,16041,16042,16043,16044,16045,
-16046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,
-16058,16059,16060,16061,16062,16063,16064,16065,16066,16067,16068,16069,
-16070,16071,16072,16073,16074,16075,16076,16077,16078,16079,16080,16081,
-16082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,
-16094,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,
-16106,16107,16108,16109,16110,16111,16112,16113,16114,16115,16116,16117,
-16118,16119,16120,16121,16122,16123,16124,16125,16126,16127,16128,16129,
-16130,16131,16132,16133,16134,16135,16136,16137,16138,16139,16140,16141,
-16142,16143,16144,16145,16146,16147,16148,16149,16150,16151,16152,16153,
-16154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,16165,
-16166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,
-16178,16179,16180,16181,16182,16183,16184,16185,16186,16187,16188,16189,
-16190,16191,16192,16193,16194,16195,16196,16197,16198,16199,16200,16201,
-16202,16203,16204,16205,16206,16207,16208,16209,16210,16211,16212,16213,
-16214,16215,16216,16217,16218,16219,16220,16221,16222,16223,16224,16225,
-16226,16227,16228,16229,16230,16231,16232,16233,16234,16235,16236,16237,
-16238,16239,16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,
-16250,16251,16252,16253,16254,16255,16256,16257,16258,16259,16260,16261,
-16262,16263,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,
-16274,16275,16276,16277,16278,16279,16280,16281,16282,16283,16284,16285,
-16286,16287,16288,16289,16290,16291,16292,16293,16294,16295,16296,16297,
-16298,16299,16300,16301,16302,16303,16304,16305,16306,16307,16308,16309,
-16310,16311,16312,16313,16314,16315,16316,16317,16318,16319,16320,16321,
-16322,16323,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,
-16334,16335,16336,16337,16338,16339,16340,16341,16342,16343,16344,16345,
-16346,16347,16348,16349,16350,16351,16352,16353,16354,16355,16356,16357,
-16358,16359,16360,16361,16362,16363,16364,16365,16366,16367,16368,16369,
-16370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,
-16382,16383,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,
-16394,16395,16396,16397,16398,16399,16400,16401,16402,16403,16404,16405,
-16406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,
-16418,16419,16420,16421,16422,16423,16424,16425,16426,16427,16428,16429,
-16430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,
-16442,16443,16444,16445,16446,16447,16448,16449,16450,16451,16452,16453,
-16454,16455,16456,16457,16458,16459,16460,16461,16462,16463,16464,16465,
-16466,16467,16468,16469,16470,16471,16472,16473,16474,16475,16476,16477,
-16478,16479,16480,16481,16482,16483,16484,16485,16486,16487,16488,16489,
-16490,16491,16492,16493,16494,16495,16496,16497,16498,16499,16500,16501,
-16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,
-16514,16515,16516,16517,16518,16519,16520,16521,16522,16523,16524,16525,
-16526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,
-16538,16539,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,
-16550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,
-16562,16563,16564,16565,16566,16567,16568,16569,16570,16571,16572,16573,
-16574,16575,16576,16577,16578,16579,16580,16581,16582,16583,16584,16585,
-16586,16587,16588,16589,16590,16591,16592,16593,16594,16595,16596,16597,
-16598,16599,16600,16601,16602,16603,16604,16605,16606,16607,16608,16609,
-16610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,16621,
-16622,16623,16624,16625,16626,16627,16628,16629,16630,16631,16632,16633,
-16634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,
-16646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,
-16658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,
-16670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,
-16682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,
-16694,16695,16696,16697,16698,16699,16700,16701,16702,16703,16704,16705,
-16706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,
-16718,16719,16720,16721,16722,16723,16724,16725,16726,16727,16728,16729,
-16730,16731,16732,16733,16734,16735,16736,16737,16738,16739,16740,16741,
-16742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,
-16754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,
-16766,16767,16768,16769,16770,16771,16772,16773,16774,16775,16776,16777,
-16778,16779,16780,16781,16782,16783,16784,16785,16786,16787,16788,16789,
-16790,16791,16792,16793,16794,16795,16796,16797,16798,16799,16800,16801,
-16802,16803,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,
-16814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825,
-16826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,
-16838,16839,16840,16841,16842,16843,16844,16845,16846,16847,16848,16849,
-16850,16851,16852,16853,16854,16855,16856,16857,16858,16859,16860,16861,
-16862,16863,16864,16865,16866,16867,16868,16869,16870,16871,16872,16873,
-16874,16875,16876,16877,16878,16879,16880,16881,16882,16883,16884,16885,
-16886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,
-16898,16899,16900,16901,16902,16903,16904,16905,16906,16907,16908,16909,
-16910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,
-16922,16923,16924,16925,16926,16927,16928,16929,16930,16931,16932,16933,
-16934,16935,16936,16937,16938,16939,16940,16941,16942,16943,16944,16945,
-16946,16947,16948,16949,16950,16951,16952,16953,16954,16955,16956,16957,
-16958,16959,16960,16961,16962,16963,16964,16965,16966,16967,16968,16969,
-16970,16971,16972,16973,16974,16975,16976,16977,16978,16979,16980,16981,
-16982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16993,
-16994,16995,16996,16997,16998,16999,17000,17001,17002,17003,17004,17005,
-17006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,
-17018,17019,17020,17021,17022,17023,17024,17025,17026,17027,17028,17029,
-17030,17031,17032,17033,17034,17035,17036,17037,17038,17039,17040,17041,
-17042,17043,17044,17045,17046,17047,17048,17049,17050,17051,17052,17053,
-17054,17055,17056,17057,17058,17059,17060,17061,17062,17063,17064,17065,
-17066,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,17077,
-17078,17079,17080,17081,17082,17083,17084,17085,17086,17087,17088,17089,
-17090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,
-17102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,
-17114,17115,17116,17117,17118,17119,17120,17121,17122,17123,17124,17125,
-17126,17127,17128,17129,17130,17131,17132,17133,17134,17135,17136,17137,
-17138,17139,17140,17141,17142,17143,17144,17145,17146,17147,17148,17149,
-17150,17151,17152,17153,17154,17155,17156,17157,17158,17159,17160,17161,
-17162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,17173,
-17174,17175,17176,17177,17178,17179,17180,17181,17182,17183,17184,17185,
-17186,17187,17188,17189,17190,17191,17192,17193,17194,17195,17196,17197,
-17198,17199,17200,17201,17202,17203,17204,17205,17206,17207,17208,17209,
-17210,17211,17212,17213,17214,17215,17216,17217,17218,17219,17220,17221,
-17222,17223,17224,17225,17226,17227,17228,17229,17230,17231,17232,17233,
-17234,17235,17236,17237,17238,17239,17240,17241,17242,17243,17244,17245,
-17246,17247,17248,17249,17250,17251,17252,17253,17254,17255,17256,17257,
-17258,17259,17260,17261,17262,17263,17264,17265,17266,17267,17268,17269,
-17270,17271,17272,17273,17274,17275,17276,17277,17278,17279,17280,17281,
-17282,17283,17284,17285,17286,17287,17288,17289,17290,17291,17292,17293,
-17294,17295,17296,17297,17298,17299,17300,17301,17302,17303,17304,17305,
-17306,17307,17308,17309,17310,17311,17312,17313,17314,17315,17316,17317,
-17318,17319,17320,17321,17322,17323,17324,17325,17326,17327,17328,17329,
-17330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,
-17342,17343,17344,17345,17346,17347,17348,17349,17350,17351,17352,17353,
-17354,17355,17356,17357,17358,17359,17360,17361,17362,17363,17364,17365,
-17366,17367,17368,17369,17370,17371,17372,17373,17374,17375,17376,17377,
-17378,17379,17380,17381,17382,17383,17384,17385,17386,17387,17388,17389,
-17390,17391,17392,17393,17394,17395,17396,17397,17398,17399,17400,17401,
-17402,17403,17404,17405,17406,17407,17408,17409,17410,17411,17412,17413,
-17414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,
-17426,17427,17428,17429,17430,17431,17432,17433,17434,17435,17436,17437,
-17438,17439,17440,17441,17442,17443,17444,17445,17446,17447,17448,17449,
-17450,17451,17452,17453,17454,17455,17456,17457,17458,17459,17460,17461,
-17462,17463,17464,17465,17466,17467,17468,17469,17470,17471,17472,17473,
-17474,17475,17476,17477,17478,17479,17480,17481,17482,17483,17484,17485,
-17486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,
-17498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,
-17510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,
-17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,
-17534,17535,17536,17537,17538,17539,17540,17541,17542,17543,17544,17545,
-17546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,
-17558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,
-17570,17571,17572,17573,17574,17575,17576,17577,17578,17579,17580,17581,
-17582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,
-17594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,
-17606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,
-17618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17629,
-17630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,
-17642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,
-17654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,
-17666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17676,17677,
-17678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,
-17690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,
-17702,17703,17704,17705,17706,17707,17708,17709,17710,17711,17712,17713,
-17714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,
-17726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,
-17738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,
-17750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,
-17762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,
-17774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,
-17786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,
-17798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,
-17810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,
-17822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,
-17834,17835,17836,17837,17838,17839,17840,17841,17842,17843,17844,17845,
-17846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,
-17858,17859,17860,17861,17862,17863,17864,17865,17866,17867,17868,17869,
-17870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,
-17882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,
-17894,17895,17896,17897,17898,17899,17900,17901,17902,17903,17904,17905,
-17906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,
-17918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,
-17930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,
-17942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,
-17954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,
-17966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,
-17978,17979,17980,17981,17982,17983,17984,17985,17986,17987,17988,17989,
-17990,17991,17992,17993,17994,17995,17996,17997,17998,17999,18000,18001,
-18002,18003,18004,18005,18006,18007,18008,18009,18010,18011,18012,18013,
-18014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,
-18026,18027,18028,18029,18030,18031,18032,18033,18034,18035,18036,18037,
-18038,18039,18040,18041,18042,18043,18044,18045,18046,18047,18048,18049,
-18050,18051,18052,18053,18054,18055,18056,18057,18058,18059,18060,18061,
-18062,18063,18064,18065,18066,18067,18068,18069,18070,18071,18072,18073,
-18074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,
-18086,18087,18088,18089,18090,18091,18092,18093,18094,18095,18096,18097,
-18098,18099,18100,18101,18102,18103,18104,18105,18106,18107,18108,18109,
-18110,18111,18112,18113,18114,18115,18116,18117,18118,18119,18120,18121,
-18122,18123,18124,18125,18126,18127,18128,18129,18130,18131,18132,18133,
-18134,18135,18136,18137,18138,18139,18140,18141,18142,18143,18144,18145,
-18146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,
-18158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,
-18170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,
-18182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,
-18194,18195,18196,18197,18198,18199,18200,18201,18202,18203,18204,18205,
-18206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,
-18218,18219,18220,18221,18222,18223,18224,18225,18226,18227,18228,18229,
-18230,18231,18232,18233,18234,18235,18236,18237,18238,18239,18240,18241,
-18242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,
-18254,18255,18256,18257,18258,18259,18260,18261,18262,18263,18264,18265,
-18266,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,
-18278,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,
-18290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,
-18302,18303,18304,18305,18306,18307,18308,18309,18310,18311,18312,18313,
-18314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18325,
-18326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,
-18338,18339,18340,18341,18342,18343,18344,18345,18346,18347,18348,18349,
-18350,18351,18352,18353,18354,18355,18356,18357,18358,18359,18360,18361,
-18362,18363,18364,18365,18366,18367,18368,18369,18370,18371,18372,18373,
-18374,18375,18376,18377,18378,18379,18380,18381,18382,18383,18384,18385,
-18386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,
-18398,18399,18400,18401,18402,18403,18404,18405,18406,18407,18408,18409,
-18410,18411,18412,18413,18414,18415,18416,18417,18418,18419,18420,18421,
-18422,18423,18424,18425,18426,18427,18428,18429,18430,18431,18432,18433,
-18434,18435,18436,18437,18438,18439,18440,18441,18442,18443,18444,18445,
-18446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18457,
-18458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,
-18470,18471,18472,18473,18474,18475,18476,18477,18478,18479,18480,18481,
-18482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,
-18494,18495,18496,18497,18498,18499,18500,18501,18502,18503,18504,18505,
-18506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,
-18518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,
-18530,18531,18532,18533,18534,18535,18536,18537,18538,18539,18540,18541,
-18542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,
-18554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,
-18566,18567,18568,18569,18570,18571,18572,18573,18574,18575,18576,18577,
-18578,18579,18580,18581,18582,18583,18584,18585,18586,18587,18588,18589,
-18590,18591,18592,18593,18594,18595,18596,18597,18598,18599,18600,18601,
-18602,18603,18604,18605,18606,18607,18608,18609,18610,18611,18612,18613,
-18614,18615,18616,18617,18618,18619,18620,18621,18622,18623,18624,18625,
-18626,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,
-18638,18639,18640,18641,18642,18643,18644,18645,18646,18647,18648,18649,
-18650,18651,18652,18653,18654,18655,18656,18657,18658,18659,18660,18661,
-18662,18663,18664,18665,18666,18667,18668,18669,18670,18671,18672,18673,
-18674,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,
-18686,18687,18688,18689,18690,18691,18692,18693,18694,18695,18696,18697,
-18698,18699,18700,18701,18702,18703,18704,18705,18706,18707,18708,18709,
-18710,18711,18712,18713,18714,18715,18716,18717,18718,18719,18720,18721,
-18722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,
-18734,18735,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,
-18746,18747,18748,18749,18750,18751,18752,18753,18754,18755,18756,18757,
-18758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,
-18770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,
-18782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18792,18793,
-18794,18795,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,
-18806,18807,18808,18809,18810,18811,18812,18813,18814,18815,18816,18817,
-18818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18829,
-18830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,
-18842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,
-18854,18855,18856,18857,18858,18859,18860,18861,18862,18863,18864,18865,
-18866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,
-18878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18889,
-18890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,
-18902,18903,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,
-18914,18915,18916,18917,18918,18919,18920,18921,18922,18923,18924,18925,
-18926,18927,18928,18929,18930,18931,18932,18933,18934,18935,18936,18937,
-18938,18939,18940,18941,18942,18943,18944,18945,18946,18947,18948,18949,
-18950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,
-18962,18963,18964,18965,18966,18967,18968,18969,18970,18971,18972,18973,
-18974,18975,18976,18977,18978,18979,18980,18981,18982,18983,18984,18985,
-18986,18987,18988,18989,18990,18991,18992,18993,18994,18995,18996,18997,
-18998,18999,19000,19001,19002,19003,19004,19005,19006,19007,19008,19009,
-19010,19011,19012,19013,19014,19015,19016,19017,19018,19019,19020,19021,
-19022,19023,19024,19025,19026,19027,19028,19029,19030,19031,19032,19033,
-19034,19035,19036,19037,19038,19039,19040,19041,19042,19043,19044,19045,
-19046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,
-19058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,
-19070,19071,19072,19073,19074,19075,19076,19077,19078,19079,19080,19081,
-19082,19083,19084,19085,19086,19087,19088,19089,19090,19091,19092,19093,
-19094,19095,19096,19097,19098,19099,19100,19101,19102,19103,19104,19105,
-19106,19107,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,
-19118,19119,19120,19121,19122,19123,19124,19125,19126,19127,19128,19129,
-19130,19131,19132,19133,19134,19135,19136,19137,19138,19139,19140,19141,
-19142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19152,19153,
-19154,19155,19156,19157,19158,19159,19160,19161,19162,19163,19164,19165,
-19166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,19177,
-19178,19179,19180,19181,19182,19183,19184,19185,19186,19187,19188,19189,
-19190,19191,19192,19193,19194,19195,19196,19197,19198,19199,19200,19201,
-19202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,
-19214,19215,19216,19217,19218,19219,19220,19221,19222,19223,19224,19225,
-19226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,
-19238,19239,19240,19241,19242,19243,19244,19245,19246,19247,19248,19249,
-19250,19251,19252,19253,19254,19255,19256,19257,19258,19259,19260,19261,
-19262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,
-19274,19275,19276,19277,19278,19279,19280,19281,19282,19283,19284,19285,
-19286,19287,19288,19289,19290,19291,19292,19293,19294,19295,19296,19297,
-19298,19299,19300,19301,19302,19303,19304,19305,19306,19307,19308,19309,
-19310,19311,19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,
-19322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,19333,
-19334,19335,19336,19337,19338,19339,19340,19341,19342,19343,19344,19345,
-19346,19347,19348,19349,19350,19351,19352,19353,19354,19355,19356,19357,
-19358,19359,19360,19361,19362,19363,19364,19365,19366,19367,19368,19369,
-19370,19371,19372,19373,19374,19375,19376,19377,19378,19379,19380,19381,
-19382,19383,19384,19385,19386,19387,19388,19389,19390,19391,19392,19393,
-19394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,19405,
-19406,19407,19408,19409,19410,19411,19412,19413,19414,19415,19416,19417,
-19418,19419,19420,19421,19422,19423,19424,19425,19426,19427,19428,19429,
-19430,19431,19432,19433,19434,19435,19436,19437,19438,19439,19440,19441,
-19442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,
-19454,19455,19456,19457,19458,19459,19460,19461,19462,19463,19464,19465,
-19466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,19477,
-19478,19479,19480,19481,19482,19483,19484,19485,19486,19487,19488,19489,
-19490,19491,19492,19493,19494,19495,19496,19497,19498,19499,19500,19501,
-19502,19503,19504,19505,19506,19507,19508,19509,19510,19511,19512,19513,
-19514,19515,19516,19517,19518,19519,19520,19521,19522,19523,19524,19525,
-19526,19527,19528,19529,19530,19531,19532,19533,19534,19535,19536,19537,
-19538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,
-19550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19561,
-19562,19563,19564,19565,19566,19567,19568,19569,19570,19571,19572,19573,
-19574,19575,19576,19577,19578,19579,19580,19581,19582,19583,19584,19585,
-19586,19587,19588,19589,19590,19591,19592,19593,19594,19595,19596,19597,
-19598,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,
-19610,19611,19612,19613,19614,19615,19616,19617,19618,19619,19620,19621,
-19622,19623,19624,19625,19626,19627,19628,19629,19630,19631,19632,19633,
-19634,19635,19636,19637,19638,19639,19640,19641,19642,19643,19644,19645,
-19646,19647,19648,19649,19650,19651,19652,19653,19654,19655,19656,19657,
-19658,19659,19660,19661,19662,19663,19664,19665,19666,19667,19668,19669,
-19670,19671,19672,19673,19674,19675,19676,19677,19678,19679,19680,19681,
-19682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,
-19694,19695,19696,19697,19698,19699,19700,19701,19702,19703,19704,19705,
-19706,19707,19708,19709,19710,19711,19712,19713,19714,19715,19716,19717,
-19718,19719,19720,19721,19722,19723,19724,19725,19726,19727,19728,19729,
-19730,19731,19732,19733,19734,19735,19736,19737,19738,19739,19740,19741,
-19742,19743,19744,19745,19746,19747,19748,19749,19750,19751,19752,19753,
-19754,19755,19756,19757,19758,19759,19760,19761,19762,19763,19764,19765,
-19766,19767,19768,19769,19770,19771,19772,19773,19774,19775,19776,19777,
-19778,19779,19780,19781,19782,19783,19784,19785,19786,19787,19788,19789,
-19790,19791,19792,19793,19794,19795,19796,19797,19798,19799,19800,19801,
-19802,19803,19804,19805,19806,19807,19808,19809,19810,19811,19812,19813,
-19814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,
-19826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,
-19838,19839,19840,19841,19842,19843,19844,19845,19846,19847,19848,19849,
-19850,19851,19852,19853,19854,19855,19856,19857,19858,19859,19860,19861,
-19862,19863,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,
-19874,19875,19876,19877,19878,19879,19880,19881,19882,19883,19884,19885,
-19886,19887,19888,19889,19890,19891,19892,19893,19894,19895,19896,19897,
-19898,19899,19900,19901,19902,19903,19904,19905,19906,19907,19908,19909,
-19910,19911,19912,19913,19914,19915,19916,19917,19918,19919,19920,19921,
-19922,19923,19924,19925,19926,19927,19928,19929,19930,19931,19932,19933,
-19934,19935,19936,19937,19938,19939,19940,19941,19942,19943,19944,19945,
-19946,19947,19948,19949,19950,19951,19952,19953,19954,19955,19956,19957,
-19958,19959,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,
-19970,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,19981,
-19982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,
-19994,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,20005,
-20006,20007,20008,20009,20010,20011,20012,20013,20014,20015,20016,20017,
-20018,20019,20020,20021,20022,20023,20024,20025,20026,20027,20028,20029,
-20030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,
-20042,20043,20044,20045,20046,20047,20048,20049,20050,20051,20052,20053,
-20054,20055,20056,20057,20058,20059,20060,20061,20062,20063,20064,20065,
-20066,20067,20068,20069,20070,20071,20072,20073,20074,20075,20076,20077,
-20078,20079,20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,
-20090,20091,20092,20093,20094,20095,20096,20097,20098,20099,20100,20101,
-20102,20103,20104,20105,20106,20107,20108,20109,20110,20111,20112,20113,
-20114,20115,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,
-20126,20127,20128,20129,20130,20131,20132,20133,20134,20135,20136,20137,
-20138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,
-20150,20151,20152,20153,20154,20155,20156,20157,20158,20159,20160,20161,
-20162,20163,20164,20165,20166,20167,20168,20169,20170,20171,20172,20173,
-20174,20175,20176,20177,20178,20179,20180,20181,20182,20183,20184,20185,
-20186,20187,20188,20189,20190,20191,20192,20193,20194,20195,20196,20197,
-20198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,20209,
-20210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,
-20222,20223,20224,20225,20226,20227,20228,20229,20230,20231,20232,20233,
-20234,20235,20236,20237,20238,20239,20240,20241,20242,20243,20244,20245,
-20246,20247,20248,20249,20250,20251,20252,20253,20254,20255,20256,20257,
-20258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,
-20270,20271,20272,20273,20274,20275,20276,20277,20278,20279,20280,20281,
-20282,20283,20284,20285,20286,20287,20288,20289,20290,20291,20292,20293,
-20294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,
-20306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,
-20318,20319,20320,20321,20322,20323,20324,20325,20326,20327,20328,20329,
-20330,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,
-20342,20343,20344,20345,20346,20347,20348,20349,20350,20351,20352,20353,
-20354,20355,20356,20357,20358,20359,20360,20361,20362,20363,20364,20365,
-20366,20367,20368,20369,20370,20371,20372,20373,20374,20375,20376,20377,
-20378,20379,20380,20381,20382,20383,20384,20385,20386,20387,20388,20389,
-20390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,
-20402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,
-20414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,
-20426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,
-20438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,
-20450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,
-20462,20463,20464,20465,20466,20467,20468,20469,20470,20471,20472,20473,
-20474,20475,20476,20477,20478,20479,20480,20481,20482,20483,20484,20485,
-20486,20487,20488,20489,20490,20491,20492,20493,20494,20495,20496,20497,
-20498,20499,20500,20501,20502,20503,20504,20505,20506,20507,20508,20509,
-20510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,
-20522,20523,20524,20525,20526,20527,20528,20529,20530,20531,20532,20533,
-20534,20535,20536,20537,20538,20539,20540,20541,20542,20543,20544,20545,
-20546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,
-20558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,
-20570,20571,20572,20573,20574,20575,20576,20577,20578,20579,20580,20581,
-20582,20583,20584,20585,20586,20587,20588,20589,20590,20591,20592,20593,
-20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,
-20606,20607,20608,20609,20610,20611,20612,20613,20614,20615,20616,20617,
-20618,20619,20620,20621,20622,20623,20624,20625,20626,20627,20628,20629,
-20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,
-20642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,
-20654,20655,20656,20657,20658,20659,20660,20661,20662,20663,20664,20665,
-20666,20667,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,
-20678,20679,20680,20681,20682,20683,20684,20685,20686,20687,20688,20689,
-20690,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,
-20702,20703,20704,20705,20706,20707,20708,20709,20710,20711,20712,20713,
-20714,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,20725,
-20726,20727,20728,20729,20730,20731,20732,20733,20734,20735,20736,20737,
-20738,20739,20740,20741,20742,20743,20744,20745,20746,20747,20748,20749,
-20750,20751,20752,20753,20754,20755,20756,20757,20758,20759,20760,20761,
-20762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,
-20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,
-20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,
-20798,20799,20800,20801,20802,20803,20804,20805,20806,20807,20808,20809,
-20810,20811,20812,20813,20814,20815,20816,20817,20818,20819,20820,20821,
-20822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,
-20834,20835,20836,20837,20838,20839,20840,20841,20842,20843,20844,20845,
-20846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,
-20858,20859,20860,20861,20862,20863,20864,20865,20866,20867,20868,20869,
-20870,20871,20872,20873,20874,20875,20876,20877,20878,20879,20880,20881,
-20882,20883,20884,20885,20886,20887,20888,20889,20890,20891,20892,20893,
-20894,20895,20896,20897,20898,20899,20900,20901,20902,20903,20904,20905,
-20906,20907,20908,20909,20910,20911,20912,20913,20914,20915,20916,20917,
-20918,20919,20920,20921,20922,20923,20924,20925,20926,20927,20928,20929,
-20930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,20941,
-20942,20943,20944,20945,20946,20947,20948,20949,20950,20951,20952,20953,
-20954,20955,20956,20957,20958,20959,20960,20961,20962,20963,20964,20965,
-20966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,
-20978,20979,20980,20981,20982,20983,20984,20985,20986,20987,20988,20989,
-20990,20991,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,
-21002,21003,21004,21005,21006,21007,21008,21009,21010,21011,21012,21013,
-21014,21015,21016,21017,21018,21019,21020,21021,21022,21023,21024,21025,
-21026,21027,21028,21029,21030,21031,21032,21033,21034,21035,21036,21037,
-21038,21039,21040,21041,21042,21043,21044,21045,21046,21047,21048,21049,
-21050,21051,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,
-21062,21063,21064,21065,21066,21067,21068,21069,21070,21071,21072,21073,
-21074,21075,21076,21077,21078,21079,21080,21081,21082,21083,21084,21085,
-21086,21087,21088,21089,21090,21091,21092,21093,21094,21095,21096,21097,
-21098,21099,21100,21101,21102,21103,21104,21105,21106,21107,21108,21109,
-21110,21111,21112,21113,21114,21115,21116,21117,21118,21119,21120,21121,
-21122,21123,21124,21125,21126,21127,21128,21129,21130,21131,21132,21133,
-21134,21135,21136,21137,21138,21139,21140,21141,21142,21143,21144,21145,
-21146,21147,21148,21149,21150,21151,21152,21153,21154,21155,21156,21157,
-21158,21159,21160,21161,21162,21163,21164,21165,21166,21167,21168,21169,
-21170,21171,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,
-21182,21183,21184,21185,21186,21187,21188,21189,21190,21191,21192,21193,
-21194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,
-21206,21207,21208,21209,21210,21211,21212,21213,21214,21215,21216,21217,
-21218,21219,21220,21221,21222,21223,21224,21225,21226,21227,21228,21229,
-21230,21231,21232,21233,21234,21235,21236,21237,21238,21239,21240,21241,
-21242,21243,21244,21245,21246,21247,21248,21249,21250,21251,21252,21253,
-21254,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,
-21266,21267,21268,21269,21270,21271,21272,21273,21274,21275,21276,21277,
-21278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,
-21290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,
-21302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,
-21314,21315,21316,21317,21318,21319,21320,21321,21322,21323,21324,21325,
-21326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,
-21338,21339,21340,21341,21342,21343,21344,21345,21346,21347,21348,21349,
-21350,21351,21352,21353,21354,21355,21356,21357,21358,21359,21360,21361,
-21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,
-21374,21375,21376,21377,21378,21379,21380,21381,21382,21383,21384,21385,
-21386,21387,21388,21389,21390,21391,21392,21393,21394,21395,21396,21397,
-21398,21399,21400,21401,21402,21403,21404,21405,21406,21407,21408,21409,
-21410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,21421,
-21422,21423,21424,21425,21426,21427,21428,21429,21430,21431,21432,21433,
-21434,21435,21436,21437,21438,21439,21440,21441,21442,21443,21444,21445,
-21446,21447,21448,21449,21450,21451,21452,21453,21454,21455,21456,21457,
-21458,21459,21460,21461,21462,21463,21464,21465,21466,21467,21468,21469,
-21470,21471,21472,21473,21474,21475,21476,21477,21478,21479,21480,21481,
-21482,21483,21484,21485,21486,21487,21488,21489,21490,21491,21492,21493,
-21494,21495,21496,21497,21498,21499,21500,21501,21502,21503,21504,21505,
-21506,21507,21508,21509,21510,21511,21512,21513,21514,21515,21516,21517,
-21518,21519,21520,21521,21522,21523,21524,21525,21526,21527,21528,21529,
-21530,21531,21532,21533,21534,21535,21536,21537,21538,21539,21540,21541,
-21542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552,21553,
-21554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,
-21566,21567,21568,21569,21570,21571,21572,21573,21574,21575,21576,21577,
-21578,21579,21580,21581,21582,21583,21584,21585,21586,21587,21588,21589,
-21590,21591,21592,21593,21594,21595,21596,21597,21598,21599,21600,21601,
-21602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,
-21614,21615,21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,
-21626,21627,21628,21629,21630,21631,21632,21633,21634,21635,21636,21637,
-21638,21639,21640,21641,21642,21643,21644,21645,21646,21647,21648,21649,
-21650,21651,21652,21653,21654,21655,21656,21657,21658,21659,21660,21661,
-21662,21663,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,
-21674,21675,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,
-21686,21687,21688,21689,21690,21691,21692,21693,21694,21695,21696,21697,
-21698,21699,21700,21701,21702,21703,21704,21705,21706,21707,21708,21709,
-21710,21711,21712,21713,21714,21715,21716,21717,21718,21719,21720,21721,
-21722,21723,21724,21725,21726,21727,21728,21729,21730,21731,21732,21733,
-21734,21735,21736,21737,21738,21739,21740,21741,21742,21743,21744,21745,
-21746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,
-21758,21759,21760,21761,21762,21763,21764,21765,21766,21767,21768,21769,
-21770,21771,21772,21773,21774,21775,21776,21777,21778,21779,21780,21781,
-21782,21783,21784,21785,21786,21787,21788,21789,21790,21791,21792,21793,
-21794,21795,21796,21797,21798,21799,21800,21801,21802,21803,21804,21805,
-21806,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,
-21818,21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,21829,
-21830,21831,21832,21833,21834,21835,21836,21837,21838,21839,21840,21841,
-21842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,
-21854,21855,21856,21857,21858,21859,21860,21861,21862,21863,21864,21865,
-21866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21877,
-21878,21879,21880,21881,21882,21883,21884,21885,21886,21887,21888,21889,
-21890,21891,21892,21893,21894,21895,21896,21897,21898,21899,21900,21901,
-21902,21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,21913,
-21914,21915,21916,21917,21918,21919,21920,21921,21922,21923,21924,21925,
-21926,21927,21928,21929,21930,21931,21932,21933,21934,21935,21936,21937,
-21938,21939,21940,21941,21942,21943,21944,21945,21946,21947,21948,21949,
-21950,21951,21952,21953,21954,21955,21956,21957,21958,21959,21960,21961,
-21962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,
-21974,21975,21976,21977,21978,21979,21980,21981,21982,21983,21984,21985,
-21986,21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,21997,
-21998,21999,22000,22001,22002,22003,22004,22005,22006,22007,22008,22009,
-22010,22011,22012,22013,22014,22015,22016,22017,22018,22019,22020,22021,
-22022,22023,22024,22025,22026,22027,22028,22029,22030,22031,22032,22033,
-22034,22035,22036,22037,22038,22039,22040,22041,22042,22043,22044,22045,
-22046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,
-22058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,
-22070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,
-22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,
-22094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,
-22106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,22117,
-22118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,
-22130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,
-22142,22143,22144,22145,22146,22147,22148,22149,22150,22151,22152,22153,
-22154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,
-22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,
-22178,22179,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,
-22190,22191,22192,22193,22194,22195,22196,22197,22198,22199,22200,22201,
-22202,22203,22204,22205,22206,22207,22208,22209,22210,22211,22212,22213,
-22214,22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,22225,
-22226,22227,22228,22229,22230,22231,22232,22233,22234,22235,22236,22237,
-22238,22239,22240,22241,22242,22243,22244,22245,22246,22247,22248,22249,
-22250,22251,22252,22253,22254,22255,22256,22257,22258,22259,22260,22261,
-22262,22263,22264,22265,22266,22267,22268,22269,22270,22271,22272,22273,
-22274,22275,22276,22277,22278,22279,22280,22281,22282,22283,22284,22285,
-22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,
-22298,22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,22309,
-22310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,22321,
-22322,22323,22324,22325,22326,22327,22328,22329,22330,22331,22332,22333,
-22334,22335,22336,22337,22338,22339,22340,22341,22342,22343,22344,22345,
-22346,22347,22348,22349,22350,22351,22352,22353,22354,22355,22356,22357,
-22358,22359,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,
-22370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,
-22382,22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,
-22394,22395,22396,22397,22398,22399,22400,22401,22402,22403,22404,22405,
-22406,22407,22408,22409,22410,22411,22412,22413,22414,22415,22416,22417,
-22418,22419,22420,22421,22422,22423,22424,22425,22426,22427,22428,22429,
-22430,22431,22432,22433,22434,22435,22436,22437,22438,22439,22440,22441,
-22442,22443,22444,22445,22446,22447,22448,22449,22450,22451,22452,22453,
-22454,22455,22456,22457,22458,22459,22460,22461,22462,22463,22464,22465,
-22466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,
-22478,22479,22480,22481,22482,22483,22484,22485,22486,22487,22488,22489,
-22490,22491,22492,22493,22494,22495,22496,22497,22498,22499,22500,22501,
-22502,22503,22504,22505,22506,22507,22508,22509,22510,22511,22512,22513,
-22514,22515,22516,22517,22518,22519,22520,22521,22522,22523,22524,22525,
-22526,22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,22537,
-22538,22539,22540,22541,22542,22543,22544,22545,22546,22547,22548,22549,
-22550,22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,22561,
-22562,22563,22564,22565,22566,22567,22568,22569,22570,22571,22572,22573,
-22574,22575,22576,22577,22578,22579,22580,22581,22582,22583,22584,22585,
-22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22596,22597,
-22598,22599,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,
-22610,22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,22621,
-22622,22623,22624,22625,22626,22627,22628,22629,22630,22631,22632,22633,
-22634,22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,
-22646,22647,22648,22649,22650,22651,22652,22653,22654,22655,22656,22657,
-22658,22659,22660,22661,22662,22663,22664,22665,22666,22667,22668,22669,
-22670,22671,22672,22673,22674,22675,22676,22677,22678,22679,22680,22681,
-22682,22683,22684,22685,22686,22687,22688,22689,22690,22691,22692,22693,
-22694,22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,22705,
-22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22716,22717,
-22718,22719,22720,22721,22722,22723,22724,22725,22726,22727,22728,22729,
-22730,22731,22732,22733,22734,22735,22736,22737,22738,22739,22740,22741,
-22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,
-22754,22755,22756,22757,22758,22759,22760,22761,22762,22763,22764,22765,
-22766,22767,22768,22769,22770,22771,22772,22773,22774,22775,22776,22777,
-22778,22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,22789,
-22790,22791,22792,22793,22794,22795,22796,22797,22798,22799,22800,22801,
-22802,22803,22804,22805,22806,22807,22808,22809,22810,22811,22812,22813,
-22814,22815,22816,22817,22818,22819,22820,22821,22822,22823,22824,22825,
-22826,22827,22828,22829,22830,22831,22832,22833,22834,22835,22836,22837,
-22838,22839,22840,22841,22842,22843,22844,22845,22846,22847,22848,22849,
-22850,22851,22852,22853,22854,22855,22856,22857,22858,22859,22860,22861,
-22862,22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,22873,
-22874,22875,22876,22877,22878,22879,22880,22881,22882,22883,22884,22885,
-22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,
-22898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,
-22910,22911,22912,22913,22914,22915,22916,22917,22918,22919,22920,22921,
-22922,22923,22924,22925,22926,22927,22928,22929,22930,22931,22932,22933,
-22934,22935,22936,22937,22938,22939,22940,22941,22942,22943,22944,22945,
-22946,22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,22957,
-22958,22959,22960,22961,22962,22963,22964,22965,22966,22967,22968,22969,
-22970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,
-22982,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,
-22994,22995,22996,22997,22998,22999,23000,23001,23002,23003,23004,23005,
-23006,23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,23017,
-23018,23019,23020,23021,23022,23023,23024,23025,23026,23027,23028,23029,
-23030,23031,23032,23033,23034,23035,23036,23037,23038,23039,23040,23041,
-23042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,
-23054,23055,23056,23057,23058,23059,23060,23061,23062,23063,23064,23065,
-23066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,
-23078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,
-23090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,
-23102,23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,23113,
-23114,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23125,
-23126,23127,23128,23129,23130,23131,23132,23133,23134,23135,23136,23137,
-23138,23139,23140,23141,23142,23143,23144,23145,23146,23147,23148,23149,
-23150,23151,23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,
-23162,23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,23173,
-23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,
-23186,23187,23188,23189,23190,23191,23192,23193,23194,23195,23196,23197,
-23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,
-23210,23211,23212,23213,23214,23215,23216,23217,23218,23219,23220,23221,
-23222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,
-23234,23235,23236,23237,23238,23239,23240,23241,23242,23243,23244,23245,
-23246,23247,23248,23249,23250,23251,23252,23253,23254,23255,23256,23257,
-23258,23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,23269,
-23270,23271,23272,23273,23274,23275,23276,23277,23278,23279,23280,23281,
-23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,
-23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23305,
-23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,
-23318,23319,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,
-23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,
-23342,23343,23344,23345,23346,23347,23348,23349,23350,23351,23352,23353,
-23354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,
-23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,
-23378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23389,
-23390,23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,23401,
-23402,23403,23404,23405,23406,23407,23408,23409,23410,23411,23412,23413,
-23414,23415,23416,23417,23418,23419,23420,23421,23422,23423,23424,23425,
-23426,23427,23428,23429,23430,23431,23432,23433,23434,23435,23436,23437,
-23438,23439,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,
-23450,23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,23461,
-23462,23463,23464,23465,23466,23467,23468,23469,23470,23471,23472,23473,
-23474,23475,23476,23477,23478,23479,23480,23481,23482,23483,23484,23485,
-23486,23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,23497,
-23498,23499,23500,23501,23502,23503,23504,23505,23506,23507,23508,23509,
-23510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,
-23522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,
-23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,
-23546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,
-23558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,
-23570,23571,23572,23573,23574,23575,23576,23577,23578,23579,23580,23581,
-23582,23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,23593,
-23594,23595,23596,23597,23598,23599,23600,23601,23602,23603,23604,23605,
-23606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,
-23618,23619,23620,23621,23622,23623,23624,23625,23626,23627,23628,23629,
-23630,23631,23632,23633,23634,23635,23636,23637,23638,23639,23640,23641,
-23642,23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,
-23654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,
-23666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,
-23678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,
-23690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,
-23702,23703,23704,23705,23706,23707,23708,23709,23710,23711,23712,23713,
-23714,23715,23716,23717,23718,23719,23720,23721,23722,23723,23724,23725,
-23726,23727,23728,23729,23730,23731,23732,23733,23734,23735,23736,23737,
-23738,23739,23740,23741,23742,23743,23744,23745,23746,23747,23748,23749,
-23750,23751,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,
-23762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,
-23774,23775,23776,23777,23778,23779,23780,23781,23782,23783,23784,23785,
-23786,23787,23788,23789,23790,23791,23792,23793,23794,23795,23796,23797,
-23798,23799,23800,23801,23802,23803,23804,23805,23806,23807,23808,23809,
-23810,23811,23812,23813,23814,23815,23816,23817,23818,23819,23820,23821,
-23822,23823,23824,23825,23826,23827,23828,23829,23830,23831,23832,23833,
-23834,23835,23836,23837,23838,23839,23840,23841,23842,23843,23844,23845,
-23846,23847,23848,23849,23850,23851,23852,23853,23854,23855,23856,23857,
-23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,
-23870,23871,23872,23873,23874,23875,23876,23877,23878,23879,23880,23881,
-23882,23883,23884,23885,23886,23887,23888,23889,23890,23891,23892,23893,
-23894,23895,23896,23897,23898,23899,23900,23901,23902,23903,23904,23905,
-23906,23907,23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,
-23918,23919,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,
-23930,23931,23932,23933,23934,23935,23936,23937,23938,23939,23940,23941,
-23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,
-23954,23955,23956,23957,23958,23959,23960,23961,23962,23963,23964,23965,
-23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,
-23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,
-23990,23991,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,
-24002,24003,24004,24005,24006,24007,24008,24009,24010,24011,24012,24013,
-24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,
-24026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,
-24038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,
-24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,
-24062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,
-24074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,
-24086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,
-24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,
-24110,24111,24112,24113,24114,24115,24116,24117,24118,24119,24120,24121,
-24122,24123,24124,24125,24126,24127,24128,24129,24130,24131,24132,24133,
-24134,24135,24136,24137,24138,24139,24140,24141,24142,24143,24144,24145,
-24146,24147,24148,24149,24150,24151,24152,24153,24154,24155,24156,24157,
-24158,24159,24160,24161,24162,24163,24164,24165,24166,24167,24168,24169,
-24170,24171,24172,24173,24174,24175,24176,24177,24178,24179,24180,24181,
-24182,24183,24184,24185,24186,24187,24188,24189,24190,24191,24192,24193,
-24194,24195,24196,24197,24198,24199,24200,24201,24202,24203,24204,24205,
-24206,24207,24208,24209,24210,24211,24212,24213,24214,24215,24216,24217,
-24218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,
-24230,24231,24232,24233,24234,24235,24236,24237,24238,24239,24240,24241,
-24242,24243,24244,24245,24246,24247,24248,24249,24250,24251,24252,24253,
-24254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,
-24266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,24277,
-24278,24279,24280,24281,24282,24283,24284,24285,24286,24287,24288,24289,
-24290,24291,24292,24293,24294,24295,24296,24297,24298,24299,24300,24301,
-24302,24303,24304,24305,24306,24307,24308,24309,24310,24311,24312,24313,
-24314,24315,24316,24317,24318,24319,24320,24321,24322,24323,24324,24325,
-24326,24327,24328,24329,24330,24331,24332,24333,24334,24335,24336,24337,
-24338,24339,24340,24341,24342,24343,24344,24345,24346,24347,24348,24349,
-24350,24351,24352,24353,24354,24355,24356,24357,24358,24359,24360,24361,
-24362,24363,24364,24365,24366,24367,24368,24369,24370,24371,24372,24373,
-24374,24375,24376,24377,24378,24379,24380,24381,24382,24383,24384,24385,
-24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,
-24398,24399,24400,24401,24402,24403,24404,24405,24406,24407,24408,24409,
-24410,24411,24412,24413,24414,24415,24416,24417,24418,24419,24420,24421,
-24422,24423,24424,24425,24426,24427,24428,24429,24430,24431,24432,24433,
-24434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,
-24446,24447,24448,24449,24450,24451,24452,24453,24454,24455,24456,24457,
-24458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,
-24470,24471,24472,24473,24474,24475,24476,24477,24478,24479,24480,24481,
-24482,24483,24484,24485,24486,24487,24488,24489,24490,24491,24492,24493,
-24494,24495,24496,24497,24498,24499,24500,24501,24502,24503,24504,24505,
-24506,24507,24508,24509,24510,24511,24512,24513,24514,24515,24516,24517,
-24518,24519,24520,24521,24522,24523,24524,24525,24526,24527,24528,24529,
-24530,24531,24532,24533,24534,24535,24536,24537,24538,24539,24540,24541,
-24542,24543,24544,24545,24546,24547,24548,24549,24550,24551,24552,24553,
-24554,24555,24556,24557,24558,24559,24560,24561,24562,24563,24564,24565,
-24566,24567,24568,24569,24570,24571,24572,24573,24574,24575,24576,24577,
-24578,24579,24580,24581,24582,24583,24584,24585,24586,24587,24588,24589,
-24590,24591,24592,24593,24594,24595,24596,24597,24598,24599,24600,24601,
-24602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,24613,
-24614,24615,24616,24617,24618,24619,24620,24621,24622,24623,24624,24625,
-24626,24627,24628,24629,24630,24631,24632,24633,24634,24635,24636,24637,
-24638,24639,24640,24641,24642,24643,24644,24645,24646,24647,24648,24649,
-24650,24651,24652,24653,24654,24655,24656,24657,24658,24659,24660,24661,
-24662,24663,24664,24665,24666,24667,24668,24669,24670,24671,24672,24673,
-24674,24675,24676,24677,24678,24679,24680,24681,24682,24683,24684,24685,
-24686,24687,24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,
-24698,24699,24700,24701,24702,24703,24704,24705,24706,24707,24708,24709,
-24710,24711,24712,24713,24714,24715,24716,24717,24718,24719,24720,24721,
-24722,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24733,
-24734,24735,24736,24737,24738,24739,24740,24741,24742,24743,24744,24745,
-24746,24747,24748,24749,24750,24751,24752,24753,24754,24755,24756,24757,
-24758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,
-24770,24771,24772,24773,24774,24775,24776,24777,24778,24779,24780,24781,
-24782,24783,24784,24785,24786,24787,24788,24789,24790,24791,24792,24793,
-24794,24795,24796,24797,24798,24799,24800,24801,24802,24803,24804,24805,
-24806,24807,24808,24809,24810,24811,24812,24813,24814,24815,24816,24817,
-24818,24819,24820,24821,24822,24823,24824,24825,24826,24827,24828,24829,
-24830,24831,24832,24833,24834,24835,24836,24837,24838,24839,24840,24841,
-24842,24843,24844,24845,24846,24847,24848,24849,24850,24851,24852,24853,
-24854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,
-24866,24867,24868,24869,24870,24871,24872,24873,24874,24875,24876,24877,
-24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,
-24890,24891,24892,24893,24894,24895,24896,24897,24898,24899,24900,24901,
-24902,24903,24904,24905,24906,24907,24908,24909,24910,24911,24912,24913,
-24914,24915,24916,24917,24918,24919,24920,24921,24922,24923,24924,24925,
-24926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,
-24938,24939,24940,24941,24942,24943,24944,24945,24946,24947,24948,24949,
-24950,24951,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,
-24962,24963,24964,24965,24966,24967,24968,24969,24970,24971,24972,24973,
-24974,24975,24976,24977,24978,24979,24980,24981,24982,24983,24984,24985,
-24986,24987,24988,24989,24990,24991,24992,24993,24994,24995,24996,24997,
-24998,24999,25000,25001,25002,25003,25004,25005,25006,25007,25008,25009,
-25010,25011,25012,25013,25014,25015,25016,25017,25018,25019,25020,25021,
-25022,25023,25024,25025,25026,25027,25028,25029,25030,25031,25032,25033,
-25034,25035,25036,25037,25038,25039,25040,25041,25042,25043,25044,25045,
-25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,
-25058,25059,25060,25061,25062,25063,25064,25065,25066,25067,25068,25069,
-25070,25071,25072,25073,25074,25075,25076,25077,25078,25079,25080,25081,
-25082,25083,25084,25085,25086,25087,25088,25089,25090,25091,25092,25093,
-25094,25095,25096,25097,25098,25099,25100,25101,25102,25103,25104,25105,
-25106,25107,25108,25109,25110,25111,25112,25113,25114,25115,25116,25117,
-25118,25119,25120,25121,25122,25123,25124,25125,25126,25127,25128,25129,
-25130,25131,25132,25133,25134,25135,25136,25137,25138,25139,25140,25141,
-25142,25143,25144,25145,25146,25147,25148,25149,25150,25151,25152,25153,
-25154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,
-25166,25167,25168,25169,25170,25171,25172,25173,25174,25175,25176,25177,
-25178,25179,25180,25181,25182,25183,25184,25185,25186,25187,25188,25189,
-25190,25191,25192,25193,25194,25195,25196,25197,25198,25199,25200,25201,
-25202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,
-25214,25215,25216,25217,25218,25219,25220,25221,25222,25223,25224,25225,
-25226,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,25237,
-25238,25239,25240,25241,25242,25243,25244,25245,25246,25247,25248,25249,
-25250,25251,25252,25253,25254,25255,25256,25257,25258,25259,25260,25261,
-25262,25263,25264,25265,25266,25267,25268,25269,25270,25271,25272,25273,
-25274,25275,25276,25277,25278,25279,25280,25281,25282,25283,25284,25285,
-25286,25287,25288,25289,25290,25291,25292,25293,25294,25295,25296,25297,
-25298,25299,25300,25301,25302,25303,25304,25305,25306,25307,25308,25309,
-25310,25311,25312,25313,25314,25315,25316,25317,25318,25319,25320,25321,
-25322,25323,25324,25325,25326,25327,25328,25329,25330,25331,25332,25333,
-25334,25335,25336,25337,25338,25339,25340,25341,25342,25343,25344,25345,
-25346,25347,25348,25349,25350,25351,25352,25353,25354,25355,25356,25357,
-25358,25359,25360,25361,25362,25363,25364,25365,25366,25367,25368,25369,
-25370,25371,25372,25373,25374,25375,25376,25377,25378,25379,25380,25381,
-25382,25383,25384,25385,25386,25387,25388,25389,25390,25391,25392,25393,
-25394,25395,25396,25397,25398,25399,25400,25401,25402,25403,25404,25405,
-25406,25407,25408,25409,25410,25411,25412,25413,25414,25415,25416,25417,
-25418,25419,25420,25421,25422,25423,25424,25425,25426,25427,25428,25429,
-25430,25431,25432,25433,25434,25435,25436,25437,25438,25439,25440,25441,
-25442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,
-25454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,
-25466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,
-25478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,
-25490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,25501,
-25502,25503,25504,25505,25506,25507,25508,25509,25510,25511,25512,25513,
-25514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,
-25526,25527,25528,25529,25530,25531,25532,25533,25534,25535,25536,25537,
-25538,25539,25540,25541,25542,25543,25544,25545,25546,25547,25548,25549,
-25550,25551,25552,25553,25554,25555,25556,25557,25558,25559,25560,25561,
-25562,25563,25564,25565,25566,25567,25568,25569,25570,25571,25572,25573,
-25574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,25585,
-25586,25587,25588,25589,25590,25591,25592,25593,25594,25595,25596,25597,
-25598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,
-25610,25611,25612,25613,25614,25615,25616,25617,25618,25619,25620,25621,
-25622,25623,25624,25625,25626,25627,25628,25629,25630,25631,25632,25633,
-25634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,
-25646,25647,25648,25649,25650,25651,25652,25653,25654,25655,25656,25657,
-25658,25659,25660,25661,25662,25663,25664,25665,25666,25667,25668,25669,
-25670,25671,25672,25673,25674,25675,25676,25677,25678,25679,25680,25681,
-25682,25683,25684,25685,25686,25687,25688,25689,25690,25691,25692,25693,
-25694,25695,25696,25697,25698,25699,25700,25701,25702,25703,25704,25705,
-25706,25707,25708,25709,25710,25711,25712,25713,25714,25715,25716,25717,
-25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,25728,25729,
-25730,25731,25732,25733,25734,25735,25736,25737,25738,25739,25740,25741,
-25742,25743,25744,25745,25746,25747,25748,25749,25750,25751,25752,25753,
-25754,25755,25756,25757,25758,25759,25760,25761,25762,25763,25764,25765,
-25766,25767,25768,25769,25770,25771,25772,25773,25774,25775,25776,25777,
-25778,25779,25780,25781,25782,25783,25784,25785,25786,25787,25788,25789,
-25790,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,25801,
-25802,25803,25804,25805,25806,25807,25808,25809,25810,25811,25812,25813,
-25814,25815,25816,25817,25818,25819,25820,25821,25822,25823,25824,25825,
-25826,25827,25828,25829,25830,25831,25832,25833,25834,25835,25836,25837,
-25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,
-25850,25851,25852,25853,25854,25855,25856,25857,25858,25859,25860,25861,
-25862,25863,25864,25865,25866,25867,25868,25869,25870,25871,25872,25873,
-25874,25875,25876,25877,25878,25879,25880,25881,25882,25883,25884,25885,
-25886,25887,25888,25889,25890,25891,25892,25893,25894,25895,25896,25897,
-25898,25899,25900,25901,25902,25903,25904,25905,25906,25907,25908,25909,
-25910,25911,25912,25913,25914,25915,25916,25917,25918,25919,25920,25921,
-25922,25923,25924,25925,25926,25927,25928,25929,25930,25931,25932,25933,
-25934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,25945,
-25946,25947,25948,25949,25950,25951,25952,25953,25954,25955,25956,25957,
-25958,25959,25960,25961,25962,25963,25964,25965,25966,25967,25968,25969,
-25970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,
-25982,25983,25984,25985,25986,25987,25988,25989,25990,25991,25992,25993,
-25994,25995,25996,25997,25998,25999,26000,26001,26002,26003,26004,26005,
-26006,26007,26008,26009,26010,26011,26012,26013,26014,26015,26016,26017,
-26018,26019,26020,26021,26022,26023,26024,26025,26026,26027,26028,26029,
-26030,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,
-26042,26043,26044,26045,26046,26047,26048,26049,26050,26051,26052,26053,
-26054,26055,26056,26057,26058,26059,26060,26061,26062,26063,26064,26065,
-26066,26067,26068,26069,26070,26071,26072,26073,26074,26075,26076,26077,
-26078,26079,26080,26081,26082,26083,26084,26085,26086,26087,26088,26089,
-26090,26091,26092,26093,26094,26095,26096,26097,26098,26099,26100,26101,
-26102,26103,26104,26105,26106,26107,26108,26109,26110,26111,26112,26113,
-26114,26115,26116,26117,26118,26119,26120,26121,26122,26123,26124,26125,
-26126,26127,26128,26129,26130,26131,26132,26133,26134,26135,26136,26137,
-26138,26139,26140,26141,26142,26143,26144,26145,26146,26147,26148,26149,
-26150,26151,26152,26153,26154,26155,26156,26157,26158,26159,26160,26161,
-26162,26163,26164,26165,26166,26167,26168,26169,26170,26171,26172,26173,
-26174,26175,26176,26177,26178,26179,26180,26181,26182,26183,26184,26185,
-26186,26187,26188,26189,26190,26191,26192,26193,26194,26195,26196,26197,
-26198,26199,26200,26201,26202,26203,26204,26205,26206,26207,26208,26209,
-26210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,
-26222,26223,26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,
-26234,26235,26236,26237,26238,26239,26240,26241,26242,26243,26244,26245,
-26246,26247,26248,26249,26250,26251,26252,26253,26254,26255,26256,26257,
-26258,26259,26260,26261,26262,26263,26264,26265,26266,26267,26268,26269,
-26270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,
-26282,26283,26284,26285,26286,26287,26288,26289,26290,26291,26292,26293,
-26294,26295,26296,26297,26298,26299,26300,26301,26302,26303,26304,26305,
-26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,
-26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26329,
-26330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,
-26342,26343,26344,26345,26346,26347,26348,26349,26350,26351,26352,26353,
-26354,26355,26356,26357,26358,26359,26360,26361,26362,26363,26364,26365,
-26366,26367,26368,26369,26370,26371,26372,26373,26374,26375,26376,26377,
-26378,26379,26380,26381,26382,26383,26384,26385,26386,26387,26388,26389,
-26390,26391,26392,26393,26394,26395,26396,26397,26398,26399,26400,26401,
-26402,26403,26404,26405,26406,26407,26408,26409,26410,26411,26412,26413,
-26414,26415,26416,26417,26418,26419,26420,26421,26422,26423,26424,26425,
-26426,26427,26428,26429,26430,26431,26432,26433,26434,26435,26436,26437,
-26438,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,
-26450,26451,26452,26453,26454,26455,26456,26457,26458,26459,26460,26461,
-26462,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,
-26474,26475,26476,26477,26478,26479,26480,26481,26482,26483,26484,26485,
-26486,26487,26488,26489,26490,26491,26492,26493,26494,26495,26496,26497,
-26498,26499,26500,26501,26502,26503,26504,26505,26506,26507,26508,26509,
-26510,26511,26512,26513,26514,26515,26516,26517,26518,26519,26520,26521,
-26522,26523,26524,26525,26526,26527,26528,26529,26530,26531,26532,26533,
-26534,26535,26536,26537,26538,26539,26540,26541,26542,26543,26544,26545,
-26546,26547,26548,26549,26550,26551,26552,26553,26554,26555,26556,26557,
-26558,26559,26560,26561,26562,26563,26564,26565,26566,26567,26568,26569,
-26570,26571,26572,26573,26574,26575,26576,26577,26578,26579,26580,26581,
-26582,26583,26584,26585,26586,26587,26588,26589,26590,26591,26592,26593,
-26594,26595,26596,26597,26598,26599,26600,26601,26602,26603,26604,26605,
-26606,26607,26608,26609,26610,26611,26612,26613,26614,26615,26616,26617,
-26618,26619,26620,26621,26622,26623,26624,26625,26626,26627,26628,26629,
-26630,26631,26632,26633,26634,26635,26636,26637,26638,26639,26640,26641,
-26642,26643,26644,26645,26646,26647,26648,26649,26650,26651,26652,26653,
-26654,26655,26656,26657,26658,26659,26660,26661,26662,26663,26664,26665,
-26666,26667,26668,26669,26670,26671,26672,26673,26674,26675,26676,26677,
-26678,26679,26680,26681,26682,26683,26684,26685,26686,26687,26688,26689,
-26690,26691,26692,26693,26694,26695,26696,26697,26698,26699,26700,26701,
-26702,26703,26704,26705,26706,26707,26708,26709,26710,26711,26712,26713,
-26714,26715,26716,26717,26718,26719,26720,26721,26722,26723,26724,26725,
-26726,26727,26728,26729,26730,26731,26732,26733,26734,26735,26736,26737,
-26738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,
-26750,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,
-26762,26763,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,
-26774,26775,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,
-26786,26787,26788,26789,26790,26791,26792,26793,26794,26795,26796,26797,
-26798,26799,26800,26801,26802,26803,26804,26805,26806,26807,26808,26809,
-26810,26811,26812,26813,26814,26815,26816,26817,26818,26819,26820,26821,
-26822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,
-26834,26835,26836,26837,26838,26839,26840,26841,26842,26843,26844,26845,
-26846,26847,26848,26849,26850,26851,26852,26853,26854,26855,26856,26857,
-26858,26859,26860,26861,26862,26863,26864,26865,26866,26867,26868,26869,
-26870,26871,26872,26873,26874,26875,26876,26877,26878,26879,26880,26881,
-26882,26883,26884,26885,26886,26887,26888,26889,26890,26891,26892,26893,
-26894,26895,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,
-26906,26907,26908,26909,26910,26911,26912,26913,26914,26915,26916,26917,
-26918,26919,26920,26921,26922,26923,26924,26925,26926,26927,26928,26929,
-26930,26931,26932,26933,26934,26935,26936,26937,26938,26939,26940,26941,
-26942,26943,26944,26945,26946,26947,26948,26949,26950,26951,26952,26953,
-26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26964,26965,
-26966,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,26977,
-26978,26979,26980,26981,26982,26983,26984,26985,26986,26987,26988,26989,
-26990,26991,26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,
-27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,
-27014,27015,27016,27017,27018,27019,27020,27021,27022,27023,27024,27025,
-27026,27027,27028,27029,27030,27031,27032,27033,27034,27035,27036,27037,
-27038,27039,27040,27041,27042,27043,27044,27045,27046,27047,27048,27049,
-27050,27051,27052,27053,27054,27055,27056,27057,27058,27059,27060,27061,
-27062,27063,27064,27065,27066,27067,27068,27069,27070,27071,27072,27073,
-27074,27075,27076,27077,27078,27079,27080,27081,27082,27083,27084,27085,
-27086,27087,27088,27089,27090,27091,27092,27093,27094,27095,27096,27097,
-27098,27099,27100,27101,27102,27103,27104,27105,27106,27107,27108,27109,
-27110,27111,27112,27113,27114,27115,27116,27117,27118,27119,27120,27121,
-27122,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27133,
-27134,27135,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,
-27146,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,
-27158,27159,27160,27161,27162,27163,27164,27165,27166,27167,27168,27169,
-27170,27171,27172,27173,27174,27175,27176,27177,27178,27179,27180,27181,
-27182,27183,27184,27185,27186,27187,27188,27189,27190,27191,27192,27193,
-27194,27195,27196,27197,27198,27199,27200,27201,27202,27203,27204,27205,
-27206,27207,27208,27209,27210,27211,27212,27213,27214,27215,27216,27217,
-27218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,
-27230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,
-27242,27243,27244,27245,27246,27247,27248,27249,27250,27251,27252,27253,
-27254,27255,27256,27257,27258,27259,27260,27261,27262,27263,27264,27265,
-27266,27267,27268,27269,27270,27271,27272,27273,27274,27275,27276,27277,
-27278,27279,27280,27281,27282,27283,27284,27285,27286,27287,27288,27289,
-27290,27291,27292,27293,27294,27295,27296,27297,27298,27299,27300,27301,
-27302,27303,27304,27305,27306,27307,27308,27309,27310,27311,27312,27313,
-27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,
-27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,
-27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,
-27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,
-27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,
-27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,
-27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,
-27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,
-27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,
-27422,27423,27424,27425,27426,27427,27428,27429,27430,27431,27432,27433,
-27434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,27445,
-27446,27447,27448,27449,27450,27451,27452,27453,27454,27455,27456,27457,
-27458,27459,27460,27461,27462,27463,27464,27465,27466,27467,27468,27469,
-27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27481,
-27482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,
-27494,27495,27496,27497,27498,27499,27500,27501,27502,27503,27504,27505,
-27506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,
-27518,27519,27520,27521,27522,27523,27524,27525,27526,27527,27528,27529,
-27530,27531,27532,27533,27534,27535,27536,27537,27538,27539,27540,27541,
-27542,27543,27544,27545,27546,27547,27548,27549,27550,27551,27552,27553,
-27554,27555,27556,27557,27558,27559,27560,27561,27562,27563,27564,27565,
-27566,27567,27568,27569,27570,27571,27572,27573,27574,27575,27576,27577,
-27578,27579,27580,27581,27582,27583,27584,27585,27586,27587,27588,27589,
-27590,27591,27592,27593,27594,27595,27596,27597,27598,27599,27600,27601,
-27602,27603,27604,27605,27606,27607,27608,27609,27610,27611,27612,27613,
-27614,27615,27616,27617,27618,27619,27620,27621,27622,27623,27624,27625,
-27626,27627,27628,27629,27630,27631,27632,27633,27634,27635,27636,27637,
-27638,27639,27640,27641,27642,27643,27644,27645,27646,27647,27648,27649,
-27650,27651,27652,27653,27654,27655,27656,27657,27658,27659,27660,27661,
-27662,27663,27664,27665,27666,27667,27668,27669,27670,27671,27672,27673,
-27674,27675,27676,27677,27678,27679,27680,27681,27682,27683,27684,27685,
-27686,27687,27688,27689,27690,27691,27692,27693,27694,27695,27696,27697,
-27698,27699,27700,27701,27702,27703,27704,27705,27706,27707,27708,27709,
-27710,27711,27712,27713,27714,27715,27716,27717,27718,27719,27720,27721,
-27722,27723,27724,27725,27726,27727,27728,27729,27730,27731,27732,27733,
-27734,27735,27736,27737,27738,27739,27740,27741,27742,27743,27744,27745,
-27746,27747,27748,27749,27750,27751,27752,27753,27754,27755,27756,27757,
-27758,27759,27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,
-27770,27771,27772,27773,27774,27775,27776,27777,27778,27779,27780,27781,
-27782,27783,27784,27785,27786,27787,27788,27789,27790,27791,27792,27793,
-27794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27804,27805,
-27806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,
-27818,27819,27820,27821,27822,27823,27824,27825,27826,27827,27828,27829,
-27830,27831,27832,27833,27834,27835,27836,27837,27838,27839,27840,27841,
-27842,27843,27844,27845,27846,27847,27848,27849,27850,27851,27852,27853,
-27854,27855,27856,27857,27858,27859,27860,27861,27862,27863,27864,27865,
-27866,27867,27868,27869,27870,27871,27872,27873,27874,27875,27876,27877,
-27878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,
-27890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,
-27902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,
-27914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,
-27926,27927,27928,27929,27930,27931,27932,27933,27934,27935,27936,27937,
-27938,27939,27940,27941,27942,27943,27944,27945,27946,27947,27948,27949,
-27950,27951,27952,27953,27954,27955,27956,27957,27958,27959,27960,27961,
-27962,27963,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,
-27974,27975,27976,27977,27978,27979,27980,27981,27982,27983,27984,27985,
-27986,27987,27988,27989,27990,27991,27992,27993,27994,27995,27996,27997,
-27998,27999,28000,28001,28002,28003,28004,28005,28006,28007,28008,28009,
-28010,28011,28012,28013,28014,28015,28016,28017,28018,28019,28020,28021,
-28022,28023,28024,28025,28026,28027,28028,28029,28030,28031,28032,28033,
-28034,28035,28036,28037,28038,28039,28040,28041,28042,28043,28044,28045,
-28046,28047,28048,28049,28050,28051,28052,28053,28054,28055,28056,28057,
-28058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,
-28070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,
-28082,28083,28084,28085,28086,28087,28088,28089,28090,28091,28092,28093,
-28094,28095,28096,28097,28098,28099,28100,28101,28102,28103,28104,28105,
-28106,28107,28108,28109,28110,28111,28112,28113,28114,28115,28116,28117,
-28118,28119,28120,28121,28122,28123,28124,28125,28126,28127,28128,28129,
-28130,28131,28132,28133,28134,28135,28136,28137,28138,28139,28140,28141,
-28142,28143,28144,28145,28146,28147,28148,28149,28150,28151,28152,28153,
-28154,28155,28156,28157,28158,28159,28160,28161,28162,28163,28164,28165,
-28166,28167,28168,28169,28170,28171,28172,28173,28174,28175,28176,28177,
-28178,28179,28180,28181,28182,28183,28184,28185,28186,28187,28188,28189,
-28190,28191,28192,28193,28194,28195,28196,28197,28198,28199,28200,28201,
-28202,28203,28204,28205,28206,28207,28208,28209,28210,28211,28212,28213,
-28214,28215,28216,28217,28218,28219,28220,28221,28222,28223,28224,28225,
-28226,28227,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,
-28238,28239,28240,28241,28242,28243,28244,28245,28246,28247,28248,28249,
-28250,28251,28252,28253,28254,28255,28256,28257,28258,28259,28260,28261,
-28262,28263,28264,28265,28266,28267,28268,28269,28270,28271,28272,28273,
-28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,
-28286,28287,28288,28289,28290,28291,28292,28293,28294,28295,28296,28297,
-28298,28299,28300,28301,28302,28303,28304,28305,28306,28307,28308,28309,
-28310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,
-28322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,
-28334,28335,28336,28337,28338,28339,28340,28341,28342,28343,28344,28345,
-28346,28347,28348,28349,28350,28351,28352,28353,28354,28355,28356,28357,
-28358,28359,28360,28361,28362,28363,28364,28365,28366,28367,28368,28369,
-28370,28371,28372,28373,28374,28375,28376,28377,28378,28379,28380,28381,
-28382,28383,28384,28385,28386,28387,28388,28389,28390,28391,28392,28393,
-28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,
-28406,28407,28408,28409,28410,28411,28412,28413,28414,28415,28416,28417,
-28418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,
-28430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,
-28442,28443,28444,28445,28446,28447,28448,28449,28450,28451,28452,28453,
-28454,28455,28456,28457,28458,28459,28460,28461,28462,28463,28464,28465,
-28466,28467,28468,28469,28470,28471,28472,28473,28474,28475,28476,28477,
-28478,28479,28480,28481,28482,28483,28484,28485,28486,28487,28488,28489,
-28490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,
-28502,28503,28504,28505,28506,28507,28508,28509,28510,28511,28512,28513,
-28514,28515,28516,28517,28518,28519,28520,28521,28522,28523,28524,28525,
-28526,28527,28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,
-28538,28539,28540,28541,28542,28543,28544,28545,28546,28547,28548,28549,
-28550,28551,28552,28553,28554,28555,28556,28557,28558,28559,28560,28561,
-28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28572,28573,
-28574,28575,28576,28577,28578,28579,28580,28581,28582,28583,28584,28585,
-28586,28587,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,
-28598,28599,28600,28601,28602,28603,28604,28605,28606,28607,28608,28609,
-28610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,28621,
-28622,28623,28624,28625,28626,28627,28628,28629,28630,28631,28632,28633,
-28634,28635,28636,28637,28638,28639,28640,28641,28642,28643,28644,28645,
-28646,28647,28648,28649,28650,28651,28652,28653,28654,28655,28656,28657,
-28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,
-28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,
-28682,28683,28684,28685,28686,28687,28688,28689,28690,28691,28692,28693,
-28694,28695,28696,28697,28698,28699,28700,28701,28702,28703,28704,28705,
-28706,28707,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,
-28718,28719,28720,28721,28722,28723,28724,28725,28726,28727,28728,28729,
-28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,
-28742,28743,28744,28745,28746,28747,28748,28749,28750,28751,28752,28753,
-28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,
-28766,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,
-28778,28779,28780,28781,28782,28783,28784,28785,28786,28787,28788,28789,
-28790,28791,28792,28793,28794,28795,28796,28797,28798,28799,28800,28801,
-28802,28803,28804,28805,28806,28807,28808,28809,28810,28811,28812,28813,
-28814,28815,28816,28817,28818,28819,28820,28821,28822,28823,28824,28825,
-28826,28827,28828,28829,28830,28831,28832,28833,28834,28835,28836,28837,
-28838,28839,28840,28841,28842,28843,28844,28845,28846,28847,28848,28849,
-28850,28851,28852,28853,28854,28855,28856,28857,28858,28859,28860,28861,
-28862,28863,28864,28865,28866,28867,28868,28869,28870,28871,28872,28873,
-28874,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,
-28886,28887,28888,28889,28890,28891,28892,28893,28894,28895,28896,28897,
-28898,28899,28900,28901,28902,28903,28904,28905,28906,28907,28908,28909,
-28910,28911,28912,28913,28914,28915,28916,28917,28918,28919,28920,28921,
-28922,28923,28924,28925,28926,28927,28928,28929,28930,28931,28932,28933,
-28934,28935,28936,28937,28938,28939,28940,28941,28942,28943,28944,28945,
-28946,28947,28948,28949,28950,28951,28952,28953,28954,28955,28956,28957,
-28958,28959,28960,28961,28962,28963,28964,28965,28966,28967,28968,28969,
-28970,28971,28972,28973,28974,28975,28976,28977,28978,28979,28980,28981,
-28982,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,
-28994,28995,28996,28997,28998,28999,29000,29001,29002,29003,29004,29005,
-29006,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,
-29018,29019,29020,29021,29022,29023,29024,29025,29026,29027,29028,29029,
-29030,29031,29032,29033,29034,29035,29036,29037,29038,29039,29040,29041,
-29042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,
-29054,29055,29056,29057,29058,29059,29060,29061,29062,29063,29064,29065,
-29066,29067,29068,29069,29070,29071,29072,29073,29074,29075,29076,29077,
-29078,29079,29080,29081,29082,29083,29084,29085,29086,29087,29088,29089,
-29090,29091,29092,29093,29094,29095,29096,29097,29098,29099,29100,29101,
-29102,29103,29104,29105,29106,29107,29108,29109,29110,29111,29112,29113,
-29114,29115,29116,29117,29118,29119,29120,29121,29122,29123,29124,29125,
-29126,29127,29128,29129,29130,29131,29132,29133,29134,29135,29136,29137,
-29138,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,29149,
-29150,29151,29152,29153,29154,29155,29156,29157,29158,29159,29160,29161,
-29162,29163,29164,29165,29166,29167,29168,29169,29170,29171,29172,29173,
-29174,29175,29176,29177,29178,29179,29180,29181,29182,29183,29184,29185,
-29186,29187,29188,29189,29190,29191,29192,29193,29194,29195,29196,29197,
-29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,
-29210,29211,29212,29213,29214,29215,29216,29217,29218,29219,29220,29221,
-29222,29223,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,
-29234,29235,29236,29237,29238,29239,29240,29241,29242,29243,29244,29245,
-29246,29247,29248,29249,29250,29251,29252,29253,29254,29255,29256,29257,
-29258,29259,29260,29261,29262,29263,29264,29265,29266,29267,29268,29269,
-29270,29271,29272,29273,29274,29275,29276,29277,29278,29279,29280,29281,
-29282,29283,29284,29285,29286,29287,29288,29289,29290,29291,29292,29293,
-29294,29295,29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,
-29306,29307,29308,29309,29310,29311,29312,29313,29314,29315,29316,29317,
-29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,
-29330,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,
-29342,29343,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,
-29354,29355,29356,29357,29358,29359,29360,29361,29362,29363,29364,29365,
-29366,29367,29368,29369,29370,29371,29372,29373,29374,29375,29376,29377,
-29378,29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,
-29390,29391,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,
-29402,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,
-29414,29415,29416,29417,29418,29419,29420,29421,29422,29423,29424,29425,
-29426,29427,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,
-29438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,
-29450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,
-29462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,
-29474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,
-29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,
-29498,29499,29500,29501,29502,29503,29504,29505,29506,29507,29508,29509,
-29510,29511,29512,29513,29514,29515,29516,29517,29518,29519,29520,29521,
-29522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,
-29534,29535,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,
-29546,29547,29548,29549,29550,29551,29552,29553,29554,29555,29556,29557,
-29558,29559,29560,29561,29562,29563,29564,29565,29566,29567,29568,29569,
-29570,29571,29572,29573,29574,29575,29576,29577,29578,29579,29580,29581,
-29582,29583,29584,29585,29586,29587,29588,29589,29590,29591,29592,29593,
-29594,29595,29596,29597,29598,29599,29600,29601,29602,29603,29604,29605,
-29606,29607,29608,29609,29610,29611,29612,29613,29614,29615,29616,29617,
-29618,29619,29620,29621,29622,29623,29624,29625,29626,29627,29628,29629,
-29630,29631,29632,29633,29634,29635,29636,29637,29638,29639,29640,29641,
-29642,29643,29644,29645,29646,29647,29648,29649,29650,29651,29652,29653,
-29654,29655,29656,29657,29658,29659,29660,29661,29662,29663,29664,29665,
-29666,29667,29668,29669,29670,29671,29672,29673,29674,29675,29676,29677,
-29678,29679,29680,29681,29682,29683,29684,29685,29686,29687,29688,29689,
-29690,29691,29692,29693,29694,29695,29696,29697,29698,29699,29700,29701,
-29702,29703,29704,29705,29706,29707,29708,29709,29710,29711,29712,29713,
-29714,29715,29716,29717,29718,29719,29720,29721,29722,29723,29724,29725,
-29726,29727,29728,29729,29730,29731,29732,29733,29734,29735,29736,29737,
-29738,29739,29740,29741,29742,29743,29744,29745,29746,29747,29748,29749,
-29750,29751,29752,29753,29754,29755,29756,29757,29758,29759,29760,29761,
-29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,
-29774,29775,29776,29777,29778,29779,29780,29781,29782,29783,29784,29785,
-29786,29787,29788,29789,29790,29791,29792,29793,29794,29795,29796,29797,
-29798,29799,29800,29801,29802,29803,29804,29805,29806,29807,29808,29809,
-29810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,
-29822,29823,29824,29825,29826,29827,29828,29829,29830,29831,29832,29833,
-29834,29835,29836,29837,29838,29839,29840,29841,29842,29843,29844,29845,
-29846,29847,29848,29849,29850,29851,29852,29853,29854,29855,29856,29857,
-29858,29859,29860,29861,29862,29863,29864,29865,29866,29867,29868,29869,
-29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,
-29882,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,
-29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,
-29906,29907,29908,29909,29910,29911,29912,29913,29914,29915,29916,29917,
-29918,29919,29920,29921,29922,29923,29924,29925,29926,29927,29928,29929,
-29930,29931,29932,29933,29934,29935,29936,29937,29938,29939,29940,29941,
-29942,29943,29944,29945,29946,29947,29948,29949,29950,29951,29952,29953,
-29954,29955,29956,29957,29958,29959,29960,29961,29962,29963,29964,29965,
-29966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,29977,
-29978,29979,29980,29981,29982,29983,29984,29985,29986,29987,29988,29989,
-29990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,
-30002,30003,30004,30005,30006,30007,30008,30009,30010,30011,30012,30013,
-30014,30015,30016,30017,30018,30019,30020,30021,30022,30023,30024,30025,
-30026,30027,30028,30029,30030,30031,30032,30033,30034,30035,30036,30037,
-30038,30039,30040,30041,30042,30043,30044,30045,30046,30047,30048,30049,
-30050,30051,30052,30053,30054,30055,30056,30057,30058,30059,30060,30061,
-30062,30063,30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,
-30074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,
-30086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,
-30098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,
-30110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,
-30122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,
-30134,30135,30136,30137,30138,30139,30140,30141,30142,30143,30144,30145,
-30146,30147,30148,30149,30150,30151,30152,30153,30154,30155,30156,30157,
-30158,30159,30160,30161,30162,30163,30164,30165,30166,30167,30168,30169,
-30170,30171,30172,30173,30174,30175,30176,30177,30178,30179,30180,30181,
-30182,30183,30184,30185,30186,30187,30188,30189,30190,30191,30192,30193,
-30194,30195,30196,30197,30198,30199,30200,30201,30202,30203,30204,30205,
-30206,30207,30208,30209,30210,30211,30212,30213,30214,30215,30216,30217,
-30218,30219,30220,30221,30222,30223,30224,30225,30226,30227,30228,30229,
-30230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,
-30242,30243,30244,30245,30246,30247,30248,30249,30250,30251,30252,30253,
-30254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,
-30266,30267,30268,30269,30270,30271,30272,30273,30274,30275,30276,30277,
-30278,30279,30280,30281,30282,30283,30284,30285,30286,30287,30288,30289,
-30290,30291,30292,30293,30294,30295,30296,30297,30298,30299,30300,30301,
-30302,30303,30304,30305,30306,30307,30308,30309,30310,30311,30312,30313,
-30314,30315,30316,30317,30318,30319,30320,30321,30322,30323,30324,30325,
-30326,30327,30328,30329,30330,30331,30332,30333,30334,30335,30336,30337,
-30338,30339,30340,30341,30342,30343,30344,30345,30346,30347,30348,30349,
-30350,30351,30352,30353,30354,30355,30356,30357,30358,30359,30360,30361,
-30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30372,30373,
-30374,30375,30376,30377,30378,30379,30380,30381,30382,30383,30384,30385,
-30386,30387,30388,30389,30390,30391,30392,30393,30394,30395,30396,30397,
-30398,30399,30400,30401,30402,30403,30404,30405,30406,30407,30408,30409,
-30410,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,30421,
-30422,30423,30424,30425,30426,30427,30428,30429,30430,30431,30432,30433,
-30434,30435,30436,30437,30438,30439,30440,30441,30442,30443,30444,30445,
-30446,30447,30448,30449,30450,30451,30452,30453,30454,30455,30456,30457,
-30458,30459,30460,30461,30462,30463,30464,30465,30466,30467,30468,30469,
-30470,30471,30472,30473,30474,30475,30476,30477,30478,30479,30480,30481,
-30482,30483,30484,30485,30486,30487,30488,30489,30490,30491,30492,30493,
-30494,30495,30496,30497,30498,30499,30500,30501,30502,30503,30504,30505,
-30506,30507,30508,30509,30510,30511,30512,30513,30514,30515,30516,30517,
-30518,30519,30520,30521,30522,30523,30524,30525,30526,30527,30528,30529,
-30530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,
-30542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,
-30554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,
-30566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,
-30578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,
-30590,30591,30592,30593,30594,30595,30596,30597,30598,30599,30600,30601,
-30602,30603,30604,30605,30606,30607,30608,30609,30610,30611,30612,30613,
-30614,30615,30616,30617,30618,30619,30620,30621,30622,30623,30624,30625,
-30626,30627,30628,30629,30630,30631,30632,30633,30634,30635,30636,30637,
-30638,30639,30640,30641,30642,30643,30644,30645,30646,30647,30648,30649,
-30650,30651,30652,30653,30654,30655,30656,30657,30658,30659,30660,30661,
-30662,30663,30664,30665,30666,30667,30668,30669,30670,30671,30672,30673,
-30674,30675,30676,30677,30678,30679,30680,30681,30682,30683,30684,30685,
-30686,30687,30688,30689,30690,30691,30692,30693,30694,30695,30696,30697,
-30698,30699,30700,30701,30702,30703,30704,30705,30706,30707,30708,30709,
-30710,30711,30712,30713,30714,30715,30716,30717,30718,30719,30720,30721,
-30722,30723,30724,30725,30726,30727,30728,30729,30730,30731,30732,30733,
-30734,30735,30736,30737,30738,30739,30740,30741,30742,30743,30744,30745,
-30746,30747,30748,30749,30750,30751,30752,30753,30754,30755,30756,30757,
-30758,30759,30760,30761,30762,30763,30764,30765,30766,30767,30768,30769,
-30770,30771,30772,30773,30774,30775,30776,30777,30778,30779,30780,30781,
-30782,30783,30784,30785,30786,30787,30788,30789,30790,30791,30792,30793,
-30794,30795,30796,30797,30798,30799,30800,30801,30802,30803,30804,30805,
-30806,30807,30808,30809,30810,30811,30812,30813,30814,30815,30816,30817,
-30818,30819,30820,30821,30822,30823,30824,30825,30826,30827,30828,30829,
-30830,30831,30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,
-30842,30843,30844,30845,30846,30847,30848,30849,30850,30851,30852,30853,
-30854,30855,30856,30857,30858,30859,30860,30861,30862,30863,30864,30865,
-30866,30867,30868,30869,30870,30871,30872,30873,30874,30875,30876,30877,
-30878,30879,30880,30881,30882,30883,30884,30885,30886,30887,30888,30889,
-30890,30891,30892,30893,30894,30895,30896,30897,30898,30899,30900,30901,
-30902,30903,30904,30905,30906,30907,30908,30909,30910,30911,30912,30913,
-30914,30915,30916,30917,30918,30919,30920,30921,30922,30923,30924,30925,
-30926,30927,30928,30929,30930,30931,30932,30933,30934,30935,30936,30937,
-30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,
-30950,30951,30952,30953,30954,30955,30956,30957,30958,30959,30960,30961,
-30962,30963,30964,30965,30966,30967,30968,30969,30970,30971,30972,30973,
-30974,30975,30976,30977,30978,30979,30980,30981,30982,30983,30984,30985,
-30986,30987,30988,30989,30990,30991,30992,30993,30994,30995,30996,30997,
-30998,30999,31000,31001,31002,31003,31004,31005,31006,31007,31008,31009,
-31010,31011,31012,31013,31014,31015,31016,31017,31018,31019,31020,31021,
-31022,31023,31024,31025,31026,31027,31028,31029,31030,31031,31032,31033,
-31034,31035,31036,31037,31038,31039,31040,31041,31042,31043,31044,31045,
-31046,31047,31048,31049,31050,31051,31052,31053,31054,31055,31056,31057,
-31058,31059,31060,31061,31062,31063,31064,31065,31066,31067,31068,31069,
-31070,31071,31072,31073,31074,31075,31076,31077,31078,31079,31080,31081,
-31082,31083,31084,31085,31086,31087,31088,31089,31090,31091,31092,31093,
-31094,31095,31096,31097,31098,31099,31100,31101,31102,31103,31104,31105,
-31106,31107,31108,31109,31110,31111,31112,31113,31114,31115,31116,31117,
-31118,31119,31120,31121,31122,31123,31124,31125,31126,31127,31128,31129,
-31130,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,
-31142,31143,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,
-31154,31155,31156,31157,31158,31159,31160,31161,31162,31163,31164,31165,
-31166,31167,31168,31169,31170,31171,31172,31173,31174,31175,31176,31177,
-31178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,
-31190,31191,31192,31193,31194,31195,31196,31197,31198,31199,31200,31201,
-31202,31203,31204,31205,31206,31207,31208,31209,31210,31211,31212,31213,
-31214,31215,31216,31217,31218,31219,31220,31221,31222,31223,31224,31225,
-31226,31227,31228,31229,31230,31231,31232,31233,31234,31235,31236,31237,
-31238,31239,31240,31241,31242,31243,31244,31245,31246,31247,31248,31249,
-31250,31251,31252,31253,31254,31255,31256,31257,31258,31259,31260,31261,
-31262,31263,31264,31265,31266,31267,31268,31269,31270,31271,31272,31273,
-31274,31275,31276,31277,31278,31279,31280,31281,31282,31283,31284,31285,
-31286,31287,31288,31289,31290,31291,31292,31293,31294,31295,31296,31297,
-31298,31299,31300,31301,31302,31303,31304,31305,31306,31307,31308,31309,
-31310,31311,31312,31313,31314,31315,31316,31317,31318,31319,31320,31321,
-31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,
-31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,
-31346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,
-31358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,
-31370,31371,31372,31373,31374,31375,31376,31377,31378,31379,31380,31381,
-31382,31383,31384,31385,31386,31387,31388,31389,31390,31391,31392,31393,
-31394,31395,31396,31397,31398,31399,31400,31401,31402,31403,31404,31405,
-31406,31407,31408,31409,31410,31411,31412,31413,31414,31415,31416,31417,
-31418,31419,31420,31421,31422,31423,31424,31425,31426,31427,31428,31429,
-31430,31431,31432,31433,31434,31435,31436,31437,31438,31439,31440,31441,
-31442,31443,31444,31445,31446,31447,31448,31449,31450,31451,31452,31453,
-31454,31455,31456,31457,31458,31459,31460,31461,31462,31463,31464,31465,
-31466,31467,31468,31469,31470,31471,31472,31473,31474,31475,31476,31477,
-31478,31479,31480,31481,31482,31483,31484,31485,31486,31487,31488,31489,
-31490,31491,31492,31493,31494,31495,31496,31497,31498,31499,31500,31501,
-31502,31503,31504,31505,31506,31507,31508,31509,31510,31511,31512,31513,
-31514,31515,31516,31517,31518,31519,31520,31521,31522,31523,31524,31525,
-31526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,
-31538,31539,31540,31541,31542,31543,31544,31545,31546,31547,31548,31549,
-31550,31551,31552,31553,31554,31555,31556,31557,31558,31559,31560,31561,
-31562,31563,31564,31565,31566,31567,31568,31569,31570,31571,31572,31573,
-31574,31575,31576,31577,31578,31579,31580,31581,31582,31583,31584,31585,
-31586,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,
-31598,31599,31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,
-31610,31611,31612,31613,31614,31615,31616,31617,31618,31619,31620,31621,
-31622,31623,31624,31625,31626,31627,31628,31629,31630,31631,31632,31633,
-31634,31635,31636,31637,31638,31639,31640,31641,31642,31643,31644,31645,
-31646,31647,31648,31649,31650,31651,31652,31653,31654,31655,31656,31657,
-31658,31659,31660,31661,31662,31663,31664,31665,31666,31667,31668,31669,
-31670,31671,31672,31673,31674,31675,31676,31677,31678,31679,31680,31681,
-31682,31683,31684,31685,31686,31687,31688,31689,31690,31691,31692,31693,
-31694,31695,31696,31697,31698,31699,31700,31701,31702,31703,31704,31705,
-31706,31707,31708,31709,31710,31711,31712,31713,31714,31715,31716,31717,
-31718,31719,31720,31721,31722,31723,31724,31725,31726,31727,31728,31729,
-31730,31731,31732,31733,31734,31735,31736,31737,31738,31739,31740,31741,
-31742,31743,31744,31745,31746,31747,31748,31749,31750,31751,31752,31753,
-31754,31755,31756,31757,31758,31759,31760,31761,31762,31763,31764,31765,
-31766,31767,31768,31769,31770,31771,31772,31773,31774,31775,31776,31777,
-31778,31779,31780,31781,31782,31783,31784,31785,31786,31787,31788,31789,
-31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31800,31801,
-31802,31803,31804,31805,31806,31807,31808,31809,31810,31811,31812,31813,
-31814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,
-31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,
-31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,
-31850,31851,31852,31853,31854,31855,31856,31857,31858,31859,31860,31861,
-31862,31863,31864,31865,31866,31867,31868,31869,31870,31871,31872,31873,
-31874,31875,31876,31877,31878,31879,31880,31881,31882,31883,31884,31885,
-31886,31887,31888,31889,31890,31891,31892,31893,31894,31895,31896,31897,
-31898,31899,31900,31901,31902,31903,31904,31905,31906,31907,31908,31909,
-31910,31911,31912,31913,31914,31915,31916,31917,31918,31919,31920,31921,
-31922,31923,31924,31925,31926,31927,31928,31929,31930,31931,31932,31933,
-31934,31935,31936,31937,31938,31939,31940,31941,31942,31943,31944,31945,
-31946,31947,31948,31949,31950,31951,31952,31953,31954,31955,31956,31957,
-31958,31959,31960,31961,31962,31963,31964,31965,31966,31967,31968,31969,
-31970,31971,31972,31973,31974,31975,31976,31977,31978,31979,31980,31981,
-31982,31983,31984,31985,31986,31987,31988,31989,31990,31991,31992,31993,
-31994,31995,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,
-32006,32007,32008,32009,32010,32011,32012,32013,32014,32015,32016,32017,
-32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,
-32030,32031,32032,32033,32034,32035,32036,32037,32038,32039,32040,32041,
-32042,32043,32044,32045,32046,32047,32048,32049,32050,32051,32052,32053,
-32054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,
-32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,
-32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,
-32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,
-32102,32103,32104,32105,32106,32107,32108,32109,32110,32111,32112,32113,
-32114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,
-32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,
-32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,
-32150,32151,32152,32153,32154,32155,32156,32157,32158,32159,32160,32161,
-32162,32163,32164,32165,32166,32167,32168,32169,32170,32171,32172,32173,
-32174,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,
-32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,
-32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,
-32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,
-32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,
-32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,
-32246,32247,32248,32249,32250,32251,32252,32253,32254,32255,32256,32257,
-32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,
-32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,
-32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,
-32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,
-32306,32307,32308,32309,32310,32311,32312,32313,32314,32315,32316,32317,
-32318,32319,32320,32321,32322,32323,32324,32325,32326,32327,32328,32329,
-32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,
-32342,32343,32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,
-32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,
-32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,
-32378,32379,32380,32381,32382,32383,32384,32385,32386,32387,32388,32389,
-32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,
-32402,32403,32404,32405,32406,32407,32408,32409,32410,32411,32412,32413,
-32414,32415,32416,32417,32418,32419,32420,32421,32422,32423,32424,32425,
-32426,32427,32428,32429,32430,32431,32432,32433,32434,32435,32436,32437,
-32438,32439,32440,32441,32442,32443,32444,32445,32446,32447,32448,32449,
-32450,32451,32452,32453,32454,32455,32456,32457,32458,32459,32460,32461,
-32462,32463,32464,32465,32466,32467,32468,32469,32470,32471,32472,32473,
-32474,32475,32476,32477,32478,32479,32480,32481,32482,32483,32484,32485,
-32486,32487,32488,32489,32490,32491,32492,32493,32494,32495,32496,32497,
-32498,32499,32500,32501,32502,32503,32504,32505,32506,32507,32508,32509,
-32510,32511,32512,32513,32514,32515,32516,32517,32518,32519,32520,32521,
-32522,32523,32524,32525,32526,32527,32528,32529,32530,32531,32532,32533,
-32534,32535,32536,32537,32538,32539,32540,32541,32542,32543,32544,32545,
-32546,32547,32548,32549,32550,32551,32552,32553,32554,32555,32556,32557,
-32558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,
-32570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,
-32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,
-32594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,
-32606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,
-32618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,
-32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,
-32642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,
-32654,32655,32656,32657,32658,32659,32660,32661,32662,32663,32664,32665,
-32666,32667,32668,32669,32670,32671,32672,32673,32674,32675,32676,32677,
-32678,32679,32680,32681,32682,32683,32684,32685,32686,32687,32688,32689,
-32690,32691,32692,32693,32694,32695,32696,32697,32698,32699,32700,32701,
-32702,32703,32704,32705,32706,32707,32708,32709,32710,32711,32712,32713,
-32714,32715,32716,32717,32718,32719,32720,32721,32722,32723,32724,32725,
-32726,32727,32728,32729,32730,32731,32732,32733,32734,32735,32736,32737,
-32738,32739,32740,32741,32742,32743,32744,32745,32746,32747,32748,32749,
-32750,32751,32752,32753,32754,32755,32756,32757,32758,32759,32760,32761,
-32762,32763,32764,32765,32766,32767,32768L,32769L,32770L,32771L,32772L,
-32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,32781L,32782L,
-32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,32791L,32792L,
-32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,32801L,32802L,
-32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,32811L,32812L,
-32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,32821L,32822L,
-32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,32831L,32832L,
-32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,32841L,32842L,
-32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,32851L,32852L,
-32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,32861L,32862L,
-32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,32871L,32872L,
-32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,32881L,32882L,
-32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,32891L,32892L,
-32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,32901L,32902L,
-32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,32911L,32912L,
-32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,32921L,32922L,
-32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,32931L,32932L,
-32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,32941L,32942L,
-32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,32951L,32952L,
-32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,32961L,32962L,
-32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,32971L,32972L,
-32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,32981L,32982L,
-32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,32991L,32992L,
-32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,33001L,33002L,
-33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,33011L,33012L,
-33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,33021L,33022L,
-33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,33031L,33032L,
-33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,33041L,33042L,
-33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,33051L,33052L,
-33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,33061L,33062L,
-33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,33071L,33072L,
-33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,33081L,33082L,
-33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,33091L,33092L,
-33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,33101L,33102L,
-33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,33111L,33112L,
-33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,33121L,33122L,
-33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,33131L,33132L,
-33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,33141L,33142L,
-33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,33151L,33152L,
-33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,33161L,33162L,
-33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,33171L,33172L,
-33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,33181L,33182L,
-33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,33191L,33192L,
-33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,33201L,33202L,
-33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,33211L,33212L,
-33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,33221L,33222L,
-33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,33231L,33232L,
-33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,33241L,33242L,
-33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,33251L,33252L,
-33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,33261L,33262L,
-33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,33271L,33272L,
-33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,33281L,33282L,
-33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,33291L,33292L,
-33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,33301L,33302L,
-33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,33311L,33312L,
-33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,33321L,33322L,
-33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,33331L,33332L,
-33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,33341L,33342L,
-33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,33351L,33352L,
-33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,33361L,33362L,
-33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,33371L,33372L,
-33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,33381L,33382L,
-33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,33391L,33392L,
-33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,33401L,33402L,
-33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,33411L,33412L,
-33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,33421L,33422L,
-33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,33431L,33432L,
-33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,33441L,33442L,
-33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,33451L,33452L,
-33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,33461L,33462L,
-33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,33471L,33472L,
-33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,33481L,33482L,
-33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,33491L,33492L,
-33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,33501L,33502L,
-33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,33511L,33512L,
-33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,33521L,33522L,
-33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,33531L,33532L,
-33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,33541L,33542L,
-33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,33551L,33552L,
-33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,33561L,33562L,
-33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,33571L,33572L,
-33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,33581L,33582L,
-33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,33591L,33592L,
-33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,33601L,33602L,
-33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,33611L,33612L,
-33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,33621L,33622L,
-33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,33631L,33632L,
-33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,33641L,33642L,
-33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,33651L,33652L,
-33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,33661L,33662L,
-33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,33671L,33672L,
-33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,33681L,33682L,
-33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,33691L,33692L,
-33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,33701L,33702L,
-33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,33711L,33712L,
-33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,33721L,33722L,
-33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,33731L,33732L,
-33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,33741L,33742L,
-33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,33751L,33752L,
-33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,33761L,33762L,
-33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,33771L,33772L,
-33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,33781L,33782L,
-33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,33791L,33792L,
-33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,33801L,33802L,
-33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,33811L,33812L,
-33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,33821L,33822L,
-33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,33831L,33832L,
-33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,33841L,33842L,
-33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,33851L,33852L,
-33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,33861L,33862L,
-33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,33871L,33872L,
-33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,33881L,33882L,
-33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,33891L,33892L,
-33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,33901L,33902L,
-33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,33911L,33912L,
-33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,33921L,33922L,
-33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,33931L,33932L,
-33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,33941L,33942L,
-33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,33951L,33952L,
-33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,33961L,33962L,
-33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,33971L,33972L,
-33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,33981L,33982L,
-33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,33991L,33992L,
-33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,34001L,34002L,
-34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,34011L,34012L,
-34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,34021L,34022L,
-34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,34031L,34032L,
-34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,34041L,34042L,
-34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,34051L,34052L,
-34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,34061L,34062L,
-34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,34071L,34072L,
-34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,34081L,34082L,
-34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,34091L,34092L,
-34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,34101L,34102L,
-34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,34111L,34112L,
-34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,34121L,34122L,
-34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,34131L,34132L,
-34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,34141L,34142L,
-34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,34151L,34152L,
-34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,34161L,34162L,
-34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,34171L,34172L,
-34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,34181L,34182L,
-34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,34191L,34192L,
-34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,34201L,34202L,
-34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,34211L,34212L,
-34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,34221L,34222L,
-34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,34231L,34232L,
-34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,34241L,34242L,
-34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,34251L,34252L,
-34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,34261L,34262L,
-34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,34271L,34272L,
-34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,34281L,34282L,
-34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,34291L,34292L,
-34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,34301L,34302L,
-34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,34311L,34312L,
-34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,34321L,34322L,
-34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,34331L,34332L,
-34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,34341L,34342L,
-34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,34351L,34352L,
-34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,34361L,34362L,
-34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,34371L,34372L,
-34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,34381L,34382L,
-34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,34391L,34392L,
-34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,34401L,34402L,
-34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,34411L,34412L,
-34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,34421L,34422L,
-34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,34431L,34432L,
-34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,34441L,34442L,
-34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,34451L,34452L,
-34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,34461L,34462L,
-34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,34471L,34472L,
-34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,34481L,34482L,
-34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,34491L,34492L,
-34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,34501L,34502L,
-34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,34511L,34512L,
-34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,34521L,34522L,
-34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,34531L,34532L,
-34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,34541L,34542L,
-34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,34551L,34552L,
-34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,34561L,34562L,
-34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,34571L,34572L,
-34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,34581L,34582L,
-34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,34591L,34592L,
-34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,34601L,34602L,
-34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,34611L,34612L,
-34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,34621L,34622L,
-34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,34631L,34632L,
-34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,34641L,34642L,
-34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,34651L,34652L,
-34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,34661L,34662L,
-34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,34671L,34672L,
-34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,34681L,34682L,
-34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,34691L,34692L,
-34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,34701L,34702L,
-34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,34711L,34712L,
-34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,34721L,34722L,
-34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,34731L,34732L,
-34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,34741L,34742L,
-34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,34751L,34752L,
-34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,34761L,34762L,
-34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,34771L,34772L,
-34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,34781L,34782L,
-34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,34791L,34792L,
-34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,34801L,34802L,
-34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,34811L,34812L,
-34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,34821L,34822L,
-34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,34831L,34832L,
-34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,34841L,34842L,
-34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,34851L,34852L,
-34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,34861L,34862L,
-34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,34871L,34872L,
-34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,34881L,34882L,
-34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,34891L,34892L,
-34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,34901L,34902L,
-34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,34911L,34912L,
-34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,34921L,34922L,
-34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,34931L,34932L,
-34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,34941L,34942L,
-34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,34951L,34952L,
-34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,34961L,34962L,
-34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,34971L,34972L,
-34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,34981L,34982L,
-34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,34991L,34992L,
-34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,35001L,35002L,
-35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,35011L,35012L,
-35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,35021L,35022L,
-35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,35031L,35032L,
-35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,35041L,35042L,
-35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,35051L,35052L,
-35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,35061L,35062L,
-35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,35071L,35072L,
-35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,35081L,35082L,
-35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,35091L,35092L,
-35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,35101L,35102L,
-35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,35111L,35112L,
-35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,35121L,35122L,
-35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,35131L,35132L,
-35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,35141L,35142L,
-35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,35151L,35152L,
-35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,35161L,35162L,
-35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,35171L,35172L,
-35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,35181L,35182L,
-35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,35191L,35192L,
-35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,35201L,35202L,
-35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,35211L,35212L,
-35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,35221L,35222L,
-35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,35231L,35232L,
-35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,35241L,35242L,
-35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,35251L,35252L,
-35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,35261L,35262L,
-35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,35271L,35272L,
-35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,35281L,35282L,
-35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,35291L,35292L,
-35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,35301L,35302L,
-35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,35311L,35312L,
-35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,35321L,35322L,
-35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,35331L,35332L,
-35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,35341L,35342L,
-35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,35351L,35352L,
-35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,35361L,35362L,
-35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,35371L,35372L,
-35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,35381L,35382L,
-35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,35391L,35392L,
-35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,35401L,35402L,
-35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,35411L,35412L,
-35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,35421L,35422L,
-35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,35431L,35432L,
-35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,35441L,35442L,
-35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,35451L,35452L,
-35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,35461L,35462L,
-35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,35471L,35472L,
-35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,35481L,35482L,
-35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,35491L,35492L,
-35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,35501L,35502L,
-35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,35511L,35512L,
-35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,35521L,35522L,
-35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,35531L,35532L,
-35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,35541L,35542L,
-35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,35551L,35552L,
-35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,35561L,35562L,
-35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,35571L,35572L,
-35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,35581L,35582L,
-35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,35591L,35592L,
-35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,35601L,35602L,
-35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,35611L,35612L,
-35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,35621L,35622L,
-35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,35631L,35632L,
-35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,35641L,35642L,
-35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,35651L,35652L,
-35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,35661L,35662L,
-35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,35671L,35672L,
-35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,35681L,35682L,
-35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,35691L,35692L,
-35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,35701L,35702L,
-35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,35711L,35712L,
-35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,35721L,35722L,
-35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,35731L,35732L,
-35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,35741L,35742L,
-35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,35751L,35752L,
-35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,35761L,35762L,
-35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,35771L,35772L,
-35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,35781L,35782L,
-35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,35791L,35792L,
-35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,35801L,35802L,
-35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,35811L,35812L,
-35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,35821L,35822L,
-35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,35831L,35832L,
-35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,35841L,35842L,
-35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,35851L,35852L,
-35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,35861L,35862L,
-35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,35871L,35872L,
-35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,35881L,35882L,
-35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,35891L,35892L,
-35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,35901L,35902L,
-35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,35911L,35912L,
-35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,35921L,35922L,
-35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,35931L,35932L,
-35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,35941L,35942L,
-35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,35951L,35952L,
-35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,35961L,35962L,
-35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,35971L,35972L,
-35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,35981L,35982L,
-35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,35991L,35992L,
-35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,36001L,36002L,
-36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,36011L,36012L,
-36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,36021L,36022L,
-36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,36031L,36032L,
-36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,36041L,36042L,
-36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,36051L,36052L,
-36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,36061L,36062L,
-36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,36071L,36072L,
-36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,36081L,36082L,
-36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,36091L,36092L,
-36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,36101L,36102L,
-36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,36111L,36112L,
-36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,36121L,36122L,
-36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,36131L,36132L,
-36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,36141L,36142L,
-36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,36151L,36152L,
-36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,36161L,36162L,
-36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,36171L,36172L,
-36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,36181L,36182L,
-36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,36191L,36192L,
-36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,36201L,36202L,
-36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,36211L,36212L,
-36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,36221L,36222L,
-36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,36231L,36232L,
-36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,36241L,36242L,
-36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,36251L,36252L,
-36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,36261L,36262L,
-36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,36271L,36272L,
-36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,36281L,36282L,
-36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,36291L,36292L,
-36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,36301L,36302L,
-36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,36311L,36312L,
-36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,36321L,36322L,
-36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,36331L,36332L,
-36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,36341L,36342L,
-36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,36351L,36352L,
-36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,36361L,36362L,
-36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,36371L,36372L,
-36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,36381L,36382L,
-36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,36391L,36392L,
-36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,36401L,36402L,
-36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,36411L,36412L,
-36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,36421L,36422L,
-36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,36431L,36432L,
-36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,36441L,36442L,
-36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,36451L,36452L,
-36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,36461L,36462L,
-36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,36471L,36472L,
-36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,36481L,36482L,
-36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,36491L,36492L,
-36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,36501L,36502L,
-36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,36511L,36512L,
-36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,36521L,36522L,
-36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,36531L,36532L,
-36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,36541L,36542L,
-36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,36551L,36552L,
-36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,36561L,36562L,
-36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,36571L,36572L,
-36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,36581L,36582L,
-36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,36591L,36592L,
-36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,36601L,36602L,
-36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,36611L,36612L,
-36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,36621L,36622L,
-36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,36631L,36632L,
-36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,36641L,36642L,
-36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,36651L,36652L,
-36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,36661L,36662L,
-36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,36671L,36672L,
-36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,36681L,36682L,
-36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,36691L,36692L,
-36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,36701L,36702L,
-36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,36711L,36712L,
-36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,36721L,36722L,
-36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,36731L,36732L,
-36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,36741L,36742L,
-36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,36751L,36752L,
-36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,36761L,36762L,
-36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,36771L,36772L,
-36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,36781L,36782L,
-36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,36791L,36792L,
-36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,36801L,36802L,
-36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,36811L,36812L,
-36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,36821L,36822L,
-36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,36831L,36832L,
-36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,36841L,36842L,
-36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,36851L,36852L,
-36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,36861L,36862L,
-36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,36871L,36872L,
-36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,36881L,36882L,
-36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,36891L,36892L,
-36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,36901L,36902L,
-36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,36911L,36912L,
-36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,36921L,36922L,
-36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,36931L,36932L,
-36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,36941L,36942L,
-36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,36951L,36952L,
-36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,36961L,36962L,
-36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,36971L,36972L,
-36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,36981L,36982L,
-36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,36991L,36992L,
-36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,37001L,37002L,
-37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,37011L,37012L,
-37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,37021L,37022L,
-37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,37031L,37032L,
-37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,37041L,37042L,
-37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,37051L,37052L,
-37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,37061L,37062L,
-37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,37071L,37072L,
-37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,37081L,37082L,
-37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,37091L,37092L,
-37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,37101L,37102L,
-37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,37111L,37112L,
-37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,37121L,37122L,
-37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,37131L,37132L,
-37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,37141L,37142L,
-37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,37151L,37152L,
-37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,37161L,37162L,
-37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,37171L,37172L,
-37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,37181L,37182L,
-37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,37191L,37192L,
-37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,37201L,37202L,
-37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,37211L,37212L,
-37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,37221L,37222L,
-37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,37231L,37232L,
-37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,37241L,37242L,
-37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,37251L,37252L,
-37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,37261L,37262L,
-37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,37271L,37272L,
-37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,37281L,37282L,
-37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,37291L,37292L,
-37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,37301L,37302L,
-37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,37311L,37312L,
-37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,37321L,37322L,
-37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,37331L,37332L,
-37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,37341L,37342L,
-37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,37351L,37352L,
-37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,37361L,37362L,
-37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,37371L,37372L,
-37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,37381L,37382L,
-37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,37391L,37392L,
-37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,37401L,37402L,
-37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,37411L,37412L,
-37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,37421L,37422L,
-37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,37431L,37432L,
-37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,37441L,37442L,
-37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,37451L,37452L,
-37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,37461L,37462L,
-37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,37471L,37472L,
-37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,37481L,37482L,
-37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,37491L,37492L,
-37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,37501L,37502L,
-37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,37511L,37512L,
-37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,37521L,37522L,
-37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,37531L,37532L,
-37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,37541L,37542L,
-37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,37551L,37552L,
-37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,37561L,37562L,
-37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,37571L,37572L,
-37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,37581L,37582L,
-37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,37591L,37592L,
-37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,37601L,37602L,
-37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,37611L,37612L,
-37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,37621L,37622L,
-37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,37631L,37632L,
-37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,37641L,37642L,
-37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,37651L,37652L,
-37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,37661L,37662L,
-37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,37671L,37672L,
-37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,37681L,37682L,
-37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,37691L,37692L,
-37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,37701L,37702L,
-37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,37711L,37712L,
-37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,37721L,37722L,
-37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,37731L,37732L,
-37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,37741L,37742L,
-37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,37751L,37752L,
-37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,37761L,37762L,
-37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,37771L,37772L,
-37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,37781L,37782L,
-37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,37791L,37792L,
-37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,37801L,37802L,
-37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,37811L,37812L,
-37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,37821L,37822L,
-37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,37831L,37832L,
-37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,37841L,37842L,
-37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,37851L,37852L,
-37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,37861L,37862L,
-37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,37871L,37872L,
-37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,37881L,37882L,
-37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,37891L,37892L,
-37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,37901L,37902L,
-37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,37911L,37912L,
-37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,37921L,37922L,
-37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,37931L,37932L,
-37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,37941L,37942L,
-37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,37951L,37952L,
-37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,37961L,37962L,
-37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,37971L,37972L,
-37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,37981L,37982L,
-37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,37991L,37992L,
-37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,38001L,38002L,
-38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,38011L,38012L,
-38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,38021L,38022L,
-38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,38031L,38032L,
-38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,38041L,38042L,
-38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,38051L,38052L,
-38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,38061L,38062L,
-38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,38071L,38072L,
-38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,38081L,38082L,
-38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,38091L,38092L,
-38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,38101L,38102L,
-38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,38111L,38112L,
-38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,38121L,38122L,
-38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,38131L,38132L,
-38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,38141L,38142L,
-38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,38151L,38152L,
-38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,38161L,38162L,
-38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,38171L,38172L,
-38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,38181L,38182L,
-38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,38191L,38192L,
-38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,38201L,38202L,
-38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,38211L,38212L,
-38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,38221L,38222L,
-38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,38231L,38232L,
-38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,38241L,38242L,
-38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,38251L,38252L,
-38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,38261L,38262L,
-38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,38271L,38272L,
-38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,38281L,38282L,
-38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,38291L,38292L,
-38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,38301L,38302L,
-38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,38311L,38312L,
-38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,38321L,38322L,
-38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,38331L,38332L,
-38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,38341L,38342L,
-38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,38351L,38352L,
-38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,38361L,38362L,
-38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,38371L,38372L,
-38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,38381L,38382L,
-38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,38391L,38392L,
-38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,38401L,38402L,
-38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,38411L,38412L,
-38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,38421L,38422L,
-38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,38431L,38432L,
-38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,38441L,38442L,
-38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,38451L,38452L,
-38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,38461L,38462L,
-38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,38471L,38472L,
-38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,38481L,38482L,
-38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,38491L,38492L,
-38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,38501L,38502L,
-38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,38511L,38512L,
-38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,38521L,38522L,
-38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,38531L,38532L,
-38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,38541L,38542L,
-38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,38551L,38552L,
-38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,38561L,38562L,
-38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,38571L,38572L,
-38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,38581L,38582L,
-38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,38591L,38592L,
-38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,38601L,38602L,
-38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,38611L,38612L,
-38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,38621L,38622L,
-38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,38631L,38632L,
-38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,38641L,38642L,
-38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,38651L,38652L,
-38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,38661L,38662L,
-38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,38671L,38672L,
-38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,38681L,38682L,
-38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,38691L,38692L,
-38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,38701L,38702L,
-38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,38711L,38712L,
-38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,38721L,38722L,
-38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,38731L,38732L,
-38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,38741L,38742L,
-38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,38751L,38752L,
-38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,38761L,38762L,
-38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,38771L,38772L,
-38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,38781L,38782L,
-38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,38791L,38792L,
-38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,38801L,38802L,
-38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,38811L,38812L,
-38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,38821L,38822L,
-38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,38831L,38832L,
-38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,38841L,38842L,
-38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,38851L,38852L,
-38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,38861L,38862L,
-38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,38871L,38872L,
-38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,38881L,38882L,
-38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,38891L,38892L,
-38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,38901L,38902L,
-38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,38911L,38912L,
-38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,38921L,38922L,
-38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,38931L,38932L,
-38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,38941L,38942L,
-38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,38951L,38952L,
-38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,38961L,38962L,
-38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,38971L,38972L,
-38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,38981L,38982L,
-38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,38991L,38992L,
-38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,39001L,39002L,
-39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,39011L,39012L,
-39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,39021L,39022L,
-39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,39031L,39032L,
-39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,39041L,39042L,
-39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,39051L,39052L,
-39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,39061L,39062L,
-39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,39071L,39072L,
-39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,39081L,39082L,
-39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,39091L,39092L,
-39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,39101L,39102L,
-39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,39111L,39112L,
-39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,39121L,39122L,
-39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,39131L,39132L,
-39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,39141L,39142L,
-39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,39151L,39152L,
-39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,39161L,39162L,
-39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,39171L,39172L,
-39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,39181L,39182L,
-39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,39191L,39192L,
-39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,39201L,39202L,
-39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,39211L,39212L,
-39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,39221L,39222L,
-39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,39231L,39232L,
-39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,39241L,39242L,
-39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,39251L,39252L,
-39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,39261L,39262L,
-39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,39271L,39272L,
-39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,39281L,39282L,
-39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,39291L,39292L,
-39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,39301L,39302L,
-39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,39311L,39312L,
-39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,39321L,39322L,
-39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,39331L,39332L,
-39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,39341L,39342L,
-39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,39351L,39352L,
-39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,39361L,39362L,
-39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,39371L,39372L,
-39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,39381L,39382L,
-39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,39391L,39392L,
-39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,39401L,39402L,
-39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,39411L,39412L,
-39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,39421L,39422L,
-39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,39431L,39432L,
-39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,39441L,39442L,
-39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,39451L,39452L,
-39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,39461L,39462L,
-39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,39471L,39472L,
-39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,39481L,39482L,
-39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,39491L,39492L,
-39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,39501L,39502L,
-39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,39511L,39512L,
-39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,39521L,39522L,
-39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,39531L,39532L,
-39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,39541L,39542L,
-39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,39551L,39552L,
-39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,39561L,39562L,
-39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,39571L,39572L,
-39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,39581L,39582L,
-39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,39591L,39592L,
-39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,39601L,39602L,
-39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,39611L,39612L,
-39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,39621L,39622L,
-39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,39631L,39632L,
-39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,39641L,39642L,
-39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,39651L,39652L,
-39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,39661L,39662L,
-39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,39671L,39672L,
-39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,39681L,39682L,
-39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,39691L,39692L,
-39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,39701L,39702L,
-39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,39711L,39712L,
-39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,39721L,39722L,
-39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,39731L,39732L,
-39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,39741L,39742L,
-39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,39751L,39752L,
-39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,39761L,39762L,
-39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,39771L,39772L,
-39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,39781L,39782L,
-39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,39791L,39792L,
-39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,39801L,39802L,
-39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,39811L,39812L,
-39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,39821L,39822L,
-39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,39831L,39832L,
-39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,39841L,39842L,
-39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,39851L,39852L,
-39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,39861L,39862L,
-39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,39871L,39872L,
-39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,39881L,39882L,
-39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,39891L,39892L,
-39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,39901L,39902L,
-39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,39911L,39912L,
-39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,39921L,39922L,
-39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,39931L,39932L,
-39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,39941L,39942L,
-39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,39951L,39952L,
-39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,39961L,39962L,
-39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,39971L,39972L,
-39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,39981L,39982L,
-39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,39991L,39992L,
-39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,40001L,40002L,
-40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,40011L,40012L,
-40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,40021L,40022L,
-40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,40031L,40032L,
-40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,40041L,40042L,
-40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,40051L,40052L,
-40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,40061L,40062L,
-40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,40071L,40072L,
-40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,40081L,40082L,
-40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,40091L,40092L,
-40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,40101L,40102L,
-40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,40111L,40112L,
-40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,40121L,40122L,
-40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,40131L,40132L,
-40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,40141L,40142L,
-40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,40151L,40152L,
-40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,40161L,40162L,
-40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,40171L,40172L,
-40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,40181L,40182L,
-40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,40191L,40192L,
-40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,40201L,40202L,
-40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,40211L,40212L,
-40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,40221L,40222L,
-40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,40231L,40232L,
-40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,40241L,40242L,
-40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,40251L,40252L,
-40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,40261L,40262L,
-40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,40271L,40272L,
-40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,40281L,40282L,
-40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,40291L,40292L,
-40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,40301L,40302L,
-40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,40311L,40312L,
-40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,40321L,40322L,
-40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,40331L,40332L,
-40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,40341L,40342L,
-40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,40351L,40352L,
-40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,40361L,40362L,
-40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,40371L,40372L,
-40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,40381L,40382L,
-40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,40391L,40392L,
-40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,40401L,40402L,
-40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,40411L,40412L,
-40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,40421L,40422L,
-40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,40431L,40432L,
-40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,40441L,40442L,
-40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,40451L,40452L,
-40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,40461L,40462L,
-40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,40471L,40472L,
-40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,40481L,40482L,
-40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,40491L,40492L,
-40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,40501L,40502L,
-40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,40511L,40512L,
-40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,40521L,40522L,
-40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,40531L,40532L,
-40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,40541L,40542L,
-40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,40551L,40552L,
-40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,40561L,40562L,
-40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,40571L,40572L,
-40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,40581L,40582L,
-40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,40591L,40592L,
-40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,40601L,40602L,
-40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,40611L,40612L,
-40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,40621L,40622L,
-40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,40631L,40632L,
-40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,40641L,40642L,
-40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,40651L,40652L,
-40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,40661L,40662L,
-40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,40671L,40672L,
-40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,40681L,40682L,
-40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,40691L,40692L,
-40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,40701L,40702L,
-40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,40711L,40712L,
-40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,40721L,40722L,
-40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,40731L,40732L,
-40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,40741L,40742L,
-40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,40751L,40752L,
-40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,40761L,40762L,
-40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,40771L,40772L,
-40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,40781L,40782L,
-40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,40791L,40792L,
-40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,40801L,40802L,
-40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,40811L,40812L,
-40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,40821L,40822L,
-40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,40831L,40832L,
-40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,40841L,40842L,
-40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,40851L,40852L,
-40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,40861L,40862L,
-40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,40871L,40872L,
-40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,40881L,40882L,
-40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,40891L,40892L,
-40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,40901L,40902L,
-40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,40911L,40912L,
-40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,40921L,40922L,
-40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,40931L,40932L,
-40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,40941L,40942L,
-40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,40951L,40952L,
-40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,40961L,40962L,
-40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,40971L,40972L,
-40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,40981L,40982L,
-40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,40991L,40992L,
-40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,41001L,41002L,
-41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,41011L,41012L,
-41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,41021L,41022L,
-41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,41031L,41032L,
-41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,41041L,41042L,
-41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,41051L,41052L,
-41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,41061L,41062L,
-41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,41071L,41072L,
-41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,41081L,41082L,
-41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,41091L,41092L,
-41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,41101L,41102L,
-41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,41111L,41112L,
-41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,41121L,41122L,
-41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,41131L,41132L,
-41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,41141L,41142L,
-41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,41151L,41152L,
-41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,41161L,41162L,
-41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,41171L,41172L,
-41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,41181L,41182L,
-41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,41191L,41192L,
-41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,41201L,41202L,
-41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,41211L,41212L,
-41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,41221L,41222L,
-41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,41231L,41232L,
-41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,41241L,41242L,
-41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,41251L,41252L,
-41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,41261L,41262L,
-41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,41271L,41272L,
-41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,41281L,41282L,
-41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,41291L,41292L,
-41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,41301L,41302L,
-41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,41311L,41312L,
-41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,41321L,41322L,
-41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,41331L,41332L,
-41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,41341L,41342L,
-41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,41351L,41352L,
-41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,41361L,41362L,
-41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,41371L,41372L,
-41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,41381L,41382L,
-41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,41391L,41392L,
-41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,41401L,41402L,
-41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,41411L,41412L,
-41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,41421L,41422L,
-41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,41431L,41432L,
-41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,41441L,41442L,
-41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,41451L,41452L,
-41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,41461L,41462L,
-41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,41471L,41472L,
-41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,41481L,41482L,
-41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,41491L,41492L,
-41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,41501L,41502L,
-41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,41511L,41512L,
-41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,41521L,41522L,
-41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,41531L,41532L,
-41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,41541L,41542L,
-41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,41551L,41552L,
-41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,41561L,41562L,
-41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,41571L,41572L,
-41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,41581L,41582L,
-41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,41591L,41592L,
-41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,41601L,41602L,
-41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,41611L,41612L,
-41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,41621L,41622L,
-41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,41631L,41632L,
-41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,41641L,41642L,
-41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,41651L,41652L,
-41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,41661L,41662L,
-41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,41671L,41672L,
-41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,41681L,41682L,
-41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,41691L,41692L,
-41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,41701L,41702L,
-41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,41711L,41712L,
-41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,41721L,41722L,
-41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,41731L,41732L,
-41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,41741L,41742L,
-41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,41751L,41752L,
-41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,41761L,41762L,
-41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,41771L,41772L,
-41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,41781L,41782L,
-41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,41791L,41792L,
-41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,41801L,41802L,
-41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,41811L,41812L,
-41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,41821L,41822L,
-41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,41831L,41832L,
-41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,41841L,41842L,
-41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,41851L,41852L,
-41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,41861L,41862L,
-41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,41871L,41872L,
-41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,41881L,41882L,
-41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,41891L,41892L,
-41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,41901L,41902L,
-41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,41911L,41912L,
-41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,41921L,41922L,
-41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,41931L,41932L,
-41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,41941L,41942L,
-41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,41951L,41952L,
-41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,41961L,41962L,
-41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,41971L,41972L,
-41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,41981L,41982L,
-41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,41991L,41992L,
-41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,42001L,42002L,
-42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,42011L,42012L,
-42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,42021L,42022L,
-42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,42031L,42032L,
-42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,42041L,42042L,
-42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,42051L,42052L,
-42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,42061L,42062L,
-42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,42071L,42072L,
-42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,42081L,42082L,
-42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,42091L,42092L,
-42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,42101L,42102L,
-42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,42111L,42112L,
-42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,42121L,42122L,
-42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,42131L,42132L,
-42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,42141L,42142L,
-42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,42151L,42152L,
-42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,42161L,42162L,
-42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,42171L,42172L,
-42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,42181L,42182L,
-42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,42191L,42192L,
-42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,42201L,42202L,
-42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,42211L,42212L,
-42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,42221L,42222L,
-42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,42231L,42232L,
-42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,42241L,42242L,
-42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,42251L,42252L,
-42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,42261L,42262L,
-42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,42271L,42272L,
-42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,42281L,42282L,
-42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,42291L,42292L,
-42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,42301L,42302L,
-42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,42311L,42312L,
-42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,42321L,42322L,
-42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,42331L,42332L,
-42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,42341L,42342L,
-42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,42351L,42352L,
-42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,42361L,42362L,
-42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,42371L,42372L,
-42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,42381L,42382L,
-42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,42391L,42392L,
-42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,42401L,42402L,
-42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,42411L,42412L,
-42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,42421L,42422L,
-42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,42431L,42432L,
-42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,42441L,42442L,
-42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,42451L,42452L,
-42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,42461L,42462L,
-42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,42471L,42472L,
-42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,42481L,42482L,
-42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,42491L,42492L,
-42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,42501L,42502L,
-42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,42511L,42512L,
-42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,42521L,42522L,
-42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,42531L,42532L,
-42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,42541L,42542L,
-42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,42551L,42552L,
-42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,42560L,42562L,
-42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,42570L,42572L,
-42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,42580L,42582L,
-42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,42590L,42592L,
-42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,42600L,42602L,
-42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,42611L,42612L,
-42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,42621L,42622L,
-42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,42630L,42632L,
-42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,42640L,42642L,
-42642L,42644L,42644L,42646L,42646L,42648L,42649L,42650L,42651L,42652L,
-42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,42661L,42662L,
-42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,42671L,42672L,
-42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,42681L,42682L,
-42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,42691L,42692L,
-42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,42701L,42702L,
-42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,42711L,42712L,
-42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,42721L,42722L,
-42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,42731L,42732L,
-42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,42741L,42742L,
-42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,42751L,42752L,
-42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,42761L,42762L,
-42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,42771L,42772L,
-42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,42781L,42782L,
-42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,42790L,42792L,
-42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,42801L,42802L,
-42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,42810L,42812L,
-42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,42820L,42822L,
-42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,42830L,42832L,
-42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,42840L,42842L,
-42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,42850L,42852L,
-42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,42860L,42862L,
-42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,42871L,42872L,
-42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,42880L,42882L,
-42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,42891L,42891L,
-42893L,42894L,42895L,42896L,42896L,42898L,42899L,42900L,42901L,42902L,
-42903L,42904L,42905L,42906L,42907L,42908L,42909L,42910L,42911L,42912L,
-42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,42920L,42922L,
-42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,42931L,42932L,
-42933L,42934L,42935L,42936L,42937L,42938L,42939L,42940L,42941L,42942L,
-42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,42951L,42952L,
-42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,42961L,42962L,
-42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,42971L,42972L,
-42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,42981L,42982L,
-42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,42991L,42992L,
-42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,43001L,43002L,
-43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,43011L,43012L,
-43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,43021L,43022L,
-43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,43031L,43032L,
-43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,43041L,43042L,
-43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,43051L,43052L,
-43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,43061L,43062L,
-43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,43071L,43072L,
-43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,43081L,43082L,
-43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,43091L,43092L,
-43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,43101L,43102L,
-43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,43111L,43112L,
-43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,43121L,43122L,
-43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,43131L,43132L,
-43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,43141L,43142L,
-43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,43151L,43152L,
-43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,43161L,43162L,
-43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,43171L,43172L,
-43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,43181L,43182L,
-43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,43191L,43192L,
-43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,43201L,43202L,
-43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,43211L,43212L,
-43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,43221L,43222L,
-43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,43231L,43232L,
-43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,43241L,43242L,
-43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,43251L,43252L,
-43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,43261L,43262L,
-43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,43271L,43272L,
-43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,43281L,43282L,
-43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,43291L,43292L,
-43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,43301L,43302L,
-43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,43311L,43312L,
-43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,43321L,43322L,
-43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,43331L,43332L,
-43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,43341L,43342L,
-43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,43351L,43352L,
-43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,43361L,43362L,
-43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,43371L,43372L,
-43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,43381L,43382L,
-43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,43391L,43392L,
-43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,43401L,43402L,
-43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,43411L,43412L,
-43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,43421L,43422L,
-43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,43431L,43432L,
-43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,43441L,43442L,
-43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,43451L,43452L,
-43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,43461L,43462L,
-43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,43471L,43472L,
-43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,43481L,43482L,
-43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,43491L,43492L,
-43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,43501L,43502L,
-43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,43511L,43512L,
-43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,43521L,43522L,
-43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,43531L,43532L,
-43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,43541L,43542L,
-43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,43551L,43552L,
-43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,43561L,43562L,
-43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,43571L,43572L,
-43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,43581L,43582L,
-43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,43591L,43592L,
-43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,43601L,43602L,
-43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,43611L,43612L,
-43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,43621L,43622L,
-43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,43631L,43632L,
-43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,43641L,43642L,
-43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,43651L,43652L,
-43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,43661L,43662L,
-43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,43671L,43672L,
-43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,43681L,43682L,
-43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,43691L,43692L,
-43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,43701L,43702L,
-43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,43711L,43712L,
-43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,43721L,43722L,
-43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,43731L,43732L,
-43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,43741L,43742L,
-43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,43751L,43752L,
-43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,43761L,43762L,
-43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,43771L,43772L,
-43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,43781L,43782L,
-43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,43791L,43792L,
-43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,43801L,43802L,
-43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,43811L,43812L,
-43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,43821L,43822L,
-43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,43831L,43832L,
-43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,43841L,43842L,
-43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,43851L,43852L,
-43853L,43854L,43855L,43856L,43857L,43858L,43859L,43860L,43861L,43862L,
-43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,43871L,43872L,
-43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,43881L,43882L,
-43883L,43884L,43885L,43886L,43887L,43888L,43889L,43890L,43891L,43892L,
-43893L,43894L,43895L,43896L,43897L,43898L,43899L,43900L,43901L,43902L,
-43903L,43904L,43905L,43906L,43907L,43908L,43909L,43910L,43911L,43912L,
-43913L,43914L,43915L,43916L,43917L,43918L,43919L,43920L,43921L,43922L,
-43923L,43924L,43925L,43926L,43927L,43928L,43929L,43930L,43931L,43932L,
-43933L,43934L,43935L,43936L,43937L,43938L,43939L,43940L,43941L,43942L,
-43943L,43944L,43945L,43946L,43947L,43948L,43949L,43950L,43951L,43952L,
-43953L,43954L,43955L,43956L,43957L,43958L,43959L,43960L,43961L,43962L,
-43963L,43964L,43965L,43966L,43967L,43968L,43969L,43970L,43971L,43972L,
-43973L,43974L,43975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,
-43983L,43984L,43985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,
-43993L,43994L,43995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,
-44003L,44004L,44005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,
-44013L,44014L,44015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,
-44023L,44024L,44025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,
-44033L,44034L,44035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,
-44043L,44044L,44045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,
-44053L,44054L,44055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,
-44063L,44064L,44065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,
-44073L,44074L,44075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,
-44083L,44084L,44085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,
-44093L,44094L,44095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,
-44103L,44104L,44105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,
-44113L,44114L,44115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,
-44123L,44124L,44125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,
-44133L,44134L,44135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,
-44143L,44144L,44145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,
-44153L,44154L,44155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,
-44163L,44164L,44165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,
-44173L,44174L,44175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,
-44183L,44184L,44185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,
-44193L,44194L,44195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,
-44203L,44204L,44205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,
-44213L,44214L,44215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,
-44223L,44224L,44225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,
-44233L,44234L,44235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,
-44243L,44244L,44245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,
-44253L,44254L,44255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,
-44263L,44264L,44265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,
-44273L,44274L,44275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,
-44283L,44284L,44285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,
-44293L,44294L,44295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,
-44303L,44304L,44305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,
-44313L,44314L,44315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,
-44323L,44324L,44325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,
-44333L,44334L,44335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,
-44343L,44344L,44345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,
-44353L,44354L,44355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,
-44363L,44364L,44365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,
-44373L,44374L,44375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,
-44383L,44384L,44385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,
-44393L,44394L,44395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,
-44403L,44404L,44405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,
-44413L,44414L,44415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,
-44423L,44424L,44425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,
-44433L,44434L,44435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,
-44443L,44444L,44445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,
-44453L,44454L,44455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,
-44463L,44464L,44465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,
-44473L,44474L,44475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,
-44483L,44484L,44485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,
-44493L,44494L,44495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,
-44503L,44504L,44505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,
-44513L,44514L,44515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,
-44523L,44524L,44525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,
-44533L,44534L,44535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,
-44543L,44544L,44545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,
-44553L,44554L,44555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,
-44563L,44564L,44565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,
-44573L,44574L,44575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,
-44583L,44584L,44585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,
-44593L,44594L,44595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,
-44603L,44604L,44605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,
-44613L,44614L,44615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,
-44623L,44624L,44625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,
-44633L,44634L,44635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,
-44643L,44644L,44645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,
-44653L,44654L,44655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,
-44663L,44664L,44665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,
-44673L,44674L,44675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,
-44683L,44684L,44685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,
-44693L,44694L,44695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,
-44703L,44704L,44705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,
-44713L,44714L,44715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,
-44723L,44724L,44725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,
-44733L,44734L,44735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,
-44743L,44744L,44745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,
-44753L,44754L,44755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,
-44763L,44764L,44765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,
-44773L,44774L,44775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,
-44783L,44784L,44785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,
-44793L,44794L,44795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,
-44803L,44804L,44805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,
-44813L,44814L,44815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,
-44823L,44824L,44825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,
-44833L,44834L,44835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,
-44843L,44844L,44845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,
-44853L,44854L,44855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,
-44863L,44864L,44865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,
-44873L,44874L,44875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,
-44883L,44884L,44885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,
-44893L,44894L,44895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,
-44903L,44904L,44905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,
-44913L,44914L,44915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,
-44923L,44924L,44925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,
-44933L,44934L,44935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,
-44943L,44944L,44945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,
-44953L,44954L,44955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,
-44963L,44964L,44965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,
-44973L,44974L,44975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,
-44983L,44984L,44985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,
-44993L,44994L,44995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,
-45003L,45004L,45005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,
-45013L,45014L,45015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,
-45023L,45024L,45025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,
-45033L,45034L,45035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,
-45043L,45044L,45045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,
-45053L,45054L,45055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,
-45063L,45064L,45065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,
-45073L,45074L,45075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,
-45083L,45084L,45085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,
-45093L,45094L,45095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,
-45103L,45104L,45105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,
-45113L,45114L,45115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,
-45123L,45124L,45125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,
-45133L,45134L,45135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,
-45143L,45144L,45145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,
-45153L,45154L,45155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,
-45163L,45164L,45165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,
-45173L,45174L,45175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,
-45183L,45184L,45185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,
-45193L,45194L,45195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,
-45203L,45204L,45205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,
-45213L,45214L,45215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,
-45223L,45224L,45225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,
-45233L,45234L,45235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,
-45243L,45244L,45245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,
-45253L,45254L,45255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,
-45263L,45264L,45265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,
-45273L,45274L,45275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,
-45283L,45284L,45285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,
-45293L,45294L,45295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,
-45303L,45304L,45305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,
-45313L,45314L,45315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,
-45323L,45324L,45325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,
-45333L,45334L,45335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,
-45343L,45344L,45345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,
-45353L,45354L,45355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,
-45363L,45364L,45365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,
-45373L,45374L,45375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,
-45383L,45384L,45385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,
-45393L,45394L,45395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,
-45403L,45404L,45405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,
-45413L,45414L,45415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,
-45423L,45424L,45425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,
-45433L,45434L,45435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,
-45443L,45444L,45445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,
-45453L,45454L,45455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,
-45463L,45464L,45465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,
-45473L,45474L,45475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,
-45483L,45484L,45485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,
-45493L,45494L,45495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,
-45503L,45504L,45505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,
-45513L,45514L,45515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,
-45523L,45524L,45525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,
-45533L,45534L,45535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,
-45543L,45544L,45545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,
-45553L,45554L,45555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,
-45563L,45564L,45565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,
-45573L,45574L,45575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,
-45583L,45584L,45585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,
-45593L,45594L,45595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,
-45603L,45604L,45605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,
-45613L,45614L,45615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,
-45623L,45624L,45625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,
-45633L,45634L,45635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,
-45643L,45644L,45645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,
-45653L,45654L,45655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,
-45663L,45664L,45665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,
-45673L,45674L,45675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,
-45683L,45684L,45685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,
-45693L,45694L,45695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,
-45703L,45704L,45705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,
-45713L,45714L,45715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,
-45723L,45724L,45725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,
-45733L,45734L,45735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,
-45743L,45744L,45745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,
-45753L,45754L,45755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,
-45763L,45764L,45765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,
-45773L,45774L,45775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,
-45783L,45784L,45785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,
-45793L,45794L,45795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,
-45803L,45804L,45805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,
-45813L,45814L,45815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,
-45823L,45824L,45825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,
-45833L,45834L,45835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,
-45843L,45844L,45845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,
-45853L,45854L,45855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,
-45863L,45864L,45865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,
-45873L,45874L,45875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,
-45883L,45884L,45885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,
-45893L,45894L,45895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,
-45903L,45904L,45905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,
-45913L,45914L,45915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,
-45923L,45924L,45925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,
-45933L,45934L,45935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,
-45943L,45944L,45945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,
-45953L,45954L,45955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,
-45963L,45964L,45965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,
-45973L,45974L,45975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,
-45983L,45984L,45985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,
-45993L,45994L,45995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,
-46003L,46004L,46005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,
-46013L,46014L,46015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,
-46023L,46024L,46025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,
-46033L,46034L,46035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,
-46043L,46044L,46045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,
-46053L,46054L,46055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,
-46063L,46064L,46065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,
-46073L,46074L,46075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,
-46083L,46084L,46085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,
-46093L,46094L,46095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,
-46103L,46104L,46105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,
-46113L,46114L,46115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,
-46123L,46124L,46125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,
-46133L,46134L,46135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,
-46143L,46144L,46145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,
-46153L,46154L,46155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,
-46163L,46164L,46165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,
-46173L,46174L,46175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,
-46183L,46184L,46185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,
-46193L,46194L,46195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,
-46203L,46204L,46205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,
-46213L,46214L,46215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,
-46223L,46224L,46225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,
-46233L,46234L,46235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,
-46243L,46244L,46245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,
-46253L,46254L,46255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,
-46263L,46264L,46265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,
-46273L,46274L,46275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,
-46283L,46284L,46285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,
-46293L,46294L,46295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,
-46303L,46304L,46305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,
-46313L,46314L,46315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,
-46323L,46324L,46325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,
-46333L,46334L,46335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,
-46343L,46344L,46345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,
-46353L,46354L,46355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,
-46363L,46364L,46365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,
-46373L,46374L,46375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,
-46383L,46384L,46385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,
-46393L,46394L,46395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,
-46403L,46404L,46405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,
-46413L,46414L,46415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,
-46423L,46424L,46425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,
-46433L,46434L,46435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,
-46443L,46444L,46445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,
-46453L,46454L,46455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,
-46463L,46464L,46465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,
-46473L,46474L,46475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,
-46483L,46484L,46485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,
-46493L,46494L,46495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,
-46503L,46504L,46505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,
-46513L,46514L,46515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,
-46523L,46524L,46525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,
-46533L,46534L,46535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,
-46543L,46544L,46545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,
-46553L,46554L,46555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,
-46563L,46564L,46565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,
-46573L,46574L,46575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,
-46583L,46584L,46585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,
-46593L,46594L,46595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,
-46603L,46604L,46605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,
-46613L,46614L,46615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,
-46623L,46624L,46625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,
-46633L,46634L,46635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,
-46643L,46644L,46645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,
-46653L,46654L,46655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,
-46663L,46664L,46665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,
-46673L,46674L,46675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,
-46683L,46684L,46685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,
-46693L,46694L,46695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,
-46703L,46704L,46705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,
-46713L,46714L,46715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,
-46723L,46724L,46725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,
-46733L,46734L,46735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,
-46743L,46744L,46745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,
-46753L,46754L,46755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,
-46763L,46764L,46765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,
-46773L,46774L,46775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,
-46783L,46784L,46785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,
-46793L,46794L,46795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,
-46803L,46804L,46805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,
-46813L,46814L,46815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,
-46823L,46824L,46825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,
-46833L,46834L,46835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,
-46843L,46844L,46845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,
-46853L,46854L,46855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,
-46863L,46864L,46865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,
-46873L,46874L,46875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,
-46883L,46884L,46885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,
-46893L,46894L,46895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,
-46903L,46904L,46905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,
-46913L,46914L,46915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,
-46923L,46924L,46925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,
-46933L,46934L,46935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,
-46943L,46944L,46945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,
-46953L,46954L,46955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,
-46963L,46964L,46965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,
-46973L,46974L,46975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,
-46983L,46984L,46985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,
-46993L,46994L,46995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,
-47003L,47004L,47005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,
-47013L,47014L,47015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,
-47023L,47024L,47025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,
-47033L,47034L,47035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,
-47043L,47044L,47045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,
-47053L,47054L,47055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,
-47063L,47064L,47065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,
-47073L,47074L,47075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,
-47083L,47084L,47085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,
-47093L,47094L,47095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,
-47103L,47104L,47105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,
-47113L,47114L,47115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,
-47123L,47124L,47125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,
-47133L,47134L,47135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,
-47143L,47144L,47145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,
-47153L,47154L,47155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,
-47163L,47164L,47165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,
-47173L,47174L,47175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,
-47183L,47184L,47185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,
-47193L,47194L,47195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,
-47203L,47204L,47205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,
-47213L,47214L,47215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,
-47223L,47224L,47225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,
-47233L,47234L,47235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,
-47243L,47244L,47245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,
-47253L,47254L,47255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,
-47263L,47264L,47265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,
-47273L,47274L,47275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,
-47283L,47284L,47285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,
-47293L,47294L,47295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,
-47303L,47304L,47305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,
-47313L,47314L,47315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,
-47323L,47324L,47325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,
-47333L,47334L,47335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,
-47343L,47344L,47345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,
-47353L,47354L,47355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,
-47363L,47364L,47365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,
-47373L,47374L,47375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,
-47383L,47384L,47385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,
-47393L,47394L,47395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,
-47403L,47404L,47405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,
-47413L,47414L,47415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,
-47423L,47424L,47425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,
-47433L,47434L,47435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,
-47443L,47444L,47445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,
-47453L,47454L,47455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,
-47463L,47464L,47465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,
-47473L,47474L,47475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,
-47483L,47484L,47485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,
-47493L,47494L,47495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,
-47503L,47504L,47505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,
-47513L,47514L,47515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,
-47523L,47524L,47525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,
-47533L,47534L,47535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,
-47543L,47544L,47545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,
-47553L,47554L,47555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,
-47563L,47564L,47565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,
-47573L,47574L,47575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,
-47583L,47584L,47585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,
-47593L,47594L,47595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,
-47603L,47604L,47605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,
-47613L,47614L,47615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,
-47623L,47624L,47625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,
-47633L,47634L,47635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,
-47643L,47644L,47645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,
-47653L,47654L,47655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,
-47663L,47664L,47665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,
-47673L,47674L,47675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,
-47683L,47684L,47685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,
-47693L,47694L,47695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,
-47703L,47704L,47705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,
-47713L,47714L,47715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,
-47723L,47724L,47725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,
-47733L,47734L,47735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,
-47743L,47744L,47745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,
-47753L,47754L,47755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,
-47763L,47764L,47765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,
-47773L,47774L,47775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,
-47783L,47784L,47785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,
-47793L,47794L,47795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,
-47803L,47804L,47805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,
-47813L,47814L,47815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,
-47823L,47824L,47825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,
-47833L,47834L,47835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,
-47843L,47844L,47845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,
-47853L,47854L,47855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,
-47863L,47864L,47865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,
-47873L,47874L,47875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,
-47883L,47884L,47885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,
-47893L,47894L,47895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,
-47903L,47904L,47905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,
-47913L,47914L,47915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,
-47923L,47924L,47925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,
-47933L,47934L,47935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,
-47943L,47944L,47945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,
-47953L,47954L,47955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,
-47963L,47964L,47965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,
-47973L,47974L,47975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,
-47983L,47984L,47985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,
-47993L,47994L,47995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,
-48003L,48004L,48005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,
-48013L,48014L,48015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,
-48023L,48024L,48025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,
-48033L,48034L,48035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,
-48043L,48044L,48045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,
-48053L,48054L,48055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,
-48063L,48064L,48065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,
-48073L,48074L,48075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,
-48083L,48084L,48085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,
-48093L,48094L,48095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,
-48103L,48104L,48105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,
-48113L,48114L,48115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,
-48123L,48124L,48125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,
-48133L,48134L,48135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,
-48143L,48144L,48145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,
-48153L,48154L,48155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,
-48163L,48164L,48165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,
-48173L,48174L,48175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,
-48183L,48184L,48185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,
-48193L,48194L,48195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,
-48203L,48204L,48205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,
-48213L,48214L,48215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,
-48223L,48224L,48225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,
-48233L,48234L,48235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,
-48243L,48244L,48245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,
-48253L,48254L,48255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,
-48263L,48264L,48265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,
-48273L,48274L,48275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,
-48283L,48284L,48285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,
-48293L,48294L,48295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,
-48303L,48304L,48305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,
-48313L,48314L,48315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,
-48323L,48324L,48325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,
-48333L,48334L,48335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,
-48343L,48344L,48345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,
-48353L,48354L,48355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,
-48363L,48364L,48365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,
-48373L,48374L,48375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,
-48383L,48384L,48385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,
-48393L,48394L,48395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,
-48403L,48404L,48405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,
-48413L,48414L,48415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,
-48423L,48424L,48425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,
-48433L,48434L,48435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,
-48443L,48444L,48445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,
-48453L,48454L,48455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,
-48463L,48464L,48465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,
-48473L,48474L,48475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,
-48483L,48484L,48485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,
-48493L,48494L,48495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,
-48503L,48504L,48505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,
-48513L,48514L,48515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,
-48523L,48524L,48525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,
-48533L,48534L,48535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,
-48543L,48544L,48545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,
-48553L,48554L,48555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,
-48563L,48564L,48565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,
-48573L,48574L,48575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,
-48583L,48584L,48585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,
-48593L,48594L,48595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,
-48603L,48604L,48605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,
-48613L,48614L,48615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,
-48623L,48624L,48625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,
-48633L,48634L,48635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,
-48643L,48644L,48645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,
-48653L,48654L,48655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,
-48663L,48664L,48665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,
-48673L,48674L,48675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,
-48683L,48684L,48685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,
-48693L,48694L,48695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,
-48703L,48704L,48705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,
-48713L,48714L,48715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,
-48723L,48724L,48725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,
-48733L,48734L,48735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,
-48743L,48744L,48745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,
-48753L,48754L,48755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,
-48763L,48764L,48765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,
-48773L,48774L,48775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,
-48783L,48784L,48785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,
-48793L,48794L,48795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,
-48803L,48804L,48805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,
-48813L,48814L,48815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,
-48823L,48824L,48825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,
-48833L,48834L,48835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,
-48843L,48844L,48845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,
-48853L,48854L,48855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,
-48863L,48864L,48865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,
-48873L,48874L,48875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,
-48883L,48884L,48885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,
-48893L,48894L,48895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,
-48903L,48904L,48905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,
-48913L,48914L,48915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,
-48923L,48924L,48925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,
-48933L,48934L,48935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,
-48943L,48944L,48945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,
-48953L,48954L,48955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,
-48963L,48964L,48965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,
-48973L,48974L,48975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,
-48983L,48984L,48985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,
-48993L,48994L,48995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,
-49003L,49004L,49005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,
-49013L,49014L,49015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,
-49023L,49024L,49025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,
-49033L,49034L,49035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,
-49043L,49044L,49045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,
-49053L,49054L,49055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,
-49063L,49064L,49065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,
-49073L,49074L,49075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,
-49083L,49084L,49085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,
-49093L,49094L,49095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,
-49103L,49104L,49105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,
-49113L,49114L,49115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,
-49123L,49124L,49125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,
-49133L,49134L,49135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,
-49143L,49144L,49145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,
-49153L,49154L,49155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,
-49163L,49164L,49165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,
-49173L,49174L,49175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,
-49183L,49184L,49185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,
-49193L,49194L,49195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,
-49203L,49204L,49205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,
-49213L,49214L,49215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,
-49223L,49224L,49225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,
-49233L,49234L,49235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,
-49243L,49244L,49245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,
-49253L,49254L,49255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,
-49263L,49264L,49265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,
-49273L,49274L,49275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,
-49283L,49284L,49285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,
-49293L,49294L,49295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,
-49303L,49304L,49305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,
-49313L,49314L,49315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,
-49323L,49324L,49325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,
-49333L,49334L,49335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,
-49343L,49344L,49345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,
-49353L,49354L,49355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,
-49363L,49364L,49365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,
-49373L,49374L,49375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,
-49383L,49384L,49385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,
-49393L,49394L,49395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,
-49403L,49404L,49405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,
-49413L,49414L,49415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,
-49423L,49424L,49425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,
-49433L,49434L,49435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,
-49443L,49444L,49445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,
-49453L,49454L,49455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,
-49463L,49464L,49465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,
-49473L,49474L,49475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,
-49483L,49484L,49485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,
-49493L,49494L,49495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,
-49503L,49504L,49505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,
-49513L,49514L,49515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,
-49523L,49524L,49525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,
-49533L,49534L,49535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,
-49543L,49544L,49545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,
-49553L,49554L,49555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,
-49563L,49564L,49565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,
-49573L,49574L,49575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,
-49583L,49584L,49585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,
-49593L,49594L,49595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,
-49603L,49604L,49605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,
-49613L,49614L,49615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,
-49623L,49624L,49625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,
-49633L,49634L,49635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,
-49643L,49644L,49645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,
-49653L,49654L,49655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,
-49663L,49664L,49665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,
-49673L,49674L,49675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,
-49683L,49684L,49685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,
-49693L,49694L,49695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,
-49703L,49704L,49705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,
-49713L,49714L,49715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,
-49723L,49724L,49725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,
-49733L,49734L,49735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,
-49743L,49744L,49745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,
-49753L,49754L,49755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,
-49763L,49764L,49765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,
-49773L,49774L,49775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,
-49783L,49784L,49785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,
-49793L,49794L,49795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,
-49803L,49804L,49805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,
-49813L,49814L,49815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,
-49823L,49824L,49825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,
-49833L,49834L,49835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,
-49843L,49844L,49845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,
-49853L,49854L,49855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,
-49863L,49864L,49865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,
-49873L,49874L,49875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,
-49883L,49884L,49885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,
-49893L,49894L,49895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,
-49903L,49904L,49905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,
-49913L,49914L,49915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,
-49923L,49924L,49925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,
-49933L,49934L,49935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,
-49943L,49944L,49945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,
-49953L,49954L,49955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,
-49963L,49964L,49965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,
-49973L,49974L,49975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,
-49983L,49984L,49985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,
-49993L,49994L,49995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,
-50003L,50004L,50005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,
-50013L,50014L,50015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,
-50023L,50024L,50025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,
-50033L,50034L,50035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,
-50043L,50044L,50045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,
-50053L,50054L,50055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,
-50063L,50064L,50065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,
-50073L,50074L,50075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,
-50083L,50084L,50085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,
-50093L,50094L,50095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,
-50103L,50104L,50105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,
-50113L,50114L,50115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,
-50123L,50124L,50125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,
-50133L,50134L,50135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,
-50143L,50144L,50145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,
-50153L,50154L,50155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,
-50163L,50164L,50165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,
-50173L,50174L,50175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,
-50183L,50184L,50185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,
-50193L,50194L,50195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,
-50203L,50204L,50205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,
-50213L,50214L,50215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,
-50223L,50224L,50225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,
-50233L,50234L,50235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,
-50243L,50244L,50245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,
-50253L,50254L,50255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,
-50263L,50264L,50265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,
-50273L,50274L,50275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,
-50283L,50284L,50285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,
-50293L,50294L,50295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,
-50303L,50304L,50305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,
-50313L,50314L,50315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,
-50323L,50324L,50325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,
-50333L,50334L,50335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,
-50343L,50344L,50345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,
-50353L,50354L,50355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,
-50363L,50364L,50365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,
-50373L,50374L,50375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,
-50383L,50384L,50385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,
-50393L,50394L,50395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,
-50403L,50404L,50405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,
-50413L,50414L,50415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,
-50423L,50424L,50425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,
-50433L,50434L,50435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,
-50443L,50444L,50445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,
-50453L,50454L,50455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,
-50463L,50464L,50465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,
-50473L,50474L,50475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,
-50483L,50484L,50485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,
-50493L,50494L,50495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,
-50503L,50504L,50505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,
-50513L,50514L,50515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,
-50523L,50524L,50525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,
-50533L,50534L,50535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,
-50543L,50544L,50545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,
-50553L,50554L,50555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,
-50563L,50564L,50565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,
-50573L,50574L,50575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,
-50583L,50584L,50585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,
-50593L,50594L,50595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,
-50603L,50604L,50605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,
-50613L,50614L,50615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,
-50623L,50624L,50625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,
-50633L,50634L,50635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,
-50643L,50644L,50645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,
-50653L,50654L,50655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,
-50663L,50664L,50665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,
-50673L,50674L,50675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,
-50683L,50684L,50685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,
-50693L,50694L,50695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,
-50703L,50704L,50705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,
-50713L,50714L,50715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,
-50723L,50724L,50725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,
-50733L,50734L,50735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,
-50743L,50744L,50745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,
-50753L,50754L,50755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,
-50763L,50764L,50765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,
-50773L,50774L,50775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,
-50783L,50784L,50785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,
-50793L,50794L,50795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,
-50803L,50804L,50805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,
-50813L,50814L,50815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,
-50823L,50824L,50825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,
-50833L,50834L,50835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,
-50843L,50844L,50845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,
-50853L,50854L,50855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,
-50863L,50864L,50865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,
-50873L,50874L,50875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,
-50883L,50884L,50885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,
-50893L,50894L,50895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,
-50903L,50904L,50905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,
-50913L,50914L,50915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,
-50923L,50924L,50925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,
-50933L,50934L,50935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,
-50943L,50944L,50945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,
-50953L,50954L,50955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,
-50963L,50964L,50965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,
-50973L,50974L,50975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,
-50983L,50984L,50985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,
-50993L,50994L,50995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,
-51003L,51004L,51005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,
-51013L,51014L,51015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,
-51023L,51024L,51025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,
-51033L,51034L,51035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,
-51043L,51044L,51045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,
-51053L,51054L,51055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,
-51063L,51064L,51065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,
-51073L,51074L,51075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,
-51083L,51084L,51085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,
-51093L,51094L,51095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,
-51103L,51104L,51105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,
-51113L,51114L,51115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,
-51123L,51124L,51125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,
-51133L,51134L,51135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,
-51143L,51144L,51145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,
-51153L,51154L,51155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,
-51163L,51164L,51165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,
-51173L,51174L,51175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,
-51183L,51184L,51185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,
-51193L,51194L,51195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,
-51203L,51204L,51205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,
-51213L,51214L,51215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,
-51223L,51224L,51225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,
-51233L,51234L,51235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,
-51243L,51244L,51245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,
-51253L,51254L,51255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,
-51263L,51264L,51265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,
-51273L,51274L,51275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,
-51283L,51284L,51285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,
-51293L,51294L,51295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,
-51303L,51304L,51305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,
-51313L,51314L,51315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,
-51323L,51324L,51325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,
-51333L,51334L,51335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,
-51343L,51344L,51345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,
-51353L,51354L,51355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,
-51363L,51364L,51365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,
-51373L,51374L,51375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,
-51383L,51384L,51385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,
-51393L,51394L,51395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,
-51403L,51404L,51405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,
-51413L,51414L,51415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,
-51423L,51424L,51425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,
-51433L,51434L,51435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,
-51443L,51444L,51445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,
-51453L,51454L,51455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,
-51463L,51464L,51465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,
-51473L,51474L,51475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,
-51483L,51484L,51485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,
-51493L,51494L,51495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,
-51503L,51504L,51505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,
-51513L,51514L,51515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,
-51523L,51524L,51525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,
-51533L,51534L,51535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,
-51543L,51544L,51545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,
-51553L,51554L,51555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,
-51563L,51564L,51565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,
-51573L,51574L,51575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,
-51583L,51584L,51585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,
-51593L,51594L,51595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,
-51603L,51604L,51605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,
-51613L,51614L,51615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,
-51623L,51624L,51625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,
-51633L,51634L,51635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,
-51643L,51644L,51645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,
-51653L,51654L,51655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,
-51663L,51664L,51665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,
-51673L,51674L,51675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,
-51683L,51684L,51685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,
-51693L,51694L,51695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,
-51703L,51704L,51705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,
-51713L,51714L,51715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,
-51723L,51724L,51725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,
-51733L,51734L,51735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,
-51743L,51744L,51745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,
-51753L,51754L,51755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,
-51763L,51764L,51765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,
-51773L,51774L,51775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,
-51783L,51784L,51785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,
-51793L,51794L,51795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,
-51803L,51804L,51805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,
-51813L,51814L,51815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,
-51823L,51824L,51825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,
-51833L,51834L,51835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,
-51843L,51844L,51845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,
-51853L,51854L,51855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,
-51863L,51864L,51865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,
-51873L,51874L,51875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,
-51883L,51884L,51885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,
-51893L,51894L,51895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,
-51903L,51904L,51905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,
-51913L,51914L,51915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,
-51923L,51924L,51925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,
-51933L,51934L,51935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,
-51943L,51944L,51945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,
-51953L,51954L,51955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,
-51963L,51964L,51965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,
-51973L,51974L,51975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,
-51983L,51984L,51985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,
-51993L,51994L,51995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,
-52003L,52004L,52005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,
-52013L,52014L,52015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,
-52023L,52024L,52025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,
-52033L,52034L,52035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,
-52043L,52044L,52045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,
-52053L,52054L,52055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,
-52063L,52064L,52065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,
-52073L,52074L,52075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,
-52083L,52084L,52085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,
-52093L,52094L,52095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,
-52103L,52104L,52105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,
-52113L,52114L,52115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,
-52123L,52124L,52125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,
-52133L,52134L,52135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,
-52143L,52144L,52145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,
-52153L,52154L,52155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,
-52163L,52164L,52165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,
-52173L,52174L,52175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,
-52183L,52184L,52185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,
-52193L,52194L,52195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,
-52203L,52204L,52205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,
-52213L,52214L,52215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,
-52223L,52224L,52225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,
-52233L,52234L,52235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,
-52243L,52244L,52245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,
-52253L,52254L,52255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,
-52263L,52264L,52265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,
-52273L,52274L,52275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,
-52283L,52284L,52285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,
-52293L,52294L,52295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,
-52303L,52304L,52305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,
-52313L,52314L,52315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,
-52323L,52324L,52325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,
-52333L,52334L,52335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,
-52343L,52344L,52345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,
-52353L,52354L,52355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,
-52363L,52364L,52365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,
-52373L,52374L,52375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,
-52383L,52384L,52385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,
-52393L,52394L,52395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,
-52403L,52404L,52405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,
-52413L,52414L,52415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,
-52423L,52424L,52425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,
-52433L,52434L,52435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,
-52443L,52444L,52445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,
-52453L,52454L,52455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,
-52463L,52464L,52465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,
-52473L,52474L,52475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,
-52483L,52484L,52485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,
-52493L,52494L,52495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,
-52503L,52504L,52505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,
-52513L,52514L,52515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,
-52523L,52524L,52525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,
-52533L,52534L,52535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,
-52543L,52544L,52545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,
-52553L,52554L,52555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,
-52563L,52564L,52565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,
-52573L,52574L,52575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,
-52583L,52584L,52585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,
-52593L,52594L,52595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,
-52603L,52604L,52605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,
-52613L,52614L,52615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,
-52623L,52624L,52625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,
-52633L,52634L,52635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,
-52643L,52644L,52645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,
-52653L,52654L,52655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,
-52663L,52664L,52665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,
-52673L,52674L,52675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,
-52683L,52684L,52685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,
-52693L,52694L,52695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,
-52703L,52704L,52705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,
-52713L,52714L,52715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,
-52723L,52724L,52725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,
-52733L,52734L,52735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,
-52743L,52744L,52745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,
-52753L,52754L,52755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,
-52763L,52764L,52765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,
-52773L,52774L,52775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,
-52783L,52784L,52785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,
-52793L,52794L,52795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,
-52803L,52804L,52805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,
-52813L,52814L,52815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,
-52823L,52824L,52825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,
-52833L,52834L,52835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,
-52843L,52844L,52845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,
-52853L,52854L,52855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,
-52863L,52864L,52865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,
-52873L,52874L,52875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,
-52883L,52884L,52885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,
-52893L,52894L,52895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,
-52903L,52904L,52905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,
-52913L,52914L,52915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,
-52923L,52924L,52925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,
-52933L,52934L,52935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,
-52943L,52944L,52945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,
-52953L,52954L,52955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,
-52963L,52964L,52965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,
-52973L,52974L,52975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,
-52983L,52984L,52985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,
-52993L,52994L,52995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,
-53003L,53004L,53005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,
-53013L,53014L,53015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,
-53023L,53024L,53025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,
-53033L,53034L,53035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,
-53043L,53044L,53045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,
-53053L,53054L,53055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,
-53063L,53064L,53065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,
-53073L,53074L,53075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,
-53083L,53084L,53085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,
-53093L,53094L,53095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,
-53103L,53104L,53105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,
-53113L,53114L,53115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,
-53123L,53124L,53125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,
-53133L,53134L,53135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,
-53143L,53144L,53145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,
-53153L,53154L,53155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,
-53163L,53164L,53165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,
-53173L,53174L,53175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,
-53183L,53184L,53185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,
-53193L,53194L,53195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,
-53203L,53204L,53205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,
-53213L,53214L,53215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,
-53223L,53224L,53225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,
-53233L,53234L,53235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,
-53243L,53244L,53245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,
-53253L,53254L,53255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,
-53263L,53264L,53265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,
-53273L,53274L,53275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,
-53283L,53284L,53285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,
-53293L,53294L,53295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,
-53303L,53304L,53305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,
-53313L,53314L,53315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,
-53323L,53324L,53325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,
-53333L,53334L,53335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,
-53343L,53344L,53345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,
-53353L,53354L,53355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,
-53363L,53364L,53365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,
-53373L,53374L,53375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,
-53383L,53384L,53385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,
-53393L,53394L,53395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,
-53403L,53404L,53405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,
-53413L,53414L,53415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,
-53423L,53424L,53425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,
-53433L,53434L,53435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,
-53443L,53444L,53445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,
-53453L,53454L,53455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,
-53463L,53464L,53465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,
-53473L,53474L,53475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,
-53483L,53484L,53485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,
-53493L,53494L,53495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,
-53503L,53504L,53505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,
-53513L,53514L,53515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,
-53523L,53524L,53525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,
-53533L,53534L,53535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,
-53543L,53544L,53545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,
-53553L,53554L,53555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,
-53563L,53564L,53565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,
-53573L,53574L,53575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,
-53583L,53584L,53585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,
-53593L,53594L,53595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,
-53603L,53604L,53605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,
-53613L,53614L,53615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,
-53623L,53624L,53625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,
-53633L,53634L,53635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,
-53643L,53644L,53645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,
-53653L,53654L,53655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,
-53663L,53664L,53665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,
-53673L,53674L,53675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,
-53683L,53684L,53685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,
-53693L,53694L,53695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,
-53703L,53704L,53705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,
-53713L,53714L,53715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,
-53723L,53724L,53725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,
-53733L,53734L,53735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,
-53743L,53744L,53745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,
-53753L,53754L,53755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,
-53763L,53764L,53765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,
-53773L,53774L,53775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,
-53783L,53784L,53785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,
-53793L,53794L,53795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,
-53803L,53804L,53805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,
-53813L,53814L,53815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,
-53823L,53824L,53825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,
-53833L,53834L,53835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,
-53843L,53844L,53845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,
-53853L,53854L,53855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,
-53863L,53864L,53865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,
-53873L,53874L,53875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,
-53883L,53884L,53885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,
-53893L,53894L,53895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,
-53903L,53904L,53905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,
-53913L,53914L,53915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,
-53923L,53924L,53925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,
-53933L,53934L,53935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,
-53943L,53944L,53945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,
-53953L,53954L,53955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,
-53963L,53964L,53965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,
-53973L,53974L,53975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,
-53983L,53984L,53985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,
-53993L,53994L,53995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,
-54003L,54004L,54005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,
-54013L,54014L,54015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,
-54023L,54024L,54025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,
-54033L,54034L,54035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,
-54043L,54044L,54045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,
-54053L,54054L,54055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,
-54063L,54064L,54065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,
-54073L,54074L,54075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,
-54083L,54084L,54085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,
-54093L,54094L,54095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,
-54103L,54104L,54105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,
-54113L,54114L,54115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,
-54123L,54124L,54125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,
-54133L,54134L,54135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,
-54143L,54144L,54145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,
-54153L,54154L,54155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,
-54163L,54164L,54165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,
-54173L,54174L,54175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,
-54183L,54184L,54185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,
-54193L,54194L,54195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,
-54203L,54204L,54205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,
-54213L,54214L,54215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,
-54223L,54224L,54225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,
-54233L,54234L,54235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,
-54243L,54244L,54245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,
-54253L,54254L,54255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,
-54263L,54264L,54265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,
-54273L,54274L,54275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,
-54283L,54284L,54285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,
-54293L,54294L,54295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,
-54303L,54304L,54305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,
-54313L,54314L,54315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,
-54323L,54324L,54325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,
-54333L,54334L,54335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,
-54343L,54344L,54345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,
-54353L,54354L,54355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,
-54363L,54364L,54365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,
-54373L,54374L,54375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,
-54383L,54384L,54385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,
-54393L,54394L,54395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,
-54403L,54404L,54405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,
-54413L,54414L,54415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,
-54423L,54424L,54425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,
-54433L,54434L,54435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,
-54443L,54444L,54445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,
-54453L,54454L,54455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,
-54463L,54464L,54465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,
-54473L,54474L,54475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,
-54483L,54484L,54485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,
-54493L,54494L,54495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,
-54503L,54504L,54505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,
-54513L,54514L,54515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,
-54523L,54524L,54525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,
-54533L,54534L,54535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,
-54543L,54544L,54545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,
-54553L,54554L,54555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,
-54563L,54564L,54565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,
-54573L,54574L,54575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,
-54583L,54584L,54585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,
-54593L,54594L,54595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,
-54603L,54604L,54605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,
-54613L,54614L,54615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,
-54623L,54624L,54625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,
-54633L,54634L,54635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,
-54643L,54644L,54645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,
-54653L,54654L,54655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,
-54663L,54664L,54665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,
-54673L,54674L,54675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,
-54683L,54684L,54685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,
-54693L,54694L,54695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,
-54703L,54704L,54705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,
-54713L,54714L,54715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,
-54723L,54724L,54725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,
-54733L,54734L,54735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,
-54743L,54744L,54745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,
-54753L,54754L,54755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,
-54763L,54764L,54765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,
-54773L,54774L,54775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,
-54783L,54784L,54785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,
-54793L,54794L,54795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,
-54803L,54804L,54805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,
-54813L,54814L,54815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,
-54823L,54824L,54825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,
-54833L,54834L,54835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,
-54843L,54844L,54845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,
-54853L,54854L,54855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,
-54863L,54864L,54865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,
-54873L,54874L,54875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,
-54883L,54884L,54885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,
-54893L,54894L,54895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,
-54903L,54904L,54905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,
-54913L,54914L,54915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,
-54923L,54924L,54925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,
-54933L,54934L,54935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,
-54943L,54944L,54945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,
-54953L,54954L,54955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,
-54963L,54964L,54965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,
-54973L,54974L,54975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,
-54983L,54984L,54985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,
-54993L,54994L,54995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,
-55003L,55004L,55005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,
-55013L,55014L,55015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,
-55023L,55024L,55025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,
-55033L,55034L,55035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,
-55043L,55044L,55045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,
-55053L,55054L,55055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,
-55063L,55064L,55065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,
-55073L,55074L,55075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,
-55083L,55084L,55085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,
-55093L,55094L,55095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,
-55103L,55104L,55105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,
-55113L,55114L,55115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,
-55123L,55124L,55125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,
-55133L,55134L,55135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,
-55143L,55144L,55145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,
-55153L,55154L,55155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,
-55163L,55164L,55165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,
-55173L,55174L,55175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,
-55183L,55184L,55185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,
-55193L,55194L,55195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,
-55203L,55204L,55205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,
-55213L,55214L,55215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,
-55223L,55224L,55225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,
-55233L,55234L,55235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,
-55243L,55244L,55245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,
-55253L,55254L,55255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,
-55263L,55264L,55265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,
-55273L,55274L,55275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,
-55283L,55284L,55285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,
-55293L,55294L,55295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,
-55303L,55304L,55305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,
-55313L,55314L,55315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,
-55323L,55324L,55325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,
-55333L,55334L,55335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,
-55343L,55344L,55345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,
-55353L,55354L,55355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,
-55363L,55364L,55365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,
-55373L,55374L,55375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,
-55383L,55384L,55385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,
-55393L,55394L,55395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,
-55403L,55404L,55405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,
-55413L,55414L,55415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,
-55423L,55424L,55425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,
-55433L,55434L,55435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,
-55443L,55444L,55445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,
-55453L,55454L,55455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,
-55463L,55464L,55465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,
-55473L,55474L,55475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,
-55483L,55484L,55485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,
-55493L,55494L,55495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,
-55503L,55504L,55505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,
-55513L,55514L,55515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,
-55523L,55524L,55525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,
-55533L,55534L,55535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,
-55543L,55544L,55545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,
-55553L,55554L,55555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,
-55563L,55564L,55565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,
-55573L,55574L,55575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,
-55583L,55584L,55585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,
-55593L,55594L,55595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,
-55603L,55604L,55605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,
-55613L,55614L,55615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,
-55623L,55624L,55625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,
-55633L,55634L,55635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,
-55643L,55644L,55645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,
-55653L,55654L,55655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,
-55663L,55664L,55665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,
-55673L,55674L,55675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,
-55683L,55684L,55685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,
-55693L,55694L,55695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,
-55703L,55704L,55705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,
-55713L,55714L,55715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,
-55723L,55724L,55725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,
-55733L,55734L,55735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,
-55743L,55744L,55745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,
-55753L,55754L,55755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,
-55763L,55764L,55765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,
-55773L,55774L,55775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,
-55783L,55784L,55785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,
-55793L,55794L,55795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,
-55803L,55804L,55805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,
-55813L,55814L,55815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,
-55823L,55824L,55825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,
-55833L,55834L,55835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,
-55843L,55844L,55845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,
-55853L,55854L,55855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,
-55863L,55864L,55865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,
-55873L,55874L,55875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,
-55883L,55884L,55885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,
-55893L,55894L,55895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,
-55903L,55904L,55905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,
-55913L,55914L,55915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,
-55923L,55924L,55925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,
-55933L,55934L,55935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,
-55943L,55944L,55945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,
-55953L,55954L,55955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,
-55963L,55964L,55965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,
-55973L,55974L,55975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,
-55983L,55984L,55985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,
-55993L,55994L,55995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,
-56003L,56004L,56005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,
-56013L,56014L,56015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,
-56023L,56024L,56025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,
-56033L,56034L,56035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,
-56043L,56044L,56045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,
-56053L,56054L,56055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,
-56063L,56064L,56065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,
-56073L,56074L,56075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,
-56083L,56084L,56085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,
-56093L,56094L,56095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,
-56103L,56104L,56105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,
-56113L,56114L,56115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,
-56123L,56124L,56125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,
-56133L,56134L,56135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,
-56143L,56144L,56145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,
-56153L,56154L,56155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,
-56163L,56164L,56165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,
-56173L,56174L,56175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,
-56183L,56184L,56185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,
-56193L,56194L,56195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,
-56203L,56204L,56205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,
-56213L,56214L,56215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,
-56223L,56224L,56225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,
-56233L,56234L,56235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,
-56243L,56244L,56245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,
-56253L,56254L,56255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,
-56263L,56264L,56265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,
-56273L,56274L,56275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,
-56283L,56284L,56285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,
-56293L,56294L,56295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,
-56303L,56304L,56305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,
-56313L,56314L,56315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,
-56323L,56324L,56325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,
-56333L,56334L,56335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,
-56343L,56344L,56345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,
-56353L,56354L,56355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,
-56363L,56364L,56365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,
-56373L,56374L,56375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,
-56383L,56384L,56385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,
-56393L,56394L,56395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,
-56403L,56404L,56405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,
-56413L,56414L,56415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,
-56423L,56424L,56425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,
-56433L,56434L,56435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,
-56443L,56444L,56445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,
-56453L,56454L,56455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,
-56463L,56464L,56465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,
-56473L,56474L,56475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,
-56483L,56484L,56485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,
-56493L,56494L,56495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,
-56503L,56504L,56505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,
-56513L,56514L,56515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,
-56523L,56524L,56525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,
-56533L,56534L,56535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,
-56543L,56544L,56545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,
-56553L,56554L,56555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,
-56563L,56564L,56565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,
-56573L,56574L,56575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,
-56583L,56584L,56585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,
-56593L,56594L,56595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,
-56603L,56604L,56605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,
-56613L,56614L,56615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,
-56623L,56624L,56625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,
-56633L,56634L,56635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,
-56643L,56644L,56645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,
-56653L,56654L,56655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,
-56663L,56664L,56665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,
-56673L,56674L,56675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,
-56683L,56684L,56685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,
-56693L,56694L,56695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,
-56703L,56704L,56705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,
-56713L,56714L,56715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,
-56723L,56724L,56725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,
-56733L,56734L,56735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,
-56743L,56744L,56745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,
-56753L,56754L,56755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,
-56763L,56764L,56765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,
-56773L,56774L,56775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,
-56783L,56784L,56785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,
-56793L,56794L,56795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,
-56803L,56804L,56805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,
-56813L,56814L,56815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,
-56823L,56824L,56825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,
-56833L,56834L,56835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,
-56843L,56844L,56845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,
-56853L,56854L,56855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,
-56863L,56864L,56865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,
-56873L,56874L,56875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,
-56883L,56884L,56885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,
-56893L,56894L,56895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,
-56903L,56904L,56905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,
-56913L,56914L,56915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,
-56923L,56924L,56925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,
-56933L,56934L,56935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,
-56943L,56944L,56945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,
-56953L,56954L,56955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,
-56963L,56964L,56965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,
-56973L,56974L,56975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,
-56983L,56984L,56985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,
-56993L,56994L,56995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,
-57003L,57004L,57005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,
-57013L,57014L,57015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,
-57023L,57024L,57025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,
-57033L,57034L,57035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,
-57043L,57044L,57045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,
-57053L,57054L,57055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,
-57063L,57064L,57065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,
-57073L,57074L,57075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,
-57083L,57084L,57085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,
-57093L,57094L,57095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,
-57103L,57104L,57105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,
-57113L,57114L,57115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,
-57123L,57124L,57125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,
-57133L,57134L,57135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,
-57143L,57144L,57145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,
-57153L,57154L,57155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,
-57163L,57164L,57165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,
-57173L,57174L,57175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,
-57183L,57184L,57185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,
-57193L,57194L,57195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,
-57203L,57204L,57205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,
-57213L,57214L,57215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,
-57223L,57224L,57225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,
-57233L,57234L,57235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,
-57243L,57244L,57245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,
-57253L,57254L,57255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,
-57263L,57264L,57265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,
-57273L,57274L,57275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,
-57283L,57284L,57285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,
-57293L,57294L,57295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,
-57303L,57304L,57305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,
-57313L,57314L,57315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,
-57323L,57324L,57325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,
-57333L,57334L,57335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,
-57343L,57344L,57345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,
-57353L,57354L,57355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,
-57363L,57364L,57365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,
-57373L,57374L,57375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,
-57383L,57384L,57385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,
-57393L,57394L,57395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,
-57403L,57404L,57405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,
-57413L,57414L,57415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,
-57423L,57424L,57425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,
-57433L,57434L,57435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,
-57443L,57444L,57445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,
-57453L,57454L,57455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,
-57463L,57464L,57465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,
-57473L,57474L,57475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,
-57483L,57484L,57485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,
-57493L,57494L,57495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,
-57503L,57504L,57505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,
-57513L,57514L,57515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,
-57523L,57524L,57525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,
-57533L,57534L,57535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,
-57543L,57544L,57545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,
-57553L,57554L,57555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,
-57563L,57564L,57565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,
-57573L,57574L,57575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,
-57583L,57584L,57585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,
-57593L,57594L,57595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,
-57603L,57604L,57605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,
-57613L,57614L,57615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,
-57623L,57624L,57625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,
-57633L,57634L,57635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,
-57643L,57644L,57645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,
-57653L,57654L,57655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,
-57663L,57664L,57665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,
-57673L,57674L,57675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,
-57683L,57684L,57685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,
-57693L,57694L,57695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,
-57703L,57704L,57705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,
-57713L,57714L,57715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,
-57723L,57724L,57725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,
-57733L,57734L,57735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,
-57743L,57744L,57745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,
-57753L,57754L,57755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,
-57763L,57764L,57765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,
-57773L,57774L,57775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,
-57783L,57784L,57785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,
-57793L,57794L,57795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,
-57803L,57804L,57805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,
-57813L,57814L,57815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,
-57823L,57824L,57825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,
-57833L,57834L,57835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,
-57843L,57844L,57845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,
-57853L,57854L,57855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,
-57863L,57864L,57865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,
-57873L,57874L,57875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,
-57883L,57884L,57885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,
-57893L,57894L,57895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,
-57903L,57904L,57905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,
-57913L,57914L,57915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,
-57923L,57924L,57925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,
-57933L,57934L,57935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,
-57943L,57944L,57945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,
-57953L,57954L,57955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,
-57963L,57964L,57965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,
-57973L,57974L,57975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,
-57983L,57984L,57985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,
-57993L,57994L,57995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,
-58003L,58004L,58005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,
-58013L,58014L,58015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,
-58023L,58024L,58025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,
-58033L,58034L,58035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,
-58043L,58044L,58045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,
-58053L,58054L,58055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,
-58063L,58064L,58065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,
-58073L,58074L,58075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,
-58083L,58084L,58085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,
-58093L,58094L,58095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,
-58103L,58104L,58105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,
-58113L,58114L,58115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,
-58123L,58124L,58125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,
-58133L,58134L,58135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,
-58143L,58144L,58145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,
-58153L,58154L,58155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,
-58163L,58164L,58165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,
-58173L,58174L,58175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,
-58183L,58184L,58185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,
-58193L,58194L,58195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,
-58203L,58204L,58205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,
-58213L,58214L,58215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,
-58223L,58224L,58225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,
-58233L,58234L,58235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,
-58243L,58244L,58245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,
-58253L,58254L,58255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,
-58263L,58264L,58265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,
-58273L,58274L,58275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,
-58283L,58284L,58285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,
-58293L,58294L,58295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,
-58303L,58304L,58305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,
-58313L,58314L,58315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,
-58323L,58324L,58325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,
-58333L,58334L,58335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,
-58343L,58344L,58345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,
-58353L,58354L,58355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,
-58363L,58364L,58365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,
-58373L,58374L,58375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,
-58383L,58384L,58385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,
-58393L,58394L,58395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,
-58403L,58404L,58405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,
-58413L,58414L,58415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,
-58423L,58424L,58425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,
-58433L,58434L,58435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,
-58443L,58444L,58445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,
-58453L,58454L,58455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,
-58463L,58464L,58465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,
-58473L,58474L,58475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,
-58483L,58484L,58485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,
-58493L,58494L,58495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,
-58503L,58504L,58505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,
-58513L,58514L,58515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,
-58523L,58524L,58525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,
-58533L,58534L,58535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,
-58543L,58544L,58545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,
-58553L,58554L,58555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,
-58563L,58564L,58565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,
-58573L,58574L,58575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,
-58583L,58584L,58585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,
-58593L,58594L,58595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,
-58603L,58604L,58605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,
-58613L,58614L,58615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,
-58623L,58624L,58625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,
-58633L,58634L,58635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,
-58643L,58644L,58645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,
-58653L,58654L,58655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,
-58663L,58664L,58665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,
-58673L,58674L,58675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,
-58683L,58684L,58685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,
-58693L,58694L,58695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,
-58703L,58704L,58705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,
-58713L,58714L,58715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,
-58723L,58724L,58725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,
-58733L,58734L,58735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,
-58743L,58744L,58745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,
-58753L,58754L,58755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,
-58763L,58764L,58765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,
-58773L,58774L,58775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,
-58783L,58784L,58785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,
-58793L,58794L,58795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,
-58803L,58804L,58805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,
-58813L,58814L,58815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,
-58823L,58824L,58825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,
-58833L,58834L,58835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,
-58843L,58844L,58845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,
-58853L,58854L,58855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,
-58863L,58864L,58865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,
-58873L,58874L,58875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,
-58883L,58884L,58885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,
-58893L,58894L,58895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,
-58903L,58904L,58905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,
-58913L,58914L,58915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,
-58923L,58924L,58925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,
-58933L,58934L,58935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,
-58943L,58944L,58945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,
-58953L,58954L,58955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,
-58963L,58964L,58965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,
-58973L,58974L,58975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,
-58983L,58984L,58985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,
-58993L,58994L,58995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,
-59003L,59004L,59005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,
-59013L,59014L,59015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,
-59023L,59024L,59025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,
-59033L,59034L,59035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,
-59043L,59044L,59045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,
-59053L,59054L,59055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,
-59063L,59064L,59065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,
-59073L,59074L,59075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,
-59083L,59084L,59085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,
-59093L,59094L,59095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,
-59103L,59104L,59105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,
-59113L,59114L,59115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,
-59123L,59124L,59125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,
-59133L,59134L,59135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,
-59143L,59144L,59145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,
-59153L,59154L,59155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,
-59163L,59164L,59165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,
-59173L,59174L,59175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,
-59183L,59184L,59185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,
-59193L,59194L,59195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,
-59203L,59204L,59205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,
-59213L,59214L,59215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,
-59223L,59224L,59225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,
-59233L,59234L,59235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,
-59243L,59244L,59245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,
-59253L,59254L,59255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,
-59263L,59264L,59265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,
-59273L,59274L,59275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,
-59283L,59284L,59285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,
-59293L,59294L,59295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,
-59303L,59304L,59305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,
-59313L,59314L,59315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,
-59323L,59324L,59325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,
-59333L,59334L,59335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,
-59343L,59344L,59345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,
-59353L,59354L,59355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,
-59363L,59364L,59365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,
-59373L,59374L,59375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,
-59383L,59384L,59385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,
-59393L,59394L,59395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,
-59403L,59404L,59405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,
-59413L,59414L,59415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,
-59423L,59424L,59425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,
-59433L,59434L,59435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,
-59443L,59444L,59445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,
-59453L,59454L,59455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,
-59463L,59464L,59465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,
-59473L,59474L,59475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,
-59483L,59484L,59485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,
-59493L,59494L,59495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,
-59503L,59504L,59505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,
-59513L,59514L,59515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,
-59523L,59524L,59525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,
-59533L,59534L,59535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,
-59543L,59544L,59545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,
-59553L,59554L,59555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,
-59563L,59564L,59565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,
-59573L,59574L,59575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,
-59583L,59584L,59585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,
-59593L,59594L,59595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,
-59603L,59604L,59605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,
-59613L,59614L,59615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,
-59623L,59624L,59625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,
-59633L,59634L,59635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,
-59643L,59644L,59645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,
-59653L,59654L,59655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,
-59663L,59664L,59665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,
-59673L,59674L,59675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,
-59683L,59684L,59685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,
-59693L,59694L,59695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,
-59703L,59704L,59705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,
-59713L,59714L,59715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,
-59723L,59724L,59725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,
-59733L,59734L,59735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,
-59743L,59744L,59745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,
-59753L,59754L,59755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,
-59763L,59764L,59765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,
-59773L,59774L,59775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,
-59783L,59784L,59785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,
-59793L,59794L,59795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,
-59803L,59804L,59805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,
-59813L,59814L,59815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,
-59823L,59824L,59825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,
-59833L,59834L,59835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,
-59843L,59844L,59845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,
-59853L,59854L,59855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,
-59863L,59864L,59865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,
-59873L,59874L,59875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,
-59883L,59884L,59885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,
-59893L,59894L,59895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,
-59903L,59904L,59905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,
-59913L,59914L,59915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,
-59923L,59924L,59925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,
-59933L,59934L,59935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,
-59943L,59944L,59945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,
-59953L,59954L,59955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,
-59963L,59964L,59965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,
-59973L,59974L,59975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,
-59983L,59984L,59985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,
-59993L,59994L,59995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,
-60003L,60004L,60005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,
-60013L,60014L,60015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,
-60023L,60024L,60025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,
-60033L,60034L,60035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,
-60043L,60044L,60045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,
-60053L,60054L,60055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,
-60063L,60064L,60065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,
-60073L,60074L,60075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,
-60083L,60084L,60085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,
-60093L,60094L,60095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,
-60103L,60104L,60105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,
-60113L,60114L,60115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,
-60123L,60124L,60125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,
-60133L,60134L,60135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,
-60143L,60144L,60145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,
-60153L,60154L,60155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,
-60163L,60164L,60165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,
-60173L,60174L,60175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,
-60183L,60184L,60185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,
-60193L,60194L,60195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,
-60203L,60204L,60205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,
-60213L,60214L,60215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,
-60223L,60224L,60225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,
-60233L,60234L,60235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,
-60243L,60244L,60245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,
-60253L,60254L,60255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,
-60263L,60264L,60265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,
-60273L,60274L,60275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,
-60283L,60284L,60285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,
-60293L,60294L,60295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,
-60303L,60304L,60305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,
-60313L,60314L,60315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,
-60323L,60324L,60325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,
-60333L,60334L,60335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,
-60343L,60344L,60345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,
-60353L,60354L,60355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,
-60363L,60364L,60365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,
-60373L,60374L,60375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,
-60383L,60384L,60385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,
-60393L,60394L,60395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,
-60403L,60404L,60405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,
-60413L,60414L,60415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,
-60423L,60424L,60425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,
-60433L,60434L,60435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,
-60443L,60444L,60445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,
-60453L,60454L,60455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,
-60463L,60464L,60465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,
-60473L,60474L,60475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,
-60483L,60484L,60485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,
-60493L,60494L,60495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,
-60503L,60504L,60505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,
-60513L,60514L,60515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,
-60523L,60524L,60525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,
-60533L,60534L,60535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,
-60543L,60544L,60545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,
-60553L,60554L,60555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,
-60563L,60564L,60565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,
-60573L,60574L,60575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,
-60583L,60584L,60585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,
-60593L,60594L,60595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,
-60603L,60604L,60605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,
-60613L,60614L,60615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,
-60623L,60624L,60625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,
-60633L,60634L,60635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,
-60643L,60644L,60645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,
-60653L,60654L,60655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,
-60663L,60664L,60665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,
-60673L,60674L,60675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,
-60683L,60684L,60685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,
-60693L,60694L,60695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,
-60703L,60704L,60705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,
-60713L,60714L,60715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,
-60723L,60724L,60725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,
-60733L,60734L,60735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,
-60743L,60744L,60745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,
-60753L,60754L,60755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,
-60763L,60764L,60765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,
-60773L,60774L,60775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,
-60783L,60784L,60785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,
-60793L,60794L,60795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,
-60803L,60804L,60805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,
-60813L,60814L,60815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,
-60823L,60824L,60825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,
-60833L,60834L,60835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,
-60843L,60844L,60845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,
-60853L,60854L,60855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,
-60863L,60864L,60865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,
-60873L,60874L,60875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,
-60883L,60884L,60885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,
-60893L,60894L,60895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,
-60903L,60904L,60905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,
-60913L,60914L,60915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,
-60923L,60924L,60925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,
-60933L,60934L,60935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,
-60943L,60944L,60945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,
-60953L,60954L,60955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,
-60963L,60964L,60965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,
-60973L,60974L,60975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,
-60983L,60984L,60985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,
-60993L,60994L,60995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,
-61003L,61004L,61005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,
-61013L,61014L,61015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,
-61023L,61024L,61025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,
-61033L,61034L,61035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,
-61043L,61044L,61045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,
-61053L,61054L,61055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,
-61063L,61064L,61065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,
-61073L,61074L,61075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,
-61083L,61084L,61085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,
-61093L,61094L,61095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,
-61103L,61104L,61105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,
-61113L,61114L,61115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,
-61123L,61124L,61125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,
-61133L,61134L,61135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,
-61143L,61144L,61145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,
-61153L,61154L,61155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,
-61163L,61164L,61165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,
-61173L,61174L,61175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,
-61183L,61184L,61185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,
-61193L,61194L,61195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,
-61203L,61204L,61205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,
-61213L,61214L,61215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,
-61223L,61224L,61225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,
-61233L,61234L,61235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,
-61243L,61244L,61245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,
-61253L,61254L,61255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,
-61263L,61264L,61265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,
-61273L,61274L,61275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,
-61283L,61284L,61285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,
-61293L,61294L,61295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,
-61303L,61304L,61305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,
-61313L,61314L,61315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,
-61323L,61324L,61325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,
-61333L,61334L,61335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,
-61343L,61344L,61345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,
-61353L,61354L,61355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,
-61363L,61364L,61365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,
-61373L,61374L,61375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,
-61383L,61384L,61385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,
-61393L,61394L,61395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,
-61403L,61404L,61405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,
-61413L,61414L,61415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,
-61423L,61424L,61425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,
-61433L,61434L,61435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,
-61443L,61444L,61445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,
-61453L,61454L,61455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,
-61463L,61464L,61465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,
-61473L,61474L,61475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,
-61483L,61484L,61485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,
-61493L,61494L,61495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,
-61503L,61504L,61505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,
-61513L,61514L,61515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,
-61523L,61524L,61525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,
-61533L,61534L,61535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,
-61543L,61544L,61545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,
-61553L,61554L,61555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,
-61563L,61564L,61565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,
-61573L,61574L,61575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,
-61583L,61584L,61585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,
-61593L,61594L,61595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,
-61603L,61604L,61605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,
-61613L,61614L,61615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,
-61623L,61624L,61625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,
-61633L,61634L,61635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,
-61643L,61644L,61645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,
-61653L,61654L,61655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,
-61663L,61664L,61665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,
-61673L,61674L,61675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,
-61683L,61684L,61685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,
-61693L,61694L,61695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,
-61703L,61704L,61705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,
-61713L,61714L,61715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,
-61723L,61724L,61725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,
-61733L,61734L,61735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,
-61743L,61744L,61745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,
-61753L,61754L,61755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,
-61763L,61764L,61765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,
-61773L,61774L,61775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,
-61783L,61784L,61785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,
-61793L,61794L,61795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,
-61803L,61804L,61805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,
-61813L,61814L,61815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,
-61823L,61824L,61825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,
-61833L,61834L,61835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,
-61843L,61844L,61845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,
-61853L,61854L,61855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,
-61863L,61864L,61865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,
-61873L,61874L,61875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,
-61883L,61884L,61885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,
-61893L,61894L,61895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,
-61903L,61904L,61905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,
-61913L,61914L,61915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,
-61923L,61924L,61925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,
-61933L,61934L,61935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,
-61943L,61944L,61945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,
-61953L,61954L,61955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,
-61963L,61964L,61965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,
-61973L,61974L,61975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,
-61983L,61984L,61985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,
-61993L,61994L,61995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,
-62003L,62004L,62005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,
-62013L,62014L,62015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,
-62023L,62024L,62025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,
-62033L,62034L,62035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,
-62043L,62044L,62045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,
-62053L,62054L,62055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,
-62063L,62064L,62065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,
-62073L,62074L,62075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,
-62083L,62084L,62085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,
-62093L,62094L,62095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,
-62103L,62104L,62105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,
-62113L,62114L,62115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,
-62123L,62124L,62125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,
-62133L,62134L,62135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,
-62143L,62144L,62145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,
-62153L,62154L,62155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,
-62163L,62164L,62165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,
-62173L,62174L,62175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,
-62183L,62184L,62185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,
-62193L,62194L,62195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,
-62203L,62204L,62205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,
-62213L,62214L,62215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,
-62223L,62224L,62225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,
-62233L,62234L,62235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,
-62243L,62244L,62245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,
-62253L,62254L,62255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,
-62263L,62264L,62265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,
-62273L,62274L,62275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,
-62283L,62284L,62285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,
-62293L,62294L,62295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,
-62303L,62304L,62305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,
-62313L,62314L,62315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,
-62323L,62324L,62325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,
-62333L,62334L,62335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,
-62343L,62344L,62345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,
-62353L,62354L,62355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,
-62363L,62364L,62365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,
-62373L,62374L,62375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,
-62383L,62384L,62385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,
-62393L,62394L,62395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,
-62403L,62404L,62405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,
-62413L,62414L,62415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,
-62423L,62424L,62425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,
-62433L,62434L,62435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,
-62443L,62444L,62445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,
-62453L,62454L,62455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,
-62463L,62464L,62465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,
-62473L,62474L,62475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,
-62483L,62484L,62485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,
-62493L,62494L,62495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,
-62503L,62504L,62505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,
-62513L,62514L,62515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,
-62523L,62524L,62525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,
-62533L,62534L,62535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,
-62543L,62544L,62545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,
-62553L,62554L,62555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,
-62563L,62564L,62565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,
-62573L,62574L,62575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,
-62583L,62584L,62585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,
-62593L,62594L,62595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,
-62603L,62604L,62605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,
-62613L,62614L,62615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,
-62623L,62624L,62625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,
-62633L,62634L,62635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,
-62643L,62644L,62645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,
-62653L,62654L,62655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,
-62663L,62664L,62665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,
-62673L,62674L,62675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,
-62683L,62684L,62685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,
-62693L,62694L,62695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,
-62703L,62704L,62705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,
-62713L,62714L,62715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,
-62723L,62724L,62725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,
-62733L,62734L,62735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,
-62743L,62744L,62745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,
-62753L,62754L,62755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,
-62763L,62764L,62765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,
-62773L,62774L,62775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,
-62783L,62784L,62785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,
-62793L,62794L,62795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,
-62803L,62804L,62805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,
-62813L,62814L,62815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,
-62823L,62824L,62825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,
-62833L,62834L,62835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,
-62843L,62844L,62845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,
-62853L,62854L,62855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,
-62863L,62864L,62865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,
-62873L,62874L,62875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,
-62883L,62884L,62885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,
-62893L,62894L,62895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,
-62903L,62904L,62905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,
-62913L,62914L,62915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,
-62923L,62924L,62925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,
-62933L,62934L,62935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,
-62943L,62944L,62945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,
-62953L,62954L,62955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,
-62963L,62964L,62965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,
-62973L,62974L,62975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,
-62983L,62984L,62985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,
-62993L,62994L,62995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,
-63003L,63004L,63005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,
-63013L,63014L,63015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,
-63023L,63024L,63025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,
-63033L,63034L,63035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,
-63043L,63044L,63045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,
-63053L,63054L,63055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,
-63063L,63064L,63065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,
-63073L,63074L,63075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,
-63083L,63084L,63085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,
-63093L,63094L,63095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,
-63103L,63104L,63105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,
-63113L,63114L,63115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,
-63123L,63124L,63125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,
-63133L,63134L,63135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,
-63143L,63144L,63145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,
-63153L,63154L,63155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,
-63163L,63164L,63165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,
-63173L,63174L,63175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,
-63183L,63184L,63185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,
-63193L,63194L,63195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,
-63203L,63204L,63205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,
-63213L,63214L,63215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,
-63223L,63224L,63225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,
-63233L,63234L,63235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,
-63243L,63244L,63245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,
-63253L,63254L,63255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,
-63263L,63264L,63265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,
-63273L,63274L,63275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,
-63283L,63284L,63285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,
-63293L,63294L,63295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,
-63303L,63304L,63305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,
-63313L,63314L,63315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,
-63323L,63324L,63325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,
-63333L,63334L,63335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,
-63343L,63344L,63345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,
-63353L,63354L,63355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,
-63363L,63364L,63365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,
-63373L,63374L,63375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,
-63383L,63384L,63385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,
-63393L,63394L,63395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,
-63403L,63404L,63405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,
-63413L,63414L,63415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,
-63423L,63424L,63425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,
-63433L,63434L,63435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,
-63443L,63444L,63445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,
-63453L,63454L,63455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,
-63463L,63464L,63465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,
-63473L,63474L,63475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,
-63483L,63484L,63485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,
-63493L,63494L,63495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,
-63503L,63504L,63505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,
-63513L,63514L,63515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,
-63523L,63524L,63525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,
-63533L,63534L,63535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,
-63543L,63544L,63545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,
-63553L,63554L,63555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,
-63563L,63564L,63565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,
-63573L,63574L,63575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,
-63583L,63584L,63585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,
-63593L,63594L,63595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,
-63603L,63604L,63605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,
-63613L,63614L,63615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,
-63623L,63624L,63625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,
-63633L,63634L,63635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,
-63643L,63644L,63645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,
-63653L,63654L,63655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,
-63663L,63664L,63665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,
-63673L,63674L,63675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,
-63683L,63684L,63685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,
-63693L,63694L,63695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,
-63703L,63704L,63705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,
-63713L,63714L,63715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,
-63723L,63724L,63725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,
-63733L,63734L,63735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,
-63743L,63744L,63745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,
-63753L,63754L,63755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,
-63763L,63764L,63765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,
-63773L,63774L,63775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,
-63783L,63784L,63785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,
-63793L,63794L,63795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,
-63803L,63804L,63805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,
-63813L,63814L,63815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,
-63823L,63824L,63825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,
-63833L,63834L,63835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,
-63843L,63844L,63845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,
-63853L,63854L,63855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,
-63863L,63864L,63865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,
-63873L,63874L,63875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,
-63883L,63884L,63885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,
-63893L,63894L,63895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,
-63903L,63904L,63905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,
-63913L,63914L,63915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,
-63923L,63924L,63925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,
-63933L,63934L,63935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,
-63943L,63944L,63945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,
-63953L,63954L,63955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,
-63963L,63964L,63965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,
-63973L,63974L,63975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,
-63983L,63984L,63985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,
-63993L,63994L,63995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,
-64003L,64004L,64005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,
-64013L,64014L,64015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,
-64023L,64024L,64025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,
-64033L,64034L,64035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,
-64043L,64044L,64045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,
-64053L,64054L,64055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,
-64063L,64064L,64065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,
-64073L,64074L,64075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,
-64083L,64084L,64085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,
-64093L,64094L,64095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,
-64103L,64104L,64105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,
-64113L,64114L,64115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,
-64123L,64124L,64125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,
-64133L,64134L,64135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,
-64143L,64144L,64145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,
-64153L,64154L,64155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,
-64163L,64164L,64165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,
-64173L,64174L,64175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,
-64183L,64184L,64185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,
-64193L,64194L,64195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,
-64203L,64204L,64205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,
-64213L,64214L,64215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,
-64223L,64224L,64225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,
-64233L,64234L,64235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,
-64243L,64244L,64245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,
-64253L,64254L,64255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,
-64263L,64264L,64265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,
-64273L,64274L,64275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,
-64283L,64284L,64285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,
-64293L,64294L,64295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,
-64303L,64304L,64305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,
-64313L,64314L,64315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,
-64323L,64324L,64325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,
-64333L,64334L,64335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,
-64343L,64344L,64345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,
-64353L,64354L,64355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,
-64363L,64364L,64365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,
-64373L,64374L,64375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,
-64383L,64384L,64385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,
-64393L,64394L,64395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,
-64403L,64404L,64405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,
-64413L,64414L,64415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,
-64423L,64424L,64425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,
-64433L,64434L,64435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,
-64443L,64444L,64445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,
-64453L,64454L,64455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,
-64463L,64464L,64465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,
-64473L,64474L,64475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,
-64483L,64484L,64485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,
-64493L,64494L,64495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,
-64503L,64504L,64505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,
-64513L,64514L,64515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,
-64523L,64524L,64525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,
-64533L,64534L,64535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,
-64543L,64544L,64545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,
-64553L,64554L,64555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,
-64563L,64564L,64565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,
-64573L,64574L,64575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,
-64583L,64584L,64585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,
-64593L,64594L,64595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,
-64603L,64604L,64605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,
-64613L,64614L,64615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,
-64623L,64624L,64625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,
-64633L,64634L,64635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,
-64643L,64644L,64645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,
-64653L,64654L,64655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,
-64663L,64664L,64665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,
-64673L,64674L,64675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,
-64683L,64684L,64685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,
-64693L,64694L,64695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,
-64703L,64704L,64705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,
-64713L,64714L,64715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,
-64723L,64724L,64725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,
-64733L,64734L,64735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,
-64743L,64744L,64745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,
-64753L,64754L,64755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,
-64763L,64764L,64765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,
-64773L,64774L,64775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,
-64783L,64784L,64785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,
-64793L,64794L,64795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,
-64803L,64804L,64805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,
-64813L,64814L,64815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,
-64823L,64824L,64825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,
-64833L,64834L,64835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,
-64843L,64844L,64845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,
-64853L,64854L,64855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,
-64863L,64864L,64865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,
-64873L,64874L,64875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,
-64883L,64884L,64885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,
-64893L,64894L,64895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,
-64903L,64904L,64905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,
-64913L,64914L,64915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,
-64923L,64924L,64925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,
-64933L,64934L,64935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,
-64943L,64944L,64945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,
-64953L,64954L,64955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,
-64963L,64964L,64965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,
-64973L,64974L,64975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,
-64983L,64984L,64985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,
-64993L,64994L,64995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,
-65003L,65004L,65005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,
-65013L,65014L,65015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,
-65023L,65024L,65025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,
-65033L,65034L,65035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,
-65043L,65044L,65045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,
-65053L,65054L,65055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,
-65063L,65064L,65065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,
-65073L,65074L,65075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,
-65083L,65084L,65085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,
-65093L,65094L,65095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,
-65103L,65104L,65105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,
-65113L,65114L,65115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,
-65123L,65124L,65125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,
-65133L,65134L,65135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,
-65143L,65144L,65145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,
-65153L,65154L,65155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,
-65163L,65164L,65165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,
-65173L,65174L,65175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,
-65183L,65184L,65185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,
-65193L,65194L,65195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,
-65203L,65204L,65205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,
-65213L,65214L,65215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,
-65223L,65224L,65225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,
-65233L,65234L,65235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,
-65243L,65244L,65245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,
-65253L,65254L,65255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,
-65263L,65264L,65265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,
-65273L,65274L,65275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,
-65283L,65284L,65285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,
-65293L,65294L,65295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,
-65303L,65304L,65305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,
-65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,
-65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,
-65333L,65334L,65335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,
-65343L,65344L,65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,
-65321L,65322L,65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,
-65331L,65332L,65333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,
-65373L,65374L,65375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,
-65383L,65384L,65385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,
-65393L,65394L,65395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,
-65403L,65404L,65405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,
-65413L,65414L,65415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,
-65423L,65424L,65425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,
-65433L,65434L,65435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,
-65443L,65444L,65445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,
-65453L,65454L,65455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,
-65463L,65464L,65465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,
-65473L,65474L,65475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,
-65483L,65484L,65485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,
-65493L,65494L,65495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,
-65503L,65504L,65505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,
-65513L,65514L,65515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,
-65523L,65524L,65525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,
-65533L,65534L,65535L,
+11373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403,
+42924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622,
+412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639,
+422,641,642,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656,657,
+439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673,674,
+675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,
+693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,
+711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,
+729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,
+747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,
+765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,
+783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,
+801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,
+819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,
+921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,
+855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,
+873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889,890,
+1021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,
+909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,
+927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906,944,
+913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,
+931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979,980,
+934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996,998,
+998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917,1014,
+1015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,
+1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,
+1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,
+1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,
+1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,
+1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,
+1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,
+1120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,
+1134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,
+1150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,
+1164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,
+1180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,
+1194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,
+1210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,
+1225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,
+1240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,
+1254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,
+1270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,
+1284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,
+1300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,
+1314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328,1329,
+1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,
+1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,
+1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,
+1375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,
+1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,
+1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,
+1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,
+1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,
+1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,
+1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,
+1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,
+1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,
+1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,
+1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,
+1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,
+1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,
+1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,
+1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,
+1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,
+1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,
+1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,
+1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,
+1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,
+1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,
+1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,
+1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,
+1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,
+1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,
+1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,
+1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,
+1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,
+1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,
+1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,
+1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,
+1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,
+1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,
+1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,
+1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,
+1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,
+1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,
+1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,
+1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,
+1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,
+1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,
+1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,
+2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,
+2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,
+2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,
+2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,
+2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,
+2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,
+2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,
+2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,
+2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,
+2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,
+2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,
+2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,
+2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,
+2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,
+2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,
+2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,
+2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,
+2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,
+2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,
+2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,
+2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,
+2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,
+2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,
+2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,
+2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,
+2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,
+2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,
+2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,
+2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,
+2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,
+2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,
+2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,
+2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,
+2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,
+2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,
+2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,
+2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,
+2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,
+2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,
+2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,
+2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,
+2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,
+2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,
+2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,
+2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,
+2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,
+2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,
+2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,
+2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,
+2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,
+2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,
+2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,
+2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,
+2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,
+2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,
+2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,
+2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,
+2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,
+2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,
+2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,
+2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,
+2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,
+2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,
+2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,
+2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,
+2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,
+2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,
+3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,
+3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,
+3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,
+3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,
+3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,
+3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,
+3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,
+3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,
+3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,
+3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,
+3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,
+3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,
+3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,
+3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,
+3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,
+3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,
+3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,
+3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,
+3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,
+3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,
+3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,
+3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,
+3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,
+3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,
+3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,
+3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,
+3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,
+3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,
+3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,
+3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,
+3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,
+3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,
+3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,
+3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,
+3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,
+3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,
+3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,
+3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,
+3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,
+3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,
+3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,
+3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,
+3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,
+3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,
+3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,
+3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,
+3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,
+3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,
+3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,
+3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,
+3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,
+3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,
+3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,
+3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,
+3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,
+3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,
+3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,
+3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,
+3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,
+3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,
+3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,
+3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,
+3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,
+3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,
+3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,
+3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,
+4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,
+4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,
+4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,
+4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,
+4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,
+4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,
+4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,
+4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,
+4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,
+4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,
+4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,
+4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,
+4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,
+4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,
+4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,
+4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,
+4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,
+4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,
+4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,
+4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,
+4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,
+4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,
+4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,
+4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,
+4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,
+4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,
+4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,
+4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,
+4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,
+4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,
+4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,
+4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,
+4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,
+4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,
+4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,
+4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,
+4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,
+4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,
+4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,
+4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,
+4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,
+4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,
+4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,
+4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,
+4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,
+4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,
+4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,
+4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,
+4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,
+4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,
+4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,
+4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,
+4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,
+4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,
+4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,
+4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,
+4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,
+4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,
+4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,
+4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,
+4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,
+4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,
+4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,
+4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,
+4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,
+4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,
+4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,
+5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,
+5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,
+5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,
+5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,
+5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,
+5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,
+5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,
+5110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123,5124,
+5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,
+5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,
+5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,
+5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,
+5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,
+5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,
+5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,
+5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,
+5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,
+5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,
+5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,
+5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,
+5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,
+5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,
+5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,
+5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,
+5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,
+5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,
+5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,
+5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,
+5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,
+5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,
+5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,
+5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,
+5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,
+5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,
+5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,
+5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,
+5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,
+5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,
+5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,
+5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,
+5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,
+5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,
+5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,
+5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,
+5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,
+5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,
+5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,
+5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,
+5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,
+5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,
+5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,
+5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,
+5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,
+5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,
+5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,
+5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,
+5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,
+5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,
+5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,
+5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,
+5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,
+5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,
+5935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,
+5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,
+5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,
+5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,
+5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,
+6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,
+6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,
+6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,
+6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,
+6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,
+6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,
+6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,
+6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,
+6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,
+6145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,
+6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,
+6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,
+6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,
+6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,
+6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,
+6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,
+6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,
+6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,
+6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,
+6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,
+6310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,
+6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,
+6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,
+6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,
+6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,
+6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,
+6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,
+6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,
+6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,
+6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,
+6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,
+6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,
+6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,
+6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,
+6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,
+6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,
+6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,
+6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,
+6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,
+6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,
+6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,
+6625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,
+6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,
+6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,
+6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,
+6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,
+6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,
+6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,
+6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,
+6745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,
+6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,
+6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,
+6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,
+6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,
+6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,
+6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,
+6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,
+6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,
+6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,
+6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,
+6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,
+6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,
+6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,
+6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,
+6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,
+6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,
+7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,
+7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,
+7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,
+7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,
+7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,
+7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,
+7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,
+7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,
+7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,
+7135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,
+7150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,
+7165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,
+7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,
+7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,
+7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,
+7225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,
+7240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,
+7255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,
+7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,
+7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054,1057,
+1058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312,7313,
+7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,
+7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,
+7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,
+7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,
+7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,
+7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,
+7404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,
+7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,
+7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,
+7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,
+7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,
+7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,
+7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,
+7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,
+7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,
+7539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551,7552,
+7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,
+7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,
+7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,
+7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,
+7613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,
+7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,
+7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,
+7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,
+7673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684,7684,7686,7686,
+7688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698,7700,7700,7702,
+7702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714,7714,7716,7716,
+7718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728,7730,7730,7732,
+7732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744,7744,7746,7746,
+7748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758,7760,7760,7762,
+7762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774,7774,7776,7776,
+7778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788,7790,7790,7792,
+7792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804,7804,7806,7806,
+7808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818,7820,7820,7822,
+7822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834,7776,7836,7837,
+7838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848,7850,7850,7852,
+7852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864,7864,7866,7866,
+7868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878,7880,7880,7882,
+7882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894,7894,7896,7896,
+7898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908,7910,7910,7912,
+7912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924,7924,7926,7926,
+7928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947,7948,7949,7950,
+7951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962,7963,7964,7965,
+7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977,7978,7979,7980,
+7981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992,7993,7994,7995,
+7996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999,8008,8009,8010,
+8011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,8025,
+8018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029,8030,8031,8040,
+8041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044,8045,8046,8047,
+8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,8062,
+8063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,
+8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,
+8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,
+8108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119,8120,8121,8122,
+8123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,
+8138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149,8150,8151,8152,
+8153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164,8172,8166,8167,
+8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,
+8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,
+8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,
+8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,
+8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,
+8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,
+8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,
+8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,
+8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,
+8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,
+8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,
+8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,
+8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,
+8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,
+8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,
+8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,
+8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,
+8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,
+8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,
+8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,
+8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,
+8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,
+8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,
+8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8498,8527,
+8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,
+8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,
+8558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,
+8557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584,8585,8586,8587,
+8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,
+8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,
+8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,8632,
+8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645,8646,8647,
+8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661,8662,
+8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,
+8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,
+8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,
+8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,
+8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,
+8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749,8750,8751,8752,
+8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764,8765,8766,8767,
+8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,
+8783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794,8795,8796,8797,
+8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809,8810,8811,8812,
+8813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,
+8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839,8840,8841,8842,
+8843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854,8855,8856,8857,
+8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,
+8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,
+8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901,8902,
+8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917,
+8918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,8930,8931,8932,
+8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944,8945,8946,8947,
+8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962,
+8963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977,
+8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,
+8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,
+9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022,
+9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,
+9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,
+9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067,
+9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,
+9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,
+9098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,
+9113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,
+9128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,
+9143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154,9155,9156,9157,
+9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,9170,9171,9172,
+9173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184,9185,9186,9187,
+9188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199,9200,9201,9202,
+9203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214,9215,9216,9217,
+9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,
+9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,
+9248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259,9260,9261,9262,
+9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274,9275,9276,9277,
+9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,9291,9292,
+9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304,9305,9306,9307,
+9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,
+9323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,
+9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,
+9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,
+9368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,
+9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,
+9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,
+9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398,9399,9400,9401,
+9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,
+9417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454,9455,9456,9457,
+9458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,
+9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,
+9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,
+9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,
+9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,
+9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,
+9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,
+9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,
+9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,
+9593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604,9605,9606,9607,
+9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,
+9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634,9635,9636,9637,
+9638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649,9650,9651,9652,
+9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,
+9668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,9682,
+9683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694,9695,9696,9697,
+9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,9710,9711,9712,
+9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,
+9728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739,9740,9741,9742,
+9743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,
+9758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,
+9773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784,9785,9786,9787,
+9788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799,9800,9801,9802,
+9803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,
+9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,
+9833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844,9845,9846,9847,
+9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,9862,
+9863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874,9875,9876,9877,
+9878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889,9890,9891,9892,
+9893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904,9905,9906,9907,
+9908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919,9920,9921,9922,
+9923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,
+9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,
+9953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964,9965,9966,9967,
+9968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979,9980,9981,9982,
+9983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,
+9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,10009,
+10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021,
+10022,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033,
+10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,
+10046,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,10057,
+10058,10059,10060,10061,10062,10063,10064,10065,10066,10067,10068,10069,
+10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,
+10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,
+10094,10095,10096,10097,10098,10099,10100,10101,10102,10103,10104,10105,
+10106,10107,10108,10109,10110,10111,10112,10113,10114,10115,10116,10117,
+10118,10119,10120,10121,10122,10123,10124,10125,10126,10127,10128,10129,
+10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,10141,
+10142,10143,10144,10145,10146,10147,10148,10149,10150,10151,10152,10153,
+10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,
+10166,10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,
+10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,
+10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201,
+10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213,
+10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,
+10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237,
+10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249,
+10250,10251,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261,
+10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,
+10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,
+10286,10287,10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,
+10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,10308,10309,
+10310,10311,10312,10313,10314,10315,10316,10317,10318,10319,10320,10321,
+10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,
+10334,10335,10336,10337,10338,10339,10340,10341,10342,10343,10344,10345,
+10346,10347,10348,10349,10350,10351,10352,10353,10354,10355,10356,10357,
+10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,10368,10369,
+10370,10371,10372,10373,10374,10375,10376,10377,10378,10379,10380,10381,
+10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,10393,
+10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,
+10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,10417,
+10418,10419,10420,10421,10422,10423,10424,10425,10426,10427,10428,10429,
+10430,10431,10432,10433,10434,10435,10436,10437,10438,10439,10440,10441,
+10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453,
+10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,
+10466,10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,
+10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489,
+10490,10491,10492,10493,10494,10495,10496,10497,10498,10499,10500,10501,
+10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513,
+10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525,
+10526,10527,10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,
+10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549,
+10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561,
+10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573,
+10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,
+10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,
+10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,10608,10609,
+10610,10611,10612,10613,10614,10615,10616,10617,10618,10619,10620,10621,
+10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633,
+10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,
+10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10657,
+10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669,
+10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681,
+10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692,10693,
+10694,10695,10696,10697,10698,10699,10700,10701,10702,10703,10704,10705,
+10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717,
+10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729,
+10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741,
+10742,10743,10744,10745,10746,10747,10748,10749,10750,10751,10752,10753,
+10754,10755,10756,10757,10758,10759,10760,10761,10762,10763,10764,10765,
+10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,
+10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789,
+10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801,
+10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813,
+10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,
+10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837,
+10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849,
+10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861,
+10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,
+10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885,
+10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897,
+10898,10899,10900,10901,10902,10903,10904,10905,10906,10907,10908,10909,
+10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,
+10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,10933,
+10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10944,10945,
+10946,10947,10948,10949,10950,10951,10952,10953,10954,10955,10956,10957,
+10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10969,
+10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,
+10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,
+10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005,
+11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,11016,11017,
+11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029,
+11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,
+11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,
+11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,
+11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,
+11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,
+11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,
+11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113,
+11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,
+11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,
+11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,
+11150,11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,
+11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,
+11174,11175,11176,11177,11178,11179,11180,11181,11182,11183,11184,11185,
+11186,11187,11188,11189,11190,11191,11192,11193,11194,11195,11196,11197,
+11198,11199,11200,11201,11202,11203,11204,11205,11206,11207,11208,11209,
+11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,
+11222,11223,11224,11225,11226,11227,11228,11229,11230,11231,11232,11233,
+11234,11235,11236,11237,11238,11239,11240,11241,11242,11243,11244,11245,
+11246,11247,11248,11249,11250,11251,11252,11253,11254,11255,11256,11257,
+11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,
+11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
+11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
+11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
+11306,11307,11308,11309,11310,11311,11264,11265,11266,11267,11268,11269,
+11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
+11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
+11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
+11306,11307,11308,11309,11310,11359,11360,11360,11362,11363,11364,570,574,
+11367,11367,11369,11369,11371,11371,11373,11374,11375,11376,11377,11378,
+11378,11380,11381,11381,11383,11384,11385,11386,11387,11388,11389,11390,
+11391,11392,11392,11394,11394,11396,11396,11398,11398,11400,11400,11402,
+11402,11404,11404,11406,11406,11408,11408,11410,11410,11412,11412,11414,
+11414,11416,11416,11418,11418,11420,11420,11422,11422,11424,11424,11426,
+11426,11428,11428,11430,11430,11432,11432,11434,11434,11436,11436,11438,
+11438,11440,11440,11442,11442,11444,11444,11446,11446,11448,11448,11450,
+11450,11452,11452,11454,11454,11456,11456,11458,11458,11460,11460,11462,
+11462,11464,11464,11466,11466,11468,11468,11470,11470,11472,11472,11474,
+11474,11476,11476,11478,11478,11480,11480,11482,11482,11484,11484,11486,
+11486,11488,11488,11490,11490,11492,11493,11494,11495,11496,11497,11498,
+11499,11499,11501,11501,11503,11504,11505,11506,11506,11508,11509,11510,
+11511,11512,11513,11514,11515,11516,11517,11518,11519,4256,4257,4258,4259,
+4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,
+4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,
+4290,4291,4292,4293,11558,4295,11560,11561,11562,11563,11564,4301,11566,
+11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578,
+11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,
+11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,
+11603,11604,11605,11606,11607,11608,11609,11610,11611,11612,11613,11614,
+11615,11616,11617,11618,11619,11620,11621,11622,11623,11624,11625,11626,
+11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638,
+11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,
+11651,11652,11653,11654,11655,11656,11657,11658,11659,11660,11661,11662,
+11663,11664,11665,11666,11667,11668,11669,11670,11671,11672,11673,11674,
+11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685,11686,
+11687,11688,11689,11690,11691,11692,11693,11694,11695,11696,11697,11698,
+11699,11700,11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,
+11711,11712,11713,11714,11715,11716,11717,11718,11719,11720,11721,11722,
+11723,11724,11725,11726,11727,11728,11729,11730,11731,11732,11733,11734,
+11735,11736,11737,11738,11739,11740,11741,11742,11743,11744,11745,11746,
+11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,
+11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,
+11771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782,
+11783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794,
+11795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806,
+11807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,11818,
+11819,11820,11821,11822,11823,11824,11825,11826,11827,11828,11829,11830,
+11831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842,
+11843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854,
+11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866,
+11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,
+11879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890,
+11891,11892,11893,11894,11895,11896,11897,11898,11899,11900,11901,11902,
+11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913,11914,
+11915,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,
+11927,11928,11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,
+11939,11940,11941,11942,11943,11944,11945,11946,11947,11948,11949,11950,
+11951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962,
+11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,
+11975,11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,
+11987,11988,11989,11990,11991,11992,11993,11994,11995,11996,11997,11998,
+11999,12000,12001,12002,12003,12004,12005,12006,12007,12008,12009,12010,
+12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021,12022,
+12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,
+12035,12036,12037,12038,12039,12040,12041,12042,12043,12044,12045,12046,
+12047,12048,12049,12050,12051,12052,12053,12054,12055,12056,12057,12058,
+12059,12060,12061,12062,12063,12064,12065,12066,12067,12068,12069,12070,
+12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,
+12083,12084,12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,
+12095,12096,12097,12098,12099,12100,12101,12102,12103,12104,12105,12106,
+12107,12108,12109,12110,12111,12112,12113,12114,12115,12116,12117,12118,
+12119,12120,12121,12122,12123,12124,12125,12126,12127,12128,12129,12130,
+12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,
+12143,12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154,
+12155,12156,12157,12158,12159,12160,12161,12162,12163,12164,12165,12166,
+12167,12168,12169,12170,12171,12172,12173,12174,12175,12176,12177,12178,
+12179,12180,12181,12182,12183,12184,12185,12186,12187,12188,12189,12190,
+12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,
+12203,12204,12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,
+12215,12216,12217,12218,12219,12220,12221,12222,12223,12224,12225,12226,
+12227,12228,12229,12230,12231,12232,12233,12234,12235,12236,12237,12238,
+12239,12240,12241,12242,12243,12244,12245,12246,12247,12248,12249,12250,
+12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,
+12263,12264,12265,12266,12267,12268,12269,12270,12271,12272,12273,12274,
+12275,12276,12277,12278,12279,12280,12281,12282,12283,12284,12285,12286,
+12287,12288,12289,12290,12291,12292,12293,12294,12295,12296,12297,12298,
+12299,12300,12301,12302,12303,12304,12305,12306,12307,12308,12309,12310,
+12311,12312,12313,12314,12315,12316,12317,12318,12319,12320,12321,12322,
+12323,12324,12325,12326,12327,12328,12329,12330,12331,12332,12333,12334,
+12335,12336,12337,12338,12339,12340,12341,12342,12343,12344,12345,12346,
+12347,12348,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358,
+12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,
+12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,
+12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,
+12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,
+12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,
+12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,
+12431,12432,12433,12434,12435,12436,12437,12438,12439,12440,12441,12442,
+12443,12444,12445,12446,12447,12448,12449,12450,12451,12452,12453,12454,
+12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,
+12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,
+12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,
+12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,
+12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,
+12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,
+12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,
+12539,12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,
+12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,
+12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,
+12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,12586,
+12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,
+12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,
+12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,
+12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,
+12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,
+12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,
+12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,
+12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,
+12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,
+12695,12696,12697,12698,12699,12700,12701,12702,12703,12704,12705,12706,
+12707,12708,12709,12710,12711,12712,12713,12714,12715,12716,12717,12718,
+12719,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12730,
+12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742,
+12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,
+12755,12756,12757,12758,12759,12760,12761,12762,12763,12764,12765,12766,
+12767,12768,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778,
+12779,12780,12781,12782,12783,12784,12785,12786,12787,12788,12789,12790,
+12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,
+12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,
+12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,
+12827,12828,12829,12830,12831,12832,12833,12834,12835,12836,12837,12838,
+12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849,12850,
+12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,12862,
+12863,12864,12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,
+12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12886,
+12887,12888,12889,12890,12891,12892,12893,12894,12895,12896,12897,12898,
+12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,
+12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,
+12923,12924,12925,12926,12927,12928,12929,12930,12931,12932,12933,12934,
+12935,12936,12937,12938,12939,12940,12941,12942,12943,12944,12945,12946,
+12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,12957,12958,
+12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,
+12971,12972,12973,12974,12975,12976,12977,12978,12979,12980,12981,12982,
+12983,12984,12985,12986,12987,12988,12989,12990,12991,12992,12993,12994,
+12995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,13006,
+13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018,
+13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,13030,
+13031,13032,13033,13034,13035,13036,13037,13038,13039,13040,13041,13042,
+13043,13044,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054,
+13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065,13066,
+13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,
+13079,13080,13081,13082,13083,13084,13085,13086,13087,13088,13089,13090,
+13091,13092,13093,13094,13095,13096,13097,13098,13099,13100,13101,13102,
+13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113,13114,
+13115,13116,13117,13118,13119,13120,13121,13122,13123,13124,13125,13126,
+13127,13128,13129,13130,13131,13132,13133,13134,13135,13136,13137,13138,
+13139,13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,
+13151,13152,13153,13154,13155,13156,13157,13158,13159,13160,13161,13162,
+13163,13164,13165,13166,13167,13168,13169,13170,13171,13172,13173,13174,
+13175,13176,13177,13178,13179,13180,13181,13182,13183,13184,13185,13186,
+13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,
+13199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210,
+13211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222,
+13223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234,
+13235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246,
+13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,
+13259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270,
+13271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282,
+13283,13284,13285,13286,13287,13288,13289,13290,13291,13292,13293,13294,
+13295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306,
+13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,
+13319,13320,13321,13322,13323,13324,13325,13326,13327,13328,13329,13330,
+13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,
+13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,
+13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,
+13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,
+13379,13380,13381,13382,13383,13384,13385,13386,13387,13388,13389,13390,
+13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,
+13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,
+13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,
+13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,
+13439,13440,13441,13442,13443,13444,13445,13446,13447,13448,13449,13450,
+13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,
+13463,13464,13465,13466,13467,13468,13469,13470,13471,13472,13473,13474,
+13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,
+13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,
+13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,
+13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522,
+13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,
+13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,
+13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,
+13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,
+13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,
+13583,13584,13585,13586,13587,13588,13589,13590,13591,13592,13593,13594,
+13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,
+13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,
+13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,
+13631,13632,13633,13634,13635,13636,13637,13638,13639,13640,13641,13642,
+13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,
+13655,13656,13657,13658,13659,13660,13661,13662,13663,13664,13665,13666,
+13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,
+13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,
+13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,
+13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13713,13714,
+13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,
+13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,
+13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,
+13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13761,13762,
+13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,
+13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,
+13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,
+13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,
+13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,
+13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,
+13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,
+13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,
+13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,
+13871,13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,
+13883,13884,13885,13886,13887,13888,13889,13890,13891,13892,13893,13894,
+13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,
+13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,
+13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,
+13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,
+13943,13944,13945,13946,13947,13948,13949,13950,13951,13952,13953,13954,
+13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,
+13967,13968,13969,13970,13971,13972,13973,13974,13975,13976,13977,13978,
+13979,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,
+13991,13992,13993,13994,13995,13996,13997,13998,13999,14000,14001,14002,
+14003,14004,14005,14006,14007,14008,14009,14010,14011,14012,14013,14014,
+14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,
+14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,
+14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,
+14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,
+14063,14064,14065,14066,14067,14068,14069,14070,14071,14072,14073,14074,
+14075,14076,14077,14078,14079,14080,14081,14082,14083,14084,14085,14086,
+14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,
+14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14110,
+14111,14112,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,
+14123,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,
+14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,
+14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,
+14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,
+14171,14172,14173,14174,14175,14176,14177,14178,14179,14180,14181,14182,
+14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,
+14195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,
+14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,
+14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,
+14231,14232,14233,14234,14235,14236,14237,14238,14239,14240,14241,14242,
+14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,
+14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,
+14267,14268,14269,14270,14271,14272,14273,14274,14275,14276,14277,14278,
+14279,14280,14281,14282,14283,14284,14285,14286,14287,14288,14289,14290,
+14291,14292,14293,14294,14295,14296,14297,14298,14299,14300,14301,14302,
+14303,14304,14305,14306,14307,14308,14309,14310,14311,14312,14313,14314,
+14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,14325,14326,
+14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,
+14339,14340,14341,14342,14343,14344,14345,14346,14347,14348,14349,14350,
+14351,14352,14353,14354,14355,14356,14357,14358,14359,14360,14361,14362,
+14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,
+14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14385,14386,
+14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,
+14399,14400,14401,14402,14403,14404,14405,14406,14407,14408,14409,14410,
+14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,14421,14422,
+14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,
+14435,14436,14437,14438,14439,14440,14441,14442,14443,14444,14445,14446,
+14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,
+14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,
+14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,
+14483,14484,14485,14486,14487,14488,14489,14490,14491,14492,14493,14494,
+14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,
+14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14518,
+14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,
+14531,14532,14533,14534,14535,14536,14537,14538,14539,14540,14541,14542,
+14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,
+14555,14556,14557,14558,14559,14560,14561,14562,14563,14564,14565,14566,
+14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,
+14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,
+14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,
+14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,
+14615,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,
+14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,
+14639,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,
+14651,14652,14653,14654,14655,14656,14657,14658,14659,14660,14661,14662,
+14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,
+14675,14676,14677,14678,14679,14680,14681,14682,14683,14684,14685,14686,
+14687,14688,14689,14690,14691,14692,14693,14694,14695,14696,14697,14698,
+14699,14700,14701,14702,14703,14704,14705,14706,14707,14708,14709,14710,
+14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,
+14723,14724,14725,14726,14727,14728,14729,14730,14731,14732,14733,14734,
+14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,
+14747,14748,14749,14750,14751,14752,14753,14754,14755,14756,14757,14758,
+14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,14769,14770,
+14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,
+14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,
+14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,
+14807,14808,14809,14810,14811,14812,14813,14814,14815,14816,14817,14818,
+14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,
+14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,
+14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,
+14855,14856,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,
+14867,14868,14869,14870,14871,14872,14873,14874,14875,14876,14877,14878,
+14879,14880,14881,14882,14883,14884,14885,14886,14887,14888,14889,14890,
+14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,
+14903,14904,14905,14906,14907,14908,14909,14910,14911,14912,14913,14914,
+14915,14916,14917,14918,14919,14920,14921,14922,14923,14924,14925,14926,
+14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,
+14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,
+14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,
+14963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,
+14975,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,
+14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,
+14999,15000,15001,15002,15003,15004,15005,15006,15007,15008,15009,15010,
+15011,15012,15013,15014,15015,15016,15017,15018,15019,15020,15021,15022,
+15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,
+15035,15036,15037,15038,15039,15040,15041,15042,15043,15044,15045,15046,
+15047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058,
+15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,
+15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,
+15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,
+15095,15096,15097,15098,15099,15100,15101,15102,15103,15104,15105,15106,
+15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,
+15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,
+15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,
+15143,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,
+15155,15156,15157,15158,15159,15160,15161,15162,15163,15164,15165,15166,
+15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,
+15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15190,
+15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,
+15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,
+15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,
+15227,15228,15229,15230,15231,15232,15233,15234,15235,15236,15237,15238,
+15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,
+15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,
+15263,15264,15265,15266,15267,15268,15269,15270,15271,15272,15273,15274,
+15275,15276,15277,15278,15279,15280,15281,15282,15283,15284,15285,15286,
+15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,
+15299,15300,15301,15302,15303,15304,15305,15306,15307,15308,15309,15310,
+15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,
+15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,
+15335,15336,15337,15338,15339,15340,15341,15342,15343,15344,15345,15346,
+15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,
+15359,15360,15361,15362,15363,15364,15365,15366,15367,15368,15369,15370,
+15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,
+15383,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,
+15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,
+15407,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15418,
+15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,
+15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,
+15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15453,15454,
+15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,
+15467,15468,15469,15470,15471,15472,15473,15474,15475,15476,15477,15478,
+15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,
+15491,15492,15493,15494,15495,15496,15497,15498,15499,15500,15501,15502,
+15503,15504,15505,15506,15507,15508,15509,15510,15511,15512,15513,15514,
+15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,
+15527,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,
+15539,15540,15541,15542,15543,15544,15545,15546,15547,15548,15549,15550,
+15551,15552,15553,15554,15555,15556,15557,15558,15559,15560,15561,15562,
+15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,
+15575,15576,15577,15578,15579,15580,15581,15582,15583,15584,15585,15586,
+15587,15588,15589,15590,15591,15592,15593,15594,15595,15596,15597,15598,
+15599,15600,15601,15602,15603,15604,15605,15606,15607,15608,15609,15610,
+15611,15612,15613,15614,15615,15616,15617,15618,15619,15620,15621,15622,
+15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,
+15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,
+15647,15648,15649,15650,15651,15652,15653,15654,15655,15656,15657,15658,
+15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,
+15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,
+15683,15684,15685,15686,15687,15688,15689,15690,15691,15692,15693,15694,
+15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,
+15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15717,15718,
+15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,
+15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,
+15743,15744,15745,15746,15747,15748,15749,15750,15751,15752,15753,15754,
+15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,
+15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,
+15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15789,15790,
+15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,
+15803,15804,15805,15806,15807,15808,15809,15810,15811,15812,15813,15814,
+15815,15816,15817,15818,15819,15820,15821,15822,15823,15824,15825,15826,
+15827,15828,15829,15830,15831,15832,15833,15834,15835,15836,15837,15838,
+15839,15840,15841,15842,15843,15844,15845,15846,15847,15848,15849,15850,
+15851,15852,15853,15854,15855,15856,15857,15858,15859,15860,15861,15862,
+15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15874,
+15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,
+15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,
+15899,15900,15901,15902,15903,15904,15905,15906,15907,15908,15909,15910,
+15911,15912,15913,15914,15915,15916,15917,15918,15919,15920,15921,15922,
+15923,15924,15925,15926,15927,15928,15929,15930,15931,15932,15933,15934,
+15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,
+15947,15948,15949,15950,15951,15952,15953,15954,15955,15956,15957,15958,
+15959,15960,15961,15962,15963,15964,15965,15966,15967,15968,15969,15970,
+15971,15972,15973,15974,15975,15976,15977,15978,15979,15980,15981,15982,
+15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,
+15995,15996,15997,15998,15999,16000,16001,16002,16003,16004,16005,16006,
+16007,16008,16009,16010,16011,16012,16013,16014,16015,16016,16017,16018,
+16019,16020,16021,16022,16023,16024,16025,16026,16027,16028,16029,16030,
+16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,
+16043,16044,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,
+16055,16056,16057,16058,16059,16060,16061,16062,16063,16064,16065,16066,
+16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,
+16079,16080,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,
+16091,16092,16093,16094,16095,16096,16097,16098,16099,16100,16101,16102,
+16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,16113,16114,
+16115,16116,16117,16118,16119,16120,16121,16122,16123,16124,16125,16126,
+16127,16128,16129,16130,16131,16132,16133,16134,16135,16136,16137,16138,
+16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,16149,16150,
+16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,
+16163,16164,16165,16166,16167,16168,16169,16170,16171,16172,16173,16174,
+16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,16186,
+16187,16188,16189,16190,16191,16192,16193,16194,16195,16196,16197,16198,
+16199,16200,16201,16202,16203,16204,16205,16206,16207,16208,16209,16210,
+16211,16212,16213,16214,16215,16216,16217,16218,16219,16220,16221,16222,
+16223,16224,16225,16226,16227,16228,16229,16230,16231,16232,16233,16234,
+16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,16245,16246,
+16247,16248,16249,16250,16251,16252,16253,16254,16255,16256,16257,16258,
+16259,16260,16261,16262,16263,16264,16265,16266,16267,16268,16269,16270,
+16271,16272,16273,16274,16275,16276,16277,16278,16279,16280,16281,16282,
+16283,16284,16285,16286,16287,16288,16289,16290,16291,16292,16293,16294,
+16295,16296,16297,16298,16299,16300,16301,16302,16303,16304,16305,16306,
+16307,16308,16309,16310,16311,16312,16313,16314,16315,16316,16317,16318,
+16319,16320,16321,16322,16323,16324,16325,16326,16327,16328,16329,16330,
+16331,16332,16333,16334,16335,16336,16337,16338,16339,16340,16341,16342,
+16343,16344,16345,16346,16347,16348,16349,16350,16351,16352,16353,16354,
+16355,16356,16357,16358,16359,16360,16361,16362,16363,16364,16365,16366,
+16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,
+16379,16380,16381,16382,16383,16384,16385,16386,16387,16388,16389,16390,
+16391,16392,16393,16394,16395,16396,16397,16398,16399,16400,16401,16402,
+16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,
+16415,16416,16417,16418,16419,16420,16421,16422,16423,16424,16425,16426,
+16427,16428,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,
+16439,16440,16441,16442,16443,16444,16445,16446,16447,16448,16449,16450,
+16451,16452,16453,16454,16455,16456,16457,16458,16459,16460,16461,16462,
+16463,16464,16465,16466,16467,16468,16469,16470,16471,16472,16473,16474,
+16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,16485,16486,
+16487,16488,16489,16490,16491,16492,16493,16494,16495,16496,16497,16498,
+16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,
+16511,16512,16513,16514,16515,16516,16517,16518,16519,16520,16521,16522,
+16523,16524,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,
+16535,16536,16537,16538,16539,16540,16541,16542,16543,16544,16545,16546,
+16547,16548,16549,16550,16551,16552,16553,16554,16555,16556,16557,16558,
+16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,16569,16570,
+16571,16572,16573,16574,16575,16576,16577,16578,16579,16580,16581,16582,
+16583,16584,16585,16586,16587,16588,16589,16590,16591,16592,16593,16594,
+16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,16605,16606,
+16607,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,
+16619,16620,16621,16622,16623,16624,16625,16626,16627,16628,16629,16630,
+16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,
+16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,
+16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,
+16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,
+16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,
+16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16701,16702,
+16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,
+16715,16716,16717,16718,16719,16720,16721,16722,16723,16724,16725,16726,
+16727,16728,16729,16730,16731,16732,16733,16734,16735,16736,16737,16738,
+16739,16740,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,
+16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762,
+16763,16764,16765,16766,16767,16768,16769,16770,16771,16772,16773,16774,
+16775,16776,16777,16778,16779,16780,16781,16782,16783,16784,16785,16786,
+16787,16788,16789,16790,16791,16792,16793,16794,16795,16796,16797,16798,
+16799,16800,16801,16802,16803,16804,16805,16806,16807,16808,16809,16810,
+16811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822,
+16823,16824,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,
+16835,16836,16837,16838,16839,16840,16841,16842,16843,16844,16845,16846,
+16847,16848,16849,16850,16851,16852,16853,16854,16855,16856,16857,16858,
+16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,
+16871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882,
+16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,
+16895,16896,16897,16898,16899,16900,16901,16902,16903,16904,16905,16906,
+16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,
+16919,16920,16921,16922,16923,16924,16925,16926,16927,16928,16929,16930,
+16931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942,
+16943,16944,16945,16946,16947,16948,16949,16950,16951,16952,16953,16954,
+16955,16956,16957,16958,16959,16960,16961,16962,16963,16964,16965,16966,
+16967,16968,16969,16970,16971,16972,16973,16974,16975,16976,16977,16978,
+16979,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,
+16991,16992,16993,16994,16995,16996,16997,16998,16999,17000,17001,17002,
+17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,
+17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,17025,17026,
+17027,17028,17029,17030,17031,17032,17033,17034,17035,17036,17037,17038,
+17039,17040,17041,17042,17043,17044,17045,17046,17047,17048,17049,17050,
+17051,17052,17053,17054,17055,17056,17057,17058,17059,17060,17061,17062,
+17063,17064,17065,17066,17067,17068,17069,17070,17071,17072,17073,17074,
+17075,17076,17077,17078,17079,17080,17081,17082,17083,17084,17085,17086,
+17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,
+17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,
+17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,
+17123,17124,17125,17126,17127,17128,17129,17130,17131,17132,17133,17134,
+17135,17136,17137,17138,17139,17140,17141,17142,17143,17144,17145,17146,
+17147,17148,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,
+17159,17160,17161,17162,17163,17164,17165,17166,17167,17168,17169,17170,
+17171,17172,17173,17174,17175,17176,17177,17178,17179,17180,17181,17182,
+17183,17184,17185,17186,17187,17188,17189,17190,17191,17192,17193,17194,
+17195,17196,17197,17198,17199,17200,17201,17202,17203,17204,17205,17206,
+17207,17208,17209,17210,17211,17212,17213,17214,17215,17216,17217,17218,
+17219,17220,17221,17222,17223,17224,17225,17226,17227,17228,17229,17230,
+17231,17232,17233,17234,17235,17236,17237,17238,17239,17240,17241,17242,
+17243,17244,17245,17246,17247,17248,17249,17250,17251,17252,17253,17254,
+17255,17256,17257,17258,17259,17260,17261,17262,17263,17264,17265,17266,
+17267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278,
+17279,17280,17281,17282,17283,17284,17285,17286,17287,17288,17289,17290,
+17291,17292,17293,17294,17295,17296,17297,17298,17299,17300,17301,17302,
+17303,17304,17305,17306,17307,17308,17309,17310,17311,17312,17313,17314,
+17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,
+17327,17328,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,
+17339,17340,17341,17342,17343,17344,17345,17346,17347,17348,17349,17350,
+17351,17352,17353,17354,17355,17356,17357,17358,17359,17360,17361,17362,
+17363,17364,17365,17366,17367,17368,17369,17370,17371,17372,17373,17374,
+17375,17376,17377,17378,17379,17380,17381,17382,17383,17384,17385,17386,
+17387,17388,17389,17390,17391,17392,17393,17394,17395,17396,17397,17398,
+17399,17400,17401,17402,17403,17404,17405,17406,17407,17408,17409,17410,
+17411,17412,17413,17414,17415,17416,17417,17418,17419,17420,17421,17422,
+17423,17424,17425,17426,17427,17428,17429,17430,17431,17432,17433,17434,
+17435,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17446,
+17447,17448,17449,17450,17451,17452,17453,17454,17455,17456,17457,17458,
+17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,17469,17470,
+17471,17472,17473,17474,17475,17476,17477,17478,17479,17480,17481,17482,
+17483,17484,17485,17486,17487,17488,17489,17490,17491,17492,17493,17494,
+17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,
+17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,
+17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,
+17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,17541,17542,
+17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,
+17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,
+17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17578,
+17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,
+17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,
+17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,
+17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,
+17627,17628,17629,17630,17631,17632,17633,17634,17635,17636,17637,17638,
+17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,
+17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,
+17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,
+17675,17676,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,
+17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,
+17699,17700,17701,17702,17703,17704,17705,17706,17707,17708,17709,17710,
+17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,
+17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,
+17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,
+17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,
+17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,
+17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,
+17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,
+17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,
+17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,
+17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,
+17831,17832,17833,17834,17835,17836,17837,17838,17839,17840,17841,17842,
+17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,
+17855,17856,17857,17858,17859,17860,17861,17862,17863,17864,17865,17866,
+17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,
+17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,
+17891,17892,17893,17894,17895,17896,17897,17898,17899,17900,17901,17902,
+17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,
+17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,
+17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,
+17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,
+17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,
+17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,
+17975,17976,17977,17978,17979,17980,17981,17982,17983,17984,17985,17986,
+17987,17988,17989,17990,17991,17992,17993,17994,17995,17996,17997,17998,
+17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,18010,
+18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,
+18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,
+18035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046,
+18047,18048,18049,18050,18051,18052,18053,18054,18055,18056,18057,18058,
+18059,18060,18061,18062,18063,18064,18065,18066,18067,18068,18069,18070,
+18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,
+18083,18084,18085,18086,18087,18088,18089,18090,18091,18092,18093,18094,
+18095,18096,18097,18098,18099,18100,18101,18102,18103,18104,18105,18106,
+18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,18117,18118,
+18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,
+18131,18132,18133,18134,18135,18136,18137,18138,18139,18140,18141,18142,
+18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,
+18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,
+18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,
+18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,
+18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,18202,
+18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,
+18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,
+18227,18228,18229,18230,18231,18232,18233,18234,18235,18236,18237,18238,
+18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,
+18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,
+18263,18264,18265,18266,18267,18268,18269,18270,18271,18272,18273,18274,
+18275,18276,18277,18278,18279,18280,18281,18282,18283,18284,18285,18286,
+18287,18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298,
+18299,18300,18301,18302,18303,18304,18305,18306,18307,18308,18309,18310,
+18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,
+18323,18324,18325,18326,18327,18328,18329,18330,18331,18332,18333,18334,
+18335,18336,18337,18338,18339,18340,18341,18342,18343,18344,18345,18346,
+18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,
+18359,18360,18361,18362,18363,18364,18365,18366,18367,18368,18369,18370,
+18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,
+18383,18384,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,
+18395,18396,18397,18398,18399,18400,18401,18402,18403,18404,18405,18406,
+18407,18408,18409,18410,18411,18412,18413,18414,18415,18416,18417,18418,
+18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,
+18431,18432,18433,18434,18435,18436,18437,18438,18439,18440,18441,18442,
+18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,
+18455,18456,18457,18458,18459,18460,18461,18462,18463,18464,18465,18466,
+18467,18468,18469,18470,18471,18472,18473,18474,18475,18476,18477,18478,
+18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,
+18491,18492,18493,18494,18495,18496,18497,18498,18499,18500,18501,18502,
+18503,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,
+18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,
+18527,18528,18529,18530,18531,18532,18533,18534,18535,18536,18537,18538,
+18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,
+18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,
+18563,18564,18565,18566,18567,18568,18569,18570,18571,18572,18573,18574,
+18575,18576,18577,18578,18579,18580,18581,18582,18583,18584,18585,18586,
+18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18598,
+18599,18600,18601,18602,18603,18604,18605,18606,18607,18608,18609,18610,
+18611,18612,18613,18614,18615,18616,18617,18618,18619,18620,18621,18622,
+18623,18624,18625,18626,18627,18628,18629,18630,18631,18632,18633,18634,
+18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,18645,18646,
+18647,18648,18649,18650,18651,18652,18653,18654,18655,18656,18657,18658,
+18659,18660,18661,18662,18663,18664,18665,18666,18667,18668,18669,18670,
+18671,18672,18673,18674,18675,18676,18677,18678,18679,18680,18681,18682,
+18683,18684,18685,18686,18687,18688,18689,18690,18691,18692,18693,18694,
+18695,18696,18697,18698,18699,18700,18701,18702,18703,18704,18705,18706,
+18707,18708,18709,18710,18711,18712,18713,18714,18715,18716,18717,18718,
+18719,18720,18721,18722,18723,18724,18725,18726,18727,18728,18729,18730,
+18731,18732,18733,18734,18735,18736,18737,18738,18739,18740,18741,18742,
+18743,18744,18745,18746,18747,18748,18749,18750,18751,18752,18753,18754,
+18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,
+18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,
+18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,
+18791,18792,18793,18794,18795,18796,18797,18798,18799,18800,18801,18802,
+18803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814,
+18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,
+18827,18828,18829,18830,18831,18832,18833,18834,18835,18836,18837,18838,
+18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,
+18851,18852,18853,18854,18855,18856,18857,18858,18859,18860,18861,18862,
+18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,
+18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,
+18887,18888,18889,18890,18891,18892,18893,18894,18895,18896,18897,18898,
+18899,18900,18901,18902,18903,18904,18905,18906,18907,18908,18909,18910,
+18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18922,
+18923,18924,18925,18926,18927,18928,18929,18930,18931,18932,18933,18934,
+18935,18936,18937,18938,18939,18940,18941,18942,18943,18944,18945,18946,
+18947,18948,18949,18950,18951,18952,18953,18954,18955,18956,18957,18958,
+18959,18960,18961,18962,18963,18964,18965,18966,18967,18968,18969,18970,
+18971,18972,18973,18974,18975,18976,18977,18978,18979,18980,18981,18982,
+18983,18984,18985,18986,18987,18988,18989,18990,18991,18992,18993,18994,
+18995,18996,18997,18998,18999,19000,19001,19002,19003,19004,19005,19006,
+19007,19008,19009,19010,19011,19012,19013,19014,19015,19016,19017,19018,
+19019,19020,19021,19022,19023,19024,19025,19026,19027,19028,19029,19030,
+19031,19032,19033,19034,19035,19036,19037,19038,19039,19040,19041,19042,
+19043,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,
+19055,19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066,
+19067,19068,19069,19070,19071,19072,19073,19074,19075,19076,19077,19078,
+19079,19080,19081,19082,19083,19084,19085,19086,19087,19088,19089,19090,
+19091,19092,19093,19094,19095,19096,19097,19098,19099,19100,19101,19102,
+19103,19104,19105,19106,19107,19108,19109,19110,19111,19112,19113,19114,
+19115,19116,19117,19118,19119,19120,19121,19122,19123,19124,19125,19126,
+19127,19128,19129,19130,19131,19132,19133,19134,19135,19136,19137,19138,
+19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,
+19151,19152,19153,19154,19155,19156,19157,19158,19159,19160,19161,19162,
+19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,
+19175,19176,19177,19178,19179,19180,19181,19182,19183,19184,19185,19186,
+19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,
+19199,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,
+19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,19221,19222,
+19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,
+19235,19236,19237,19238,19239,19240,19241,19242,19243,19244,19245,19246,
+19247,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,
+19259,19260,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,
+19271,19272,19273,19274,19275,19276,19277,19278,19279,19280,19281,19282,
+19283,19284,19285,19286,19287,19288,19289,19290,19291,19292,19293,19294,
+19295,19296,19297,19298,19299,19300,19301,19302,19303,19304,19305,19306,
+19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,19317,19318,
+19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,
+19331,19332,19333,19334,19335,19336,19337,19338,19339,19340,19341,19342,
+19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,19353,19354,
+19355,19356,19357,19358,19359,19360,19361,19362,19363,19364,19365,19366,
+19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,
+19379,19380,19381,19382,19383,19384,19385,19386,19387,19388,19389,19390,
+19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,
+19403,19404,19405,19406,19407,19408,19409,19410,19411,19412,19413,19414,
+19415,19416,19417,19418,19419,19420,19421,19422,19423,19424,19425,19426,
+19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,19438,
+19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,
+19451,19452,19453,19454,19455,19456,19457,19458,19459,19460,19461,19462,
+19463,19464,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,
+19475,19476,19477,19478,19479,19480,19481,19482,19483,19484,19485,19486,
+19487,19488,19489,19490,19491,19492,19493,19494,19495,19496,19497,19498,
+19499,19500,19501,19502,19503,19504,19505,19506,19507,19508,19509,19510,
+19511,19512,19513,19514,19515,19516,19517,19518,19519,19520,19521,19522,
+19523,19524,19525,19526,19527,19528,19529,19530,19531,19532,19533,19534,
+19535,19536,19537,19538,19539,19540,19541,19542,19543,19544,19545,19546,
+19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,
+19559,19560,19561,19562,19563,19564,19565,19566,19567,19568,19569,19570,
+19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582,
+19583,19584,19585,19586,19587,19588,19589,19590,19591,19592,19593,19594,
+19595,19596,19597,19598,19599,19600,19601,19602,19603,19604,19605,19606,
+19607,19608,19609,19610,19611,19612,19613,19614,19615,19616,19617,19618,
+19619,19620,19621,19622,19623,19624,19625,19626,19627,19628,19629,19630,
+19631,19632,19633,19634,19635,19636,19637,19638,19639,19640,19641,19642,
+19643,19644,19645,19646,19647,19648,19649,19650,19651,19652,19653,19654,
+19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,
+19667,19668,19669,19670,19671,19672,19673,19674,19675,19676,19677,19678,
+19679,19680,19681,19682,19683,19684,19685,19686,19687,19688,19689,19690,
+19691,19692,19693,19694,19695,19696,19697,19698,19699,19700,19701,19702,
+19703,19704,19705,19706,19707,19708,19709,19710,19711,19712,19713,19714,
+19715,19716,19717,19718,19719,19720,19721,19722,19723,19724,19725,19726,
+19727,19728,19729,19730,19731,19732,19733,19734,19735,19736,19737,19738,
+19739,19740,19741,19742,19743,19744,19745,19746,19747,19748,19749,19750,
+19751,19752,19753,19754,19755,19756,19757,19758,19759,19760,19761,19762,
+19763,19764,19765,19766,19767,19768,19769,19770,19771,19772,19773,19774,
+19775,19776,19777,19778,19779,19780,19781,19782,19783,19784,19785,19786,
+19787,19788,19789,19790,19791,19792,19793,19794,19795,19796,19797,19798,
+19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,19809,19810,
+19811,19812,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,
+19823,19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834,
+19835,19836,19837,19838,19839,19840,19841,19842,19843,19844,19845,19846,
+19847,19848,19849,19850,19851,19852,19853,19854,19855,19856,19857,19858,
+19859,19860,19861,19862,19863,19864,19865,19866,19867,19868,19869,19870,
+19871,19872,19873,19874,19875,19876,19877,19878,19879,19880,19881,19882,
+19883,19884,19885,19886,19887,19888,19889,19890,19891,19892,19893,19894,
+19895,19896,19897,19898,19899,19900,19901,19902,19903,19904,19905,19906,
+19907,19908,19909,19910,19911,19912,19913,19914,19915,19916,19917,19918,
+19919,19920,19921,19922,19923,19924,19925,19926,19927,19928,19929,19930,
+19931,19932,19933,19934,19935,19936,19937,19938,19939,19940,19941,19942,
+19943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,19954,
+19955,19956,19957,19958,19959,19960,19961,19962,19963,19964,19965,19966,
+19967,19968,19969,19970,19971,19972,19973,19974,19975,19976,19977,19978,
+19979,19980,19981,19982,19983,19984,19985,19986,19987,19988,19989,19990,
+19991,19992,19993,19994,19995,19996,19997,19998,19999,20000,20001,20002,
+20003,20004,20005,20006,20007,20008,20009,20010,20011,20012,20013,20014,
+20015,20016,20017,20018,20019,20020,20021,20022,20023,20024,20025,20026,
+20027,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,
+20039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050,
+20051,20052,20053,20054,20055,20056,20057,20058,20059,20060,20061,20062,
+20063,20064,20065,20066,20067,20068,20069,20070,20071,20072,20073,20074,
+20075,20076,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,
+20087,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,20098,
+20099,20100,20101,20102,20103,20104,20105,20106,20107,20108,20109,20110,
+20111,20112,20113,20114,20115,20116,20117,20118,20119,20120,20121,20122,
+20123,20124,20125,20126,20127,20128,20129,20130,20131,20132,20133,20134,
+20135,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,
+20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,20157,20158,
+20159,20160,20161,20162,20163,20164,20165,20166,20167,20168,20169,20170,
+20171,20172,20173,20174,20175,20176,20177,20178,20179,20180,20181,20182,
+20183,20184,20185,20186,20187,20188,20189,20190,20191,20192,20193,20194,
+20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,
+20207,20208,20209,20210,20211,20212,20213,20214,20215,20216,20217,20218,
+20219,20220,20221,20222,20223,20224,20225,20226,20227,20228,20229,20230,
+20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,
+20243,20244,20245,20246,20247,20248,20249,20250,20251,20252,20253,20254,
+20255,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,
+20267,20268,20269,20270,20271,20272,20273,20274,20275,20276,20277,20278,
+20279,20280,20281,20282,20283,20284,20285,20286,20287,20288,20289,20290,
+20291,20292,20293,20294,20295,20296,20297,20298,20299,20300,20301,20302,
+20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,
+20315,20316,20317,20318,20319,20320,20321,20322,20323,20324,20325,20326,
+20327,20328,20329,20330,20331,20332,20333,20334,20335,20336,20337,20338,
+20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350,
+20351,20352,20353,20354,20355,20356,20357,20358,20359,20360,20361,20362,
+20363,20364,20365,20366,20367,20368,20369,20370,20371,20372,20373,20374,
+20375,20376,20377,20378,20379,20380,20381,20382,20383,20384,20385,20386,
+20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,
+20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,
+20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,
+20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,
+20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,
+20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,
+20459,20460,20461,20462,20463,20464,20465,20466,20467,20468,20469,20470,
+20471,20472,20473,20474,20475,20476,20477,20478,20479,20480,20481,20482,
+20483,20484,20485,20486,20487,20488,20489,20490,20491,20492,20493,20494,
+20495,20496,20497,20498,20499,20500,20501,20502,20503,20504,20505,20506,
+20507,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,
+20519,20520,20521,20522,20523,20524,20525,20526,20527,20528,20529,20530,
+20531,20532,20533,20534,20535,20536,20537,20538,20539,20540,20541,20542,
+20543,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,
+20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,
+20567,20568,20569,20570,20571,20572,20573,20574,20575,20576,20577,20578,
+20579,20580,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,
+20591,20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,
+20603,20604,20605,20606,20607,20608,20609,20610,20611,20612,20613,20614,
+20615,20616,20617,20618,20619,20620,20621,20622,20623,20624,20625,20626,
+20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,
+20639,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,
+20651,20652,20653,20654,20655,20656,20657,20658,20659,20660,20661,20662,
+20663,20664,20665,20666,20667,20668,20669,20670,20671,20672,20673,20674,
+20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,
+20687,20688,20689,20690,20691,20692,20693,20694,20695,20696,20697,20698,
+20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20710,
+20711,20712,20713,20714,20715,20716,20717,20718,20719,20720,20721,20722,
+20723,20724,20725,20726,20727,20728,20729,20730,20731,20732,20733,20734,
+20735,20736,20737,20738,20739,20740,20741,20742,20743,20744,20745,20746,
+20747,20748,20749,20750,20751,20752,20753,20754,20755,20756,20757,20758,
+20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20769,20770,
+20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,
+20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,
+20795,20796,20797,20798,20799,20800,20801,20802,20803,20804,20805,20806,
+20807,20808,20809,20810,20811,20812,20813,20814,20815,20816,20817,20818,
+20819,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,
+20831,20832,20833,20834,20835,20836,20837,20838,20839,20840,20841,20842,
+20843,20844,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,
+20855,20856,20857,20858,20859,20860,20861,20862,20863,20864,20865,20866,
+20867,20868,20869,20870,20871,20872,20873,20874,20875,20876,20877,20878,
+20879,20880,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,
+20891,20892,20893,20894,20895,20896,20897,20898,20899,20900,20901,20902,
+20903,20904,20905,20906,20907,20908,20909,20910,20911,20912,20913,20914,
+20915,20916,20917,20918,20919,20920,20921,20922,20923,20924,20925,20926,
+20927,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,
+20939,20940,20941,20942,20943,20944,20945,20946,20947,20948,20949,20950,
+20951,20952,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,
+20963,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,
+20975,20976,20977,20978,20979,20980,20981,20982,20983,20984,20985,20986,
+20987,20988,20989,20990,20991,20992,20993,20994,20995,20996,20997,20998,
+20999,21000,21001,21002,21003,21004,21005,21006,21007,21008,21009,21010,
+21011,21012,21013,21014,21015,21016,21017,21018,21019,21020,21021,21022,
+21023,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,
+21035,21036,21037,21038,21039,21040,21041,21042,21043,21044,21045,21046,
+21047,21048,21049,21050,21051,21052,21053,21054,21055,21056,21057,21058,
+21059,21060,21061,21062,21063,21064,21065,21066,21067,21068,21069,21070,
+21071,21072,21073,21074,21075,21076,21077,21078,21079,21080,21081,21082,
+21083,21084,21085,21086,21087,21088,21089,21090,21091,21092,21093,21094,
+21095,21096,21097,21098,21099,21100,21101,21102,21103,21104,21105,21106,
+21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118,
+21119,21120,21121,21122,21123,21124,21125,21126,21127,21128,21129,21130,
+21131,21132,21133,21134,21135,21136,21137,21138,21139,21140,21141,21142,
+21143,21144,21145,21146,21147,21148,21149,21150,21151,21152,21153,21154,
+21155,21156,21157,21158,21159,21160,21161,21162,21163,21164,21165,21166,
+21167,21168,21169,21170,21171,21172,21173,21174,21175,21176,21177,21178,
+21179,21180,21181,21182,21183,21184,21185,21186,21187,21188,21189,21190,
+21191,21192,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,
+21203,21204,21205,21206,21207,21208,21209,21210,21211,21212,21213,21214,
+21215,21216,21217,21218,21219,21220,21221,21222,21223,21224,21225,21226,
+21227,21228,21229,21230,21231,21232,21233,21234,21235,21236,21237,21238,
+21239,21240,21241,21242,21243,21244,21245,21246,21247,21248,21249,21250,
+21251,21252,21253,21254,21255,21256,21257,21258,21259,21260,21261,21262,
+21263,21264,21265,21266,21267,21268,21269,21270,21271,21272,21273,21274,
+21275,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,
+21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,
+21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,
+21311,21312,21313,21314,21315,21316,21317,21318,21319,21320,21321,21322,
+21323,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,
+21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,21345,21346,
+21347,21348,21349,21350,21351,21352,21353,21354,21355,21356,21357,21358,
+21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,
+21371,21372,21373,21374,21375,21376,21377,21378,21379,21380,21381,21382,
+21383,21384,21385,21386,21387,21388,21389,21390,21391,21392,21393,21394,
+21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,
+21407,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,
+21419,21420,21421,21422,21423,21424,21425,21426,21427,21428,21429,21430,
+21431,21432,21433,21434,21435,21436,21437,21438,21439,21440,21441,21442,
+21443,21444,21445,21446,21447,21448,21449,21450,21451,21452,21453,21454,
+21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,
+21467,21468,21469,21470,21471,21472,21473,21474,21475,21476,21477,21478,
+21479,21480,21481,21482,21483,21484,21485,21486,21487,21488,21489,21490,
+21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,21502,
+21503,21504,21505,21506,21507,21508,21509,21510,21511,21512,21513,21514,
+21515,21516,21517,21518,21519,21520,21521,21522,21523,21524,21525,21526,
+21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,21537,21538,
+21539,21540,21541,21542,21543,21544,21545,21546,21547,21548,21549,21550,
+21551,21552,21553,21554,21555,21556,21557,21558,21559,21560,21561,21562,
+21563,21564,21565,21566,21567,21568,21569,21570,21571,21572,21573,21574,
+21575,21576,21577,21578,21579,21580,21581,21582,21583,21584,21585,21586,
+21587,21588,21589,21590,21591,21592,21593,21594,21595,21596,21597,21598,
+21599,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,
+21611,21612,21613,21614,21615,21616,21617,21618,21619,21620,21621,21622,
+21623,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21634,
+21635,21636,21637,21638,21639,21640,21641,21642,21643,21644,21645,21646,
+21647,21648,21649,21650,21651,21652,21653,21654,21655,21656,21657,21658,
+21659,21660,21661,21662,21663,21664,21665,21666,21667,21668,21669,21670,
+21671,21672,21673,21674,21675,21676,21677,21678,21679,21680,21681,21682,
+21683,21684,21685,21686,21687,21688,21689,21690,21691,21692,21693,21694,
+21695,21696,21697,21698,21699,21700,21701,21702,21703,21704,21705,21706,
+21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,
+21719,21720,21721,21722,21723,21724,21725,21726,21727,21728,21729,21730,
+21731,21732,21733,21734,21735,21736,21737,21738,21739,21740,21741,21742,
+21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,
+21755,21756,21757,21758,21759,21760,21761,21762,21763,21764,21765,21766,
+21767,21768,21769,21770,21771,21772,21773,21774,21775,21776,21777,21778,
+21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21789,21790,
+21791,21792,21793,21794,21795,21796,21797,21798,21799,21800,21801,21802,
+21803,21804,21805,21806,21807,21808,21809,21810,21811,21812,21813,21814,
+21815,21816,21817,21818,21819,21820,21821,21822,21823,21824,21825,21826,
+21827,21828,21829,21830,21831,21832,21833,21834,21835,21836,21837,21838,
+21839,21840,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850,
+21851,21852,21853,21854,21855,21856,21857,21858,21859,21860,21861,21862,
+21863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874,
+21875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886,
+21887,21888,21889,21890,21891,21892,21893,21894,21895,21896,21897,21898,
+21899,21900,21901,21902,21903,21904,21905,21906,21907,21908,21909,21910,
+21911,21912,21913,21914,21915,21916,21917,21918,21919,21920,21921,21922,
+21923,21924,21925,21926,21927,21928,21929,21930,21931,21932,21933,21934,
+21935,21936,21937,21938,21939,21940,21941,21942,21943,21944,21945,21946,
+21947,21948,21949,21950,21951,21952,21953,21954,21955,21956,21957,21958,
+21959,21960,21961,21962,21963,21964,21965,21966,21967,21968,21969,21970,
+21971,21972,21973,21974,21975,21976,21977,21978,21979,21980,21981,21982,
+21983,21984,21985,21986,21987,21988,21989,21990,21991,21992,21993,21994,
+21995,21996,21997,21998,21999,22000,22001,22002,22003,22004,22005,22006,
+22007,22008,22009,22010,22011,22012,22013,22014,22015,22016,22017,22018,
+22019,22020,22021,22022,22023,22024,22025,22026,22027,22028,22029,22030,
+22031,22032,22033,22034,22035,22036,22037,22038,22039,22040,22041,22042,
+22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,
+22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,
+22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,
+22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,
+22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,
+22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,
+22115,22116,22117,22118,22119,22120,22121,22122,22123,22124,22125,22126,
+22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138,
+22139,22140,22141,22142,22143,22144,22145,22146,22147,22148,22149,22150,
+22151,22152,22153,22154,22155,22156,22157,22158,22159,22160,22161,22162,
+22163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,
+22175,22176,22177,22178,22179,22180,22181,22182,22183,22184,22185,22186,
+22187,22188,22189,22190,22191,22192,22193,22194,22195,22196,22197,22198,
+22199,22200,22201,22202,22203,22204,22205,22206,22207,22208,22209,22210,
+22211,22212,22213,22214,22215,22216,22217,22218,22219,22220,22221,22222,
+22223,22224,22225,22226,22227,22228,22229,22230,22231,22232,22233,22234,
+22235,22236,22237,22238,22239,22240,22241,22242,22243,22244,22245,22246,
+22247,22248,22249,22250,22251,22252,22253,22254,22255,22256,22257,22258,
+22259,22260,22261,22262,22263,22264,22265,22266,22267,22268,22269,22270,
+22271,22272,22273,22274,22275,22276,22277,22278,22279,22280,22281,22282,
+22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,
+22295,22296,22297,22298,22299,22300,22301,22302,22303,22304,22305,22306,
+22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,
+22319,22320,22321,22322,22323,22324,22325,22326,22327,22328,22329,22330,
+22331,22332,22333,22334,22335,22336,22337,22338,22339,22340,22341,22342,
+22343,22344,22345,22346,22347,22348,22349,22350,22351,22352,22353,22354,
+22355,22356,22357,22358,22359,22360,22361,22362,22363,22364,22365,22366,
+22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,
+22379,22380,22381,22382,22383,22384,22385,22386,22387,22388,22389,22390,
+22391,22392,22393,22394,22395,22396,22397,22398,22399,22400,22401,22402,
+22403,22404,22405,22406,22407,22408,22409,22410,22411,22412,22413,22414,
+22415,22416,22417,22418,22419,22420,22421,22422,22423,22424,22425,22426,
+22427,22428,22429,22430,22431,22432,22433,22434,22435,22436,22437,22438,
+22439,22440,22441,22442,22443,22444,22445,22446,22447,22448,22449,22450,
+22451,22452,22453,22454,22455,22456,22457,22458,22459,22460,22461,22462,
+22463,22464,22465,22466,22467,22468,22469,22470,22471,22472,22473,22474,
+22475,22476,22477,22478,22479,22480,22481,22482,22483,22484,22485,22486,
+22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,22498,
+22499,22500,22501,22502,22503,22504,22505,22506,22507,22508,22509,22510,
+22511,22512,22513,22514,22515,22516,22517,22518,22519,22520,22521,22522,
+22523,22524,22525,22526,22527,22528,22529,22530,22531,22532,22533,22534,
+22535,22536,22537,22538,22539,22540,22541,22542,22543,22544,22545,22546,
+22547,22548,22549,22550,22551,22552,22553,22554,22555,22556,22557,22558,
+22559,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,22570,
+22571,22572,22573,22574,22575,22576,22577,22578,22579,22580,22581,22582,
+22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,
+22595,22596,22597,22598,22599,22600,22601,22602,22603,22604,22605,22606,
+22607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618,
+22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,
+22631,22632,22633,22634,22635,22636,22637,22638,22639,22640,22641,22642,
+22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,
+22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,22665,22666,
+22667,22668,22669,22670,22671,22672,22673,22674,22675,22676,22677,22678,
+22679,22680,22681,22682,22683,22684,22685,22686,22687,22688,22689,22690,
+22691,22692,22693,22694,22695,22696,22697,22698,22699,22700,22701,22702,
+22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,
+22715,22716,22717,22718,22719,22720,22721,22722,22723,22724,22725,22726,
+22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22737,22738,
+22739,22740,22741,22742,22743,22744,22745,22746,22747,22748,22749,22750,
+22751,22752,22753,22754,22755,22756,22757,22758,22759,22760,22761,22762,
+22763,22764,22765,22766,22767,22768,22769,22770,22771,22772,22773,22774,
+22775,22776,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,
+22787,22788,22789,22790,22791,22792,22793,22794,22795,22796,22797,22798,
+22799,22800,22801,22802,22803,22804,22805,22806,22807,22808,22809,22810,
+22811,22812,22813,22814,22815,22816,22817,22818,22819,22820,22821,22822,
+22823,22824,22825,22826,22827,22828,22829,22830,22831,22832,22833,22834,
+22835,22836,22837,22838,22839,22840,22841,22842,22843,22844,22845,22846,
+22847,22848,22849,22850,22851,22852,22853,22854,22855,22856,22857,22858,
+22859,22860,22861,22862,22863,22864,22865,22866,22867,22868,22869,22870,
+22871,22872,22873,22874,22875,22876,22877,22878,22879,22880,22881,22882,
+22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,22894,
+22895,22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906,
+22907,22908,22909,22910,22911,22912,22913,22914,22915,22916,22917,22918,
+22919,22920,22921,22922,22923,22924,22925,22926,22927,22928,22929,22930,
+22931,22932,22933,22934,22935,22936,22937,22938,22939,22940,22941,22942,
+22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22954,
+22955,22956,22957,22958,22959,22960,22961,22962,22963,22964,22965,22966,
+22967,22968,22969,22970,22971,22972,22973,22974,22975,22976,22977,22978,
+22979,22980,22981,22982,22983,22984,22985,22986,22987,22988,22989,22990,
+22991,22992,22993,22994,22995,22996,22997,22998,22999,23000,23001,23002,
+23003,23004,23005,23006,23007,23008,23009,23010,23011,23012,23013,23014,
+23015,23016,23017,23018,23019,23020,23021,23022,23023,23024,23025,23026,
+23027,23028,23029,23030,23031,23032,23033,23034,23035,23036,23037,23038,
+23039,23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050,
+23051,23052,23053,23054,23055,23056,23057,23058,23059,23060,23061,23062,
+23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,
+23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,
+23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,
+23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,23109,23110,
+23111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23121,23122,
+23123,23124,23125,23126,23127,23128,23129,23130,23131,23132,23133,23134,
+23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,23146,
+23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,
+23159,23160,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,
+23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,
+23183,23184,23185,23186,23187,23188,23189,23190,23191,23192,23193,23194,
+23195,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,
+23207,23208,23209,23210,23211,23212,23213,23214,23215,23216,23217,23218,
+23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,
+23231,23232,23233,23234,23235,23236,23237,23238,23239,23240,23241,23242,
+23243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254,
+23255,23256,23257,23258,23259,23260,23261,23262,23263,23264,23265,23266,
+23267,23268,23269,23270,23271,23272,23273,23274,23275,23276,23277,23278,
+23279,23280,23281,23282,23283,23284,23285,23286,23287,23288,23289,23290,
+23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,
+23303,23304,23305,23306,23307,23308,23309,23310,23311,23312,23313,23314,
+23315,23316,23317,23318,23319,23320,23321,23322,23323,23324,23325,23326,
+23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,
+23339,23340,23341,23342,23343,23344,23345,23346,23347,23348,23349,23350,
+23351,23352,23353,23354,23355,23356,23357,23358,23359,23360,23361,23362,
+23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,
+23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386,
+23387,23388,23389,23390,23391,23392,23393,23394,23395,23396,23397,23398,
+23399,23400,23401,23402,23403,23404,23405,23406,23407,23408,23409,23410,
+23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422,
+23423,23424,23425,23426,23427,23428,23429,23430,23431,23432,23433,23434,
+23435,23436,23437,23438,23439,23440,23441,23442,23443,23444,23445,23446,
+23447,23448,23449,23450,23451,23452,23453,23454,23455,23456,23457,23458,
+23459,23460,23461,23462,23463,23464,23465,23466,23467,23468,23469,23470,
+23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,23481,23482,
+23483,23484,23485,23486,23487,23488,23489,23490,23491,23492,23493,23494,
+23495,23496,23497,23498,23499,23500,23501,23502,23503,23504,23505,23506,
+23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,
+23519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530,
+23531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,
+23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,
+23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,
+23567,23568,23569,23570,23571,23572,23573,23574,23575,23576,23577,23578,
+23579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23590,
+23591,23592,23593,23594,23595,23596,23597,23598,23599,23600,23601,23602,
+23603,23604,23605,23606,23607,23608,23609,23610,23611,23612,23613,23614,
+23615,23616,23617,23618,23619,23620,23621,23622,23623,23624,23625,23626,
+23627,23628,23629,23630,23631,23632,23633,23634,23635,23636,23637,23638,
+23639,23640,23641,23642,23643,23644,23645,23646,23647,23648,23649,23650,
+23651,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,
+23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674,
+23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,
+23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,
+23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,23710,
+23711,23712,23713,23714,23715,23716,23717,23718,23719,23720,23721,23722,
+23723,23724,23725,23726,23727,23728,23729,23730,23731,23732,23733,23734,
+23735,23736,23737,23738,23739,23740,23741,23742,23743,23744,23745,23746,
+23747,23748,23749,23750,23751,23752,23753,23754,23755,23756,23757,23758,
+23759,23760,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770,
+23771,23772,23773,23774,23775,23776,23777,23778,23779,23780,23781,23782,
+23783,23784,23785,23786,23787,23788,23789,23790,23791,23792,23793,23794,
+23795,23796,23797,23798,23799,23800,23801,23802,23803,23804,23805,23806,
+23807,23808,23809,23810,23811,23812,23813,23814,23815,23816,23817,23818,
+23819,23820,23821,23822,23823,23824,23825,23826,23827,23828,23829,23830,
+23831,23832,23833,23834,23835,23836,23837,23838,23839,23840,23841,23842,
+23843,23844,23845,23846,23847,23848,23849,23850,23851,23852,23853,23854,
+23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,
+23867,23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,23878,
+23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,23890,
+23891,23892,23893,23894,23895,23896,23897,23898,23899,23900,23901,23902,
+23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23913,23914,
+23915,23916,23917,23918,23919,23920,23921,23922,23923,23924,23925,23926,
+23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23938,
+23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,
+23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23961,23962,
+23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,
+23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,
+23987,23988,23989,23990,23991,23992,23993,23994,23995,23996,23997,23998,
+23999,24000,24001,24002,24003,24004,24005,24006,24007,24008,24009,24010,
+24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,
+24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,
+24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,
+24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,
+24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,
+24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,
+24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,
+24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,
+24107,24108,24109,24110,24111,24112,24113,24114,24115,24116,24117,24118,
+24119,24120,24121,24122,24123,24124,24125,24126,24127,24128,24129,24130,
+24131,24132,24133,24134,24135,24136,24137,24138,24139,24140,24141,24142,
+24143,24144,24145,24146,24147,24148,24149,24150,24151,24152,24153,24154,
+24155,24156,24157,24158,24159,24160,24161,24162,24163,24164,24165,24166,
+24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24178,
+24179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190,
+24191,24192,24193,24194,24195,24196,24197,24198,24199,24200,24201,24202,
+24203,24204,24205,24206,24207,24208,24209,24210,24211,24212,24213,24214,
+24215,24216,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,
+24227,24228,24229,24230,24231,24232,24233,24234,24235,24236,24237,24238,
+24239,24240,24241,24242,24243,24244,24245,24246,24247,24248,24249,24250,
+24251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262,
+24263,24264,24265,24266,24267,24268,24269,24270,24271,24272,24273,24274,
+24275,24276,24277,24278,24279,24280,24281,24282,24283,24284,24285,24286,
+24287,24288,24289,24290,24291,24292,24293,24294,24295,24296,24297,24298,
+24299,24300,24301,24302,24303,24304,24305,24306,24307,24308,24309,24310,
+24311,24312,24313,24314,24315,24316,24317,24318,24319,24320,24321,24322,
+24323,24324,24325,24326,24327,24328,24329,24330,24331,24332,24333,24334,
+24335,24336,24337,24338,24339,24340,24341,24342,24343,24344,24345,24346,
+24347,24348,24349,24350,24351,24352,24353,24354,24355,24356,24357,24358,
+24359,24360,24361,24362,24363,24364,24365,24366,24367,24368,24369,24370,
+24371,24372,24373,24374,24375,24376,24377,24378,24379,24380,24381,24382,
+24383,24384,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,
+24395,24396,24397,24398,24399,24400,24401,24402,24403,24404,24405,24406,
+24407,24408,24409,24410,24411,24412,24413,24414,24415,24416,24417,24418,
+24419,24420,24421,24422,24423,24424,24425,24426,24427,24428,24429,24430,
+24431,24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442,
+24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,24453,24454,
+24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,
+24467,24468,24469,24470,24471,24472,24473,24474,24475,24476,24477,24478,
+24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,24489,24490,
+24491,24492,24493,24494,24495,24496,24497,24498,24499,24500,24501,24502,
+24503,24504,24505,24506,24507,24508,24509,24510,24511,24512,24513,24514,
+24515,24516,24517,24518,24519,24520,24521,24522,24523,24524,24525,24526,
+24527,24528,24529,24530,24531,24532,24533,24534,24535,24536,24537,24538,
+24539,24540,24541,24542,24543,24544,24545,24546,24547,24548,24549,24550,
+24551,24552,24553,24554,24555,24556,24557,24558,24559,24560,24561,24562,
+24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,24573,24574,
+24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,24586,
+24587,24588,24589,24590,24591,24592,24593,24594,24595,24596,24597,24598,
+24599,24600,24601,24602,24603,24604,24605,24606,24607,24608,24609,24610,
+24611,24612,24613,24614,24615,24616,24617,24618,24619,24620,24621,24622,
+24623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633,24634,
+24635,24636,24637,24638,24639,24640,24641,24642,24643,24644,24645,24646,
+24647,24648,24649,24650,24651,24652,24653,24654,24655,24656,24657,24658,
+24659,24660,24661,24662,24663,24664,24665,24666,24667,24668,24669,24670,
+24671,24672,24673,24674,24675,24676,24677,24678,24679,24680,24681,24682,
+24683,24684,24685,24686,24687,24688,24689,24690,24691,24692,24693,24694,
+24695,24696,24697,24698,24699,24700,24701,24702,24703,24704,24705,24706,
+24707,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,
+24719,24720,24721,24722,24723,24724,24725,24726,24727,24728,24729,24730,
+24731,24732,24733,24734,24735,24736,24737,24738,24739,24740,24741,24742,
+24743,24744,24745,24746,24747,24748,24749,24750,24751,24752,24753,24754,
+24755,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,
+24767,24768,24769,24770,24771,24772,24773,24774,24775,24776,24777,24778,
+24779,24780,24781,24782,24783,24784,24785,24786,24787,24788,24789,24790,
+24791,24792,24793,24794,24795,24796,24797,24798,24799,24800,24801,24802,
+24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,24813,24814,
+24815,24816,24817,24818,24819,24820,24821,24822,24823,24824,24825,24826,
+24827,24828,24829,24830,24831,24832,24833,24834,24835,24836,24837,24838,
+24839,24840,24841,24842,24843,24844,24845,24846,24847,24848,24849,24850,
+24851,24852,24853,24854,24855,24856,24857,24858,24859,24860,24861,24862,
+24863,24864,24865,24866,24867,24868,24869,24870,24871,24872,24873,24874,
+24875,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,
+24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,
+24899,24900,24901,24902,24903,24904,24905,24906,24907,24908,24909,24910,
+24911,24912,24913,24914,24915,24916,24917,24918,24919,24920,24921,24922,
+24923,24924,24925,24926,24927,24928,24929,24930,24931,24932,24933,24934,
+24935,24936,24937,24938,24939,24940,24941,24942,24943,24944,24945,24946,
+24947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958,
+24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,
+24971,24972,24973,24974,24975,24976,24977,24978,24979,24980,24981,24982,
+24983,24984,24985,24986,24987,24988,24989,24990,24991,24992,24993,24994,
+24995,24996,24997,24998,24999,25000,25001,25002,25003,25004,25005,25006,
+25007,25008,25009,25010,25011,25012,25013,25014,25015,25016,25017,25018,
+25019,25020,25021,25022,25023,25024,25025,25026,25027,25028,25029,25030,
+25031,25032,25033,25034,25035,25036,25037,25038,25039,25040,25041,25042,
+25043,25044,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,
+25055,25056,25057,25058,25059,25060,25061,25062,25063,25064,25065,25066,
+25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25077,25078,
+25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,
+25091,25092,25093,25094,25095,25096,25097,25098,25099,25100,25101,25102,
+25103,25104,25105,25106,25107,25108,25109,25110,25111,25112,25113,25114,
+25115,25116,25117,25118,25119,25120,25121,25122,25123,25124,25125,25126,
+25127,25128,25129,25130,25131,25132,25133,25134,25135,25136,25137,25138,
+25139,25140,25141,25142,25143,25144,25145,25146,25147,25148,25149,25150,
+25151,25152,25153,25154,25155,25156,25157,25158,25159,25160,25161,25162,
+25163,25164,25165,25166,25167,25168,25169,25170,25171,25172,25173,25174,
+25175,25176,25177,25178,25179,25180,25181,25182,25183,25184,25185,25186,
+25187,25188,25189,25190,25191,25192,25193,25194,25195,25196,25197,25198,
+25199,25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210,
+25211,25212,25213,25214,25215,25216,25217,25218,25219,25220,25221,25222,
+25223,25224,25225,25226,25227,25228,25229,25230,25231,25232,25233,25234,
+25235,25236,25237,25238,25239,25240,25241,25242,25243,25244,25245,25246,
+25247,25248,25249,25250,25251,25252,25253,25254,25255,25256,25257,25258,
+25259,25260,25261,25262,25263,25264,25265,25266,25267,25268,25269,25270,
+25271,25272,25273,25274,25275,25276,25277,25278,25279,25280,25281,25282,
+25283,25284,25285,25286,25287,25288,25289,25290,25291,25292,25293,25294,
+25295,25296,25297,25298,25299,25300,25301,25302,25303,25304,25305,25306,
+25307,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,25318,
+25319,25320,25321,25322,25323,25324,25325,25326,25327,25328,25329,25330,
+25331,25332,25333,25334,25335,25336,25337,25338,25339,25340,25341,25342,
+25343,25344,25345,25346,25347,25348,25349,25350,25351,25352,25353,25354,
+25355,25356,25357,25358,25359,25360,25361,25362,25363,25364,25365,25366,
+25367,25368,25369,25370,25371,25372,25373,25374,25375,25376,25377,25378,
+25379,25380,25381,25382,25383,25384,25385,25386,25387,25388,25389,25390,
+25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,
+25403,25404,25405,25406,25407,25408,25409,25410,25411,25412,25413,25414,
+25415,25416,25417,25418,25419,25420,25421,25422,25423,25424,25425,25426,
+25427,25428,25429,25430,25431,25432,25433,25434,25435,25436,25437,25438,
+25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,
+25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,
+25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,
+25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,
+25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,
+25499,25500,25501,25502,25503,25504,25505,25506,25507,25508,25509,25510,
+25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,
+25523,25524,25525,25526,25527,25528,25529,25530,25531,25532,25533,25534,
+25535,25536,25537,25538,25539,25540,25541,25542,25543,25544,25545,25546,
+25547,25548,25549,25550,25551,25552,25553,25554,25555,25556,25557,25558,
+25559,25560,25561,25562,25563,25564,25565,25566,25567,25568,25569,25570,
+25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,
+25583,25584,25585,25586,25587,25588,25589,25590,25591,25592,25593,25594,
+25595,25596,25597,25598,25599,25600,25601,25602,25603,25604,25605,25606,
+25607,25608,25609,25610,25611,25612,25613,25614,25615,25616,25617,25618,
+25619,25620,25621,25622,25623,25624,25625,25626,25627,25628,25629,25630,
+25631,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,
+25643,25644,25645,25646,25647,25648,25649,25650,25651,25652,25653,25654,
+25655,25656,25657,25658,25659,25660,25661,25662,25663,25664,25665,25666,
+25667,25668,25669,25670,25671,25672,25673,25674,25675,25676,25677,25678,
+25679,25680,25681,25682,25683,25684,25685,25686,25687,25688,25689,25690,
+25691,25692,25693,25694,25695,25696,25697,25698,25699,25700,25701,25702,
+25703,25704,25705,25706,25707,25708,25709,25710,25711,25712,25713,25714,
+25715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,
+25727,25728,25729,25730,25731,25732,25733,25734,25735,25736,25737,25738,
+25739,25740,25741,25742,25743,25744,25745,25746,25747,25748,25749,25750,
+25751,25752,25753,25754,25755,25756,25757,25758,25759,25760,25761,25762,
+25763,25764,25765,25766,25767,25768,25769,25770,25771,25772,25773,25774,
+25775,25776,25777,25778,25779,25780,25781,25782,25783,25784,25785,25786,
+25787,25788,25789,25790,25791,25792,25793,25794,25795,25796,25797,25798,
+25799,25800,25801,25802,25803,25804,25805,25806,25807,25808,25809,25810,
+25811,25812,25813,25814,25815,25816,25817,25818,25819,25820,25821,25822,
+25823,25824,25825,25826,25827,25828,25829,25830,25831,25832,25833,25834,
+25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,
+25847,25848,25849,25850,25851,25852,25853,25854,25855,25856,25857,25858,
+25859,25860,25861,25862,25863,25864,25865,25866,25867,25868,25869,25870,
+25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,25881,25882,
+25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25893,25894,
+25895,25896,25897,25898,25899,25900,25901,25902,25903,25904,25905,25906,
+25907,25908,25909,25910,25911,25912,25913,25914,25915,25916,25917,25918,
+25919,25920,25921,25922,25923,25924,25925,25926,25927,25928,25929,25930,
+25931,25932,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,
+25943,25944,25945,25946,25947,25948,25949,25950,25951,25952,25953,25954,
+25955,25956,25957,25958,25959,25960,25961,25962,25963,25964,25965,25966,
+25967,25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978,
+25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,
+25991,25992,25993,25994,25995,25996,25997,25998,25999,26000,26001,26002,
+26003,26004,26005,26006,26007,26008,26009,26010,26011,26012,26013,26014,
+26015,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,26026,
+26027,26028,26029,26030,26031,26032,26033,26034,26035,26036,26037,26038,
+26039,26040,26041,26042,26043,26044,26045,26046,26047,26048,26049,26050,
+26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,26061,26062,
+26063,26064,26065,26066,26067,26068,26069,26070,26071,26072,26073,26074,
+26075,26076,26077,26078,26079,26080,26081,26082,26083,26084,26085,26086,
+26087,26088,26089,26090,26091,26092,26093,26094,26095,26096,26097,26098,
+26099,26100,26101,26102,26103,26104,26105,26106,26107,26108,26109,26110,
+26111,26112,26113,26114,26115,26116,26117,26118,26119,26120,26121,26122,
+26123,26124,26125,26126,26127,26128,26129,26130,26131,26132,26133,26134,
+26135,26136,26137,26138,26139,26140,26141,26142,26143,26144,26145,26146,
+26147,26148,26149,26150,26151,26152,26153,26154,26155,26156,26157,26158,
+26159,26160,26161,26162,26163,26164,26165,26166,26167,26168,26169,26170,
+26171,26172,26173,26174,26175,26176,26177,26178,26179,26180,26181,26182,
+26183,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,26194,
+26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,26205,26206,
+26207,26208,26209,26210,26211,26212,26213,26214,26215,26216,26217,26218,
+26219,26220,26221,26222,26223,26224,26225,26226,26227,26228,26229,26230,
+26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,26241,26242,
+26243,26244,26245,26246,26247,26248,26249,26250,26251,26252,26253,26254,
+26255,26256,26257,26258,26259,26260,26261,26262,26263,26264,26265,26266,
+26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,
+26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,26289,26290,
+26291,26292,26293,26294,26295,26296,26297,26298,26299,26300,26301,26302,
+26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,
+26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,
+26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,
+26339,26340,26341,26342,26343,26344,26345,26346,26347,26348,26349,26350,
+26351,26352,26353,26354,26355,26356,26357,26358,26359,26360,26361,26362,
+26363,26364,26365,26366,26367,26368,26369,26370,26371,26372,26373,26374,
+26375,26376,26377,26378,26379,26380,26381,26382,26383,26384,26385,26386,
+26387,26388,26389,26390,26391,26392,26393,26394,26395,26396,26397,26398,
+26399,26400,26401,26402,26403,26404,26405,26406,26407,26408,26409,26410,
+26411,26412,26413,26414,26415,26416,26417,26418,26419,26420,26421,26422,
+26423,26424,26425,26426,26427,26428,26429,26430,26431,26432,26433,26434,
+26435,26436,26437,26438,26439,26440,26441,26442,26443,26444,26445,26446,
+26447,26448,26449,26450,26451,26452,26453,26454,26455,26456,26457,26458,
+26459,26460,26461,26462,26463,26464,26465,26466,26467,26468,26469,26470,
+26471,26472,26473,26474,26475,26476,26477,26478,26479,26480,26481,26482,
+26483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494,
+26495,26496,26497,26498,26499,26500,26501,26502,26503,26504,26505,26506,
+26507,26508,26509,26510,26511,26512,26513,26514,26515,26516,26517,26518,
+26519,26520,26521,26522,26523,26524,26525,26526,26527,26528,26529,26530,
+26531,26532,26533,26534,26535,26536,26537,26538,26539,26540,26541,26542,
+26543,26544,26545,26546,26547,26548,26549,26550,26551,26552,26553,26554,
+26555,26556,26557,26558,26559,26560,26561,26562,26563,26564,26565,26566,
+26567,26568,26569,26570,26571,26572,26573,26574,26575,26576,26577,26578,
+26579,26580,26581,26582,26583,26584,26585,26586,26587,26588,26589,26590,
+26591,26592,26593,26594,26595,26596,26597,26598,26599,26600,26601,26602,
+26603,26604,26605,26606,26607,26608,26609,26610,26611,26612,26613,26614,
+26615,26616,26617,26618,26619,26620,26621,26622,26623,26624,26625,26626,
+26627,26628,26629,26630,26631,26632,26633,26634,26635,26636,26637,26638,
+26639,26640,26641,26642,26643,26644,26645,26646,26647,26648,26649,26650,
+26651,26652,26653,26654,26655,26656,26657,26658,26659,26660,26661,26662,
+26663,26664,26665,26666,26667,26668,26669,26670,26671,26672,26673,26674,
+26675,26676,26677,26678,26679,26680,26681,26682,26683,26684,26685,26686,
+26687,26688,26689,26690,26691,26692,26693,26694,26695,26696,26697,26698,
+26699,26700,26701,26702,26703,26704,26705,26706,26707,26708,26709,26710,
+26711,26712,26713,26714,26715,26716,26717,26718,26719,26720,26721,26722,
+26723,26724,26725,26726,26727,26728,26729,26730,26731,26732,26733,26734,
+26735,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746,
+26747,26748,26749,26750,26751,26752,26753,26754,26755,26756,26757,26758,
+26759,26760,26761,26762,26763,26764,26765,26766,26767,26768,26769,26770,
+26771,26772,26773,26774,26775,26776,26777,26778,26779,26780,26781,26782,
+26783,26784,26785,26786,26787,26788,26789,26790,26791,26792,26793,26794,
+26795,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,
+26807,26808,26809,26810,26811,26812,26813,26814,26815,26816,26817,26818,
+26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,
+26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,
+26843,26844,26845,26846,26847,26848,26849,26850,26851,26852,26853,26854,
+26855,26856,26857,26858,26859,26860,26861,26862,26863,26864,26865,26866,
+26867,26868,26869,26870,26871,26872,26873,26874,26875,26876,26877,26878,
+26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,26889,26890,
+26891,26892,26893,26894,26895,26896,26897,26898,26899,26900,26901,26902,
+26903,26904,26905,26906,26907,26908,26909,26910,26911,26912,26913,26914,
+26915,26916,26917,26918,26919,26920,26921,26922,26923,26924,26925,26926,
+26927,26928,26929,26930,26931,26932,26933,26934,26935,26936,26937,26938,
+26939,26940,26941,26942,26943,26944,26945,26946,26947,26948,26949,26950,
+26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,
+26963,26964,26965,26966,26967,26968,26969,26970,26971,26972,26973,26974,
+26975,26976,26977,26978,26979,26980,26981,26982,26983,26984,26985,26986,
+26987,26988,26989,26990,26991,26992,26993,26994,26995,26996,26997,26998,
+26999,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,
+27011,27012,27013,27014,27015,27016,27017,27018,27019,27020,27021,27022,
+27023,27024,27025,27026,27027,27028,27029,27030,27031,27032,27033,27034,
+27035,27036,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,
+27047,27048,27049,27050,27051,27052,27053,27054,27055,27056,27057,27058,
+27059,27060,27061,27062,27063,27064,27065,27066,27067,27068,27069,27070,
+27071,27072,27073,27074,27075,27076,27077,27078,27079,27080,27081,27082,
+27083,27084,27085,27086,27087,27088,27089,27090,27091,27092,27093,27094,
+27095,27096,27097,27098,27099,27100,27101,27102,27103,27104,27105,27106,
+27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27117,27118,
+27119,27120,27121,27122,27123,27124,27125,27126,27127,27128,27129,27130,
+27131,27132,27133,27134,27135,27136,27137,27138,27139,27140,27141,27142,
+27143,27144,27145,27146,27147,27148,27149,27150,27151,27152,27153,27154,
+27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,27165,27166,
+27167,27168,27169,27170,27171,27172,27173,27174,27175,27176,27177,27178,
+27179,27180,27181,27182,27183,27184,27185,27186,27187,27188,27189,27190,
+27191,27192,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,
+27203,27204,27205,27206,27207,27208,27209,27210,27211,27212,27213,27214,
+27215,27216,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,
+27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,
+27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27249,27250,
+27251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262,
+27263,27264,27265,27266,27267,27268,27269,27270,27271,27272,27273,27274,
+27275,27276,27277,27278,27279,27280,27281,27282,27283,27284,27285,27286,
+27287,27288,27289,27290,27291,27292,27293,27294,27295,27296,27297,27298,
+27299,27300,27301,27302,27303,27304,27305,27306,27307,27308,27309,27310,
+27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,
+27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,
+27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,
+27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,
+27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,
+27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,
+27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,
+27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,
+27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,
+27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,27430,
+27431,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27442,
+27443,27444,27445,27446,27447,27448,27449,27450,27451,27452,27453,27454,
+27455,27456,27457,27458,27459,27460,27461,27462,27463,27464,27465,27466,
+27467,27468,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,
+27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,
+27491,27492,27493,27494,27495,27496,27497,27498,27499,27500,27501,27502,
+27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514,
+27515,27516,27517,27518,27519,27520,27521,27522,27523,27524,27525,27526,
+27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,
+27539,27540,27541,27542,27543,27544,27545,27546,27547,27548,27549,27550,
+27551,27552,27553,27554,27555,27556,27557,27558,27559,27560,27561,27562,
+27563,27564,27565,27566,27567,27568,27569,27570,27571,27572,27573,27574,
+27575,27576,27577,27578,27579,27580,27581,27582,27583,27584,27585,27586,
+27587,27588,27589,27590,27591,27592,27593,27594,27595,27596,27597,27598,
+27599,27600,27601,27602,27603,27604,27605,27606,27607,27608,27609,27610,
+27611,27612,27613,27614,27615,27616,27617,27618,27619,27620,27621,27622,
+27623,27624,27625,27626,27627,27628,27629,27630,27631,27632,27633,27634,
+27635,27636,27637,27638,27639,27640,27641,27642,27643,27644,27645,27646,
+27647,27648,27649,27650,27651,27652,27653,27654,27655,27656,27657,27658,
+27659,27660,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,
+27671,27672,27673,27674,27675,27676,27677,27678,27679,27680,27681,27682,
+27683,27684,27685,27686,27687,27688,27689,27690,27691,27692,27693,27694,
+27695,27696,27697,27698,27699,27700,27701,27702,27703,27704,27705,27706,
+27707,27708,27709,27710,27711,27712,27713,27714,27715,27716,27717,27718,
+27719,27720,27721,27722,27723,27724,27725,27726,27727,27728,27729,27730,
+27731,27732,27733,27734,27735,27736,27737,27738,27739,27740,27741,27742,
+27743,27744,27745,27746,27747,27748,27749,27750,27751,27752,27753,27754,
+27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,27766,
+27767,27768,27769,27770,27771,27772,27773,27774,27775,27776,27777,27778,
+27779,27780,27781,27782,27783,27784,27785,27786,27787,27788,27789,27790,
+27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,
+27803,27804,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,
+27815,27816,27817,27818,27819,27820,27821,27822,27823,27824,27825,27826,
+27827,27828,27829,27830,27831,27832,27833,27834,27835,27836,27837,27838,
+27839,27840,27841,27842,27843,27844,27845,27846,27847,27848,27849,27850,
+27851,27852,27853,27854,27855,27856,27857,27858,27859,27860,27861,27862,
+27863,27864,27865,27866,27867,27868,27869,27870,27871,27872,27873,27874,
+27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,
+27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,
+27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,
+27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,
+27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,27933,27934,
+27935,27936,27937,27938,27939,27940,27941,27942,27943,27944,27945,27946,
+27947,27948,27949,27950,27951,27952,27953,27954,27955,27956,27957,27958,
+27959,27960,27961,27962,27963,27964,27965,27966,27967,27968,27969,27970,
+27971,27972,27973,27974,27975,27976,27977,27978,27979,27980,27981,27982,
+27983,27984,27985,27986,27987,27988,27989,27990,27991,27992,27993,27994,
+27995,27996,27997,27998,27999,28000,28001,28002,28003,28004,28005,28006,
+28007,28008,28009,28010,28011,28012,28013,28014,28015,28016,28017,28018,
+28019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030,
+28031,28032,28033,28034,28035,28036,28037,28038,28039,28040,28041,28042,
+28043,28044,28045,28046,28047,28048,28049,28050,28051,28052,28053,28054,
+28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,
+28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,
+28079,28080,28081,28082,28083,28084,28085,28086,28087,28088,28089,28090,
+28091,28092,28093,28094,28095,28096,28097,28098,28099,28100,28101,28102,
+28103,28104,28105,28106,28107,28108,28109,28110,28111,28112,28113,28114,
+28115,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,28126,
+28127,28128,28129,28130,28131,28132,28133,28134,28135,28136,28137,28138,
+28139,28140,28141,28142,28143,28144,28145,28146,28147,28148,28149,28150,
+28151,28152,28153,28154,28155,28156,28157,28158,28159,28160,28161,28162,
+28163,28164,28165,28166,28167,28168,28169,28170,28171,28172,28173,28174,
+28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,
+28187,28188,28189,28190,28191,28192,28193,28194,28195,28196,28197,28198,
+28199,28200,28201,28202,28203,28204,28205,28206,28207,28208,28209,28210,
+28211,28212,28213,28214,28215,28216,28217,28218,28219,28220,28221,28222,
+28223,28224,28225,28226,28227,28228,28229,28230,28231,28232,28233,28234,
+28235,28236,28237,28238,28239,28240,28241,28242,28243,28244,28245,28246,
+28247,28248,28249,28250,28251,28252,28253,28254,28255,28256,28257,28258,
+28259,28260,28261,28262,28263,28264,28265,28266,28267,28268,28269,28270,
+28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,
+28283,28284,28285,28286,28287,28288,28289,28290,28291,28292,28293,28294,
+28295,28296,28297,28298,28299,28300,28301,28302,28303,28304,28305,28306,
+28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,
+28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,
+28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,28341,28342,
+28343,28344,28345,28346,28347,28348,28349,28350,28351,28352,28353,28354,
+28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,
+28367,28368,28369,28370,28371,28372,28373,28374,28375,28376,28377,28378,
+28379,28380,28381,28382,28383,28384,28385,28386,28387,28388,28389,28390,
+28391,28392,28393,28394,28395,28396,28397,28398,28399,28400,28401,28402,
+28403,28404,28405,28406,28407,28408,28409,28410,28411,28412,28413,28414,
+28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,
+28427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438,
+28439,28440,28441,28442,28443,28444,28445,28446,28447,28448,28449,28450,
+28451,28452,28453,28454,28455,28456,28457,28458,28459,28460,28461,28462,
+28463,28464,28465,28466,28467,28468,28469,28470,28471,28472,28473,28474,
+28475,28476,28477,28478,28479,28480,28481,28482,28483,28484,28485,28486,
+28487,28488,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,
+28499,28500,28501,28502,28503,28504,28505,28506,28507,28508,28509,28510,
+28511,28512,28513,28514,28515,28516,28517,28518,28519,28520,28521,28522,
+28523,28524,28525,28526,28527,28528,28529,28530,28531,28532,28533,28534,
+28535,28536,28537,28538,28539,28540,28541,28542,28543,28544,28545,28546,
+28547,28548,28549,28550,28551,28552,28553,28554,28555,28556,28557,28558,
+28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,
+28571,28572,28573,28574,28575,28576,28577,28578,28579,28580,28581,28582,
+28583,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,
+28595,28596,28597,28598,28599,28600,28601,28602,28603,28604,28605,28606,
+28607,28608,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,
+28619,28620,28621,28622,28623,28624,28625,28626,28627,28628,28629,28630,
+28631,28632,28633,28634,28635,28636,28637,28638,28639,28640,28641,28642,
+28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28654,
+28655,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,
+28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,
+28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,28690,
+28691,28692,28693,28694,28695,28696,28697,28698,28699,28700,28701,28702,
+28703,28704,28705,28706,28707,28708,28709,28710,28711,28712,28713,28714,
+28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28725,28726,
+28727,28728,28729,28730,28731,28732,28733,28734,28735,28736,28737,28738,
+28739,28740,28741,28742,28743,28744,28745,28746,28747,28748,28749,28750,
+28751,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,
+28763,28764,28765,28766,28767,28768,28769,28770,28771,28772,28773,28774,
+28775,28776,28777,28778,28779,28780,28781,28782,28783,28784,28785,28786,
+28787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798,
+28799,28800,28801,28802,28803,28804,28805,28806,28807,28808,28809,28810,
+28811,28812,28813,28814,28815,28816,28817,28818,28819,28820,28821,28822,
+28823,28824,28825,28826,28827,28828,28829,28830,28831,28832,28833,28834,
+28835,28836,28837,28838,28839,28840,28841,28842,28843,28844,28845,28846,
+28847,28848,28849,28850,28851,28852,28853,28854,28855,28856,28857,28858,
+28859,28860,28861,28862,28863,28864,28865,28866,28867,28868,28869,28870,
+28871,28872,28873,28874,28875,28876,28877,28878,28879,28880,28881,28882,
+28883,28884,28885,28886,28887,28888,28889,28890,28891,28892,28893,28894,
+28895,28896,28897,28898,28899,28900,28901,28902,28903,28904,28905,28906,
+28907,28908,28909,28910,28911,28912,28913,28914,28915,28916,28917,28918,
+28919,28920,28921,28922,28923,28924,28925,28926,28927,28928,28929,28930,
+28931,28932,28933,28934,28935,28936,28937,28938,28939,28940,28941,28942,
+28943,28944,28945,28946,28947,28948,28949,28950,28951,28952,28953,28954,
+28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28966,
+28967,28968,28969,28970,28971,28972,28973,28974,28975,28976,28977,28978,
+28979,28980,28981,28982,28983,28984,28985,28986,28987,28988,28989,28990,
+28991,28992,28993,28994,28995,28996,28997,28998,28999,29000,29001,29002,
+29003,29004,29005,29006,29007,29008,29009,29010,29011,29012,29013,29014,
+29015,29016,29017,29018,29019,29020,29021,29022,29023,29024,29025,29026,
+29027,29028,29029,29030,29031,29032,29033,29034,29035,29036,29037,29038,
+29039,29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050,
+29051,29052,29053,29054,29055,29056,29057,29058,29059,29060,29061,29062,
+29063,29064,29065,29066,29067,29068,29069,29070,29071,29072,29073,29074,
+29075,29076,29077,29078,29079,29080,29081,29082,29083,29084,29085,29086,
+29087,29088,29089,29090,29091,29092,29093,29094,29095,29096,29097,29098,
+29099,29100,29101,29102,29103,29104,29105,29106,29107,29108,29109,29110,
+29111,29112,29113,29114,29115,29116,29117,29118,29119,29120,29121,29122,
+29123,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29134,
+29135,29136,29137,29138,29139,29140,29141,29142,29143,29144,29145,29146,
+29147,29148,29149,29150,29151,29152,29153,29154,29155,29156,29157,29158,
+29159,29160,29161,29162,29163,29164,29165,29166,29167,29168,29169,29170,
+29171,29172,29173,29174,29175,29176,29177,29178,29179,29180,29181,29182,
+29183,29184,29185,29186,29187,29188,29189,29190,29191,29192,29193,29194,
+29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,
+29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,
+29219,29220,29221,29222,29223,29224,29225,29226,29227,29228,29229,29230,
+29231,29232,29233,29234,29235,29236,29237,29238,29239,29240,29241,29242,
+29243,29244,29245,29246,29247,29248,29249,29250,29251,29252,29253,29254,
+29255,29256,29257,29258,29259,29260,29261,29262,29263,29264,29265,29266,
+29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,29277,29278,
+29279,29280,29281,29282,29283,29284,29285,29286,29287,29288,29289,29290,
+29291,29292,29293,29294,29295,29296,29297,29298,29299,29300,29301,29302,
+29303,29304,29305,29306,29307,29308,29309,29310,29311,29312,29313,29314,
+29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,
+29327,29328,29329,29330,29331,29332,29333,29334,29335,29336,29337,29338,
+29339,29340,29341,29342,29343,29344,29345,29346,29347,29348,29349,29350,
+29351,29352,29353,29354,29355,29356,29357,29358,29359,29360,29361,29362,
+29363,29364,29365,29366,29367,29368,29369,29370,29371,29372,29373,29374,
+29375,29376,29377,29378,29379,29380,29381,29382,29383,29384,29385,29386,
+29387,29388,29389,29390,29391,29392,29393,29394,29395,29396,29397,29398,
+29399,29400,29401,29402,29403,29404,29405,29406,29407,29408,29409,29410,
+29411,29412,29413,29414,29415,29416,29417,29418,29419,29420,29421,29422,
+29423,29424,29425,29426,29427,29428,29429,29430,29431,29432,29433,29434,
+29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,
+29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,
+29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,
+29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,
+29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,
+29495,29496,29497,29498,29499,29500,29501,29502,29503,29504,29505,29506,
+29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29517,29518,
+29519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530,
+29531,29532,29533,29534,29535,29536,29537,29538,29539,29540,29541,29542,
+29543,29544,29545,29546,29547,29548,29549,29550,29551,29552,29553,29554,
+29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566,
+29567,29568,29569,29570,29571,29572,29573,29574,29575,29576,29577,29578,
+29579,29580,29581,29582,29583,29584,29585,29586,29587,29588,29589,29590,
+29591,29592,29593,29594,29595,29596,29597,29598,29599,29600,29601,29602,
+29603,29604,29605,29606,29607,29608,29609,29610,29611,29612,29613,29614,
+29615,29616,29617,29618,29619,29620,29621,29622,29623,29624,29625,29626,
+29627,29628,29629,29630,29631,29632,29633,29634,29635,29636,29637,29638,
+29639,29640,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,
+29651,29652,29653,29654,29655,29656,29657,29658,29659,29660,29661,29662,
+29663,29664,29665,29666,29667,29668,29669,29670,29671,29672,29673,29674,
+29675,29676,29677,29678,29679,29680,29681,29682,29683,29684,29685,29686,
+29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,
+29699,29700,29701,29702,29703,29704,29705,29706,29707,29708,29709,29710,
+29711,29712,29713,29714,29715,29716,29717,29718,29719,29720,29721,29722,
+29723,29724,29725,29726,29727,29728,29729,29730,29731,29732,29733,29734,
+29735,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29746,
+29747,29748,29749,29750,29751,29752,29753,29754,29755,29756,29757,29758,
+29759,29760,29761,29762,29763,29764,29765,29766,29767,29768,29769,29770,
+29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29781,29782,
+29783,29784,29785,29786,29787,29788,29789,29790,29791,29792,29793,29794,
+29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29805,29806,
+29807,29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818,
+29819,29820,29821,29822,29823,29824,29825,29826,29827,29828,29829,29830,
+29831,29832,29833,29834,29835,29836,29837,29838,29839,29840,29841,29842,
+29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,29854,
+29855,29856,29857,29858,29859,29860,29861,29862,29863,29864,29865,29866,
+29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,
+29879,29880,29881,29882,29883,29884,29885,29886,29887,29888,29889,29890,
+29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,
+29903,29904,29905,29906,29907,29908,29909,29910,29911,29912,29913,29914,
+29915,29916,29917,29918,29919,29920,29921,29922,29923,29924,29925,29926,
+29927,29928,29929,29930,29931,29932,29933,29934,29935,29936,29937,29938,
+29939,29940,29941,29942,29943,29944,29945,29946,29947,29948,29949,29950,
+29951,29952,29953,29954,29955,29956,29957,29958,29959,29960,29961,29962,
+29963,29964,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,
+29975,29976,29977,29978,29979,29980,29981,29982,29983,29984,29985,29986,
+29987,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,
+29999,30000,30001,30002,30003,30004,30005,30006,30007,30008,30009,30010,
+30011,30012,30013,30014,30015,30016,30017,30018,30019,30020,30021,30022,
+30023,30024,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,
+30035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046,
+30047,30048,30049,30050,30051,30052,30053,30054,30055,30056,30057,30058,
+30059,30060,30061,30062,30063,30064,30065,30066,30067,30068,30069,30070,
+30071,30072,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,
+30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,
+30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,
+30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,
+30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,
+30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,
+30143,30144,30145,30146,30147,30148,30149,30150,30151,30152,30153,30154,
+30155,30156,30157,30158,30159,30160,30161,30162,30163,30164,30165,30166,
+30167,30168,30169,30170,30171,30172,30173,30174,30175,30176,30177,30178,
+30179,30180,30181,30182,30183,30184,30185,30186,30187,30188,30189,30190,
+30191,30192,30193,30194,30195,30196,30197,30198,30199,30200,30201,30202,
+30203,30204,30205,30206,30207,30208,30209,30210,30211,30212,30213,30214,
+30215,30216,30217,30218,30219,30220,30221,30222,30223,30224,30225,30226,
+30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,
+30239,30240,30241,30242,30243,30244,30245,30246,30247,30248,30249,30250,
+30251,30252,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,
+30263,30264,30265,30266,30267,30268,30269,30270,30271,30272,30273,30274,
+30275,30276,30277,30278,30279,30280,30281,30282,30283,30284,30285,30286,
+30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,30297,30298,
+30299,30300,30301,30302,30303,30304,30305,30306,30307,30308,30309,30310,
+30311,30312,30313,30314,30315,30316,30317,30318,30319,30320,30321,30322,
+30323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334,
+30335,30336,30337,30338,30339,30340,30341,30342,30343,30344,30345,30346,
+30347,30348,30349,30350,30351,30352,30353,30354,30355,30356,30357,30358,
+30359,30360,30361,30362,30363,30364,30365,30366,30367,30368,30369,30370,
+30371,30372,30373,30374,30375,30376,30377,30378,30379,30380,30381,30382,
+30383,30384,30385,30386,30387,30388,30389,30390,30391,30392,30393,30394,
+30395,30396,30397,30398,30399,30400,30401,30402,30403,30404,30405,30406,
+30407,30408,30409,30410,30411,30412,30413,30414,30415,30416,30417,30418,
+30419,30420,30421,30422,30423,30424,30425,30426,30427,30428,30429,30430,
+30431,30432,30433,30434,30435,30436,30437,30438,30439,30440,30441,30442,
+30443,30444,30445,30446,30447,30448,30449,30450,30451,30452,30453,30454,
+30455,30456,30457,30458,30459,30460,30461,30462,30463,30464,30465,30466,
+30467,30468,30469,30470,30471,30472,30473,30474,30475,30476,30477,30478,
+30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30489,30490,
+30491,30492,30493,30494,30495,30496,30497,30498,30499,30500,30501,30502,
+30503,30504,30505,30506,30507,30508,30509,30510,30511,30512,30513,30514,
+30515,30516,30517,30518,30519,30520,30521,30522,30523,30524,30525,30526,
+30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,
+30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,
+30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,
+30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,
+30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586,
+30587,30588,30589,30590,30591,30592,30593,30594,30595,30596,30597,30598,
+30599,30600,30601,30602,30603,30604,30605,30606,30607,30608,30609,30610,
+30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,
+30623,30624,30625,30626,30627,30628,30629,30630,30631,30632,30633,30634,
+30635,30636,30637,30638,30639,30640,30641,30642,30643,30644,30645,30646,
+30647,30648,30649,30650,30651,30652,30653,30654,30655,30656,30657,30658,
+30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30669,30670,
+30671,30672,30673,30674,30675,30676,30677,30678,30679,30680,30681,30682,
+30683,30684,30685,30686,30687,30688,30689,30690,30691,30692,30693,30694,
+30695,30696,30697,30698,30699,30700,30701,30702,30703,30704,30705,30706,
+30707,30708,30709,30710,30711,30712,30713,30714,30715,30716,30717,30718,
+30719,30720,30721,30722,30723,30724,30725,30726,30727,30728,30729,30730,
+30731,30732,30733,30734,30735,30736,30737,30738,30739,30740,30741,30742,
+30743,30744,30745,30746,30747,30748,30749,30750,30751,30752,30753,30754,
+30755,30756,30757,30758,30759,30760,30761,30762,30763,30764,30765,30766,
+30767,30768,30769,30770,30771,30772,30773,30774,30775,30776,30777,30778,
+30779,30780,30781,30782,30783,30784,30785,30786,30787,30788,30789,30790,
+30791,30792,30793,30794,30795,30796,30797,30798,30799,30800,30801,30802,
+30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,30813,30814,
+30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30826,
+30827,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,30838,
+30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,30849,30850,
+30851,30852,30853,30854,30855,30856,30857,30858,30859,30860,30861,30862,
+30863,30864,30865,30866,30867,30868,30869,30870,30871,30872,30873,30874,
+30875,30876,30877,30878,30879,30880,30881,30882,30883,30884,30885,30886,
+30887,30888,30889,30890,30891,30892,30893,30894,30895,30896,30897,30898,
+30899,30900,30901,30902,30903,30904,30905,30906,30907,30908,30909,30910,
+30911,30912,30913,30914,30915,30916,30917,30918,30919,30920,30921,30922,
+30923,30924,30925,30926,30927,30928,30929,30930,30931,30932,30933,30934,
+30935,30936,30937,30938,30939,30940,30941,30942,30943,30944,30945,30946,
+30947,30948,30949,30950,30951,30952,30953,30954,30955,30956,30957,30958,
+30959,30960,30961,30962,30963,30964,30965,30966,30967,30968,30969,30970,
+30971,30972,30973,30974,30975,30976,30977,30978,30979,30980,30981,30982,
+30983,30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,
+30995,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31006,
+31007,31008,31009,31010,31011,31012,31013,31014,31015,31016,31017,31018,
+31019,31020,31021,31022,31023,31024,31025,31026,31027,31028,31029,31030,
+31031,31032,31033,31034,31035,31036,31037,31038,31039,31040,31041,31042,
+31043,31044,31045,31046,31047,31048,31049,31050,31051,31052,31053,31054,
+31055,31056,31057,31058,31059,31060,31061,31062,31063,31064,31065,31066,
+31067,31068,31069,31070,31071,31072,31073,31074,31075,31076,31077,31078,
+31079,31080,31081,31082,31083,31084,31085,31086,31087,31088,31089,31090,
+31091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102,
+31103,31104,31105,31106,31107,31108,31109,31110,31111,31112,31113,31114,
+31115,31116,31117,31118,31119,31120,31121,31122,31123,31124,31125,31126,
+31127,31128,31129,31130,31131,31132,31133,31134,31135,31136,31137,31138,
+31139,31140,31141,31142,31143,31144,31145,31146,31147,31148,31149,31150,
+31151,31152,31153,31154,31155,31156,31157,31158,31159,31160,31161,31162,
+31163,31164,31165,31166,31167,31168,31169,31170,31171,31172,31173,31174,
+31175,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,
+31187,31188,31189,31190,31191,31192,31193,31194,31195,31196,31197,31198,
+31199,31200,31201,31202,31203,31204,31205,31206,31207,31208,31209,31210,
+31211,31212,31213,31214,31215,31216,31217,31218,31219,31220,31221,31222,
+31223,31224,31225,31226,31227,31228,31229,31230,31231,31232,31233,31234,
+31235,31236,31237,31238,31239,31240,31241,31242,31243,31244,31245,31246,
+31247,31248,31249,31250,31251,31252,31253,31254,31255,31256,31257,31258,
+31259,31260,31261,31262,31263,31264,31265,31266,31267,31268,31269,31270,
+31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,
+31283,31284,31285,31286,31287,31288,31289,31290,31291,31292,31293,31294,
+31295,31296,31297,31298,31299,31300,31301,31302,31303,31304,31305,31306,
+31307,31308,31309,31310,31311,31312,31313,31314,31315,31316,31317,31318,
+31319,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,
+31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,
+31343,31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354,
+31355,31356,31357,31358,31359,31360,31361,31362,31363,31364,31365,31366,
+31367,31368,31369,31370,31371,31372,31373,31374,31375,31376,31377,31378,
+31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,31389,31390,
+31391,31392,31393,31394,31395,31396,31397,31398,31399,31400,31401,31402,
+31403,31404,31405,31406,31407,31408,31409,31410,31411,31412,31413,31414,
+31415,31416,31417,31418,31419,31420,31421,31422,31423,31424,31425,31426,
+31427,31428,31429,31430,31431,31432,31433,31434,31435,31436,31437,31438,
+31439,31440,31441,31442,31443,31444,31445,31446,31447,31448,31449,31450,
+31451,31452,31453,31454,31455,31456,31457,31458,31459,31460,31461,31462,
+31463,31464,31465,31466,31467,31468,31469,31470,31471,31472,31473,31474,
+31475,31476,31477,31478,31479,31480,31481,31482,31483,31484,31485,31486,
+31487,31488,31489,31490,31491,31492,31493,31494,31495,31496,31497,31498,
+31499,31500,31501,31502,31503,31504,31505,31506,31507,31508,31509,31510,
+31511,31512,31513,31514,31515,31516,31517,31518,31519,31520,31521,31522,
+31523,31524,31525,31526,31527,31528,31529,31530,31531,31532,31533,31534,
+31535,31536,31537,31538,31539,31540,31541,31542,31543,31544,31545,31546,
+31547,31548,31549,31550,31551,31552,31553,31554,31555,31556,31557,31558,
+31559,31560,31561,31562,31563,31564,31565,31566,31567,31568,31569,31570,
+31571,31572,31573,31574,31575,31576,31577,31578,31579,31580,31581,31582,
+31583,31584,31585,31586,31587,31588,31589,31590,31591,31592,31593,31594,
+31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,
+31607,31608,31609,31610,31611,31612,31613,31614,31615,31616,31617,31618,
+31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,31629,31630,
+31631,31632,31633,31634,31635,31636,31637,31638,31639,31640,31641,31642,
+31643,31644,31645,31646,31647,31648,31649,31650,31651,31652,31653,31654,
+31655,31656,31657,31658,31659,31660,31661,31662,31663,31664,31665,31666,
+31667,31668,31669,31670,31671,31672,31673,31674,31675,31676,31677,31678,
+31679,31680,31681,31682,31683,31684,31685,31686,31687,31688,31689,31690,
+31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,31702,
+31703,31704,31705,31706,31707,31708,31709,31710,31711,31712,31713,31714,
+31715,31716,31717,31718,31719,31720,31721,31722,31723,31724,31725,31726,
+31727,31728,31729,31730,31731,31732,31733,31734,31735,31736,31737,31738,
+31739,31740,31741,31742,31743,31744,31745,31746,31747,31748,31749,31750,
+31751,31752,31753,31754,31755,31756,31757,31758,31759,31760,31761,31762,
+31763,31764,31765,31766,31767,31768,31769,31770,31771,31772,31773,31774,
+31775,31776,31777,31778,31779,31780,31781,31782,31783,31784,31785,31786,
+31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,
+31799,31800,31801,31802,31803,31804,31805,31806,31807,31808,31809,31810,
+31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31821,31822,
+31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,
+31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,
+31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,
+31859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870,
+31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31881,31882,
+31883,31884,31885,31886,31887,31888,31889,31890,31891,31892,31893,31894,
+31895,31896,31897,31898,31899,31900,31901,31902,31903,31904,31905,31906,
+31907,31908,31909,31910,31911,31912,31913,31914,31915,31916,31917,31918,
+31919,31920,31921,31922,31923,31924,31925,31926,31927,31928,31929,31930,
+31931,31932,31933,31934,31935,31936,31937,31938,31939,31940,31941,31942,
+31943,31944,31945,31946,31947,31948,31949,31950,31951,31952,31953,31954,
+31955,31956,31957,31958,31959,31960,31961,31962,31963,31964,31965,31966,
+31967,31968,31969,31970,31971,31972,31973,31974,31975,31976,31977,31978,
+31979,31980,31981,31982,31983,31984,31985,31986,31987,31988,31989,31990,
+31991,31992,31993,31994,31995,31996,31997,31998,31999,32000,32001,32002,
+32003,32004,32005,32006,32007,32008,32009,32010,32011,32012,32013,32014,
+32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,
+32027,32028,32029,32030,32031,32032,32033,32034,32035,32036,32037,32038,
+32039,32040,32041,32042,32043,32044,32045,32046,32047,32048,32049,32050,
+32051,32052,32053,32054,32055,32056,32057,32058,32059,32060,32061,32062,
+32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,
+32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,
+32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,
+32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32110,
+32111,32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122,
+32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,
+32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,
+32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158,
+32159,32160,32161,32162,32163,32164,32165,32166,32167,32168,32169,32170,
+32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,32181,32182,
+32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,
+32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,
+32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,
+32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,
+32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,
+32243,32244,32245,32246,32247,32248,32249,32250,32251,32252,32253,32254,
+32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,
+32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,
+32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,
+32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,
+32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,
+32315,32316,32317,32318,32319,32320,32321,32322,32323,32324,32325,32326,
+32327,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,
+32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,32350,
+32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,
+32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,
+32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32386,
+32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,
+32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,
+32411,32412,32413,32414,32415,32416,32417,32418,32419,32420,32421,32422,
+32423,32424,32425,32426,32427,32428,32429,32430,32431,32432,32433,32434,
+32435,32436,32437,32438,32439,32440,32441,32442,32443,32444,32445,32446,
+32447,32448,32449,32450,32451,32452,32453,32454,32455,32456,32457,32458,
+32459,32460,32461,32462,32463,32464,32465,32466,32467,32468,32469,32470,
+32471,32472,32473,32474,32475,32476,32477,32478,32479,32480,32481,32482,
+32483,32484,32485,32486,32487,32488,32489,32490,32491,32492,32493,32494,
+32495,32496,32497,32498,32499,32500,32501,32502,32503,32504,32505,32506,
+32507,32508,32509,32510,32511,32512,32513,32514,32515,32516,32517,32518,
+32519,32520,32521,32522,32523,32524,32525,32526,32527,32528,32529,32530,
+32531,32532,32533,32534,32535,32536,32537,32538,32539,32540,32541,32542,
+32543,32544,32545,32546,32547,32548,32549,32550,32551,32552,32553,32554,
+32555,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,
+32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,
+32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,
+32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,
+32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,
+32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,
+32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,
+32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,
+32651,32652,32653,32654,32655,32656,32657,32658,32659,32660,32661,32662,
+32663,32664,32665,32666,32667,32668,32669,32670,32671,32672,32673,32674,
+32675,32676,32677,32678,32679,32680,32681,32682,32683,32684,32685,32686,
+32687,32688,32689,32690,32691,32692,32693,32694,32695,32696,32697,32698,
+32699,32700,32701,32702,32703,32704,32705,32706,32707,32708,32709,32710,
+32711,32712,32713,32714,32715,32716,32717,32718,32719,32720,32721,32722,
+32723,32724,32725,32726,32727,32728,32729,32730,32731,32732,32733,32734,
+32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,32745,32746,
+32747,32748,32749,32750,32751,32752,32753,32754,32755,32756,32757,32758,
+32759,32760,32761,32762,32763,32764,32765,32766,32767,32768L,32769L,32770L,
+32771L,32772L,32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,
+32781L,32782L,32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,
+32791L,32792L,32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,
+32801L,32802L,32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,
+32811L,32812L,32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,
+32821L,32822L,32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,
+32831L,32832L,32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,
+32841L,32842L,32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,
+32851L,32852L,32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,
+32861L,32862L,32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,
+32871L,32872L,32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,
+32881L,32882L,32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,
+32891L,32892L,32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,
+32901L,32902L,32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,
+32911L,32912L,32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,
+32921L,32922L,32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,
+32931L,32932L,32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,
+32941L,32942L,32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,
+32951L,32952L,32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,
+32961L,32962L,32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,
+32971L,32972L,32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,
+32981L,32982L,32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,
+32991L,32992L,32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,
+33001L,33002L,33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,
+33011L,33012L,33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,
+33021L,33022L,33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,
+33031L,33032L,33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,
+33041L,33042L,33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,
+33051L,33052L,33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,
+33061L,33062L,33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,
+33071L,33072L,33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,
+33081L,33082L,33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,
+33091L,33092L,33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,
+33101L,33102L,33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,
+33111L,33112L,33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,
+33121L,33122L,33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,
+33131L,33132L,33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,
+33141L,33142L,33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,
+33151L,33152L,33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,
+33161L,33162L,33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,
+33171L,33172L,33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,
+33181L,33182L,33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,
+33191L,33192L,33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,
+33201L,33202L,33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,
+33211L,33212L,33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,
+33221L,33222L,33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,
+33231L,33232L,33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,
+33241L,33242L,33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,
+33251L,33252L,33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,
+33261L,33262L,33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,
+33271L,33272L,33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,
+33281L,33282L,33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,
+33291L,33292L,33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,
+33301L,33302L,33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,
+33311L,33312L,33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,
+33321L,33322L,33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,
+33331L,33332L,33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,
+33341L,33342L,33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,
+33351L,33352L,33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,
+33361L,33362L,33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,
+33371L,33372L,33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,
+33381L,33382L,33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,
+33391L,33392L,33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,
+33401L,33402L,33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,
+33411L,33412L,33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,
+33421L,33422L,33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,
+33431L,33432L,33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,
+33441L,33442L,33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,
+33451L,33452L,33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,
+33461L,33462L,33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,
+33471L,33472L,33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,
+33481L,33482L,33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,
+33491L,33492L,33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,
+33501L,33502L,33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,
+33511L,33512L,33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,
+33521L,33522L,33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,
+33531L,33532L,33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,
+33541L,33542L,33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,
+33551L,33552L,33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,
+33561L,33562L,33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,
+33571L,33572L,33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,
+33581L,33582L,33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,
+33591L,33592L,33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,
+33601L,33602L,33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,
+33611L,33612L,33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,
+33621L,33622L,33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,
+33631L,33632L,33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,
+33641L,33642L,33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,
+33651L,33652L,33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,
+33661L,33662L,33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,
+33671L,33672L,33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,
+33681L,33682L,33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,
+33691L,33692L,33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,
+33701L,33702L,33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,
+33711L,33712L,33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,
+33721L,33722L,33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,
+33731L,33732L,33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,
+33741L,33742L,33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,
+33751L,33752L,33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,
+33761L,33762L,33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,
+33771L,33772L,33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,
+33781L,33782L,33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,
+33791L,33792L,33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,
+33801L,33802L,33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,
+33811L,33812L,33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,
+33821L,33822L,33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,
+33831L,33832L,33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,
+33841L,33842L,33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,
+33851L,33852L,33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,
+33861L,33862L,33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,
+33871L,33872L,33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,
+33881L,33882L,33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,
+33891L,33892L,33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,
+33901L,33902L,33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,
+33911L,33912L,33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,
+33921L,33922L,33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,
+33931L,33932L,33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,
+33941L,33942L,33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,
+33951L,33952L,33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,
+33961L,33962L,33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,
+33971L,33972L,33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,
+33981L,33982L,33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,
+33991L,33992L,33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,
+34001L,34002L,34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,
+34011L,34012L,34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,
+34021L,34022L,34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,
+34031L,34032L,34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,
+34041L,34042L,34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,
+34051L,34052L,34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,
+34061L,34062L,34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,
+34071L,34072L,34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,
+34081L,34082L,34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,
+34091L,34092L,34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,
+34101L,34102L,34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,
+34111L,34112L,34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,
+34121L,34122L,34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,
+34131L,34132L,34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,
+34141L,34142L,34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,
+34151L,34152L,34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,
+34161L,34162L,34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,
+34171L,34172L,34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,
+34181L,34182L,34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,
+34191L,34192L,34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,
+34201L,34202L,34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,
+34211L,34212L,34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,
+34221L,34222L,34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,
+34231L,34232L,34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,
+34241L,34242L,34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,
+34251L,34252L,34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,
+34261L,34262L,34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,
+34271L,34272L,34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,
+34281L,34282L,34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,
+34291L,34292L,34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,
+34301L,34302L,34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,
+34311L,34312L,34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,
+34321L,34322L,34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,
+34331L,34332L,34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,
+34341L,34342L,34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,
+34351L,34352L,34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,
+34361L,34362L,34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,
+34371L,34372L,34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,
+34381L,34382L,34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,
+34391L,34392L,34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,
+34401L,34402L,34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,
+34411L,34412L,34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,
+34421L,34422L,34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,
+34431L,34432L,34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,
+34441L,34442L,34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,
+34451L,34452L,34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,
+34461L,34462L,34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,
+34471L,34472L,34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,
+34481L,34482L,34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,
+34491L,34492L,34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,
+34501L,34502L,34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,
+34511L,34512L,34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,
+34521L,34522L,34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,
+34531L,34532L,34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,
+34541L,34542L,34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,
+34551L,34552L,34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,
+34561L,34562L,34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,
+34571L,34572L,34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,
+34581L,34582L,34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,
+34591L,34592L,34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,
+34601L,34602L,34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,
+34611L,34612L,34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,
+34621L,34622L,34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,
+34631L,34632L,34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,
+34641L,34642L,34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,
+34651L,34652L,34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,
+34661L,34662L,34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,
+34671L,34672L,34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,
+34681L,34682L,34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,
+34691L,34692L,34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,
+34701L,34702L,34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,
+34711L,34712L,34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,
+34721L,34722L,34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,
+34731L,34732L,34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,
+34741L,34742L,34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,
+34751L,34752L,34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,
+34761L,34762L,34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,
+34771L,34772L,34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,
+34781L,34782L,34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,
+34791L,34792L,34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,
+34801L,34802L,34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,
+34811L,34812L,34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,
+34821L,34822L,34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,
+34831L,34832L,34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,
+34841L,34842L,34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,
+34851L,34852L,34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,
+34861L,34862L,34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,
+34871L,34872L,34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,
+34881L,34882L,34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,
+34891L,34892L,34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,
+34901L,34902L,34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,
+34911L,34912L,34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,
+34921L,34922L,34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,
+34931L,34932L,34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,
+34941L,34942L,34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,
+34951L,34952L,34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,
+34961L,34962L,34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,
+34971L,34972L,34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,
+34981L,34982L,34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,
+34991L,34992L,34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,
+35001L,35002L,35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,
+35011L,35012L,35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,
+35021L,35022L,35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,
+35031L,35032L,35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,
+35041L,35042L,35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,
+35051L,35052L,35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,
+35061L,35062L,35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,
+35071L,35072L,35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,
+35081L,35082L,35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,
+35091L,35092L,35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,
+35101L,35102L,35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,
+35111L,35112L,35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,
+35121L,35122L,35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,
+35131L,35132L,35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,
+35141L,35142L,35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,
+35151L,35152L,35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,
+35161L,35162L,35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,
+35171L,35172L,35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,
+35181L,35182L,35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,
+35191L,35192L,35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,
+35201L,35202L,35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,
+35211L,35212L,35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,
+35221L,35222L,35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,
+35231L,35232L,35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,
+35241L,35242L,35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,
+35251L,35252L,35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,
+35261L,35262L,35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,
+35271L,35272L,35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,
+35281L,35282L,35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,
+35291L,35292L,35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,
+35301L,35302L,35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,
+35311L,35312L,35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,
+35321L,35322L,35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,
+35331L,35332L,35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,
+35341L,35342L,35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,
+35351L,35352L,35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,
+35361L,35362L,35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,
+35371L,35372L,35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,
+35381L,35382L,35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,
+35391L,35392L,35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,
+35401L,35402L,35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,
+35411L,35412L,35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,
+35421L,35422L,35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,
+35431L,35432L,35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,
+35441L,35442L,35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,
+35451L,35452L,35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,
+35461L,35462L,35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,
+35471L,35472L,35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,
+35481L,35482L,35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,
+35491L,35492L,35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,
+35501L,35502L,35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,
+35511L,35512L,35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,
+35521L,35522L,35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,
+35531L,35532L,35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,
+35541L,35542L,35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,
+35551L,35552L,35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,
+35561L,35562L,35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,
+35571L,35572L,35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,
+35581L,35582L,35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,
+35591L,35592L,35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,
+35601L,35602L,35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,
+35611L,35612L,35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,
+35621L,35622L,35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,
+35631L,35632L,35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,
+35641L,35642L,35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,
+35651L,35652L,35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,
+35661L,35662L,35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,
+35671L,35672L,35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,
+35681L,35682L,35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,
+35691L,35692L,35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,
+35701L,35702L,35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,
+35711L,35712L,35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,
+35721L,35722L,35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,
+35731L,35732L,35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,
+35741L,35742L,35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,
+35751L,35752L,35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,
+35761L,35762L,35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,
+35771L,35772L,35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,
+35781L,35782L,35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,
+35791L,35792L,35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,
+35801L,35802L,35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,
+35811L,35812L,35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,
+35821L,35822L,35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,
+35831L,35832L,35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,
+35841L,35842L,35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,
+35851L,35852L,35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,
+35861L,35862L,35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,
+35871L,35872L,35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,
+35881L,35882L,35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,
+35891L,35892L,35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,
+35901L,35902L,35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,
+35911L,35912L,35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,
+35921L,35922L,35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,
+35931L,35932L,35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,
+35941L,35942L,35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,
+35951L,35952L,35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,
+35961L,35962L,35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,
+35971L,35972L,35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,
+35981L,35982L,35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,
+35991L,35992L,35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,
+36001L,36002L,36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,
+36011L,36012L,36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,
+36021L,36022L,36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,
+36031L,36032L,36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,
+36041L,36042L,36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,
+36051L,36052L,36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,
+36061L,36062L,36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,
+36071L,36072L,36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,
+36081L,36082L,36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,
+36091L,36092L,36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,
+36101L,36102L,36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,
+36111L,36112L,36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,
+36121L,36122L,36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,
+36131L,36132L,36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,
+36141L,36142L,36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,
+36151L,36152L,36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,
+36161L,36162L,36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,
+36171L,36172L,36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,
+36181L,36182L,36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,
+36191L,36192L,36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,
+36201L,36202L,36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,
+36211L,36212L,36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,
+36221L,36222L,36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,
+36231L,36232L,36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,
+36241L,36242L,36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,
+36251L,36252L,36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,
+36261L,36262L,36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,
+36271L,36272L,36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,
+36281L,36282L,36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,
+36291L,36292L,36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,
+36301L,36302L,36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,
+36311L,36312L,36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,
+36321L,36322L,36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,
+36331L,36332L,36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,
+36341L,36342L,36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,
+36351L,36352L,36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,
+36361L,36362L,36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,
+36371L,36372L,36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,
+36381L,36382L,36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,
+36391L,36392L,36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,
+36401L,36402L,36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,
+36411L,36412L,36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,
+36421L,36422L,36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,
+36431L,36432L,36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,
+36441L,36442L,36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,
+36451L,36452L,36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,
+36461L,36462L,36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,
+36471L,36472L,36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,
+36481L,36482L,36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,
+36491L,36492L,36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,
+36501L,36502L,36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,
+36511L,36512L,36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,
+36521L,36522L,36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,
+36531L,36532L,36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,
+36541L,36542L,36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,
+36551L,36552L,36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,
+36561L,36562L,36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,
+36571L,36572L,36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,
+36581L,36582L,36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,
+36591L,36592L,36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,
+36601L,36602L,36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,
+36611L,36612L,36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,
+36621L,36622L,36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,
+36631L,36632L,36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,
+36641L,36642L,36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,
+36651L,36652L,36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,
+36661L,36662L,36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,
+36671L,36672L,36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,
+36681L,36682L,36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,
+36691L,36692L,36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,
+36701L,36702L,36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,
+36711L,36712L,36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,
+36721L,36722L,36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,
+36731L,36732L,36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,
+36741L,36742L,36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,
+36751L,36752L,36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,
+36761L,36762L,36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,
+36771L,36772L,36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,
+36781L,36782L,36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,
+36791L,36792L,36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,
+36801L,36802L,36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,
+36811L,36812L,36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,
+36821L,36822L,36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,
+36831L,36832L,36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,
+36841L,36842L,36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,
+36851L,36852L,36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,
+36861L,36862L,36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,
+36871L,36872L,36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,
+36881L,36882L,36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,
+36891L,36892L,36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,
+36901L,36902L,36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,
+36911L,36912L,36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,
+36921L,36922L,36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,
+36931L,36932L,36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,
+36941L,36942L,36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,
+36951L,36952L,36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,
+36961L,36962L,36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,
+36971L,36972L,36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,
+36981L,36982L,36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,
+36991L,36992L,36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,
+37001L,37002L,37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,
+37011L,37012L,37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,
+37021L,37022L,37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,
+37031L,37032L,37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,
+37041L,37042L,37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,
+37051L,37052L,37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,
+37061L,37062L,37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,
+37071L,37072L,37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,
+37081L,37082L,37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,
+37091L,37092L,37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,
+37101L,37102L,37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,
+37111L,37112L,37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,
+37121L,37122L,37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,
+37131L,37132L,37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,
+37141L,37142L,37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,
+37151L,37152L,37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,
+37161L,37162L,37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,
+37171L,37172L,37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,
+37181L,37182L,37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,
+37191L,37192L,37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,
+37201L,37202L,37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,
+37211L,37212L,37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,
+37221L,37222L,37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,
+37231L,37232L,37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,
+37241L,37242L,37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,
+37251L,37252L,37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,
+37261L,37262L,37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,
+37271L,37272L,37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,
+37281L,37282L,37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,
+37291L,37292L,37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,
+37301L,37302L,37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,
+37311L,37312L,37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,
+37321L,37322L,37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,
+37331L,37332L,37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,
+37341L,37342L,37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,
+37351L,37352L,37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,
+37361L,37362L,37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,
+37371L,37372L,37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,
+37381L,37382L,37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,
+37391L,37392L,37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,
+37401L,37402L,37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,
+37411L,37412L,37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,
+37421L,37422L,37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,
+37431L,37432L,37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,
+37441L,37442L,37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,
+37451L,37452L,37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,
+37461L,37462L,37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,
+37471L,37472L,37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,
+37481L,37482L,37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,
+37491L,37492L,37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,
+37501L,37502L,37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,
+37511L,37512L,37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,
+37521L,37522L,37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,
+37531L,37532L,37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,
+37541L,37542L,37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,
+37551L,37552L,37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,
+37561L,37562L,37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,
+37571L,37572L,37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,
+37581L,37582L,37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,
+37591L,37592L,37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,
+37601L,37602L,37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,
+37611L,37612L,37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,
+37621L,37622L,37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,
+37631L,37632L,37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,
+37641L,37642L,37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,
+37651L,37652L,37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,
+37661L,37662L,37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,
+37671L,37672L,37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,
+37681L,37682L,37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,
+37691L,37692L,37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,
+37701L,37702L,37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,
+37711L,37712L,37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,
+37721L,37722L,37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,
+37731L,37732L,37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,
+37741L,37742L,37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,
+37751L,37752L,37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,
+37761L,37762L,37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,
+37771L,37772L,37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,
+37781L,37782L,37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,
+37791L,37792L,37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,
+37801L,37802L,37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,
+37811L,37812L,37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,
+37821L,37822L,37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,
+37831L,37832L,37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,
+37841L,37842L,37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,
+37851L,37852L,37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,
+37861L,37862L,37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,
+37871L,37872L,37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,
+37881L,37882L,37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,
+37891L,37892L,37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,
+37901L,37902L,37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,
+37911L,37912L,37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,
+37921L,37922L,37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,
+37931L,37932L,37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,
+37941L,37942L,37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,
+37951L,37952L,37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,
+37961L,37962L,37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,
+37971L,37972L,37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,
+37981L,37982L,37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,
+37991L,37992L,37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,
+38001L,38002L,38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,
+38011L,38012L,38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,
+38021L,38022L,38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,
+38031L,38032L,38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,
+38041L,38042L,38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,
+38051L,38052L,38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,
+38061L,38062L,38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,
+38071L,38072L,38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,
+38081L,38082L,38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,
+38091L,38092L,38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,
+38101L,38102L,38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,
+38111L,38112L,38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,
+38121L,38122L,38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,
+38131L,38132L,38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,
+38141L,38142L,38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,
+38151L,38152L,38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,
+38161L,38162L,38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,
+38171L,38172L,38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,
+38181L,38182L,38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,
+38191L,38192L,38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,
+38201L,38202L,38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,
+38211L,38212L,38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,
+38221L,38222L,38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,
+38231L,38232L,38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,
+38241L,38242L,38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,
+38251L,38252L,38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,
+38261L,38262L,38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,
+38271L,38272L,38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,
+38281L,38282L,38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,
+38291L,38292L,38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,
+38301L,38302L,38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,
+38311L,38312L,38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,
+38321L,38322L,38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,
+38331L,38332L,38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,
+38341L,38342L,38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,
+38351L,38352L,38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,
+38361L,38362L,38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,
+38371L,38372L,38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,
+38381L,38382L,38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,
+38391L,38392L,38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,
+38401L,38402L,38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,
+38411L,38412L,38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,
+38421L,38422L,38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,
+38431L,38432L,38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,
+38441L,38442L,38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,
+38451L,38452L,38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,
+38461L,38462L,38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,
+38471L,38472L,38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,
+38481L,38482L,38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,
+38491L,38492L,38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,
+38501L,38502L,38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,
+38511L,38512L,38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,
+38521L,38522L,38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,
+38531L,38532L,38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,
+38541L,38542L,38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,
+38551L,38552L,38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,
+38561L,38562L,38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,
+38571L,38572L,38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,
+38581L,38582L,38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,
+38591L,38592L,38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,
+38601L,38602L,38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,
+38611L,38612L,38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,
+38621L,38622L,38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,
+38631L,38632L,38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,
+38641L,38642L,38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,
+38651L,38652L,38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,
+38661L,38662L,38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,
+38671L,38672L,38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,
+38681L,38682L,38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,
+38691L,38692L,38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,
+38701L,38702L,38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,
+38711L,38712L,38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,
+38721L,38722L,38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,
+38731L,38732L,38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,
+38741L,38742L,38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,
+38751L,38752L,38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,
+38761L,38762L,38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,
+38771L,38772L,38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,
+38781L,38782L,38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,
+38791L,38792L,38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,
+38801L,38802L,38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,
+38811L,38812L,38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,
+38821L,38822L,38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,
+38831L,38832L,38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,
+38841L,38842L,38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,
+38851L,38852L,38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,
+38861L,38862L,38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,
+38871L,38872L,38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,
+38881L,38882L,38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,
+38891L,38892L,38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,
+38901L,38902L,38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,
+38911L,38912L,38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,
+38921L,38922L,38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,
+38931L,38932L,38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,
+38941L,38942L,38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,
+38951L,38952L,38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,
+38961L,38962L,38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,
+38971L,38972L,38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,
+38981L,38982L,38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,
+38991L,38992L,38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,
+39001L,39002L,39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,
+39011L,39012L,39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,
+39021L,39022L,39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,
+39031L,39032L,39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,
+39041L,39042L,39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,
+39051L,39052L,39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,
+39061L,39062L,39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,
+39071L,39072L,39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,
+39081L,39082L,39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,
+39091L,39092L,39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,
+39101L,39102L,39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,
+39111L,39112L,39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,
+39121L,39122L,39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,
+39131L,39132L,39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,
+39141L,39142L,39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,
+39151L,39152L,39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,
+39161L,39162L,39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,
+39171L,39172L,39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,
+39181L,39182L,39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,
+39191L,39192L,39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,
+39201L,39202L,39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,
+39211L,39212L,39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,
+39221L,39222L,39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,
+39231L,39232L,39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,
+39241L,39242L,39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,
+39251L,39252L,39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,
+39261L,39262L,39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,
+39271L,39272L,39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,
+39281L,39282L,39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,
+39291L,39292L,39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,
+39301L,39302L,39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,
+39311L,39312L,39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,
+39321L,39322L,39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,
+39331L,39332L,39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,
+39341L,39342L,39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,
+39351L,39352L,39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,
+39361L,39362L,39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,
+39371L,39372L,39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,
+39381L,39382L,39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,
+39391L,39392L,39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,
+39401L,39402L,39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,
+39411L,39412L,39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,
+39421L,39422L,39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,
+39431L,39432L,39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,
+39441L,39442L,39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,
+39451L,39452L,39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,
+39461L,39462L,39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,
+39471L,39472L,39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,
+39481L,39482L,39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,
+39491L,39492L,39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,
+39501L,39502L,39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,
+39511L,39512L,39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,
+39521L,39522L,39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,
+39531L,39532L,39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,
+39541L,39542L,39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,
+39551L,39552L,39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,
+39561L,39562L,39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,
+39571L,39572L,39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,
+39581L,39582L,39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,
+39591L,39592L,39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,
+39601L,39602L,39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,
+39611L,39612L,39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,
+39621L,39622L,39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,
+39631L,39632L,39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,
+39641L,39642L,39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,
+39651L,39652L,39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,
+39661L,39662L,39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,
+39671L,39672L,39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,
+39681L,39682L,39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,
+39691L,39692L,39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,
+39701L,39702L,39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,
+39711L,39712L,39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,
+39721L,39722L,39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,
+39731L,39732L,39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,
+39741L,39742L,39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,
+39751L,39752L,39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,
+39761L,39762L,39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,
+39771L,39772L,39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,
+39781L,39782L,39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,
+39791L,39792L,39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,
+39801L,39802L,39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,
+39811L,39812L,39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,
+39821L,39822L,39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,
+39831L,39832L,39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,
+39841L,39842L,39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,
+39851L,39852L,39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,
+39861L,39862L,39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,
+39871L,39872L,39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,
+39881L,39882L,39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,
+39891L,39892L,39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,
+39901L,39902L,39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,
+39911L,39912L,39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,
+39921L,39922L,39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,
+39931L,39932L,39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,
+39941L,39942L,39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,
+39951L,39952L,39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,
+39961L,39962L,39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,
+39971L,39972L,39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,
+39981L,39982L,39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,
+39991L,39992L,39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,
+40001L,40002L,40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,
+40011L,40012L,40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,
+40021L,40022L,40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,
+40031L,40032L,40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,
+40041L,40042L,40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,
+40051L,40052L,40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,
+40061L,40062L,40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,
+40071L,40072L,40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,
+40081L,40082L,40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,
+40091L,40092L,40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,
+40101L,40102L,40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,
+40111L,40112L,40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,
+40121L,40122L,40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,
+40131L,40132L,40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,
+40141L,40142L,40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,
+40151L,40152L,40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,
+40161L,40162L,40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,
+40171L,40172L,40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,
+40181L,40182L,40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,
+40191L,40192L,40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,
+40201L,40202L,40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,
+40211L,40212L,40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,
+40221L,40222L,40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,
+40231L,40232L,40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,
+40241L,40242L,40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,
+40251L,40252L,40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,
+40261L,40262L,40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,
+40271L,40272L,40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,
+40281L,40282L,40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,
+40291L,40292L,40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,
+40301L,40302L,40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,
+40311L,40312L,40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,
+40321L,40322L,40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,
+40331L,40332L,40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,
+40341L,40342L,40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,
+40351L,40352L,40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,
+40361L,40362L,40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,
+40371L,40372L,40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,
+40381L,40382L,40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,
+40391L,40392L,40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,
+40401L,40402L,40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,
+40411L,40412L,40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,
+40421L,40422L,40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,
+40431L,40432L,40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,
+40441L,40442L,40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,
+40451L,40452L,40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,
+40461L,40462L,40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,
+40471L,40472L,40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,
+40481L,40482L,40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,
+40491L,40492L,40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,
+40501L,40502L,40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,
+40511L,40512L,40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,
+40521L,40522L,40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,
+40531L,40532L,40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,
+40541L,40542L,40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,
+40551L,40552L,40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,
+40561L,40562L,40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,
+40571L,40572L,40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,
+40581L,40582L,40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,
+40591L,40592L,40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,
+40601L,40602L,40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,
+40611L,40612L,40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,
+40621L,40622L,40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,
+40631L,40632L,40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,
+40641L,40642L,40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,
+40651L,40652L,40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,
+40661L,40662L,40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,
+40671L,40672L,40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,
+40681L,40682L,40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,
+40691L,40692L,40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,
+40701L,40702L,40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,
+40711L,40712L,40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,
+40721L,40722L,40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,
+40731L,40732L,40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,
+40741L,40742L,40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,
+40751L,40752L,40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,
+40761L,40762L,40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,
+40771L,40772L,40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,
+40781L,40782L,40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,
+40791L,40792L,40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,
+40801L,40802L,40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,
+40811L,40812L,40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,
+40821L,40822L,40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,
+40831L,40832L,40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,
+40841L,40842L,40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,
+40851L,40852L,40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,
+40861L,40862L,40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,
+40871L,40872L,40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,
+40881L,40882L,40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,
+40891L,40892L,40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,
+40901L,40902L,40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,
+40911L,40912L,40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,
+40921L,40922L,40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,
+40931L,40932L,40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,
+40941L,40942L,40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,
+40951L,40952L,40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,
+40961L,40962L,40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,
+40971L,40972L,40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,
+40981L,40982L,40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,
+40991L,40992L,40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,
+41001L,41002L,41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,
+41011L,41012L,41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,
+41021L,41022L,41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,
+41031L,41032L,41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,
+41041L,41042L,41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,
+41051L,41052L,41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,
+41061L,41062L,41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,
+41071L,41072L,41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,
+41081L,41082L,41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,
+41091L,41092L,41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,
+41101L,41102L,41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,
+41111L,41112L,41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,
+41121L,41122L,41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,
+41131L,41132L,41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,
+41141L,41142L,41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,
+41151L,41152L,41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,
+41161L,41162L,41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,
+41171L,41172L,41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,
+41181L,41182L,41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,
+41191L,41192L,41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,
+41201L,41202L,41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,
+41211L,41212L,41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,
+41221L,41222L,41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,
+41231L,41232L,41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,
+41241L,41242L,41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,
+41251L,41252L,41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,
+41261L,41262L,41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,
+41271L,41272L,41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,
+41281L,41282L,41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,
+41291L,41292L,41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,
+41301L,41302L,41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,
+41311L,41312L,41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,
+41321L,41322L,41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,
+41331L,41332L,41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,
+41341L,41342L,41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,
+41351L,41352L,41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,
+41361L,41362L,41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,
+41371L,41372L,41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,
+41381L,41382L,41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,
+41391L,41392L,41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,
+41401L,41402L,41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,
+41411L,41412L,41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,
+41421L,41422L,41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,
+41431L,41432L,41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,
+41441L,41442L,41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,
+41451L,41452L,41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,
+41461L,41462L,41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,
+41471L,41472L,41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,
+41481L,41482L,41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,
+41491L,41492L,41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,
+41501L,41502L,41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,
+41511L,41512L,41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,
+41521L,41522L,41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,
+41531L,41532L,41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,
+41541L,41542L,41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,
+41551L,41552L,41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,
+41561L,41562L,41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,
+41571L,41572L,41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,
+41581L,41582L,41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,
+41591L,41592L,41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,
+41601L,41602L,41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,
+41611L,41612L,41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,
+41621L,41622L,41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,
+41631L,41632L,41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,
+41641L,41642L,41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,
+41651L,41652L,41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,
+41661L,41662L,41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,
+41671L,41672L,41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,
+41681L,41682L,41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,
+41691L,41692L,41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,
+41701L,41702L,41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,
+41711L,41712L,41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,
+41721L,41722L,41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,
+41731L,41732L,41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,
+41741L,41742L,41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,
+41751L,41752L,41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,
+41761L,41762L,41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,
+41771L,41772L,41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,
+41781L,41782L,41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,
+41791L,41792L,41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,
+41801L,41802L,41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,
+41811L,41812L,41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,
+41821L,41822L,41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,
+41831L,41832L,41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,
+41841L,41842L,41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,
+41851L,41852L,41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,
+41861L,41862L,41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,
+41871L,41872L,41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,
+41881L,41882L,41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,
+41891L,41892L,41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,
+41901L,41902L,41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,
+41911L,41912L,41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,
+41921L,41922L,41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,
+41931L,41932L,41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,
+41941L,41942L,41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,
+41951L,41952L,41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,
+41961L,41962L,41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,
+41971L,41972L,41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,
+41981L,41982L,41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,
+41991L,41992L,41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,
+42001L,42002L,42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,
+42011L,42012L,42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,
+42021L,42022L,42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,
+42031L,42032L,42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,
+42041L,42042L,42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,
+42051L,42052L,42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,
+42061L,42062L,42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,
+42071L,42072L,42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,
+42081L,42082L,42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,
+42091L,42092L,42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,
+42101L,42102L,42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,
+42111L,42112L,42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,
+42121L,42122L,42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,
+42131L,42132L,42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,
+42141L,42142L,42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,
+42151L,42152L,42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,
+42161L,42162L,42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,
+42171L,42172L,42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,
+42181L,42182L,42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,
+42191L,42192L,42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,
+42201L,42202L,42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,
+42211L,42212L,42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,
+42221L,42222L,42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,
+42231L,42232L,42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,
+42241L,42242L,42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,
+42251L,42252L,42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,
+42261L,42262L,42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,
+42271L,42272L,42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,
+42281L,42282L,42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,
+42291L,42292L,42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,
+42301L,42302L,42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,
+42311L,42312L,42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,
+42321L,42322L,42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,
+42331L,42332L,42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,
+42341L,42342L,42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,
+42351L,42352L,42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,
+42361L,42362L,42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,
+42371L,42372L,42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,
+42381L,42382L,42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,
+42391L,42392L,42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,
+42401L,42402L,42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,
+42411L,42412L,42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,
+42421L,42422L,42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,
+42431L,42432L,42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,
+42441L,42442L,42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,
+42451L,42452L,42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,
+42461L,42462L,42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,
+42471L,42472L,42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,
+42481L,42482L,42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,
+42491L,42492L,42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,
+42501L,42502L,42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,
+42511L,42512L,42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,
+42521L,42522L,42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,
+42531L,42532L,42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,
+42541L,42542L,42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,
+42551L,42552L,42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,
+42560L,42562L,42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,
+42570L,42572L,42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,
+42580L,42582L,42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,
+42590L,42592L,42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,
+42600L,42602L,42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,
+42611L,42612L,42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,
+42621L,42622L,42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,
+42630L,42632L,42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,
+42640L,42642L,42642L,42644L,42644L,42646L,42646L,42648L,42648L,42650L,
+42650L,42652L,42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,
+42661L,42662L,42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,
+42671L,42672L,42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,
+42681L,42682L,42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,
+42691L,42692L,42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,
+42701L,42702L,42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,
+42711L,42712L,42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,
+42721L,42722L,42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,
+42731L,42732L,42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,
+42741L,42742L,42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,
+42751L,42752L,42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,
+42761L,42762L,42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,
+42771L,42772L,42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,
+42781L,42782L,42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,
+42790L,42792L,42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,
+42801L,42802L,42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,
+42810L,42812L,42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,
+42820L,42822L,42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,
+42830L,42832L,42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,
+42840L,42842L,42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,
+42850L,42852L,42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,
+42860L,42862L,42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,
+42871L,42872L,42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,
+42880L,42882L,42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,
+42891L,42891L,42893L,42894L,42895L,42896L,42896L,42898L,42898L,42900L,
+42901L,42902L,42902L,42904L,42904L,42906L,42906L,42908L,42908L,42910L,
+42910L,42912L,42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,
+42920L,42922L,42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,
+42931L,42932L,42932L,42934L,42934L,42936L,42937L,42938L,42939L,42940L,
+42941L,42942L,42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,
+42951L,42952L,42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,
+42961L,42962L,42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,
+42971L,42972L,42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,
+42981L,42982L,42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,
+42991L,42992L,42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,
+43001L,43002L,43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,
+43011L,43012L,43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,
+43021L,43022L,43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,
+43031L,43032L,43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,
+43041L,43042L,43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,
+43051L,43052L,43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,
+43061L,43062L,43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,
+43071L,43072L,43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,
+43081L,43082L,43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,
+43091L,43092L,43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,
+43101L,43102L,43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,
+43111L,43112L,43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,
+43121L,43122L,43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,
+43131L,43132L,43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,
+43141L,43142L,43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,
+43151L,43152L,43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,
+43161L,43162L,43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,
+43171L,43172L,43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,
+43181L,43182L,43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,
+43191L,43192L,43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,
+43201L,43202L,43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,
+43211L,43212L,43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,
+43221L,43222L,43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,
+43231L,43232L,43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,
+43241L,43242L,43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,
+43251L,43252L,43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,
+43261L,43262L,43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,
+43271L,43272L,43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,
+43281L,43282L,43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,
+43291L,43292L,43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,
+43301L,43302L,43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,
+43311L,43312L,43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,
+43321L,43322L,43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,
+43331L,43332L,43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,
+43341L,43342L,43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,
+43351L,43352L,43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,
+43361L,43362L,43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,
+43371L,43372L,43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,
+43381L,43382L,43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,
+43391L,43392L,43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,
+43401L,43402L,43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,
+43411L,43412L,43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,
+43421L,43422L,43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,
+43431L,43432L,43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,
+43441L,43442L,43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,
+43451L,43452L,43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,
+43461L,43462L,43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,
+43471L,43472L,43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,
+43481L,43482L,43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,
+43491L,43492L,43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,
+43501L,43502L,43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,
+43511L,43512L,43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,
+43521L,43522L,43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,
+43531L,43532L,43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,
+43541L,43542L,43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,
+43551L,43552L,43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,
+43561L,43562L,43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,
+43571L,43572L,43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,
+43581L,43582L,43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,
+43591L,43592L,43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,
+43601L,43602L,43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,
+43611L,43612L,43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,
+43621L,43622L,43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,
+43631L,43632L,43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,
+43641L,43642L,43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,
+43651L,43652L,43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,
+43661L,43662L,43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,
+43671L,43672L,43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,
+43681L,43682L,43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,
+43691L,43692L,43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,
+43701L,43702L,43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,
+43711L,43712L,43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,
+43721L,43722L,43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,
+43731L,43732L,43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,
+43741L,43742L,43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,
+43751L,43752L,43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,
+43761L,43762L,43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,
+43771L,43772L,43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,
+43781L,43782L,43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,
+43791L,43792L,43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,
+43801L,43802L,43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,
+43811L,43812L,43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,
+43821L,43822L,43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,
+43831L,43832L,43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,
+43841L,43842L,43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,
+43851L,43852L,43853L,43854L,43855L,43856L,43857L,43858L,42931L,43860L,
+43861L,43862L,43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,
+43871L,43872L,43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,
+43881L,43882L,43883L,43884L,43885L,43886L,43887L,5024,5025,5026,5027,5028,
+5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,
+5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,
+5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,
+5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,
+5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,
+43968L,43969L,43970L,43971L,43972L,43973L,43974L,43975L,43976L,43977L,
+43978L,43979L,43980L,43981L,43982L,43983L,43984L,43985L,43986L,43987L,
+43988L,43989L,43990L,43991L,43992L,43993L,43994L,43995L,43996L,43997L,
+43998L,43999L,44000L,44001L,44002L,44003L,44004L,44005L,44006L,44007L,
+44008L,44009L,44010L,44011L,44012L,44013L,44014L,44015L,44016L,44017L,
+44018L,44019L,44020L,44021L,44022L,44023L,44024L,44025L,44026L,44027L,
+44028L,44029L,44030L,44031L,44032L,44033L,44034L,44035L,44036L,44037L,
+44038L,44039L,44040L,44041L,44042L,44043L,44044L,44045L,44046L,44047L,
+44048L,44049L,44050L,44051L,44052L,44053L,44054L,44055L,44056L,44057L,
+44058L,44059L,44060L,44061L,44062L,44063L,44064L,44065L,44066L,44067L,
+44068L,44069L,44070L,44071L,44072L,44073L,44074L,44075L,44076L,44077L,
+44078L,44079L,44080L,44081L,44082L,44083L,44084L,44085L,44086L,44087L,
+44088L,44089L,44090L,44091L,44092L,44093L,44094L,44095L,44096L,44097L,
+44098L,44099L,44100L,44101L,44102L,44103L,44104L,44105L,44106L,44107L,
+44108L,44109L,44110L,44111L,44112L,44113L,44114L,44115L,44116L,44117L,
+44118L,44119L,44120L,44121L,44122L,44123L,44124L,44125L,44126L,44127L,
+44128L,44129L,44130L,44131L,44132L,44133L,44134L,44135L,44136L,44137L,
+44138L,44139L,44140L,44141L,44142L,44143L,44144L,44145L,44146L,44147L,
+44148L,44149L,44150L,44151L,44152L,44153L,44154L,44155L,44156L,44157L,
+44158L,44159L,44160L,44161L,44162L,44163L,44164L,44165L,44166L,44167L,
+44168L,44169L,44170L,44171L,44172L,44173L,44174L,44175L,44176L,44177L,
+44178L,44179L,44180L,44181L,44182L,44183L,44184L,44185L,44186L,44187L,
+44188L,44189L,44190L,44191L,44192L,44193L,44194L,44195L,44196L,44197L,
+44198L,44199L,44200L,44201L,44202L,44203L,44204L,44205L,44206L,44207L,
+44208L,44209L,44210L,44211L,44212L,44213L,44214L,44215L,44216L,44217L,
+44218L,44219L,44220L,44221L,44222L,44223L,44224L,44225L,44226L,44227L,
+44228L,44229L,44230L,44231L,44232L,44233L,44234L,44235L,44236L,44237L,
+44238L,44239L,44240L,44241L,44242L,44243L,44244L,44245L,44246L,44247L,
+44248L,44249L,44250L,44251L,44252L,44253L,44254L,44255L,44256L,44257L,
+44258L,44259L,44260L,44261L,44262L,44263L,44264L,44265L,44266L,44267L,
+44268L,44269L,44270L,44271L,44272L,44273L,44274L,44275L,44276L,44277L,
+44278L,44279L,44280L,44281L,44282L,44283L,44284L,44285L,44286L,44287L,
+44288L,44289L,44290L,44291L,44292L,44293L,44294L,44295L,44296L,44297L,
+44298L,44299L,44300L,44301L,44302L,44303L,44304L,44305L,44306L,44307L,
+44308L,44309L,44310L,44311L,44312L,44313L,44314L,44315L,44316L,44317L,
+44318L,44319L,44320L,44321L,44322L,44323L,44324L,44325L,44326L,44327L,
+44328L,44329L,44330L,44331L,44332L,44333L,44334L,44335L,44336L,44337L,
+44338L,44339L,44340L,44341L,44342L,44343L,44344L,44345L,44346L,44347L,
+44348L,44349L,44350L,44351L,44352L,44353L,44354L,44355L,44356L,44357L,
+44358L,44359L,44360L,44361L,44362L,44363L,44364L,44365L,44366L,44367L,
+44368L,44369L,44370L,44371L,44372L,44373L,44374L,44375L,44376L,44377L,
+44378L,44379L,44380L,44381L,44382L,44383L,44384L,44385L,44386L,44387L,
+44388L,44389L,44390L,44391L,44392L,44393L,44394L,44395L,44396L,44397L,
+44398L,44399L,44400L,44401L,44402L,44403L,44404L,44405L,44406L,44407L,
+44408L,44409L,44410L,44411L,44412L,44413L,44414L,44415L,44416L,44417L,
+44418L,44419L,44420L,44421L,44422L,44423L,44424L,44425L,44426L,44427L,
+44428L,44429L,44430L,44431L,44432L,44433L,44434L,44435L,44436L,44437L,
+44438L,44439L,44440L,44441L,44442L,44443L,44444L,44445L,44446L,44447L,
+44448L,44449L,44450L,44451L,44452L,44453L,44454L,44455L,44456L,44457L,
+44458L,44459L,44460L,44461L,44462L,44463L,44464L,44465L,44466L,44467L,
+44468L,44469L,44470L,44471L,44472L,44473L,44474L,44475L,44476L,44477L,
+44478L,44479L,44480L,44481L,44482L,44483L,44484L,44485L,44486L,44487L,
+44488L,44489L,44490L,44491L,44492L,44493L,44494L,44495L,44496L,44497L,
+44498L,44499L,44500L,44501L,44502L,44503L,44504L,44505L,44506L,44507L,
+44508L,44509L,44510L,44511L,44512L,44513L,44514L,44515L,44516L,44517L,
+44518L,44519L,44520L,44521L,44522L,44523L,44524L,44525L,44526L,44527L,
+44528L,44529L,44530L,44531L,44532L,44533L,44534L,44535L,44536L,44537L,
+44538L,44539L,44540L,44541L,44542L,44543L,44544L,44545L,44546L,44547L,
+44548L,44549L,44550L,44551L,44552L,44553L,44554L,44555L,44556L,44557L,
+44558L,44559L,44560L,44561L,44562L,44563L,44564L,44565L,44566L,44567L,
+44568L,44569L,44570L,44571L,44572L,44573L,44574L,44575L,44576L,44577L,
+44578L,44579L,44580L,44581L,44582L,44583L,44584L,44585L,44586L,44587L,
+44588L,44589L,44590L,44591L,44592L,44593L,44594L,44595L,44596L,44597L,
+44598L,44599L,44600L,44601L,44602L,44603L,44604L,44605L,44606L,44607L,
+44608L,44609L,44610L,44611L,44612L,44613L,44614L,44615L,44616L,44617L,
+44618L,44619L,44620L,44621L,44622L,44623L,44624L,44625L,44626L,44627L,
+44628L,44629L,44630L,44631L,44632L,44633L,44634L,44635L,44636L,44637L,
+44638L,44639L,44640L,44641L,44642L,44643L,44644L,44645L,44646L,44647L,
+44648L,44649L,44650L,44651L,44652L,44653L,44654L,44655L,44656L,44657L,
+44658L,44659L,44660L,44661L,44662L,44663L,44664L,44665L,44666L,44667L,
+44668L,44669L,44670L,44671L,44672L,44673L,44674L,44675L,44676L,44677L,
+44678L,44679L,44680L,44681L,44682L,44683L,44684L,44685L,44686L,44687L,
+44688L,44689L,44690L,44691L,44692L,44693L,44694L,44695L,44696L,44697L,
+44698L,44699L,44700L,44701L,44702L,44703L,44704L,44705L,44706L,44707L,
+44708L,44709L,44710L,44711L,44712L,44713L,44714L,44715L,44716L,44717L,
+44718L,44719L,44720L,44721L,44722L,44723L,44724L,44725L,44726L,44727L,
+44728L,44729L,44730L,44731L,44732L,44733L,44734L,44735L,44736L,44737L,
+44738L,44739L,44740L,44741L,44742L,44743L,44744L,44745L,44746L,44747L,
+44748L,44749L,44750L,44751L,44752L,44753L,44754L,44755L,44756L,44757L,
+44758L,44759L,44760L,44761L,44762L,44763L,44764L,44765L,44766L,44767L,
+44768L,44769L,44770L,44771L,44772L,44773L,44774L,44775L,44776L,44777L,
+44778L,44779L,44780L,44781L,44782L,44783L,44784L,44785L,44786L,44787L,
+44788L,44789L,44790L,44791L,44792L,44793L,44794L,44795L,44796L,44797L,
+44798L,44799L,44800L,44801L,44802L,44803L,44804L,44805L,44806L,44807L,
+44808L,44809L,44810L,44811L,44812L,44813L,44814L,44815L,44816L,44817L,
+44818L,44819L,44820L,44821L,44822L,44823L,44824L,44825L,44826L,44827L,
+44828L,44829L,44830L,44831L,44832L,44833L,44834L,44835L,44836L,44837L,
+44838L,44839L,44840L,44841L,44842L,44843L,44844L,44845L,44846L,44847L,
+44848L,44849L,44850L,44851L,44852L,44853L,44854L,44855L,44856L,44857L,
+44858L,44859L,44860L,44861L,44862L,44863L,44864L,44865L,44866L,44867L,
+44868L,44869L,44870L,44871L,44872L,44873L,44874L,44875L,44876L,44877L,
+44878L,44879L,44880L,44881L,44882L,44883L,44884L,44885L,44886L,44887L,
+44888L,44889L,44890L,44891L,44892L,44893L,44894L,44895L,44896L,44897L,
+44898L,44899L,44900L,44901L,44902L,44903L,44904L,44905L,44906L,44907L,
+44908L,44909L,44910L,44911L,44912L,44913L,44914L,44915L,44916L,44917L,
+44918L,44919L,44920L,44921L,44922L,44923L,44924L,44925L,44926L,44927L,
+44928L,44929L,44930L,44931L,44932L,44933L,44934L,44935L,44936L,44937L,
+44938L,44939L,44940L,44941L,44942L,44943L,44944L,44945L,44946L,44947L,
+44948L,44949L,44950L,44951L,44952L,44953L,44954L,44955L,44956L,44957L,
+44958L,44959L,44960L,44961L,44962L,44963L,44964L,44965L,44966L,44967L,
+44968L,44969L,44970L,44971L,44972L,44973L,44974L,44975L,44976L,44977L,
+44978L,44979L,44980L,44981L,44982L,44983L,44984L,44985L,44986L,44987L,
+44988L,44989L,44990L,44991L,44992L,44993L,44994L,44995L,44996L,44997L,
+44998L,44999L,45000L,45001L,45002L,45003L,45004L,45005L,45006L,45007L,
+45008L,45009L,45010L,45011L,45012L,45013L,45014L,45015L,45016L,45017L,
+45018L,45019L,45020L,45021L,45022L,45023L,45024L,45025L,45026L,45027L,
+45028L,45029L,45030L,45031L,45032L,45033L,45034L,45035L,45036L,45037L,
+45038L,45039L,45040L,45041L,45042L,45043L,45044L,45045L,45046L,45047L,
+45048L,45049L,45050L,45051L,45052L,45053L,45054L,45055L,45056L,45057L,
+45058L,45059L,45060L,45061L,45062L,45063L,45064L,45065L,45066L,45067L,
+45068L,45069L,45070L,45071L,45072L,45073L,45074L,45075L,45076L,45077L,
+45078L,45079L,45080L,45081L,45082L,45083L,45084L,45085L,45086L,45087L,
+45088L,45089L,45090L,45091L,45092L,45093L,45094L,45095L,45096L,45097L,
+45098L,45099L,45100L,45101L,45102L,45103L,45104L,45105L,45106L,45107L,
+45108L,45109L,45110L,45111L,45112L,45113L,45114L,45115L,45116L,45117L,
+45118L,45119L,45120L,45121L,45122L,45123L,45124L,45125L,45126L,45127L,
+45128L,45129L,45130L,45131L,45132L,45133L,45134L,45135L,45136L,45137L,
+45138L,45139L,45140L,45141L,45142L,45143L,45144L,45145L,45146L,45147L,
+45148L,45149L,45150L,45151L,45152L,45153L,45154L,45155L,45156L,45157L,
+45158L,45159L,45160L,45161L,45162L,45163L,45164L,45165L,45166L,45167L,
+45168L,45169L,45170L,45171L,45172L,45173L,45174L,45175L,45176L,45177L,
+45178L,45179L,45180L,45181L,45182L,45183L,45184L,45185L,45186L,45187L,
+45188L,45189L,45190L,45191L,45192L,45193L,45194L,45195L,45196L,45197L,
+45198L,45199L,45200L,45201L,45202L,45203L,45204L,45205L,45206L,45207L,
+45208L,45209L,45210L,45211L,45212L,45213L,45214L,45215L,45216L,45217L,
+45218L,45219L,45220L,45221L,45222L,45223L,45224L,45225L,45226L,45227L,
+45228L,45229L,45230L,45231L,45232L,45233L,45234L,45235L,45236L,45237L,
+45238L,45239L,45240L,45241L,45242L,45243L,45244L,45245L,45246L,45247L,
+45248L,45249L,45250L,45251L,45252L,45253L,45254L,45255L,45256L,45257L,
+45258L,45259L,45260L,45261L,45262L,45263L,45264L,45265L,45266L,45267L,
+45268L,45269L,45270L,45271L,45272L,45273L,45274L,45275L,45276L,45277L,
+45278L,45279L,45280L,45281L,45282L,45283L,45284L,45285L,45286L,45287L,
+45288L,45289L,45290L,45291L,45292L,45293L,45294L,45295L,45296L,45297L,
+45298L,45299L,45300L,45301L,45302L,45303L,45304L,45305L,45306L,45307L,
+45308L,45309L,45310L,45311L,45312L,45313L,45314L,45315L,45316L,45317L,
+45318L,45319L,45320L,45321L,45322L,45323L,45324L,45325L,45326L,45327L,
+45328L,45329L,45330L,45331L,45332L,45333L,45334L,45335L,45336L,45337L,
+45338L,45339L,45340L,45341L,45342L,45343L,45344L,45345L,45346L,45347L,
+45348L,45349L,45350L,45351L,45352L,45353L,45354L,45355L,45356L,45357L,
+45358L,45359L,45360L,45361L,45362L,45363L,45364L,45365L,45366L,45367L,
+45368L,45369L,45370L,45371L,45372L,45373L,45374L,45375L,45376L,45377L,
+45378L,45379L,45380L,45381L,45382L,45383L,45384L,45385L,45386L,45387L,
+45388L,45389L,45390L,45391L,45392L,45393L,45394L,45395L,45396L,45397L,
+45398L,45399L,45400L,45401L,45402L,45403L,45404L,45405L,45406L,45407L,
+45408L,45409L,45410L,45411L,45412L,45413L,45414L,45415L,45416L,45417L,
+45418L,45419L,45420L,45421L,45422L,45423L,45424L,45425L,45426L,45427L,
+45428L,45429L,45430L,45431L,45432L,45433L,45434L,45435L,45436L,45437L,
+45438L,45439L,45440L,45441L,45442L,45443L,45444L,45445L,45446L,45447L,
+45448L,45449L,45450L,45451L,45452L,45453L,45454L,45455L,45456L,45457L,
+45458L,45459L,45460L,45461L,45462L,45463L,45464L,45465L,45466L,45467L,
+45468L,45469L,45470L,45471L,45472L,45473L,45474L,45475L,45476L,45477L,
+45478L,45479L,45480L,45481L,45482L,45483L,45484L,45485L,45486L,45487L,
+45488L,45489L,45490L,45491L,45492L,45493L,45494L,45495L,45496L,45497L,
+45498L,45499L,45500L,45501L,45502L,45503L,45504L,45505L,45506L,45507L,
+45508L,45509L,45510L,45511L,45512L,45513L,45514L,45515L,45516L,45517L,
+45518L,45519L,45520L,45521L,45522L,45523L,45524L,45525L,45526L,45527L,
+45528L,45529L,45530L,45531L,45532L,45533L,45534L,45535L,45536L,45537L,
+45538L,45539L,45540L,45541L,45542L,45543L,45544L,45545L,45546L,45547L,
+45548L,45549L,45550L,45551L,45552L,45553L,45554L,45555L,45556L,45557L,
+45558L,45559L,45560L,45561L,45562L,45563L,45564L,45565L,45566L,45567L,
+45568L,45569L,45570L,45571L,45572L,45573L,45574L,45575L,45576L,45577L,
+45578L,45579L,45580L,45581L,45582L,45583L,45584L,45585L,45586L,45587L,
+45588L,45589L,45590L,45591L,45592L,45593L,45594L,45595L,45596L,45597L,
+45598L,45599L,45600L,45601L,45602L,45603L,45604L,45605L,45606L,45607L,
+45608L,45609L,45610L,45611L,45612L,45613L,45614L,45615L,45616L,45617L,
+45618L,45619L,45620L,45621L,45622L,45623L,45624L,45625L,45626L,45627L,
+45628L,45629L,45630L,45631L,45632L,45633L,45634L,45635L,45636L,45637L,
+45638L,45639L,45640L,45641L,45642L,45643L,45644L,45645L,45646L,45647L,
+45648L,45649L,45650L,45651L,45652L,45653L,45654L,45655L,45656L,45657L,
+45658L,45659L,45660L,45661L,45662L,45663L,45664L,45665L,45666L,45667L,
+45668L,45669L,45670L,45671L,45672L,45673L,45674L,45675L,45676L,45677L,
+45678L,45679L,45680L,45681L,45682L,45683L,45684L,45685L,45686L,45687L,
+45688L,45689L,45690L,45691L,45692L,45693L,45694L,45695L,45696L,45697L,
+45698L,45699L,45700L,45701L,45702L,45703L,45704L,45705L,45706L,45707L,
+45708L,45709L,45710L,45711L,45712L,45713L,45714L,45715L,45716L,45717L,
+45718L,45719L,45720L,45721L,45722L,45723L,45724L,45725L,45726L,45727L,
+45728L,45729L,45730L,45731L,45732L,45733L,45734L,45735L,45736L,45737L,
+45738L,45739L,45740L,45741L,45742L,45743L,45744L,45745L,45746L,45747L,
+45748L,45749L,45750L,45751L,45752L,45753L,45754L,45755L,45756L,45757L,
+45758L,45759L,45760L,45761L,45762L,45763L,45764L,45765L,45766L,45767L,
+45768L,45769L,45770L,45771L,45772L,45773L,45774L,45775L,45776L,45777L,
+45778L,45779L,45780L,45781L,45782L,45783L,45784L,45785L,45786L,45787L,
+45788L,45789L,45790L,45791L,45792L,45793L,45794L,45795L,45796L,45797L,
+45798L,45799L,45800L,45801L,45802L,45803L,45804L,45805L,45806L,45807L,
+45808L,45809L,45810L,45811L,45812L,45813L,45814L,45815L,45816L,45817L,
+45818L,45819L,45820L,45821L,45822L,45823L,45824L,45825L,45826L,45827L,
+45828L,45829L,45830L,45831L,45832L,45833L,45834L,45835L,45836L,45837L,
+45838L,45839L,45840L,45841L,45842L,45843L,45844L,45845L,45846L,45847L,
+45848L,45849L,45850L,45851L,45852L,45853L,45854L,45855L,45856L,45857L,
+45858L,45859L,45860L,45861L,45862L,45863L,45864L,45865L,45866L,45867L,
+45868L,45869L,45870L,45871L,45872L,45873L,45874L,45875L,45876L,45877L,
+45878L,45879L,45880L,45881L,45882L,45883L,45884L,45885L,45886L,45887L,
+45888L,45889L,45890L,45891L,45892L,45893L,45894L,45895L,45896L,45897L,
+45898L,45899L,45900L,45901L,45902L,45903L,45904L,45905L,45906L,45907L,
+45908L,45909L,45910L,45911L,45912L,45913L,45914L,45915L,45916L,45917L,
+45918L,45919L,45920L,45921L,45922L,45923L,45924L,45925L,45926L,45927L,
+45928L,45929L,45930L,45931L,45932L,45933L,45934L,45935L,45936L,45937L,
+45938L,45939L,45940L,45941L,45942L,45943L,45944L,45945L,45946L,45947L,
+45948L,45949L,45950L,45951L,45952L,45953L,45954L,45955L,45956L,45957L,
+45958L,45959L,45960L,45961L,45962L,45963L,45964L,45965L,45966L,45967L,
+45968L,45969L,45970L,45971L,45972L,45973L,45974L,45975L,45976L,45977L,
+45978L,45979L,45980L,45981L,45982L,45983L,45984L,45985L,45986L,45987L,
+45988L,45989L,45990L,45991L,45992L,45993L,45994L,45995L,45996L,45997L,
+45998L,45999L,46000L,46001L,46002L,46003L,46004L,46005L,46006L,46007L,
+46008L,46009L,46010L,46011L,46012L,46013L,46014L,46015L,46016L,46017L,
+46018L,46019L,46020L,46021L,46022L,46023L,46024L,46025L,46026L,46027L,
+46028L,46029L,46030L,46031L,46032L,46033L,46034L,46035L,46036L,46037L,
+46038L,46039L,46040L,46041L,46042L,46043L,46044L,46045L,46046L,46047L,
+46048L,46049L,46050L,46051L,46052L,46053L,46054L,46055L,46056L,46057L,
+46058L,46059L,46060L,46061L,46062L,46063L,46064L,46065L,46066L,46067L,
+46068L,46069L,46070L,46071L,46072L,46073L,46074L,46075L,46076L,46077L,
+46078L,46079L,46080L,46081L,46082L,46083L,46084L,46085L,46086L,46087L,
+46088L,46089L,46090L,46091L,46092L,46093L,46094L,46095L,46096L,46097L,
+46098L,46099L,46100L,46101L,46102L,46103L,46104L,46105L,46106L,46107L,
+46108L,46109L,46110L,46111L,46112L,46113L,46114L,46115L,46116L,46117L,
+46118L,46119L,46120L,46121L,46122L,46123L,46124L,46125L,46126L,46127L,
+46128L,46129L,46130L,46131L,46132L,46133L,46134L,46135L,46136L,46137L,
+46138L,46139L,46140L,46141L,46142L,46143L,46144L,46145L,46146L,46147L,
+46148L,46149L,46150L,46151L,46152L,46153L,46154L,46155L,46156L,46157L,
+46158L,46159L,46160L,46161L,46162L,46163L,46164L,46165L,46166L,46167L,
+46168L,46169L,46170L,46171L,46172L,46173L,46174L,46175L,46176L,46177L,
+46178L,46179L,46180L,46181L,46182L,46183L,46184L,46185L,46186L,46187L,
+46188L,46189L,46190L,46191L,46192L,46193L,46194L,46195L,46196L,46197L,
+46198L,46199L,46200L,46201L,46202L,46203L,46204L,46205L,46206L,46207L,
+46208L,46209L,46210L,46211L,46212L,46213L,46214L,46215L,46216L,46217L,
+46218L,46219L,46220L,46221L,46222L,46223L,46224L,46225L,46226L,46227L,
+46228L,46229L,46230L,46231L,46232L,46233L,46234L,46235L,46236L,46237L,
+46238L,46239L,46240L,46241L,46242L,46243L,46244L,46245L,46246L,46247L,
+46248L,46249L,46250L,46251L,46252L,46253L,46254L,46255L,46256L,46257L,
+46258L,46259L,46260L,46261L,46262L,46263L,46264L,46265L,46266L,46267L,
+46268L,46269L,46270L,46271L,46272L,46273L,46274L,46275L,46276L,46277L,
+46278L,46279L,46280L,46281L,46282L,46283L,46284L,46285L,46286L,46287L,
+46288L,46289L,46290L,46291L,46292L,46293L,46294L,46295L,46296L,46297L,
+46298L,46299L,46300L,46301L,46302L,46303L,46304L,46305L,46306L,46307L,
+46308L,46309L,46310L,46311L,46312L,46313L,46314L,46315L,46316L,46317L,
+46318L,46319L,46320L,46321L,46322L,46323L,46324L,46325L,46326L,46327L,
+46328L,46329L,46330L,46331L,46332L,46333L,46334L,46335L,46336L,46337L,
+46338L,46339L,46340L,46341L,46342L,46343L,46344L,46345L,46346L,46347L,
+46348L,46349L,46350L,46351L,46352L,46353L,46354L,46355L,46356L,46357L,
+46358L,46359L,46360L,46361L,46362L,46363L,46364L,46365L,46366L,46367L,
+46368L,46369L,46370L,46371L,46372L,46373L,46374L,46375L,46376L,46377L,
+46378L,46379L,46380L,46381L,46382L,46383L,46384L,46385L,46386L,46387L,
+46388L,46389L,46390L,46391L,46392L,46393L,46394L,46395L,46396L,46397L,
+46398L,46399L,46400L,46401L,46402L,46403L,46404L,46405L,46406L,46407L,
+46408L,46409L,46410L,46411L,46412L,46413L,46414L,46415L,46416L,46417L,
+46418L,46419L,46420L,46421L,46422L,46423L,46424L,46425L,46426L,46427L,
+46428L,46429L,46430L,46431L,46432L,46433L,46434L,46435L,46436L,46437L,
+46438L,46439L,46440L,46441L,46442L,46443L,46444L,46445L,46446L,46447L,
+46448L,46449L,46450L,46451L,46452L,46453L,46454L,46455L,46456L,46457L,
+46458L,46459L,46460L,46461L,46462L,46463L,46464L,46465L,46466L,46467L,
+46468L,46469L,46470L,46471L,46472L,46473L,46474L,46475L,46476L,46477L,
+46478L,46479L,46480L,46481L,46482L,46483L,46484L,46485L,46486L,46487L,
+46488L,46489L,46490L,46491L,46492L,46493L,46494L,46495L,46496L,46497L,
+46498L,46499L,46500L,46501L,46502L,46503L,46504L,46505L,46506L,46507L,
+46508L,46509L,46510L,46511L,46512L,46513L,46514L,46515L,46516L,46517L,
+46518L,46519L,46520L,46521L,46522L,46523L,46524L,46525L,46526L,46527L,
+46528L,46529L,46530L,46531L,46532L,46533L,46534L,46535L,46536L,46537L,
+46538L,46539L,46540L,46541L,46542L,46543L,46544L,46545L,46546L,46547L,
+46548L,46549L,46550L,46551L,46552L,46553L,46554L,46555L,46556L,46557L,
+46558L,46559L,46560L,46561L,46562L,46563L,46564L,46565L,46566L,46567L,
+46568L,46569L,46570L,46571L,46572L,46573L,46574L,46575L,46576L,46577L,
+46578L,46579L,46580L,46581L,46582L,46583L,46584L,46585L,46586L,46587L,
+46588L,46589L,46590L,46591L,46592L,46593L,46594L,46595L,46596L,46597L,
+46598L,46599L,46600L,46601L,46602L,46603L,46604L,46605L,46606L,46607L,
+46608L,46609L,46610L,46611L,46612L,46613L,46614L,46615L,46616L,46617L,
+46618L,46619L,46620L,46621L,46622L,46623L,46624L,46625L,46626L,46627L,
+46628L,46629L,46630L,46631L,46632L,46633L,46634L,46635L,46636L,46637L,
+46638L,46639L,46640L,46641L,46642L,46643L,46644L,46645L,46646L,46647L,
+46648L,46649L,46650L,46651L,46652L,46653L,46654L,46655L,46656L,46657L,
+46658L,46659L,46660L,46661L,46662L,46663L,46664L,46665L,46666L,46667L,
+46668L,46669L,46670L,46671L,46672L,46673L,46674L,46675L,46676L,46677L,
+46678L,46679L,46680L,46681L,46682L,46683L,46684L,46685L,46686L,46687L,
+46688L,46689L,46690L,46691L,46692L,46693L,46694L,46695L,46696L,46697L,
+46698L,46699L,46700L,46701L,46702L,46703L,46704L,46705L,46706L,46707L,
+46708L,46709L,46710L,46711L,46712L,46713L,46714L,46715L,46716L,46717L,
+46718L,46719L,46720L,46721L,46722L,46723L,46724L,46725L,46726L,46727L,
+46728L,46729L,46730L,46731L,46732L,46733L,46734L,46735L,46736L,46737L,
+46738L,46739L,46740L,46741L,46742L,46743L,46744L,46745L,46746L,46747L,
+46748L,46749L,46750L,46751L,46752L,46753L,46754L,46755L,46756L,46757L,
+46758L,46759L,46760L,46761L,46762L,46763L,46764L,46765L,46766L,46767L,
+46768L,46769L,46770L,46771L,46772L,46773L,46774L,46775L,46776L,46777L,
+46778L,46779L,46780L,46781L,46782L,46783L,46784L,46785L,46786L,46787L,
+46788L,46789L,46790L,46791L,46792L,46793L,46794L,46795L,46796L,46797L,
+46798L,46799L,46800L,46801L,46802L,46803L,46804L,46805L,46806L,46807L,
+46808L,46809L,46810L,46811L,46812L,46813L,46814L,46815L,46816L,46817L,
+46818L,46819L,46820L,46821L,46822L,46823L,46824L,46825L,46826L,46827L,
+46828L,46829L,46830L,46831L,46832L,46833L,46834L,46835L,46836L,46837L,
+46838L,46839L,46840L,46841L,46842L,46843L,46844L,46845L,46846L,46847L,
+46848L,46849L,46850L,46851L,46852L,46853L,46854L,46855L,46856L,46857L,
+46858L,46859L,46860L,46861L,46862L,46863L,46864L,46865L,46866L,46867L,
+46868L,46869L,46870L,46871L,46872L,46873L,46874L,46875L,46876L,46877L,
+46878L,46879L,46880L,46881L,46882L,46883L,46884L,46885L,46886L,46887L,
+46888L,46889L,46890L,46891L,46892L,46893L,46894L,46895L,46896L,46897L,
+46898L,46899L,46900L,46901L,46902L,46903L,46904L,46905L,46906L,46907L,
+46908L,46909L,46910L,46911L,46912L,46913L,46914L,46915L,46916L,46917L,
+46918L,46919L,46920L,46921L,46922L,46923L,46924L,46925L,46926L,46927L,
+46928L,46929L,46930L,46931L,46932L,46933L,46934L,46935L,46936L,46937L,
+46938L,46939L,46940L,46941L,46942L,46943L,46944L,46945L,46946L,46947L,
+46948L,46949L,46950L,46951L,46952L,46953L,46954L,46955L,46956L,46957L,
+46958L,46959L,46960L,46961L,46962L,46963L,46964L,46965L,46966L,46967L,
+46968L,46969L,46970L,46971L,46972L,46973L,46974L,46975L,46976L,46977L,
+46978L,46979L,46980L,46981L,46982L,46983L,46984L,46985L,46986L,46987L,
+46988L,46989L,46990L,46991L,46992L,46993L,46994L,46995L,46996L,46997L,
+46998L,46999L,47000L,47001L,47002L,47003L,47004L,47005L,47006L,47007L,
+47008L,47009L,47010L,47011L,47012L,47013L,47014L,47015L,47016L,47017L,
+47018L,47019L,47020L,47021L,47022L,47023L,47024L,47025L,47026L,47027L,
+47028L,47029L,47030L,47031L,47032L,47033L,47034L,47035L,47036L,47037L,
+47038L,47039L,47040L,47041L,47042L,47043L,47044L,47045L,47046L,47047L,
+47048L,47049L,47050L,47051L,47052L,47053L,47054L,47055L,47056L,47057L,
+47058L,47059L,47060L,47061L,47062L,47063L,47064L,47065L,47066L,47067L,
+47068L,47069L,47070L,47071L,47072L,47073L,47074L,47075L,47076L,47077L,
+47078L,47079L,47080L,47081L,47082L,47083L,47084L,47085L,47086L,47087L,
+47088L,47089L,47090L,47091L,47092L,47093L,47094L,47095L,47096L,47097L,
+47098L,47099L,47100L,47101L,47102L,47103L,47104L,47105L,47106L,47107L,
+47108L,47109L,47110L,47111L,47112L,47113L,47114L,47115L,47116L,47117L,
+47118L,47119L,47120L,47121L,47122L,47123L,47124L,47125L,47126L,47127L,
+47128L,47129L,47130L,47131L,47132L,47133L,47134L,47135L,47136L,47137L,
+47138L,47139L,47140L,47141L,47142L,47143L,47144L,47145L,47146L,47147L,
+47148L,47149L,47150L,47151L,47152L,47153L,47154L,47155L,47156L,47157L,
+47158L,47159L,47160L,47161L,47162L,47163L,47164L,47165L,47166L,47167L,
+47168L,47169L,47170L,47171L,47172L,47173L,47174L,47175L,47176L,47177L,
+47178L,47179L,47180L,47181L,47182L,47183L,47184L,47185L,47186L,47187L,
+47188L,47189L,47190L,47191L,47192L,47193L,47194L,47195L,47196L,47197L,
+47198L,47199L,47200L,47201L,47202L,47203L,47204L,47205L,47206L,47207L,
+47208L,47209L,47210L,47211L,47212L,47213L,47214L,47215L,47216L,47217L,
+47218L,47219L,47220L,47221L,47222L,47223L,47224L,47225L,47226L,47227L,
+47228L,47229L,47230L,47231L,47232L,47233L,47234L,47235L,47236L,47237L,
+47238L,47239L,47240L,47241L,47242L,47243L,47244L,47245L,47246L,47247L,
+47248L,47249L,47250L,47251L,47252L,47253L,47254L,47255L,47256L,47257L,
+47258L,47259L,47260L,47261L,47262L,47263L,47264L,47265L,47266L,47267L,
+47268L,47269L,47270L,47271L,47272L,47273L,47274L,47275L,47276L,47277L,
+47278L,47279L,47280L,47281L,47282L,47283L,47284L,47285L,47286L,47287L,
+47288L,47289L,47290L,47291L,47292L,47293L,47294L,47295L,47296L,47297L,
+47298L,47299L,47300L,47301L,47302L,47303L,47304L,47305L,47306L,47307L,
+47308L,47309L,47310L,47311L,47312L,47313L,47314L,47315L,47316L,47317L,
+47318L,47319L,47320L,47321L,47322L,47323L,47324L,47325L,47326L,47327L,
+47328L,47329L,47330L,47331L,47332L,47333L,47334L,47335L,47336L,47337L,
+47338L,47339L,47340L,47341L,47342L,47343L,47344L,47345L,47346L,47347L,
+47348L,47349L,47350L,47351L,47352L,47353L,47354L,47355L,47356L,47357L,
+47358L,47359L,47360L,47361L,47362L,47363L,47364L,47365L,47366L,47367L,
+47368L,47369L,47370L,47371L,47372L,47373L,47374L,47375L,47376L,47377L,
+47378L,47379L,47380L,47381L,47382L,47383L,47384L,47385L,47386L,47387L,
+47388L,47389L,47390L,47391L,47392L,47393L,47394L,47395L,47396L,47397L,
+47398L,47399L,47400L,47401L,47402L,47403L,47404L,47405L,47406L,47407L,
+47408L,47409L,47410L,47411L,47412L,47413L,47414L,47415L,47416L,47417L,
+47418L,47419L,47420L,47421L,47422L,47423L,47424L,47425L,47426L,47427L,
+47428L,47429L,47430L,47431L,47432L,47433L,47434L,47435L,47436L,47437L,
+47438L,47439L,47440L,47441L,47442L,47443L,47444L,47445L,47446L,47447L,
+47448L,47449L,47450L,47451L,47452L,47453L,47454L,47455L,47456L,47457L,
+47458L,47459L,47460L,47461L,47462L,47463L,47464L,47465L,47466L,47467L,
+47468L,47469L,47470L,47471L,47472L,47473L,47474L,47475L,47476L,47477L,
+47478L,47479L,47480L,47481L,47482L,47483L,47484L,47485L,47486L,47487L,
+47488L,47489L,47490L,47491L,47492L,47493L,47494L,47495L,47496L,47497L,
+47498L,47499L,47500L,47501L,47502L,47503L,47504L,47505L,47506L,47507L,
+47508L,47509L,47510L,47511L,47512L,47513L,47514L,47515L,47516L,47517L,
+47518L,47519L,47520L,47521L,47522L,47523L,47524L,47525L,47526L,47527L,
+47528L,47529L,47530L,47531L,47532L,47533L,47534L,47535L,47536L,47537L,
+47538L,47539L,47540L,47541L,47542L,47543L,47544L,47545L,47546L,47547L,
+47548L,47549L,47550L,47551L,47552L,47553L,47554L,47555L,47556L,47557L,
+47558L,47559L,47560L,47561L,47562L,47563L,47564L,47565L,47566L,47567L,
+47568L,47569L,47570L,47571L,47572L,47573L,47574L,47575L,47576L,47577L,
+47578L,47579L,47580L,47581L,47582L,47583L,47584L,47585L,47586L,47587L,
+47588L,47589L,47590L,47591L,47592L,47593L,47594L,47595L,47596L,47597L,
+47598L,47599L,47600L,47601L,47602L,47603L,47604L,47605L,47606L,47607L,
+47608L,47609L,47610L,47611L,47612L,47613L,47614L,47615L,47616L,47617L,
+47618L,47619L,47620L,47621L,47622L,47623L,47624L,47625L,47626L,47627L,
+47628L,47629L,47630L,47631L,47632L,47633L,47634L,47635L,47636L,47637L,
+47638L,47639L,47640L,47641L,47642L,47643L,47644L,47645L,47646L,47647L,
+47648L,47649L,47650L,47651L,47652L,47653L,47654L,47655L,47656L,47657L,
+47658L,47659L,47660L,47661L,47662L,47663L,47664L,47665L,47666L,47667L,
+47668L,47669L,47670L,47671L,47672L,47673L,47674L,47675L,47676L,47677L,
+47678L,47679L,47680L,47681L,47682L,47683L,47684L,47685L,47686L,47687L,
+47688L,47689L,47690L,47691L,47692L,47693L,47694L,47695L,47696L,47697L,
+47698L,47699L,47700L,47701L,47702L,47703L,47704L,47705L,47706L,47707L,
+47708L,47709L,47710L,47711L,47712L,47713L,47714L,47715L,47716L,47717L,
+47718L,47719L,47720L,47721L,47722L,47723L,47724L,47725L,47726L,47727L,
+47728L,47729L,47730L,47731L,47732L,47733L,47734L,47735L,47736L,47737L,
+47738L,47739L,47740L,47741L,47742L,47743L,47744L,47745L,47746L,47747L,
+47748L,47749L,47750L,47751L,47752L,47753L,47754L,47755L,47756L,47757L,
+47758L,47759L,47760L,47761L,47762L,47763L,47764L,47765L,47766L,47767L,
+47768L,47769L,47770L,47771L,47772L,47773L,47774L,47775L,47776L,47777L,
+47778L,47779L,47780L,47781L,47782L,47783L,47784L,47785L,47786L,47787L,
+47788L,47789L,47790L,47791L,47792L,47793L,47794L,47795L,47796L,47797L,
+47798L,47799L,47800L,47801L,47802L,47803L,47804L,47805L,47806L,47807L,
+47808L,47809L,47810L,47811L,47812L,47813L,47814L,47815L,47816L,47817L,
+47818L,47819L,47820L,47821L,47822L,47823L,47824L,47825L,47826L,47827L,
+47828L,47829L,47830L,47831L,47832L,47833L,47834L,47835L,47836L,47837L,
+47838L,47839L,47840L,47841L,47842L,47843L,47844L,47845L,47846L,47847L,
+47848L,47849L,47850L,47851L,47852L,47853L,47854L,47855L,47856L,47857L,
+47858L,47859L,47860L,47861L,47862L,47863L,47864L,47865L,47866L,47867L,
+47868L,47869L,47870L,47871L,47872L,47873L,47874L,47875L,47876L,47877L,
+47878L,47879L,47880L,47881L,47882L,47883L,47884L,47885L,47886L,47887L,
+47888L,47889L,47890L,47891L,47892L,47893L,47894L,47895L,47896L,47897L,
+47898L,47899L,47900L,47901L,47902L,47903L,47904L,47905L,47906L,47907L,
+47908L,47909L,47910L,47911L,47912L,47913L,47914L,47915L,47916L,47917L,
+47918L,47919L,47920L,47921L,47922L,47923L,47924L,47925L,47926L,47927L,
+47928L,47929L,47930L,47931L,47932L,47933L,47934L,47935L,47936L,47937L,
+47938L,47939L,47940L,47941L,47942L,47943L,47944L,47945L,47946L,47947L,
+47948L,47949L,47950L,47951L,47952L,47953L,47954L,47955L,47956L,47957L,
+47958L,47959L,47960L,47961L,47962L,47963L,47964L,47965L,47966L,47967L,
+47968L,47969L,47970L,47971L,47972L,47973L,47974L,47975L,47976L,47977L,
+47978L,47979L,47980L,47981L,47982L,47983L,47984L,47985L,47986L,47987L,
+47988L,47989L,47990L,47991L,47992L,47993L,47994L,47995L,47996L,47997L,
+47998L,47999L,48000L,48001L,48002L,48003L,48004L,48005L,48006L,48007L,
+48008L,48009L,48010L,48011L,48012L,48013L,48014L,48015L,48016L,48017L,
+48018L,48019L,48020L,48021L,48022L,48023L,48024L,48025L,48026L,48027L,
+48028L,48029L,48030L,48031L,48032L,48033L,48034L,48035L,48036L,48037L,
+48038L,48039L,48040L,48041L,48042L,48043L,48044L,48045L,48046L,48047L,
+48048L,48049L,48050L,48051L,48052L,48053L,48054L,48055L,48056L,48057L,
+48058L,48059L,48060L,48061L,48062L,48063L,48064L,48065L,48066L,48067L,
+48068L,48069L,48070L,48071L,48072L,48073L,48074L,48075L,48076L,48077L,
+48078L,48079L,48080L,48081L,48082L,48083L,48084L,48085L,48086L,48087L,
+48088L,48089L,48090L,48091L,48092L,48093L,48094L,48095L,48096L,48097L,
+48098L,48099L,48100L,48101L,48102L,48103L,48104L,48105L,48106L,48107L,
+48108L,48109L,48110L,48111L,48112L,48113L,48114L,48115L,48116L,48117L,
+48118L,48119L,48120L,48121L,48122L,48123L,48124L,48125L,48126L,48127L,
+48128L,48129L,48130L,48131L,48132L,48133L,48134L,48135L,48136L,48137L,
+48138L,48139L,48140L,48141L,48142L,48143L,48144L,48145L,48146L,48147L,
+48148L,48149L,48150L,48151L,48152L,48153L,48154L,48155L,48156L,48157L,
+48158L,48159L,48160L,48161L,48162L,48163L,48164L,48165L,48166L,48167L,
+48168L,48169L,48170L,48171L,48172L,48173L,48174L,48175L,48176L,48177L,
+48178L,48179L,48180L,48181L,48182L,48183L,48184L,48185L,48186L,48187L,
+48188L,48189L,48190L,48191L,48192L,48193L,48194L,48195L,48196L,48197L,
+48198L,48199L,48200L,48201L,48202L,48203L,48204L,48205L,48206L,48207L,
+48208L,48209L,48210L,48211L,48212L,48213L,48214L,48215L,48216L,48217L,
+48218L,48219L,48220L,48221L,48222L,48223L,48224L,48225L,48226L,48227L,
+48228L,48229L,48230L,48231L,48232L,48233L,48234L,48235L,48236L,48237L,
+48238L,48239L,48240L,48241L,48242L,48243L,48244L,48245L,48246L,48247L,
+48248L,48249L,48250L,48251L,48252L,48253L,48254L,48255L,48256L,48257L,
+48258L,48259L,48260L,48261L,48262L,48263L,48264L,48265L,48266L,48267L,
+48268L,48269L,48270L,48271L,48272L,48273L,48274L,48275L,48276L,48277L,
+48278L,48279L,48280L,48281L,48282L,48283L,48284L,48285L,48286L,48287L,
+48288L,48289L,48290L,48291L,48292L,48293L,48294L,48295L,48296L,48297L,
+48298L,48299L,48300L,48301L,48302L,48303L,48304L,48305L,48306L,48307L,
+48308L,48309L,48310L,48311L,48312L,48313L,48314L,48315L,48316L,48317L,
+48318L,48319L,48320L,48321L,48322L,48323L,48324L,48325L,48326L,48327L,
+48328L,48329L,48330L,48331L,48332L,48333L,48334L,48335L,48336L,48337L,
+48338L,48339L,48340L,48341L,48342L,48343L,48344L,48345L,48346L,48347L,
+48348L,48349L,48350L,48351L,48352L,48353L,48354L,48355L,48356L,48357L,
+48358L,48359L,48360L,48361L,48362L,48363L,48364L,48365L,48366L,48367L,
+48368L,48369L,48370L,48371L,48372L,48373L,48374L,48375L,48376L,48377L,
+48378L,48379L,48380L,48381L,48382L,48383L,48384L,48385L,48386L,48387L,
+48388L,48389L,48390L,48391L,48392L,48393L,48394L,48395L,48396L,48397L,
+48398L,48399L,48400L,48401L,48402L,48403L,48404L,48405L,48406L,48407L,
+48408L,48409L,48410L,48411L,48412L,48413L,48414L,48415L,48416L,48417L,
+48418L,48419L,48420L,48421L,48422L,48423L,48424L,48425L,48426L,48427L,
+48428L,48429L,48430L,48431L,48432L,48433L,48434L,48435L,48436L,48437L,
+48438L,48439L,48440L,48441L,48442L,48443L,48444L,48445L,48446L,48447L,
+48448L,48449L,48450L,48451L,48452L,48453L,48454L,48455L,48456L,48457L,
+48458L,48459L,48460L,48461L,48462L,48463L,48464L,48465L,48466L,48467L,
+48468L,48469L,48470L,48471L,48472L,48473L,48474L,48475L,48476L,48477L,
+48478L,48479L,48480L,48481L,48482L,48483L,48484L,48485L,48486L,48487L,
+48488L,48489L,48490L,48491L,48492L,48493L,48494L,48495L,48496L,48497L,
+48498L,48499L,48500L,48501L,48502L,48503L,48504L,48505L,48506L,48507L,
+48508L,48509L,48510L,48511L,48512L,48513L,48514L,48515L,48516L,48517L,
+48518L,48519L,48520L,48521L,48522L,48523L,48524L,48525L,48526L,48527L,
+48528L,48529L,48530L,48531L,48532L,48533L,48534L,48535L,48536L,48537L,
+48538L,48539L,48540L,48541L,48542L,48543L,48544L,48545L,48546L,48547L,
+48548L,48549L,48550L,48551L,48552L,48553L,48554L,48555L,48556L,48557L,
+48558L,48559L,48560L,48561L,48562L,48563L,48564L,48565L,48566L,48567L,
+48568L,48569L,48570L,48571L,48572L,48573L,48574L,48575L,48576L,48577L,
+48578L,48579L,48580L,48581L,48582L,48583L,48584L,48585L,48586L,48587L,
+48588L,48589L,48590L,48591L,48592L,48593L,48594L,48595L,48596L,48597L,
+48598L,48599L,48600L,48601L,48602L,48603L,48604L,48605L,48606L,48607L,
+48608L,48609L,48610L,48611L,48612L,48613L,48614L,48615L,48616L,48617L,
+48618L,48619L,48620L,48621L,48622L,48623L,48624L,48625L,48626L,48627L,
+48628L,48629L,48630L,48631L,48632L,48633L,48634L,48635L,48636L,48637L,
+48638L,48639L,48640L,48641L,48642L,48643L,48644L,48645L,48646L,48647L,
+48648L,48649L,48650L,48651L,48652L,48653L,48654L,48655L,48656L,48657L,
+48658L,48659L,48660L,48661L,48662L,48663L,48664L,48665L,48666L,48667L,
+48668L,48669L,48670L,48671L,48672L,48673L,48674L,48675L,48676L,48677L,
+48678L,48679L,48680L,48681L,48682L,48683L,48684L,48685L,48686L,48687L,
+48688L,48689L,48690L,48691L,48692L,48693L,48694L,48695L,48696L,48697L,
+48698L,48699L,48700L,48701L,48702L,48703L,48704L,48705L,48706L,48707L,
+48708L,48709L,48710L,48711L,48712L,48713L,48714L,48715L,48716L,48717L,
+48718L,48719L,48720L,48721L,48722L,48723L,48724L,48725L,48726L,48727L,
+48728L,48729L,48730L,48731L,48732L,48733L,48734L,48735L,48736L,48737L,
+48738L,48739L,48740L,48741L,48742L,48743L,48744L,48745L,48746L,48747L,
+48748L,48749L,48750L,48751L,48752L,48753L,48754L,48755L,48756L,48757L,
+48758L,48759L,48760L,48761L,48762L,48763L,48764L,48765L,48766L,48767L,
+48768L,48769L,48770L,48771L,48772L,48773L,48774L,48775L,48776L,48777L,
+48778L,48779L,48780L,48781L,48782L,48783L,48784L,48785L,48786L,48787L,
+48788L,48789L,48790L,48791L,48792L,48793L,48794L,48795L,48796L,48797L,
+48798L,48799L,48800L,48801L,48802L,48803L,48804L,48805L,48806L,48807L,
+48808L,48809L,48810L,48811L,48812L,48813L,48814L,48815L,48816L,48817L,
+48818L,48819L,48820L,48821L,48822L,48823L,48824L,48825L,48826L,48827L,
+48828L,48829L,48830L,48831L,48832L,48833L,48834L,48835L,48836L,48837L,
+48838L,48839L,48840L,48841L,48842L,48843L,48844L,48845L,48846L,48847L,
+48848L,48849L,48850L,48851L,48852L,48853L,48854L,48855L,48856L,48857L,
+48858L,48859L,48860L,48861L,48862L,48863L,48864L,48865L,48866L,48867L,
+48868L,48869L,48870L,48871L,48872L,48873L,48874L,48875L,48876L,48877L,
+48878L,48879L,48880L,48881L,48882L,48883L,48884L,48885L,48886L,48887L,
+48888L,48889L,48890L,48891L,48892L,48893L,48894L,48895L,48896L,48897L,
+48898L,48899L,48900L,48901L,48902L,48903L,48904L,48905L,48906L,48907L,
+48908L,48909L,48910L,48911L,48912L,48913L,48914L,48915L,48916L,48917L,
+48918L,48919L,48920L,48921L,48922L,48923L,48924L,48925L,48926L,48927L,
+48928L,48929L,48930L,48931L,48932L,48933L,48934L,48935L,48936L,48937L,
+48938L,48939L,48940L,48941L,48942L,48943L,48944L,48945L,48946L,48947L,
+48948L,48949L,48950L,48951L,48952L,48953L,48954L,48955L,48956L,48957L,
+48958L,48959L,48960L,48961L,48962L,48963L,48964L,48965L,48966L,48967L,
+48968L,48969L,48970L,48971L,48972L,48973L,48974L,48975L,48976L,48977L,
+48978L,48979L,48980L,48981L,48982L,48983L,48984L,48985L,48986L,48987L,
+48988L,48989L,48990L,48991L,48992L,48993L,48994L,48995L,48996L,48997L,
+48998L,48999L,49000L,49001L,49002L,49003L,49004L,49005L,49006L,49007L,
+49008L,49009L,49010L,49011L,49012L,49013L,49014L,49015L,49016L,49017L,
+49018L,49019L,49020L,49021L,49022L,49023L,49024L,49025L,49026L,49027L,
+49028L,49029L,49030L,49031L,49032L,49033L,49034L,49035L,49036L,49037L,
+49038L,49039L,49040L,49041L,49042L,49043L,49044L,49045L,49046L,49047L,
+49048L,49049L,49050L,49051L,49052L,49053L,49054L,49055L,49056L,49057L,
+49058L,49059L,49060L,49061L,49062L,49063L,49064L,49065L,49066L,49067L,
+49068L,49069L,49070L,49071L,49072L,49073L,49074L,49075L,49076L,49077L,
+49078L,49079L,49080L,49081L,49082L,49083L,49084L,49085L,49086L,49087L,
+49088L,49089L,49090L,49091L,49092L,49093L,49094L,49095L,49096L,49097L,
+49098L,49099L,49100L,49101L,49102L,49103L,49104L,49105L,49106L,49107L,
+49108L,49109L,49110L,49111L,49112L,49113L,49114L,49115L,49116L,49117L,
+49118L,49119L,49120L,49121L,49122L,49123L,49124L,49125L,49126L,49127L,
+49128L,49129L,49130L,49131L,49132L,49133L,49134L,49135L,49136L,49137L,
+49138L,49139L,49140L,49141L,49142L,49143L,49144L,49145L,49146L,49147L,
+49148L,49149L,49150L,49151L,49152L,49153L,49154L,49155L,49156L,49157L,
+49158L,49159L,49160L,49161L,49162L,49163L,49164L,49165L,49166L,49167L,
+49168L,49169L,49170L,49171L,49172L,49173L,49174L,49175L,49176L,49177L,
+49178L,49179L,49180L,49181L,49182L,49183L,49184L,49185L,49186L,49187L,
+49188L,49189L,49190L,49191L,49192L,49193L,49194L,49195L,49196L,49197L,
+49198L,49199L,49200L,49201L,49202L,49203L,49204L,49205L,49206L,49207L,
+49208L,49209L,49210L,49211L,49212L,49213L,49214L,49215L,49216L,49217L,
+49218L,49219L,49220L,49221L,49222L,49223L,49224L,49225L,49226L,49227L,
+49228L,49229L,49230L,49231L,49232L,49233L,49234L,49235L,49236L,49237L,
+49238L,49239L,49240L,49241L,49242L,49243L,49244L,49245L,49246L,49247L,
+49248L,49249L,49250L,49251L,49252L,49253L,49254L,49255L,49256L,49257L,
+49258L,49259L,49260L,49261L,49262L,49263L,49264L,49265L,49266L,49267L,
+49268L,49269L,49270L,49271L,49272L,49273L,49274L,49275L,49276L,49277L,
+49278L,49279L,49280L,49281L,49282L,49283L,49284L,49285L,49286L,49287L,
+49288L,49289L,49290L,49291L,49292L,49293L,49294L,49295L,49296L,49297L,
+49298L,49299L,49300L,49301L,49302L,49303L,49304L,49305L,49306L,49307L,
+49308L,49309L,49310L,49311L,49312L,49313L,49314L,49315L,49316L,49317L,
+49318L,49319L,49320L,49321L,49322L,49323L,49324L,49325L,49326L,49327L,
+49328L,49329L,49330L,49331L,49332L,49333L,49334L,49335L,49336L,49337L,
+49338L,49339L,49340L,49341L,49342L,49343L,49344L,49345L,49346L,49347L,
+49348L,49349L,49350L,49351L,49352L,49353L,49354L,49355L,49356L,49357L,
+49358L,49359L,49360L,49361L,49362L,49363L,49364L,49365L,49366L,49367L,
+49368L,49369L,49370L,49371L,49372L,49373L,49374L,49375L,49376L,49377L,
+49378L,49379L,49380L,49381L,49382L,49383L,49384L,49385L,49386L,49387L,
+49388L,49389L,49390L,49391L,49392L,49393L,49394L,49395L,49396L,49397L,
+49398L,49399L,49400L,49401L,49402L,49403L,49404L,49405L,49406L,49407L,
+49408L,49409L,49410L,49411L,49412L,49413L,49414L,49415L,49416L,49417L,
+49418L,49419L,49420L,49421L,49422L,49423L,49424L,49425L,49426L,49427L,
+49428L,49429L,49430L,49431L,49432L,49433L,49434L,49435L,49436L,49437L,
+49438L,49439L,49440L,49441L,49442L,49443L,49444L,49445L,49446L,49447L,
+49448L,49449L,49450L,49451L,49452L,49453L,49454L,49455L,49456L,49457L,
+49458L,49459L,49460L,49461L,49462L,49463L,49464L,49465L,49466L,49467L,
+49468L,49469L,49470L,49471L,49472L,49473L,49474L,49475L,49476L,49477L,
+49478L,49479L,49480L,49481L,49482L,49483L,49484L,49485L,49486L,49487L,
+49488L,49489L,49490L,49491L,49492L,49493L,49494L,49495L,49496L,49497L,
+49498L,49499L,49500L,49501L,49502L,49503L,49504L,49505L,49506L,49507L,
+49508L,49509L,49510L,49511L,49512L,49513L,49514L,49515L,49516L,49517L,
+49518L,49519L,49520L,49521L,49522L,49523L,49524L,49525L,49526L,49527L,
+49528L,49529L,49530L,49531L,49532L,49533L,49534L,49535L,49536L,49537L,
+49538L,49539L,49540L,49541L,49542L,49543L,49544L,49545L,49546L,49547L,
+49548L,49549L,49550L,49551L,49552L,49553L,49554L,49555L,49556L,49557L,
+49558L,49559L,49560L,49561L,49562L,49563L,49564L,49565L,49566L,49567L,
+49568L,49569L,49570L,49571L,49572L,49573L,49574L,49575L,49576L,49577L,
+49578L,49579L,49580L,49581L,49582L,49583L,49584L,49585L,49586L,49587L,
+49588L,49589L,49590L,49591L,49592L,49593L,49594L,49595L,49596L,49597L,
+49598L,49599L,49600L,49601L,49602L,49603L,49604L,49605L,49606L,49607L,
+49608L,49609L,49610L,49611L,49612L,49613L,49614L,49615L,49616L,49617L,
+49618L,49619L,49620L,49621L,49622L,49623L,49624L,49625L,49626L,49627L,
+49628L,49629L,49630L,49631L,49632L,49633L,49634L,49635L,49636L,49637L,
+49638L,49639L,49640L,49641L,49642L,49643L,49644L,49645L,49646L,49647L,
+49648L,49649L,49650L,49651L,49652L,49653L,49654L,49655L,49656L,49657L,
+49658L,49659L,49660L,49661L,49662L,49663L,49664L,49665L,49666L,49667L,
+49668L,49669L,49670L,49671L,49672L,49673L,49674L,49675L,49676L,49677L,
+49678L,49679L,49680L,49681L,49682L,49683L,49684L,49685L,49686L,49687L,
+49688L,49689L,49690L,49691L,49692L,49693L,49694L,49695L,49696L,49697L,
+49698L,49699L,49700L,49701L,49702L,49703L,49704L,49705L,49706L,49707L,
+49708L,49709L,49710L,49711L,49712L,49713L,49714L,49715L,49716L,49717L,
+49718L,49719L,49720L,49721L,49722L,49723L,49724L,49725L,49726L,49727L,
+49728L,49729L,49730L,49731L,49732L,49733L,49734L,49735L,49736L,49737L,
+49738L,49739L,49740L,49741L,49742L,49743L,49744L,49745L,49746L,49747L,
+49748L,49749L,49750L,49751L,49752L,49753L,49754L,49755L,49756L,49757L,
+49758L,49759L,49760L,49761L,49762L,49763L,49764L,49765L,49766L,49767L,
+49768L,49769L,49770L,49771L,49772L,49773L,49774L,49775L,49776L,49777L,
+49778L,49779L,49780L,49781L,49782L,49783L,49784L,49785L,49786L,49787L,
+49788L,49789L,49790L,49791L,49792L,49793L,49794L,49795L,49796L,49797L,
+49798L,49799L,49800L,49801L,49802L,49803L,49804L,49805L,49806L,49807L,
+49808L,49809L,49810L,49811L,49812L,49813L,49814L,49815L,49816L,49817L,
+49818L,49819L,49820L,49821L,49822L,49823L,49824L,49825L,49826L,49827L,
+49828L,49829L,49830L,49831L,49832L,49833L,49834L,49835L,49836L,49837L,
+49838L,49839L,49840L,49841L,49842L,49843L,49844L,49845L,49846L,49847L,
+49848L,49849L,49850L,49851L,49852L,49853L,49854L,49855L,49856L,49857L,
+49858L,49859L,49860L,49861L,49862L,49863L,49864L,49865L,49866L,49867L,
+49868L,49869L,49870L,49871L,49872L,49873L,49874L,49875L,49876L,49877L,
+49878L,49879L,49880L,49881L,49882L,49883L,49884L,49885L,49886L,49887L,
+49888L,49889L,49890L,49891L,49892L,49893L,49894L,49895L,49896L,49897L,
+49898L,49899L,49900L,49901L,49902L,49903L,49904L,49905L,49906L,49907L,
+49908L,49909L,49910L,49911L,49912L,49913L,49914L,49915L,49916L,49917L,
+49918L,49919L,49920L,49921L,49922L,49923L,49924L,49925L,49926L,49927L,
+49928L,49929L,49930L,49931L,49932L,49933L,49934L,49935L,49936L,49937L,
+49938L,49939L,49940L,49941L,49942L,49943L,49944L,49945L,49946L,49947L,
+49948L,49949L,49950L,49951L,49952L,49953L,49954L,49955L,49956L,49957L,
+49958L,49959L,49960L,49961L,49962L,49963L,49964L,49965L,49966L,49967L,
+49968L,49969L,49970L,49971L,49972L,49973L,49974L,49975L,49976L,49977L,
+49978L,49979L,49980L,49981L,49982L,49983L,49984L,49985L,49986L,49987L,
+49988L,49989L,49990L,49991L,49992L,49993L,49994L,49995L,49996L,49997L,
+49998L,49999L,50000L,50001L,50002L,50003L,50004L,50005L,50006L,50007L,
+50008L,50009L,50010L,50011L,50012L,50013L,50014L,50015L,50016L,50017L,
+50018L,50019L,50020L,50021L,50022L,50023L,50024L,50025L,50026L,50027L,
+50028L,50029L,50030L,50031L,50032L,50033L,50034L,50035L,50036L,50037L,
+50038L,50039L,50040L,50041L,50042L,50043L,50044L,50045L,50046L,50047L,
+50048L,50049L,50050L,50051L,50052L,50053L,50054L,50055L,50056L,50057L,
+50058L,50059L,50060L,50061L,50062L,50063L,50064L,50065L,50066L,50067L,
+50068L,50069L,50070L,50071L,50072L,50073L,50074L,50075L,50076L,50077L,
+50078L,50079L,50080L,50081L,50082L,50083L,50084L,50085L,50086L,50087L,
+50088L,50089L,50090L,50091L,50092L,50093L,50094L,50095L,50096L,50097L,
+50098L,50099L,50100L,50101L,50102L,50103L,50104L,50105L,50106L,50107L,
+50108L,50109L,50110L,50111L,50112L,50113L,50114L,50115L,50116L,50117L,
+50118L,50119L,50120L,50121L,50122L,50123L,50124L,50125L,50126L,50127L,
+50128L,50129L,50130L,50131L,50132L,50133L,50134L,50135L,50136L,50137L,
+50138L,50139L,50140L,50141L,50142L,50143L,50144L,50145L,50146L,50147L,
+50148L,50149L,50150L,50151L,50152L,50153L,50154L,50155L,50156L,50157L,
+50158L,50159L,50160L,50161L,50162L,50163L,50164L,50165L,50166L,50167L,
+50168L,50169L,50170L,50171L,50172L,50173L,50174L,50175L,50176L,50177L,
+50178L,50179L,50180L,50181L,50182L,50183L,50184L,50185L,50186L,50187L,
+50188L,50189L,50190L,50191L,50192L,50193L,50194L,50195L,50196L,50197L,
+50198L,50199L,50200L,50201L,50202L,50203L,50204L,50205L,50206L,50207L,
+50208L,50209L,50210L,50211L,50212L,50213L,50214L,50215L,50216L,50217L,
+50218L,50219L,50220L,50221L,50222L,50223L,50224L,50225L,50226L,50227L,
+50228L,50229L,50230L,50231L,50232L,50233L,50234L,50235L,50236L,50237L,
+50238L,50239L,50240L,50241L,50242L,50243L,50244L,50245L,50246L,50247L,
+50248L,50249L,50250L,50251L,50252L,50253L,50254L,50255L,50256L,50257L,
+50258L,50259L,50260L,50261L,50262L,50263L,50264L,50265L,50266L,50267L,
+50268L,50269L,50270L,50271L,50272L,50273L,50274L,50275L,50276L,50277L,
+50278L,50279L,50280L,50281L,50282L,50283L,50284L,50285L,50286L,50287L,
+50288L,50289L,50290L,50291L,50292L,50293L,50294L,50295L,50296L,50297L,
+50298L,50299L,50300L,50301L,50302L,50303L,50304L,50305L,50306L,50307L,
+50308L,50309L,50310L,50311L,50312L,50313L,50314L,50315L,50316L,50317L,
+50318L,50319L,50320L,50321L,50322L,50323L,50324L,50325L,50326L,50327L,
+50328L,50329L,50330L,50331L,50332L,50333L,50334L,50335L,50336L,50337L,
+50338L,50339L,50340L,50341L,50342L,50343L,50344L,50345L,50346L,50347L,
+50348L,50349L,50350L,50351L,50352L,50353L,50354L,50355L,50356L,50357L,
+50358L,50359L,50360L,50361L,50362L,50363L,50364L,50365L,50366L,50367L,
+50368L,50369L,50370L,50371L,50372L,50373L,50374L,50375L,50376L,50377L,
+50378L,50379L,50380L,50381L,50382L,50383L,50384L,50385L,50386L,50387L,
+50388L,50389L,50390L,50391L,50392L,50393L,50394L,50395L,50396L,50397L,
+50398L,50399L,50400L,50401L,50402L,50403L,50404L,50405L,50406L,50407L,
+50408L,50409L,50410L,50411L,50412L,50413L,50414L,50415L,50416L,50417L,
+50418L,50419L,50420L,50421L,50422L,50423L,50424L,50425L,50426L,50427L,
+50428L,50429L,50430L,50431L,50432L,50433L,50434L,50435L,50436L,50437L,
+50438L,50439L,50440L,50441L,50442L,50443L,50444L,50445L,50446L,50447L,
+50448L,50449L,50450L,50451L,50452L,50453L,50454L,50455L,50456L,50457L,
+50458L,50459L,50460L,50461L,50462L,50463L,50464L,50465L,50466L,50467L,
+50468L,50469L,50470L,50471L,50472L,50473L,50474L,50475L,50476L,50477L,
+50478L,50479L,50480L,50481L,50482L,50483L,50484L,50485L,50486L,50487L,
+50488L,50489L,50490L,50491L,50492L,50493L,50494L,50495L,50496L,50497L,
+50498L,50499L,50500L,50501L,50502L,50503L,50504L,50505L,50506L,50507L,
+50508L,50509L,50510L,50511L,50512L,50513L,50514L,50515L,50516L,50517L,
+50518L,50519L,50520L,50521L,50522L,50523L,50524L,50525L,50526L,50527L,
+50528L,50529L,50530L,50531L,50532L,50533L,50534L,50535L,50536L,50537L,
+50538L,50539L,50540L,50541L,50542L,50543L,50544L,50545L,50546L,50547L,
+50548L,50549L,50550L,50551L,50552L,50553L,50554L,50555L,50556L,50557L,
+50558L,50559L,50560L,50561L,50562L,50563L,50564L,50565L,50566L,50567L,
+50568L,50569L,50570L,50571L,50572L,50573L,50574L,50575L,50576L,50577L,
+50578L,50579L,50580L,50581L,50582L,50583L,50584L,50585L,50586L,50587L,
+50588L,50589L,50590L,50591L,50592L,50593L,50594L,50595L,50596L,50597L,
+50598L,50599L,50600L,50601L,50602L,50603L,50604L,50605L,50606L,50607L,
+50608L,50609L,50610L,50611L,50612L,50613L,50614L,50615L,50616L,50617L,
+50618L,50619L,50620L,50621L,50622L,50623L,50624L,50625L,50626L,50627L,
+50628L,50629L,50630L,50631L,50632L,50633L,50634L,50635L,50636L,50637L,
+50638L,50639L,50640L,50641L,50642L,50643L,50644L,50645L,50646L,50647L,
+50648L,50649L,50650L,50651L,50652L,50653L,50654L,50655L,50656L,50657L,
+50658L,50659L,50660L,50661L,50662L,50663L,50664L,50665L,50666L,50667L,
+50668L,50669L,50670L,50671L,50672L,50673L,50674L,50675L,50676L,50677L,
+50678L,50679L,50680L,50681L,50682L,50683L,50684L,50685L,50686L,50687L,
+50688L,50689L,50690L,50691L,50692L,50693L,50694L,50695L,50696L,50697L,
+50698L,50699L,50700L,50701L,50702L,50703L,50704L,50705L,50706L,50707L,
+50708L,50709L,50710L,50711L,50712L,50713L,50714L,50715L,50716L,50717L,
+50718L,50719L,50720L,50721L,50722L,50723L,50724L,50725L,50726L,50727L,
+50728L,50729L,50730L,50731L,50732L,50733L,50734L,50735L,50736L,50737L,
+50738L,50739L,50740L,50741L,50742L,50743L,50744L,50745L,50746L,50747L,
+50748L,50749L,50750L,50751L,50752L,50753L,50754L,50755L,50756L,50757L,
+50758L,50759L,50760L,50761L,50762L,50763L,50764L,50765L,50766L,50767L,
+50768L,50769L,50770L,50771L,50772L,50773L,50774L,50775L,50776L,50777L,
+50778L,50779L,50780L,50781L,50782L,50783L,50784L,50785L,50786L,50787L,
+50788L,50789L,50790L,50791L,50792L,50793L,50794L,50795L,50796L,50797L,
+50798L,50799L,50800L,50801L,50802L,50803L,50804L,50805L,50806L,50807L,
+50808L,50809L,50810L,50811L,50812L,50813L,50814L,50815L,50816L,50817L,
+50818L,50819L,50820L,50821L,50822L,50823L,50824L,50825L,50826L,50827L,
+50828L,50829L,50830L,50831L,50832L,50833L,50834L,50835L,50836L,50837L,
+50838L,50839L,50840L,50841L,50842L,50843L,50844L,50845L,50846L,50847L,
+50848L,50849L,50850L,50851L,50852L,50853L,50854L,50855L,50856L,50857L,
+50858L,50859L,50860L,50861L,50862L,50863L,50864L,50865L,50866L,50867L,
+50868L,50869L,50870L,50871L,50872L,50873L,50874L,50875L,50876L,50877L,
+50878L,50879L,50880L,50881L,50882L,50883L,50884L,50885L,50886L,50887L,
+50888L,50889L,50890L,50891L,50892L,50893L,50894L,50895L,50896L,50897L,
+50898L,50899L,50900L,50901L,50902L,50903L,50904L,50905L,50906L,50907L,
+50908L,50909L,50910L,50911L,50912L,50913L,50914L,50915L,50916L,50917L,
+50918L,50919L,50920L,50921L,50922L,50923L,50924L,50925L,50926L,50927L,
+50928L,50929L,50930L,50931L,50932L,50933L,50934L,50935L,50936L,50937L,
+50938L,50939L,50940L,50941L,50942L,50943L,50944L,50945L,50946L,50947L,
+50948L,50949L,50950L,50951L,50952L,50953L,50954L,50955L,50956L,50957L,
+50958L,50959L,50960L,50961L,50962L,50963L,50964L,50965L,50966L,50967L,
+50968L,50969L,50970L,50971L,50972L,50973L,50974L,50975L,50976L,50977L,
+50978L,50979L,50980L,50981L,50982L,50983L,50984L,50985L,50986L,50987L,
+50988L,50989L,50990L,50991L,50992L,50993L,50994L,50995L,50996L,50997L,
+50998L,50999L,51000L,51001L,51002L,51003L,51004L,51005L,51006L,51007L,
+51008L,51009L,51010L,51011L,51012L,51013L,51014L,51015L,51016L,51017L,
+51018L,51019L,51020L,51021L,51022L,51023L,51024L,51025L,51026L,51027L,
+51028L,51029L,51030L,51031L,51032L,51033L,51034L,51035L,51036L,51037L,
+51038L,51039L,51040L,51041L,51042L,51043L,51044L,51045L,51046L,51047L,
+51048L,51049L,51050L,51051L,51052L,51053L,51054L,51055L,51056L,51057L,
+51058L,51059L,51060L,51061L,51062L,51063L,51064L,51065L,51066L,51067L,
+51068L,51069L,51070L,51071L,51072L,51073L,51074L,51075L,51076L,51077L,
+51078L,51079L,51080L,51081L,51082L,51083L,51084L,51085L,51086L,51087L,
+51088L,51089L,51090L,51091L,51092L,51093L,51094L,51095L,51096L,51097L,
+51098L,51099L,51100L,51101L,51102L,51103L,51104L,51105L,51106L,51107L,
+51108L,51109L,51110L,51111L,51112L,51113L,51114L,51115L,51116L,51117L,
+51118L,51119L,51120L,51121L,51122L,51123L,51124L,51125L,51126L,51127L,
+51128L,51129L,51130L,51131L,51132L,51133L,51134L,51135L,51136L,51137L,
+51138L,51139L,51140L,51141L,51142L,51143L,51144L,51145L,51146L,51147L,
+51148L,51149L,51150L,51151L,51152L,51153L,51154L,51155L,51156L,51157L,
+51158L,51159L,51160L,51161L,51162L,51163L,51164L,51165L,51166L,51167L,
+51168L,51169L,51170L,51171L,51172L,51173L,51174L,51175L,51176L,51177L,
+51178L,51179L,51180L,51181L,51182L,51183L,51184L,51185L,51186L,51187L,
+51188L,51189L,51190L,51191L,51192L,51193L,51194L,51195L,51196L,51197L,
+51198L,51199L,51200L,51201L,51202L,51203L,51204L,51205L,51206L,51207L,
+51208L,51209L,51210L,51211L,51212L,51213L,51214L,51215L,51216L,51217L,
+51218L,51219L,51220L,51221L,51222L,51223L,51224L,51225L,51226L,51227L,
+51228L,51229L,51230L,51231L,51232L,51233L,51234L,51235L,51236L,51237L,
+51238L,51239L,51240L,51241L,51242L,51243L,51244L,51245L,51246L,51247L,
+51248L,51249L,51250L,51251L,51252L,51253L,51254L,51255L,51256L,51257L,
+51258L,51259L,51260L,51261L,51262L,51263L,51264L,51265L,51266L,51267L,
+51268L,51269L,51270L,51271L,51272L,51273L,51274L,51275L,51276L,51277L,
+51278L,51279L,51280L,51281L,51282L,51283L,51284L,51285L,51286L,51287L,
+51288L,51289L,51290L,51291L,51292L,51293L,51294L,51295L,51296L,51297L,
+51298L,51299L,51300L,51301L,51302L,51303L,51304L,51305L,51306L,51307L,
+51308L,51309L,51310L,51311L,51312L,51313L,51314L,51315L,51316L,51317L,
+51318L,51319L,51320L,51321L,51322L,51323L,51324L,51325L,51326L,51327L,
+51328L,51329L,51330L,51331L,51332L,51333L,51334L,51335L,51336L,51337L,
+51338L,51339L,51340L,51341L,51342L,51343L,51344L,51345L,51346L,51347L,
+51348L,51349L,51350L,51351L,51352L,51353L,51354L,51355L,51356L,51357L,
+51358L,51359L,51360L,51361L,51362L,51363L,51364L,51365L,51366L,51367L,
+51368L,51369L,51370L,51371L,51372L,51373L,51374L,51375L,51376L,51377L,
+51378L,51379L,51380L,51381L,51382L,51383L,51384L,51385L,51386L,51387L,
+51388L,51389L,51390L,51391L,51392L,51393L,51394L,51395L,51396L,51397L,
+51398L,51399L,51400L,51401L,51402L,51403L,51404L,51405L,51406L,51407L,
+51408L,51409L,51410L,51411L,51412L,51413L,51414L,51415L,51416L,51417L,
+51418L,51419L,51420L,51421L,51422L,51423L,51424L,51425L,51426L,51427L,
+51428L,51429L,51430L,51431L,51432L,51433L,51434L,51435L,51436L,51437L,
+51438L,51439L,51440L,51441L,51442L,51443L,51444L,51445L,51446L,51447L,
+51448L,51449L,51450L,51451L,51452L,51453L,51454L,51455L,51456L,51457L,
+51458L,51459L,51460L,51461L,51462L,51463L,51464L,51465L,51466L,51467L,
+51468L,51469L,51470L,51471L,51472L,51473L,51474L,51475L,51476L,51477L,
+51478L,51479L,51480L,51481L,51482L,51483L,51484L,51485L,51486L,51487L,
+51488L,51489L,51490L,51491L,51492L,51493L,51494L,51495L,51496L,51497L,
+51498L,51499L,51500L,51501L,51502L,51503L,51504L,51505L,51506L,51507L,
+51508L,51509L,51510L,51511L,51512L,51513L,51514L,51515L,51516L,51517L,
+51518L,51519L,51520L,51521L,51522L,51523L,51524L,51525L,51526L,51527L,
+51528L,51529L,51530L,51531L,51532L,51533L,51534L,51535L,51536L,51537L,
+51538L,51539L,51540L,51541L,51542L,51543L,51544L,51545L,51546L,51547L,
+51548L,51549L,51550L,51551L,51552L,51553L,51554L,51555L,51556L,51557L,
+51558L,51559L,51560L,51561L,51562L,51563L,51564L,51565L,51566L,51567L,
+51568L,51569L,51570L,51571L,51572L,51573L,51574L,51575L,51576L,51577L,
+51578L,51579L,51580L,51581L,51582L,51583L,51584L,51585L,51586L,51587L,
+51588L,51589L,51590L,51591L,51592L,51593L,51594L,51595L,51596L,51597L,
+51598L,51599L,51600L,51601L,51602L,51603L,51604L,51605L,51606L,51607L,
+51608L,51609L,51610L,51611L,51612L,51613L,51614L,51615L,51616L,51617L,
+51618L,51619L,51620L,51621L,51622L,51623L,51624L,51625L,51626L,51627L,
+51628L,51629L,51630L,51631L,51632L,51633L,51634L,51635L,51636L,51637L,
+51638L,51639L,51640L,51641L,51642L,51643L,51644L,51645L,51646L,51647L,
+51648L,51649L,51650L,51651L,51652L,51653L,51654L,51655L,51656L,51657L,
+51658L,51659L,51660L,51661L,51662L,51663L,51664L,51665L,51666L,51667L,
+51668L,51669L,51670L,51671L,51672L,51673L,51674L,51675L,51676L,51677L,
+51678L,51679L,51680L,51681L,51682L,51683L,51684L,51685L,51686L,51687L,
+51688L,51689L,51690L,51691L,51692L,51693L,51694L,51695L,51696L,51697L,
+51698L,51699L,51700L,51701L,51702L,51703L,51704L,51705L,51706L,51707L,
+51708L,51709L,51710L,51711L,51712L,51713L,51714L,51715L,51716L,51717L,
+51718L,51719L,51720L,51721L,51722L,51723L,51724L,51725L,51726L,51727L,
+51728L,51729L,51730L,51731L,51732L,51733L,51734L,51735L,51736L,51737L,
+51738L,51739L,51740L,51741L,51742L,51743L,51744L,51745L,51746L,51747L,
+51748L,51749L,51750L,51751L,51752L,51753L,51754L,51755L,51756L,51757L,
+51758L,51759L,51760L,51761L,51762L,51763L,51764L,51765L,51766L,51767L,
+51768L,51769L,51770L,51771L,51772L,51773L,51774L,51775L,51776L,51777L,
+51778L,51779L,51780L,51781L,51782L,51783L,51784L,51785L,51786L,51787L,
+51788L,51789L,51790L,51791L,51792L,51793L,51794L,51795L,51796L,51797L,
+51798L,51799L,51800L,51801L,51802L,51803L,51804L,51805L,51806L,51807L,
+51808L,51809L,51810L,51811L,51812L,51813L,51814L,51815L,51816L,51817L,
+51818L,51819L,51820L,51821L,51822L,51823L,51824L,51825L,51826L,51827L,
+51828L,51829L,51830L,51831L,51832L,51833L,51834L,51835L,51836L,51837L,
+51838L,51839L,51840L,51841L,51842L,51843L,51844L,51845L,51846L,51847L,
+51848L,51849L,51850L,51851L,51852L,51853L,51854L,51855L,51856L,51857L,
+51858L,51859L,51860L,51861L,51862L,51863L,51864L,51865L,51866L,51867L,
+51868L,51869L,51870L,51871L,51872L,51873L,51874L,51875L,51876L,51877L,
+51878L,51879L,51880L,51881L,51882L,51883L,51884L,51885L,51886L,51887L,
+51888L,51889L,51890L,51891L,51892L,51893L,51894L,51895L,51896L,51897L,
+51898L,51899L,51900L,51901L,51902L,51903L,51904L,51905L,51906L,51907L,
+51908L,51909L,51910L,51911L,51912L,51913L,51914L,51915L,51916L,51917L,
+51918L,51919L,51920L,51921L,51922L,51923L,51924L,51925L,51926L,51927L,
+51928L,51929L,51930L,51931L,51932L,51933L,51934L,51935L,51936L,51937L,
+51938L,51939L,51940L,51941L,51942L,51943L,51944L,51945L,51946L,51947L,
+51948L,51949L,51950L,51951L,51952L,51953L,51954L,51955L,51956L,51957L,
+51958L,51959L,51960L,51961L,51962L,51963L,51964L,51965L,51966L,51967L,
+51968L,51969L,51970L,51971L,51972L,51973L,51974L,51975L,51976L,51977L,
+51978L,51979L,51980L,51981L,51982L,51983L,51984L,51985L,51986L,51987L,
+51988L,51989L,51990L,51991L,51992L,51993L,51994L,51995L,51996L,51997L,
+51998L,51999L,52000L,52001L,52002L,52003L,52004L,52005L,52006L,52007L,
+52008L,52009L,52010L,52011L,52012L,52013L,52014L,52015L,52016L,52017L,
+52018L,52019L,52020L,52021L,52022L,52023L,52024L,52025L,52026L,52027L,
+52028L,52029L,52030L,52031L,52032L,52033L,52034L,52035L,52036L,52037L,
+52038L,52039L,52040L,52041L,52042L,52043L,52044L,52045L,52046L,52047L,
+52048L,52049L,52050L,52051L,52052L,52053L,52054L,52055L,52056L,52057L,
+52058L,52059L,52060L,52061L,52062L,52063L,52064L,52065L,52066L,52067L,
+52068L,52069L,52070L,52071L,52072L,52073L,52074L,52075L,52076L,52077L,
+52078L,52079L,52080L,52081L,52082L,52083L,52084L,52085L,52086L,52087L,
+52088L,52089L,52090L,52091L,52092L,52093L,52094L,52095L,52096L,52097L,
+52098L,52099L,52100L,52101L,52102L,52103L,52104L,52105L,52106L,52107L,
+52108L,52109L,52110L,52111L,52112L,52113L,52114L,52115L,52116L,52117L,
+52118L,52119L,52120L,52121L,52122L,52123L,52124L,52125L,52126L,52127L,
+52128L,52129L,52130L,52131L,52132L,52133L,52134L,52135L,52136L,52137L,
+52138L,52139L,52140L,52141L,52142L,52143L,52144L,52145L,52146L,52147L,
+52148L,52149L,52150L,52151L,52152L,52153L,52154L,52155L,52156L,52157L,
+52158L,52159L,52160L,52161L,52162L,52163L,52164L,52165L,52166L,52167L,
+52168L,52169L,52170L,52171L,52172L,52173L,52174L,52175L,52176L,52177L,
+52178L,52179L,52180L,52181L,52182L,52183L,52184L,52185L,52186L,52187L,
+52188L,52189L,52190L,52191L,52192L,52193L,52194L,52195L,52196L,52197L,
+52198L,52199L,52200L,52201L,52202L,52203L,52204L,52205L,52206L,52207L,
+52208L,52209L,52210L,52211L,52212L,52213L,52214L,52215L,52216L,52217L,
+52218L,52219L,52220L,52221L,52222L,52223L,52224L,52225L,52226L,52227L,
+52228L,52229L,52230L,52231L,52232L,52233L,52234L,52235L,52236L,52237L,
+52238L,52239L,52240L,52241L,52242L,52243L,52244L,52245L,52246L,52247L,
+52248L,52249L,52250L,52251L,52252L,52253L,52254L,52255L,52256L,52257L,
+52258L,52259L,52260L,52261L,52262L,52263L,52264L,52265L,52266L,52267L,
+52268L,52269L,52270L,52271L,52272L,52273L,52274L,52275L,52276L,52277L,
+52278L,52279L,52280L,52281L,52282L,52283L,52284L,52285L,52286L,52287L,
+52288L,52289L,52290L,52291L,52292L,52293L,52294L,52295L,52296L,52297L,
+52298L,52299L,52300L,52301L,52302L,52303L,52304L,52305L,52306L,52307L,
+52308L,52309L,52310L,52311L,52312L,52313L,52314L,52315L,52316L,52317L,
+52318L,52319L,52320L,52321L,52322L,52323L,52324L,52325L,52326L,52327L,
+52328L,52329L,52330L,52331L,52332L,52333L,52334L,52335L,52336L,52337L,
+52338L,52339L,52340L,52341L,52342L,52343L,52344L,52345L,52346L,52347L,
+52348L,52349L,52350L,52351L,52352L,52353L,52354L,52355L,52356L,52357L,
+52358L,52359L,52360L,52361L,52362L,52363L,52364L,52365L,52366L,52367L,
+52368L,52369L,52370L,52371L,52372L,52373L,52374L,52375L,52376L,52377L,
+52378L,52379L,52380L,52381L,52382L,52383L,52384L,52385L,52386L,52387L,
+52388L,52389L,52390L,52391L,52392L,52393L,52394L,52395L,52396L,52397L,
+52398L,52399L,52400L,52401L,52402L,52403L,52404L,52405L,52406L,52407L,
+52408L,52409L,52410L,52411L,52412L,52413L,52414L,52415L,52416L,52417L,
+52418L,52419L,52420L,52421L,52422L,52423L,52424L,52425L,52426L,52427L,
+52428L,52429L,52430L,52431L,52432L,52433L,52434L,52435L,52436L,52437L,
+52438L,52439L,52440L,52441L,52442L,52443L,52444L,52445L,52446L,52447L,
+52448L,52449L,52450L,52451L,52452L,52453L,52454L,52455L,52456L,52457L,
+52458L,52459L,52460L,52461L,52462L,52463L,52464L,52465L,52466L,52467L,
+52468L,52469L,52470L,52471L,52472L,52473L,52474L,52475L,52476L,52477L,
+52478L,52479L,52480L,52481L,52482L,52483L,52484L,52485L,52486L,52487L,
+52488L,52489L,52490L,52491L,52492L,52493L,52494L,52495L,52496L,52497L,
+52498L,52499L,52500L,52501L,52502L,52503L,52504L,52505L,52506L,52507L,
+52508L,52509L,52510L,52511L,52512L,52513L,52514L,52515L,52516L,52517L,
+52518L,52519L,52520L,52521L,52522L,52523L,52524L,52525L,52526L,52527L,
+52528L,52529L,52530L,52531L,52532L,52533L,52534L,52535L,52536L,52537L,
+52538L,52539L,52540L,52541L,52542L,52543L,52544L,52545L,52546L,52547L,
+52548L,52549L,52550L,52551L,52552L,52553L,52554L,52555L,52556L,52557L,
+52558L,52559L,52560L,52561L,52562L,52563L,52564L,52565L,52566L,52567L,
+52568L,52569L,52570L,52571L,52572L,52573L,52574L,52575L,52576L,52577L,
+52578L,52579L,52580L,52581L,52582L,52583L,52584L,52585L,52586L,52587L,
+52588L,52589L,52590L,52591L,52592L,52593L,52594L,52595L,52596L,52597L,
+52598L,52599L,52600L,52601L,52602L,52603L,52604L,52605L,52606L,52607L,
+52608L,52609L,52610L,52611L,52612L,52613L,52614L,52615L,52616L,52617L,
+52618L,52619L,52620L,52621L,52622L,52623L,52624L,52625L,52626L,52627L,
+52628L,52629L,52630L,52631L,52632L,52633L,52634L,52635L,52636L,52637L,
+52638L,52639L,52640L,52641L,52642L,52643L,52644L,52645L,52646L,52647L,
+52648L,52649L,52650L,52651L,52652L,52653L,52654L,52655L,52656L,52657L,
+52658L,52659L,52660L,52661L,52662L,52663L,52664L,52665L,52666L,52667L,
+52668L,52669L,52670L,52671L,52672L,52673L,52674L,52675L,52676L,52677L,
+52678L,52679L,52680L,52681L,52682L,52683L,52684L,52685L,52686L,52687L,
+52688L,52689L,52690L,52691L,52692L,52693L,52694L,52695L,52696L,52697L,
+52698L,52699L,52700L,52701L,52702L,52703L,52704L,52705L,52706L,52707L,
+52708L,52709L,52710L,52711L,52712L,52713L,52714L,52715L,52716L,52717L,
+52718L,52719L,52720L,52721L,52722L,52723L,52724L,52725L,52726L,52727L,
+52728L,52729L,52730L,52731L,52732L,52733L,52734L,52735L,52736L,52737L,
+52738L,52739L,52740L,52741L,52742L,52743L,52744L,52745L,52746L,52747L,
+52748L,52749L,52750L,52751L,52752L,52753L,52754L,52755L,52756L,52757L,
+52758L,52759L,52760L,52761L,52762L,52763L,52764L,52765L,52766L,52767L,
+52768L,52769L,52770L,52771L,52772L,52773L,52774L,52775L,52776L,52777L,
+52778L,52779L,52780L,52781L,52782L,52783L,52784L,52785L,52786L,52787L,
+52788L,52789L,52790L,52791L,52792L,52793L,52794L,52795L,52796L,52797L,
+52798L,52799L,52800L,52801L,52802L,52803L,52804L,52805L,52806L,52807L,
+52808L,52809L,52810L,52811L,52812L,52813L,52814L,52815L,52816L,52817L,
+52818L,52819L,52820L,52821L,52822L,52823L,52824L,52825L,52826L,52827L,
+52828L,52829L,52830L,52831L,52832L,52833L,52834L,52835L,52836L,52837L,
+52838L,52839L,52840L,52841L,52842L,52843L,52844L,52845L,52846L,52847L,
+52848L,52849L,52850L,52851L,52852L,52853L,52854L,52855L,52856L,52857L,
+52858L,52859L,52860L,52861L,52862L,52863L,52864L,52865L,52866L,52867L,
+52868L,52869L,52870L,52871L,52872L,52873L,52874L,52875L,52876L,52877L,
+52878L,52879L,52880L,52881L,52882L,52883L,52884L,52885L,52886L,52887L,
+52888L,52889L,52890L,52891L,52892L,52893L,52894L,52895L,52896L,52897L,
+52898L,52899L,52900L,52901L,52902L,52903L,52904L,52905L,52906L,52907L,
+52908L,52909L,52910L,52911L,52912L,52913L,52914L,52915L,52916L,52917L,
+52918L,52919L,52920L,52921L,52922L,52923L,52924L,52925L,52926L,52927L,
+52928L,52929L,52930L,52931L,52932L,52933L,52934L,52935L,52936L,52937L,
+52938L,52939L,52940L,52941L,52942L,52943L,52944L,52945L,52946L,52947L,
+52948L,52949L,52950L,52951L,52952L,52953L,52954L,52955L,52956L,52957L,
+52958L,52959L,52960L,52961L,52962L,52963L,52964L,52965L,52966L,52967L,
+52968L,52969L,52970L,52971L,52972L,52973L,52974L,52975L,52976L,52977L,
+52978L,52979L,52980L,52981L,52982L,52983L,52984L,52985L,52986L,52987L,
+52988L,52989L,52990L,52991L,52992L,52993L,52994L,52995L,52996L,52997L,
+52998L,52999L,53000L,53001L,53002L,53003L,53004L,53005L,53006L,53007L,
+53008L,53009L,53010L,53011L,53012L,53013L,53014L,53015L,53016L,53017L,
+53018L,53019L,53020L,53021L,53022L,53023L,53024L,53025L,53026L,53027L,
+53028L,53029L,53030L,53031L,53032L,53033L,53034L,53035L,53036L,53037L,
+53038L,53039L,53040L,53041L,53042L,53043L,53044L,53045L,53046L,53047L,
+53048L,53049L,53050L,53051L,53052L,53053L,53054L,53055L,53056L,53057L,
+53058L,53059L,53060L,53061L,53062L,53063L,53064L,53065L,53066L,53067L,
+53068L,53069L,53070L,53071L,53072L,53073L,53074L,53075L,53076L,53077L,
+53078L,53079L,53080L,53081L,53082L,53083L,53084L,53085L,53086L,53087L,
+53088L,53089L,53090L,53091L,53092L,53093L,53094L,53095L,53096L,53097L,
+53098L,53099L,53100L,53101L,53102L,53103L,53104L,53105L,53106L,53107L,
+53108L,53109L,53110L,53111L,53112L,53113L,53114L,53115L,53116L,53117L,
+53118L,53119L,53120L,53121L,53122L,53123L,53124L,53125L,53126L,53127L,
+53128L,53129L,53130L,53131L,53132L,53133L,53134L,53135L,53136L,53137L,
+53138L,53139L,53140L,53141L,53142L,53143L,53144L,53145L,53146L,53147L,
+53148L,53149L,53150L,53151L,53152L,53153L,53154L,53155L,53156L,53157L,
+53158L,53159L,53160L,53161L,53162L,53163L,53164L,53165L,53166L,53167L,
+53168L,53169L,53170L,53171L,53172L,53173L,53174L,53175L,53176L,53177L,
+53178L,53179L,53180L,53181L,53182L,53183L,53184L,53185L,53186L,53187L,
+53188L,53189L,53190L,53191L,53192L,53193L,53194L,53195L,53196L,53197L,
+53198L,53199L,53200L,53201L,53202L,53203L,53204L,53205L,53206L,53207L,
+53208L,53209L,53210L,53211L,53212L,53213L,53214L,53215L,53216L,53217L,
+53218L,53219L,53220L,53221L,53222L,53223L,53224L,53225L,53226L,53227L,
+53228L,53229L,53230L,53231L,53232L,53233L,53234L,53235L,53236L,53237L,
+53238L,53239L,53240L,53241L,53242L,53243L,53244L,53245L,53246L,53247L,
+53248L,53249L,53250L,53251L,53252L,53253L,53254L,53255L,53256L,53257L,
+53258L,53259L,53260L,53261L,53262L,53263L,53264L,53265L,53266L,53267L,
+53268L,53269L,53270L,53271L,53272L,53273L,53274L,53275L,53276L,53277L,
+53278L,53279L,53280L,53281L,53282L,53283L,53284L,53285L,53286L,53287L,
+53288L,53289L,53290L,53291L,53292L,53293L,53294L,53295L,53296L,53297L,
+53298L,53299L,53300L,53301L,53302L,53303L,53304L,53305L,53306L,53307L,
+53308L,53309L,53310L,53311L,53312L,53313L,53314L,53315L,53316L,53317L,
+53318L,53319L,53320L,53321L,53322L,53323L,53324L,53325L,53326L,53327L,
+53328L,53329L,53330L,53331L,53332L,53333L,53334L,53335L,53336L,53337L,
+53338L,53339L,53340L,53341L,53342L,53343L,53344L,53345L,53346L,53347L,
+53348L,53349L,53350L,53351L,53352L,53353L,53354L,53355L,53356L,53357L,
+53358L,53359L,53360L,53361L,53362L,53363L,53364L,53365L,53366L,53367L,
+53368L,53369L,53370L,53371L,53372L,53373L,53374L,53375L,53376L,53377L,
+53378L,53379L,53380L,53381L,53382L,53383L,53384L,53385L,53386L,53387L,
+53388L,53389L,53390L,53391L,53392L,53393L,53394L,53395L,53396L,53397L,
+53398L,53399L,53400L,53401L,53402L,53403L,53404L,53405L,53406L,53407L,
+53408L,53409L,53410L,53411L,53412L,53413L,53414L,53415L,53416L,53417L,
+53418L,53419L,53420L,53421L,53422L,53423L,53424L,53425L,53426L,53427L,
+53428L,53429L,53430L,53431L,53432L,53433L,53434L,53435L,53436L,53437L,
+53438L,53439L,53440L,53441L,53442L,53443L,53444L,53445L,53446L,53447L,
+53448L,53449L,53450L,53451L,53452L,53453L,53454L,53455L,53456L,53457L,
+53458L,53459L,53460L,53461L,53462L,53463L,53464L,53465L,53466L,53467L,
+53468L,53469L,53470L,53471L,53472L,53473L,53474L,53475L,53476L,53477L,
+53478L,53479L,53480L,53481L,53482L,53483L,53484L,53485L,53486L,53487L,
+53488L,53489L,53490L,53491L,53492L,53493L,53494L,53495L,53496L,53497L,
+53498L,53499L,53500L,53501L,53502L,53503L,53504L,53505L,53506L,53507L,
+53508L,53509L,53510L,53511L,53512L,53513L,53514L,53515L,53516L,53517L,
+53518L,53519L,53520L,53521L,53522L,53523L,53524L,53525L,53526L,53527L,
+53528L,53529L,53530L,53531L,53532L,53533L,53534L,53535L,53536L,53537L,
+53538L,53539L,53540L,53541L,53542L,53543L,53544L,53545L,53546L,53547L,
+53548L,53549L,53550L,53551L,53552L,53553L,53554L,53555L,53556L,53557L,
+53558L,53559L,53560L,53561L,53562L,53563L,53564L,53565L,53566L,53567L,
+53568L,53569L,53570L,53571L,53572L,53573L,53574L,53575L,53576L,53577L,
+53578L,53579L,53580L,53581L,53582L,53583L,53584L,53585L,53586L,53587L,
+53588L,53589L,53590L,53591L,53592L,53593L,53594L,53595L,53596L,53597L,
+53598L,53599L,53600L,53601L,53602L,53603L,53604L,53605L,53606L,53607L,
+53608L,53609L,53610L,53611L,53612L,53613L,53614L,53615L,53616L,53617L,
+53618L,53619L,53620L,53621L,53622L,53623L,53624L,53625L,53626L,53627L,
+53628L,53629L,53630L,53631L,53632L,53633L,53634L,53635L,53636L,53637L,
+53638L,53639L,53640L,53641L,53642L,53643L,53644L,53645L,53646L,53647L,
+53648L,53649L,53650L,53651L,53652L,53653L,53654L,53655L,53656L,53657L,
+53658L,53659L,53660L,53661L,53662L,53663L,53664L,53665L,53666L,53667L,
+53668L,53669L,53670L,53671L,53672L,53673L,53674L,53675L,53676L,53677L,
+53678L,53679L,53680L,53681L,53682L,53683L,53684L,53685L,53686L,53687L,
+53688L,53689L,53690L,53691L,53692L,53693L,53694L,53695L,53696L,53697L,
+53698L,53699L,53700L,53701L,53702L,53703L,53704L,53705L,53706L,53707L,
+53708L,53709L,53710L,53711L,53712L,53713L,53714L,53715L,53716L,53717L,
+53718L,53719L,53720L,53721L,53722L,53723L,53724L,53725L,53726L,53727L,
+53728L,53729L,53730L,53731L,53732L,53733L,53734L,53735L,53736L,53737L,
+53738L,53739L,53740L,53741L,53742L,53743L,53744L,53745L,53746L,53747L,
+53748L,53749L,53750L,53751L,53752L,53753L,53754L,53755L,53756L,53757L,
+53758L,53759L,53760L,53761L,53762L,53763L,53764L,53765L,53766L,53767L,
+53768L,53769L,53770L,53771L,53772L,53773L,53774L,53775L,53776L,53777L,
+53778L,53779L,53780L,53781L,53782L,53783L,53784L,53785L,53786L,53787L,
+53788L,53789L,53790L,53791L,53792L,53793L,53794L,53795L,53796L,53797L,
+53798L,53799L,53800L,53801L,53802L,53803L,53804L,53805L,53806L,53807L,
+53808L,53809L,53810L,53811L,53812L,53813L,53814L,53815L,53816L,53817L,
+53818L,53819L,53820L,53821L,53822L,53823L,53824L,53825L,53826L,53827L,
+53828L,53829L,53830L,53831L,53832L,53833L,53834L,53835L,53836L,53837L,
+53838L,53839L,53840L,53841L,53842L,53843L,53844L,53845L,53846L,53847L,
+53848L,53849L,53850L,53851L,53852L,53853L,53854L,53855L,53856L,53857L,
+53858L,53859L,53860L,53861L,53862L,53863L,53864L,53865L,53866L,53867L,
+53868L,53869L,53870L,53871L,53872L,53873L,53874L,53875L,53876L,53877L,
+53878L,53879L,53880L,53881L,53882L,53883L,53884L,53885L,53886L,53887L,
+53888L,53889L,53890L,53891L,53892L,53893L,53894L,53895L,53896L,53897L,
+53898L,53899L,53900L,53901L,53902L,53903L,53904L,53905L,53906L,53907L,
+53908L,53909L,53910L,53911L,53912L,53913L,53914L,53915L,53916L,53917L,
+53918L,53919L,53920L,53921L,53922L,53923L,53924L,53925L,53926L,53927L,
+53928L,53929L,53930L,53931L,53932L,53933L,53934L,53935L,53936L,53937L,
+53938L,53939L,53940L,53941L,53942L,53943L,53944L,53945L,53946L,53947L,
+53948L,53949L,53950L,53951L,53952L,53953L,53954L,53955L,53956L,53957L,
+53958L,53959L,53960L,53961L,53962L,53963L,53964L,53965L,53966L,53967L,
+53968L,53969L,53970L,53971L,53972L,53973L,53974L,53975L,53976L,53977L,
+53978L,53979L,53980L,53981L,53982L,53983L,53984L,53985L,53986L,53987L,
+53988L,53989L,53990L,53991L,53992L,53993L,53994L,53995L,53996L,53997L,
+53998L,53999L,54000L,54001L,54002L,54003L,54004L,54005L,54006L,54007L,
+54008L,54009L,54010L,54011L,54012L,54013L,54014L,54015L,54016L,54017L,
+54018L,54019L,54020L,54021L,54022L,54023L,54024L,54025L,54026L,54027L,
+54028L,54029L,54030L,54031L,54032L,54033L,54034L,54035L,54036L,54037L,
+54038L,54039L,54040L,54041L,54042L,54043L,54044L,54045L,54046L,54047L,
+54048L,54049L,54050L,54051L,54052L,54053L,54054L,54055L,54056L,54057L,
+54058L,54059L,54060L,54061L,54062L,54063L,54064L,54065L,54066L,54067L,
+54068L,54069L,54070L,54071L,54072L,54073L,54074L,54075L,54076L,54077L,
+54078L,54079L,54080L,54081L,54082L,54083L,54084L,54085L,54086L,54087L,
+54088L,54089L,54090L,54091L,54092L,54093L,54094L,54095L,54096L,54097L,
+54098L,54099L,54100L,54101L,54102L,54103L,54104L,54105L,54106L,54107L,
+54108L,54109L,54110L,54111L,54112L,54113L,54114L,54115L,54116L,54117L,
+54118L,54119L,54120L,54121L,54122L,54123L,54124L,54125L,54126L,54127L,
+54128L,54129L,54130L,54131L,54132L,54133L,54134L,54135L,54136L,54137L,
+54138L,54139L,54140L,54141L,54142L,54143L,54144L,54145L,54146L,54147L,
+54148L,54149L,54150L,54151L,54152L,54153L,54154L,54155L,54156L,54157L,
+54158L,54159L,54160L,54161L,54162L,54163L,54164L,54165L,54166L,54167L,
+54168L,54169L,54170L,54171L,54172L,54173L,54174L,54175L,54176L,54177L,
+54178L,54179L,54180L,54181L,54182L,54183L,54184L,54185L,54186L,54187L,
+54188L,54189L,54190L,54191L,54192L,54193L,54194L,54195L,54196L,54197L,
+54198L,54199L,54200L,54201L,54202L,54203L,54204L,54205L,54206L,54207L,
+54208L,54209L,54210L,54211L,54212L,54213L,54214L,54215L,54216L,54217L,
+54218L,54219L,54220L,54221L,54222L,54223L,54224L,54225L,54226L,54227L,
+54228L,54229L,54230L,54231L,54232L,54233L,54234L,54235L,54236L,54237L,
+54238L,54239L,54240L,54241L,54242L,54243L,54244L,54245L,54246L,54247L,
+54248L,54249L,54250L,54251L,54252L,54253L,54254L,54255L,54256L,54257L,
+54258L,54259L,54260L,54261L,54262L,54263L,54264L,54265L,54266L,54267L,
+54268L,54269L,54270L,54271L,54272L,54273L,54274L,54275L,54276L,54277L,
+54278L,54279L,54280L,54281L,54282L,54283L,54284L,54285L,54286L,54287L,
+54288L,54289L,54290L,54291L,54292L,54293L,54294L,54295L,54296L,54297L,
+54298L,54299L,54300L,54301L,54302L,54303L,54304L,54305L,54306L,54307L,
+54308L,54309L,54310L,54311L,54312L,54313L,54314L,54315L,54316L,54317L,
+54318L,54319L,54320L,54321L,54322L,54323L,54324L,54325L,54326L,54327L,
+54328L,54329L,54330L,54331L,54332L,54333L,54334L,54335L,54336L,54337L,
+54338L,54339L,54340L,54341L,54342L,54343L,54344L,54345L,54346L,54347L,
+54348L,54349L,54350L,54351L,54352L,54353L,54354L,54355L,54356L,54357L,
+54358L,54359L,54360L,54361L,54362L,54363L,54364L,54365L,54366L,54367L,
+54368L,54369L,54370L,54371L,54372L,54373L,54374L,54375L,54376L,54377L,
+54378L,54379L,54380L,54381L,54382L,54383L,54384L,54385L,54386L,54387L,
+54388L,54389L,54390L,54391L,54392L,54393L,54394L,54395L,54396L,54397L,
+54398L,54399L,54400L,54401L,54402L,54403L,54404L,54405L,54406L,54407L,
+54408L,54409L,54410L,54411L,54412L,54413L,54414L,54415L,54416L,54417L,
+54418L,54419L,54420L,54421L,54422L,54423L,54424L,54425L,54426L,54427L,
+54428L,54429L,54430L,54431L,54432L,54433L,54434L,54435L,54436L,54437L,
+54438L,54439L,54440L,54441L,54442L,54443L,54444L,54445L,54446L,54447L,
+54448L,54449L,54450L,54451L,54452L,54453L,54454L,54455L,54456L,54457L,
+54458L,54459L,54460L,54461L,54462L,54463L,54464L,54465L,54466L,54467L,
+54468L,54469L,54470L,54471L,54472L,54473L,54474L,54475L,54476L,54477L,
+54478L,54479L,54480L,54481L,54482L,54483L,54484L,54485L,54486L,54487L,
+54488L,54489L,54490L,54491L,54492L,54493L,54494L,54495L,54496L,54497L,
+54498L,54499L,54500L,54501L,54502L,54503L,54504L,54505L,54506L,54507L,
+54508L,54509L,54510L,54511L,54512L,54513L,54514L,54515L,54516L,54517L,
+54518L,54519L,54520L,54521L,54522L,54523L,54524L,54525L,54526L,54527L,
+54528L,54529L,54530L,54531L,54532L,54533L,54534L,54535L,54536L,54537L,
+54538L,54539L,54540L,54541L,54542L,54543L,54544L,54545L,54546L,54547L,
+54548L,54549L,54550L,54551L,54552L,54553L,54554L,54555L,54556L,54557L,
+54558L,54559L,54560L,54561L,54562L,54563L,54564L,54565L,54566L,54567L,
+54568L,54569L,54570L,54571L,54572L,54573L,54574L,54575L,54576L,54577L,
+54578L,54579L,54580L,54581L,54582L,54583L,54584L,54585L,54586L,54587L,
+54588L,54589L,54590L,54591L,54592L,54593L,54594L,54595L,54596L,54597L,
+54598L,54599L,54600L,54601L,54602L,54603L,54604L,54605L,54606L,54607L,
+54608L,54609L,54610L,54611L,54612L,54613L,54614L,54615L,54616L,54617L,
+54618L,54619L,54620L,54621L,54622L,54623L,54624L,54625L,54626L,54627L,
+54628L,54629L,54630L,54631L,54632L,54633L,54634L,54635L,54636L,54637L,
+54638L,54639L,54640L,54641L,54642L,54643L,54644L,54645L,54646L,54647L,
+54648L,54649L,54650L,54651L,54652L,54653L,54654L,54655L,54656L,54657L,
+54658L,54659L,54660L,54661L,54662L,54663L,54664L,54665L,54666L,54667L,
+54668L,54669L,54670L,54671L,54672L,54673L,54674L,54675L,54676L,54677L,
+54678L,54679L,54680L,54681L,54682L,54683L,54684L,54685L,54686L,54687L,
+54688L,54689L,54690L,54691L,54692L,54693L,54694L,54695L,54696L,54697L,
+54698L,54699L,54700L,54701L,54702L,54703L,54704L,54705L,54706L,54707L,
+54708L,54709L,54710L,54711L,54712L,54713L,54714L,54715L,54716L,54717L,
+54718L,54719L,54720L,54721L,54722L,54723L,54724L,54725L,54726L,54727L,
+54728L,54729L,54730L,54731L,54732L,54733L,54734L,54735L,54736L,54737L,
+54738L,54739L,54740L,54741L,54742L,54743L,54744L,54745L,54746L,54747L,
+54748L,54749L,54750L,54751L,54752L,54753L,54754L,54755L,54756L,54757L,
+54758L,54759L,54760L,54761L,54762L,54763L,54764L,54765L,54766L,54767L,
+54768L,54769L,54770L,54771L,54772L,54773L,54774L,54775L,54776L,54777L,
+54778L,54779L,54780L,54781L,54782L,54783L,54784L,54785L,54786L,54787L,
+54788L,54789L,54790L,54791L,54792L,54793L,54794L,54795L,54796L,54797L,
+54798L,54799L,54800L,54801L,54802L,54803L,54804L,54805L,54806L,54807L,
+54808L,54809L,54810L,54811L,54812L,54813L,54814L,54815L,54816L,54817L,
+54818L,54819L,54820L,54821L,54822L,54823L,54824L,54825L,54826L,54827L,
+54828L,54829L,54830L,54831L,54832L,54833L,54834L,54835L,54836L,54837L,
+54838L,54839L,54840L,54841L,54842L,54843L,54844L,54845L,54846L,54847L,
+54848L,54849L,54850L,54851L,54852L,54853L,54854L,54855L,54856L,54857L,
+54858L,54859L,54860L,54861L,54862L,54863L,54864L,54865L,54866L,54867L,
+54868L,54869L,54870L,54871L,54872L,54873L,54874L,54875L,54876L,54877L,
+54878L,54879L,54880L,54881L,54882L,54883L,54884L,54885L,54886L,54887L,
+54888L,54889L,54890L,54891L,54892L,54893L,54894L,54895L,54896L,54897L,
+54898L,54899L,54900L,54901L,54902L,54903L,54904L,54905L,54906L,54907L,
+54908L,54909L,54910L,54911L,54912L,54913L,54914L,54915L,54916L,54917L,
+54918L,54919L,54920L,54921L,54922L,54923L,54924L,54925L,54926L,54927L,
+54928L,54929L,54930L,54931L,54932L,54933L,54934L,54935L,54936L,54937L,
+54938L,54939L,54940L,54941L,54942L,54943L,54944L,54945L,54946L,54947L,
+54948L,54949L,54950L,54951L,54952L,54953L,54954L,54955L,54956L,54957L,
+54958L,54959L,54960L,54961L,54962L,54963L,54964L,54965L,54966L,54967L,
+54968L,54969L,54970L,54971L,54972L,54973L,54974L,54975L,54976L,54977L,
+54978L,54979L,54980L,54981L,54982L,54983L,54984L,54985L,54986L,54987L,
+54988L,54989L,54990L,54991L,54992L,54993L,54994L,54995L,54996L,54997L,
+54998L,54999L,55000L,55001L,55002L,55003L,55004L,55005L,55006L,55007L,
+55008L,55009L,55010L,55011L,55012L,55013L,55014L,55015L,55016L,55017L,
+55018L,55019L,55020L,55021L,55022L,55023L,55024L,55025L,55026L,55027L,
+55028L,55029L,55030L,55031L,55032L,55033L,55034L,55035L,55036L,55037L,
+55038L,55039L,55040L,55041L,55042L,55043L,55044L,55045L,55046L,55047L,
+55048L,55049L,55050L,55051L,55052L,55053L,55054L,55055L,55056L,55057L,
+55058L,55059L,55060L,55061L,55062L,55063L,55064L,55065L,55066L,55067L,
+55068L,55069L,55070L,55071L,55072L,55073L,55074L,55075L,55076L,55077L,
+55078L,55079L,55080L,55081L,55082L,55083L,55084L,55085L,55086L,55087L,
+55088L,55089L,55090L,55091L,55092L,55093L,55094L,55095L,55096L,55097L,
+55098L,55099L,55100L,55101L,55102L,55103L,55104L,55105L,55106L,55107L,
+55108L,55109L,55110L,55111L,55112L,55113L,55114L,55115L,55116L,55117L,
+55118L,55119L,55120L,55121L,55122L,55123L,55124L,55125L,55126L,55127L,
+55128L,55129L,55130L,55131L,55132L,55133L,55134L,55135L,55136L,55137L,
+55138L,55139L,55140L,55141L,55142L,55143L,55144L,55145L,55146L,55147L,
+55148L,55149L,55150L,55151L,55152L,55153L,55154L,55155L,55156L,55157L,
+55158L,55159L,55160L,55161L,55162L,55163L,55164L,55165L,55166L,55167L,
+55168L,55169L,55170L,55171L,55172L,55173L,55174L,55175L,55176L,55177L,
+55178L,55179L,55180L,55181L,55182L,55183L,55184L,55185L,55186L,55187L,
+55188L,55189L,55190L,55191L,55192L,55193L,55194L,55195L,55196L,55197L,
+55198L,55199L,55200L,55201L,55202L,55203L,55204L,55205L,55206L,55207L,
+55208L,55209L,55210L,55211L,55212L,55213L,55214L,55215L,55216L,55217L,
+55218L,55219L,55220L,55221L,55222L,55223L,55224L,55225L,55226L,55227L,
+55228L,55229L,55230L,55231L,55232L,55233L,55234L,55235L,55236L,55237L,
+55238L,55239L,55240L,55241L,55242L,55243L,55244L,55245L,55246L,55247L,
+55248L,55249L,55250L,55251L,55252L,55253L,55254L,55255L,55256L,55257L,
+55258L,55259L,55260L,55261L,55262L,55263L,55264L,55265L,55266L,55267L,
+55268L,55269L,55270L,55271L,55272L,55273L,55274L,55275L,55276L,55277L,
+55278L,55279L,55280L,55281L,55282L,55283L,55284L,55285L,55286L,55287L,
+55288L,55289L,55290L,55291L,55292L,55293L,55294L,55295L,55296L,55297L,
+55298L,55299L,55300L,55301L,55302L,55303L,55304L,55305L,55306L,55307L,
+55308L,55309L,55310L,55311L,55312L,55313L,55314L,55315L,55316L,55317L,
+55318L,55319L,55320L,55321L,55322L,55323L,55324L,55325L,55326L,55327L,
+55328L,55329L,55330L,55331L,55332L,55333L,55334L,55335L,55336L,55337L,
+55338L,55339L,55340L,55341L,55342L,55343L,55344L,55345L,55346L,55347L,
+55348L,55349L,55350L,55351L,55352L,55353L,55354L,55355L,55356L,55357L,
+55358L,55359L,55360L,55361L,55362L,55363L,55364L,55365L,55366L,55367L,
+55368L,55369L,55370L,55371L,55372L,55373L,55374L,55375L,55376L,55377L,
+55378L,55379L,55380L,55381L,55382L,55383L,55384L,55385L,55386L,55387L,
+55388L,55389L,55390L,55391L,55392L,55393L,55394L,55395L,55396L,55397L,
+55398L,55399L,55400L,55401L,55402L,55403L,55404L,55405L,55406L,55407L,
+55408L,55409L,55410L,55411L,55412L,55413L,55414L,55415L,55416L,55417L,
+55418L,55419L,55420L,55421L,55422L,55423L,55424L,55425L,55426L,55427L,
+55428L,55429L,55430L,55431L,55432L,55433L,55434L,55435L,55436L,55437L,
+55438L,55439L,55440L,55441L,55442L,55443L,55444L,55445L,55446L,55447L,
+55448L,55449L,55450L,55451L,55452L,55453L,55454L,55455L,55456L,55457L,
+55458L,55459L,55460L,55461L,55462L,55463L,55464L,55465L,55466L,55467L,
+55468L,55469L,55470L,55471L,55472L,55473L,55474L,55475L,55476L,55477L,
+55478L,55479L,55480L,55481L,55482L,55483L,55484L,55485L,55486L,55487L,
+55488L,55489L,55490L,55491L,55492L,55493L,55494L,55495L,55496L,55497L,
+55498L,55499L,55500L,55501L,55502L,55503L,55504L,55505L,55506L,55507L,
+55508L,55509L,55510L,55511L,55512L,55513L,55514L,55515L,55516L,55517L,
+55518L,55519L,55520L,55521L,55522L,55523L,55524L,55525L,55526L,55527L,
+55528L,55529L,55530L,55531L,55532L,55533L,55534L,55535L,55536L,55537L,
+55538L,55539L,55540L,55541L,55542L,55543L,55544L,55545L,55546L,55547L,
+55548L,55549L,55550L,55551L,55552L,55553L,55554L,55555L,55556L,55557L,
+55558L,55559L,55560L,55561L,55562L,55563L,55564L,55565L,55566L,55567L,
+55568L,55569L,55570L,55571L,55572L,55573L,55574L,55575L,55576L,55577L,
+55578L,55579L,55580L,55581L,55582L,55583L,55584L,55585L,55586L,55587L,
+55588L,55589L,55590L,55591L,55592L,55593L,55594L,55595L,55596L,55597L,
+55598L,55599L,55600L,55601L,55602L,55603L,55604L,55605L,55606L,55607L,
+55608L,55609L,55610L,55611L,55612L,55613L,55614L,55615L,55616L,55617L,
+55618L,55619L,55620L,55621L,55622L,55623L,55624L,55625L,55626L,55627L,
+55628L,55629L,55630L,55631L,55632L,55633L,55634L,55635L,55636L,55637L,
+55638L,55639L,55640L,55641L,55642L,55643L,55644L,55645L,55646L,55647L,
+55648L,55649L,55650L,55651L,55652L,55653L,55654L,55655L,55656L,55657L,
+55658L,55659L,55660L,55661L,55662L,55663L,55664L,55665L,55666L,55667L,
+55668L,55669L,55670L,55671L,55672L,55673L,55674L,55675L,55676L,55677L,
+55678L,55679L,55680L,55681L,55682L,55683L,55684L,55685L,55686L,55687L,
+55688L,55689L,55690L,55691L,55692L,55693L,55694L,55695L,55696L,55697L,
+55698L,55699L,55700L,55701L,55702L,55703L,55704L,55705L,55706L,55707L,
+55708L,55709L,55710L,55711L,55712L,55713L,55714L,55715L,55716L,55717L,
+55718L,55719L,55720L,55721L,55722L,55723L,55724L,55725L,55726L,55727L,
+55728L,55729L,55730L,55731L,55732L,55733L,55734L,55735L,55736L,55737L,
+55738L,55739L,55740L,55741L,55742L,55743L,55744L,55745L,55746L,55747L,
+55748L,55749L,55750L,55751L,55752L,55753L,55754L,55755L,55756L,55757L,
+55758L,55759L,55760L,55761L,55762L,55763L,55764L,55765L,55766L,55767L,
+55768L,55769L,55770L,55771L,55772L,55773L,55774L,55775L,55776L,55777L,
+55778L,55779L,55780L,55781L,55782L,55783L,55784L,55785L,55786L,55787L,
+55788L,55789L,55790L,55791L,55792L,55793L,55794L,55795L,55796L,55797L,
+55798L,55799L,55800L,55801L,55802L,55803L,55804L,55805L,55806L,55807L,
+55808L,55809L,55810L,55811L,55812L,55813L,55814L,55815L,55816L,55817L,
+55818L,55819L,55820L,55821L,55822L,55823L,55824L,55825L,55826L,55827L,
+55828L,55829L,55830L,55831L,55832L,55833L,55834L,55835L,55836L,55837L,
+55838L,55839L,55840L,55841L,55842L,55843L,55844L,55845L,55846L,55847L,
+55848L,55849L,55850L,55851L,55852L,55853L,55854L,55855L,55856L,55857L,
+55858L,55859L,55860L,55861L,55862L,55863L,55864L,55865L,55866L,55867L,
+55868L,55869L,55870L,55871L,55872L,55873L,55874L,55875L,55876L,55877L,
+55878L,55879L,55880L,55881L,55882L,55883L,55884L,55885L,55886L,55887L,
+55888L,55889L,55890L,55891L,55892L,55893L,55894L,55895L,55896L,55897L,
+55898L,55899L,55900L,55901L,55902L,55903L,55904L,55905L,55906L,55907L,
+55908L,55909L,55910L,55911L,55912L,55913L,55914L,55915L,55916L,55917L,
+55918L,55919L,55920L,55921L,55922L,55923L,55924L,55925L,55926L,55927L,
+55928L,55929L,55930L,55931L,55932L,55933L,55934L,55935L,55936L,55937L,
+55938L,55939L,55940L,55941L,55942L,55943L,55944L,55945L,55946L,55947L,
+55948L,55949L,55950L,55951L,55952L,55953L,55954L,55955L,55956L,55957L,
+55958L,55959L,55960L,55961L,55962L,55963L,55964L,55965L,55966L,55967L,
+55968L,55969L,55970L,55971L,55972L,55973L,55974L,55975L,55976L,55977L,
+55978L,55979L,55980L,55981L,55982L,55983L,55984L,55985L,55986L,55987L,
+55988L,55989L,55990L,55991L,55992L,55993L,55994L,55995L,55996L,55997L,
+55998L,55999L,56000L,56001L,56002L,56003L,56004L,56005L,56006L,56007L,
+56008L,56009L,56010L,56011L,56012L,56013L,56014L,56015L,56016L,56017L,
+56018L,56019L,56020L,56021L,56022L,56023L,56024L,56025L,56026L,56027L,
+56028L,56029L,56030L,56031L,56032L,56033L,56034L,56035L,56036L,56037L,
+56038L,56039L,56040L,56041L,56042L,56043L,56044L,56045L,56046L,56047L,
+56048L,56049L,56050L,56051L,56052L,56053L,56054L,56055L,56056L,56057L,
+56058L,56059L,56060L,56061L,56062L,56063L,56064L,56065L,56066L,56067L,
+56068L,56069L,56070L,56071L,56072L,56073L,56074L,56075L,56076L,56077L,
+56078L,56079L,56080L,56081L,56082L,56083L,56084L,56085L,56086L,56087L,
+56088L,56089L,56090L,56091L,56092L,56093L,56094L,56095L,56096L,56097L,
+56098L,56099L,56100L,56101L,56102L,56103L,56104L,56105L,56106L,56107L,
+56108L,56109L,56110L,56111L,56112L,56113L,56114L,56115L,56116L,56117L,
+56118L,56119L,56120L,56121L,56122L,56123L,56124L,56125L,56126L,56127L,
+56128L,56129L,56130L,56131L,56132L,56133L,56134L,56135L,56136L,56137L,
+56138L,56139L,56140L,56141L,56142L,56143L,56144L,56145L,56146L,56147L,
+56148L,56149L,56150L,56151L,56152L,56153L,56154L,56155L,56156L,56157L,
+56158L,56159L,56160L,56161L,56162L,56163L,56164L,56165L,56166L,56167L,
+56168L,56169L,56170L,56171L,56172L,56173L,56174L,56175L,56176L,56177L,
+56178L,56179L,56180L,56181L,56182L,56183L,56184L,56185L,56186L,56187L,
+56188L,56189L,56190L,56191L,56192L,56193L,56194L,56195L,56196L,56197L,
+56198L,56199L,56200L,56201L,56202L,56203L,56204L,56205L,56206L,56207L,
+56208L,56209L,56210L,56211L,56212L,56213L,56214L,56215L,56216L,56217L,
+56218L,56219L,56220L,56221L,56222L,56223L,56224L,56225L,56226L,56227L,
+56228L,56229L,56230L,56231L,56232L,56233L,56234L,56235L,56236L,56237L,
+56238L,56239L,56240L,56241L,56242L,56243L,56244L,56245L,56246L,56247L,
+56248L,56249L,56250L,56251L,56252L,56253L,56254L,56255L,56256L,56257L,
+56258L,56259L,56260L,56261L,56262L,56263L,56264L,56265L,56266L,56267L,
+56268L,56269L,56270L,56271L,56272L,56273L,56274L,56275L,56276L,56277L,
+56278L,56279L,56280L,56281L,56282L,56283L,56284L,56285L,56286L,56287L,
+56288L,56289L,56290L,56291L,56292L,56293L,56294L,56295L,56296L,56297L,
+56298L,56299L,56300L,56301L,56302L,56303L,56304L,56305L,56306L,56307L,
+56308L,56309L,56310L,56311L,56312L,56313L,56314L,56315L,56316L,56317L,
+56318L,56319L,56320L,56321L,56322L,56323L,56324L,56325L,56326L,56327L,
+56328L,56329L,56330L,56331L,56332L,56333L,56334L,56335L,56336L,56337L,
+56338L,56339L,56340L,56341L,56342L,56343L,56344L,56345L,56346L,56347L,
+56348L,56349L,56350L,56351L,56352L,56353L,56354L,56355L,56356L,56357L,
+56358L,56359L,56360L,56361L,56362L,56363L,56364L,56365L,56366L,56367L,
+56368L,56369L,56370L,56371L,56372L,56373L,56374L,56375L,56376L,56377L,
+56378L,56379L,56380L,56381L,56382L,56383L,56384L,56385L,56386L,56387L,
+56388L,56389L,56390L,56391L,56392L,56393L,56394L,56395L,56396L,56397L,
+56398L,56399L,56400L,56401L,56402L,56403L,56404L,56405L,56406L,56407L,
+56408L,56409L,56410L,56411L,56412L,56413L,56414L,56415L,56416L,56417L,
+56418L,56419L,56420L,56421L,56422L,56423L,56424L,56425L,56426L,56427L,
+56428L,56429L,56430L,56431L,56432L,56433L,56434L,56435L,56436L,56437L,
+56438L,56439L,56440L,56441L,56442L,56443L,56444L,56445L,56446L,56447L,
+56448L,56449L,56450L,56451L,56452L,56453L,56454L,56455L,56456L,56457L,
+56458L,56459L,56460L,56461L,56462L,56463L,56464L,56465L,56466L,56467L,
+56468L,56469L,56470L,56471L,56472L,56473L,56474L,56475L,56476L,56477L,
+56478L,56479L,56480L,56481L,56482L,56483L,56484L,56485L,56486L,56487L,
+56488L,56489L,56490L,56491L,56492L,56493L,56494L,56495L,56496L,56497L,
+56498L,56499L,56500L,56501L,56502L,56503L,56504L,56505L,56506L,56507L,
+56508L,56509L,56510L,56511L,56512L,56513L,56514L,56515L,56516L,56517L,
+56518L,56519L,56520L,56521L,56522L,56523L,56524L,56525L,56526L,56527L,
+56528L,56529L,56530L,56531L,56532L,56533L,56534L,56535L,56536L,56537L,
+56538L,56539L,56540L,56541L,56542L,56543L,56544L,56545L,56546L,56547L,
+56548L,56549L,56550L,56551L,56552L,56553L,56554L,56555L,56556L,56557L,
+56558L,56559L,56560L,56561L,56562L,56563L,56564L,56565L,56566L,56567L,
+56568L,56569L,56570L,56571L,56572L,56573L,56574L,56575L,56576L,56577L,
+56578L,56579L,56580L,56581L,56582L,56583L,56584L,56585L,56586L,56587L,
+56588L,56589L,56590L,56591L,56592L,56593L,56594L,56595L,56596L,56597L,
+56598L,56599L,56600L,56601L,56602L,56603L,56604L,56605L,56606L,56607L,
+56608L,56609L,56610L,56611L,56612L,56613L,56614L,56615L,56616L,56617L,
+56618L,56619L,56620L,56621L,56622L,56623L,56624L,56625L,56626L,56627L,
+56628L,56629L,56630L,56631L,56632L,56633L,56634L,56635L,56636L,56637L,
+56638L,56639L,56640L,56641L,56642L,56643L,56644L,56645L,56646L,56647L,
+56648L,56649L,56650L,56651L,56652L,56653L,56654L,56655L,56656L,56657L,
+56658L,56659L,56660L,56661L,56662L,56663L,56664L,56665L,56666L,56667L,
+56668L,56669L,56670L,56671L,56672L,56673L,56674L,56675L,56676L,56677L,
+56678L,56679L,56680L,56681L,56682L,56683L,56684L,56685L,56686L,56687L,
+56688L,56689L,56690L,56691L,56692L,56693L,56694L,56695L,56696L,56697L,
+56698L,56699L,56700L,56701L,56702L,56703L,56704L,56705L,56706L,56707L,
+56708L,56709L,56710L,56711L,56712L,56713L,56714L,56715L,56716L,56717L,
+56718L,56719L,56720L,56721L,56722L,56723L,56724L,56725L,56726L,56727L,
+56728L,56729L,56730L,56731L,56732L,56733L,56734L,56735L,56736L,56737L,
+56738L,56739L,56740L,56741L,56742L,56743L,56744L,56745L,56746L,56747L,
+56748L,56749L,56750L,56751L,56752L,56753L,56754L,56755L,56756L,56757L,
+56758L,56759L,56760L,56761L,56762L,56763L,56764L,56765L,56766L,56767L,
+56768L,56769L,56770L,56771L,56772L,56773L,56774L,56775L,56776L,56777L,
+56778L,56779L,56780L,56781L,56782L,56783L,56784L,56785L,56786L,56787L,
+56788L,56789L,56790L,56791L,56792L,56793L,56794L,56795L,56796L,56797L,
+56798L,56799L,56800L,56801L,56802L,56803L,56804L,56805L,56806L,56807L,
+56808L,56809L,56810L,56811L,56812L,56813L,56814L,56815L,56816L,56817L,
+56818L,56819L,56820L,56821L,56822L,56823L,56824L,56825L,56826L,56827L,
+56828L,56829L,56830L,56831L,56832L,56833L,56834L,56835L,56836L,56837L,
+56838L,56839L,56840L,56841L,56842L,56843L,56844L,56845L,56846L,56847L,
+56848L,56849L,56850L,56851L,56852L,56853L,56854L,56855L,56856L,56857L,
+56858L,56859L,56860L,56861L,56862L,56863L,56864L,56865L,56866L,56867L,
+56868L,56869L,56870L,56871L,56872L,56873L,56874L,56875L,56876L,56877L,
+56878L,56879L,56880L,56881L,56882L,56883L,56884L,56885L,56886L,56887L,
+56888L,56889L,56890L,56891L,56892L,56893L,56894L,56895L,56896L,56897L,
+56898L,56899L,56900L,56901L,56902L,56903L,56904L,56905L,56906L,56907L,
+56908L,56909L,56910L,56911L,56912L,56913L,56914L,56915L,56916L,56917L,
+56918L,56919L,56920L,56921L,56922L,56923L,56924L,56925L,56926L,56927L,
+56928L,56929L,56930L,56931L,56932L,56933L,56934L,56935L,56936L,56937L,
+56938L,56939L,56940L,56941L,56942L,56943L,56944L,56945L,56946L,56947L,
+56948L,56949L,56950L,56951L,56952L,56953L,56954L,56955L,56956L,56957L,
+56958L,56959L,56960L,56961L,56962L,56963L,56964L,56965L,56966L,56967L,
+56968L,56969L,56970L,56971L,56972L,56973L,56974L,56975L,56976L,56977L,
+56978L,56979L,56980L,56981L,56982L,56983L,56984L,56985L,56986L,56987L,
+56988L,56989L,56990L,56991L,56992L,56993L,56994L,56995L,56996L,56997L,
+56998L,56999L,57000L,57001L,57002L,57003L,57004L,57005L,57006L,57007L,
+57008L,57009L,57010L,57011L,57012L,57013L,57014L,57015L,57016L,57017L,
+57018L,57019L,57020L,57021L,57022L,57023L,57024L,57025L,57026L,57027L,
+57028L,57029L,57030L,57031L,57032L,57033L,57034L,57035L,57036L,57037L,
+57038L,57039L,57040L,57041L,57042L,57043L,57044L,57045L,57046L,57047L,
+57048L,57049L,57050L,57051L,57052L,57053L,57054L,57055L,57056L,57057L,
+57058L,57059L,57060L,57061L,57062L,57063L,57064L,57065L,57066L,57067L,
+57068L,57069L,57070L,57071L,57072L,57073L,57074L,57075L,57076L,57077L,
+57078L,57079L,57080L,57081L,57082L,57083L,57084L,57085L,57086L,57087L,
+57088L,57089L,57090L,57091L,57092L,57093L,57094L,57095L,57096L,57097L,
+57098L,57099L,57100L,57101L,57102L,57103L,57104L,57105L,57106L,57107L,
+57108L,57109L,57110L,57111L,57112L,57113L,57114L,57115L,57116L,57117L,
+57118L,57119L,57120L,57121L,57122L,57123L,57124L,57125L,57126L,57127L,
+57128L,57129L,57130L,57131L,57132L,57133L,57134L,57135L,57136L,57137L,
+57138L,57139L,57140L,57141L,57142L,57143L,57144L,57145L,57146L,57147L,
+57148L,57149L,57150L,57151L,57152L,57153L,57154L,57155L,57156L,57157L,
+57158L,57159L,57160L,57161L,57162L,57163L,57164L,57165L,57166L,57167L,
+57168L,57169L,57170L,57171L,57172L,57173L,57174L,57175L,57176L,57177L,
+57178L,57179L,57180L,57181L,57182L,57183L,57184L,57185L,57186L,57187L,
+57188L,57189L,57190L,57191L,57192L,57193L,57194L,57195L,57196L,57197L,
+57198L,57199L,57200L,57201L,57202L,57203L,57204L,57205L,57206L,57207L,
+57208L,57209L,57210L,57211L,57212L,57213L,57214L,57215L,57216L,57217L,
+57218L,57219L,57220L,57221L,57222L,57223L,57224L,57225L,57226L,57227L,
+57228L,57229L,57230L,57231L,57232L,57233L,57234L,57235L,57236L,57237L,
+57238L,57239L,57240L,57241L,57242L,57243L,57244L,57245L,57246L,57247L,
+57248L,57249L,57250L,57251L,57252L,57253L,57254L,57255L,57256L,57257L,
+57258L,57259L,57260L,57261L,57262L,57263L,57264L,57265L,57266L,57267L,
+57268L,57269L,57270L,57271L,57272L,57273L,57274L,57275L,57276L,57277L,
+57278L,57279L,57280L,57281L,57282L,57283L,57284L,57285L,57286L,57287L,
+57288L,57289L,57290L,57291L,57292L,57293L,57294L,57295L,57296L,57297L,
+57298L,57299L,57300L,57301L,57302L,57303L,57304L,57305L,57306L,57307L,
+57308L,57309L,57310L,57311L,57312L,57313L,57314L,57315L,57316L,57317L,
+57318L,57319L,57320L,57321L,57322L,57323L,57324L,57325L,57326L,57327L,
+57328L,57329L,57330L,57331L,57332L,57333L,57334L,57335L,57336L,57337L,
+57338L,57339L,57340L,57341L,57342L,57343L,57344L,57345L,57346L,57347L,
+57348L,57349L,57350L,57351L,57352L,57353L,57354L,57355L,57356L,57357L,
+57358L,57359L,57360L,57361L,57362L,57363L,57364L,57365L,57366L,57367L,
+57368L,57369L,57370L,57371L,57372L,57373L,57374L,57375L,57376L,57377L,
+57378L,57379L,57380L,57381L,57382L,57383L,57384L,57385L,57386L,57387L,
+57388L,57389L,57390L,57391L,57392L,57393L,57394L,57395L,57396L,57397L,
+57398L,57399L,57400L,57401L,57402L,57403L,57404L,57405L,57406L,57407L,
+57408L,57409L,57410L,57411L,57412L,57413L,57414L,57415L,57416L,57417L,
+57418L,57419L,57420L,57421L,57422L,57423L,57424L,57425L,57426L,57427L,
+57428L,57429L,57430L,57431L,57432L,57433L,57434L,57435L,57436L,57437L,
+57438L,57439L,57440L,57441L,57442L,57443L,57444L,57445L,57446L,57447L,
+57448L,57449L,57450L,57451L,57452L,57453L,57454L,57455L,57456L,57457L,
+57458L,57459L,57460L,57461L,57462L,57463L,57464L,57465L,57466L,57467L,
+57468L,57469L,57470L,57471L,57472L,57473L,57474L,57475L,57476L,57477L,
+57478L,57479L,57480L,57481L,57482L,57483L,57484L,57485L,57486L,57487L,
+57488L,57489L,57490L,57491L,57492L,57493L,57494L,57495L,57496L,57497L,
+57498L,57499L,57500L,57501L,57502L,57503L,57504L,57505L,57506L,57507L,
+57508L,57509L,57510L,57511L,57512L,57513L,57514L,57515L,57516L,57517L,
+57518L,57519L,57520L,57521L,57522L,57523L,57524L,57525L,57526L,57527L,
+57528L,57529L,57530L,57531L,57532L,57533L,57534L,57535L,57536L,57537L,
+57538L,57539L,57540L,57541L,57542L,57543L,57544L,57545L,57546L,57547L,
+57548L,57549L,57550L,57551L,57552L,57553L,57554L,57555L,57556L,57557L,
+57558L,57559L,57560L,57561L,57562L,57563L,57564L,57565L,57566L,57567L,
+57568L,57569L,57570L,57571L,57572L,57573L,57574L,57575L,57576L,57577L,
+57578L,57579L,57580L,57581L,57582L,57583L,57584L,57585L,57586L,57587L,
+57588L,57589L,57590L,57591L,57592L,57593L,57594L,57595L,57596L,57597L,
+57598L,57599L,57600L,57601L,57602L,57603L,57604L,57605L,57606L,57607L,
+57608L,57609L,57610L,57611L,57612L,57613L,57614L,57615L,57616L,57617L,
+57618L,57619L,57620L,57621L,57622L,57623L,57624L,57625L,57626L,57627L,
+57628L,57629L,57630L,57631L,57632L,57633L,57634L,57635L,57636L,57637L,
+57638L,57639L,57640L,57641L,57642L,57643L,57644L,57645L,57646L,57647L,
+57648L,57649L,57650L,57651L,57652L,57653L,57654L,57655L,57656L,57657L,
+57658L,57659L,57660L,57661L,57662L,57663L,57664L,57665L,57666L,57667L,
+57668L,57669L,57670L,57671L,57672L,57673L,57674L,57675L,57676L,57677L,
+57678L,57679L,57680L,57681L,57682L,57683L,57684L,57685L,57686L,57687L,
+57688L,57689L,57690L,57691L,57692L,57693L,57694L,57695L,57696L,57697L,
+57698L,57699L,57700L,57701L,57702L,57703L,57704L,57705L,57706L,57707L,
+57708L,57709L,57710L,57711L,57712L,57713L,57714L,57715L,57716L,57717L,
+57718L,57719L,57720L,57721L,57722L,57723L,57724L,57725L,57726L,57727L,
+57728L,57729L,57730L,57731L,57732L,57733L,57734L,57735L,57736L,57737L,
+57738L,57739L,57740L,57741L,57742L,57743L,57744L,57745L,57746L,57747L,
+57748L,57749L,57750L,57751L,57752L,57753L,57754L,57755L,57756L,57757L,
+57758L,57759L,57760L,57761L,57762L,57763L,57764L,57765L,57766L,57767L,
+57768L,57769L,57770L,57771L,57772L,57773L,57774L,57775L,57776L,57777L,
+57778L,57779L,57780L,57781L,57782L,57783L,57784L,57785L,57786L,57787L,
+57788L,57789L,57790L,57791L,57792L,57793L,57794L,57795L,57796L,57797L,
+57798L,57799L,57800L,57801L,57802L,57803L,57804L,57805L,57806L,57807L,
+57808L,57809L,57810L,57811L,57812L,57813L,57814L,57815L,57816L,57817L,
+57818L,57819L,57820L,57821L,57822L,57823L,57824L,57825L,57826L,57827L,
+57828L,57829L,57830L,57831L,57832L,57833L,57834L,57835L,57836L,57837L,
+57838L,57839L,57840L,57841L,57842L,57843L,57844L,57845L,57846L,57847L,
+57848L,57849L,57850L,57851L,57852L,57853L,57854L,57855L,57856L,57857L,
+57858L,57859L,57860L,57861L,57862L,57863L,57864L,57865L,57866L,57867L,
+57868L,57869L,57870L,57871L,57872L,57873L,57874L,57875L,57876L,57877L,
+57878L,57879L,57880L,57881L,57882L,57883L,57884L,57885L,57886L,57887L,
+57888L,57889L,57890L,57891L,57892L,57893L,57894L,57895L,57896L,57897L,
+57898L,57899L,57900L,57901L,57902L,57903L,57904L,57905L,57906L,57907L,
+57908L,57909L,57910L,57911L,57912L,57913L,57914L,57915L,57916L,57917L,
+57918L,57919L,57920L,57921L,57922L,57923L,57924L,57925L,57926L,57927L,
+57928L,57929L,57930L,57931L,57932L,57933L,57934L,57935L,57936L,57937L,
+57938L,57939L,57940L,57941L,57942L,57943L,57944L,57945L,57946L,57947L,
+57948L,57949L,57950L,57951L,57952L,57953L,57954L,57955L,57956L,57957L,
+57958L,57959L,57960L,57961L,57962L,57963L,57964L,57965L,57966L,57967L,
+57968L,57969L,57970L,57971L,57972L,57973L,57974L,57975L,57976L,57977L,
+57978L,57979L,57980L,57981L,57982L,57983L,57984L,57985L,57986L,57987L,
+57988L,57989L,57990L,57991L,57992L,57993L,57994L,57995L,57996L,57997L,
+57998L,57999L,58000L,58001L,58002L,58003L,58004L,58005L,58006L,58007L,
+58008L,58009L,58010L,58011L,58012L,58013L,58014L,58015L,58016L,58017L,
+58018L,58019L,58020L,58021L,58022L,58023L,58024L,58025L,58026L,58027L,
+58028L,58029L,58030L,58031L,58032L,58033L,58034L,58035L,58036L,58037L,
+58038L,58039L,58040L,58041L,58042L,58043L,58044L,58045L,58046L,58047L,
+58048L,58049L,58050L,58051L,58052L,58053L,58054L,58055L,58056L,58057L,
+58058L,58059L,58060L,58061L,58062L,58063L,58064L,58065L,58066L,58067L,
+58068L,58069L,58070L,58071L,58072L,58073L,58074L,58075L,58076L,58077L,
+58078L,58079L,58080L,58081L,58082L,58083L,58084L,58085L,58086L,58087L,
+58088L,58089L,58090L,58091L,58092L,58093L,58094L,58095L,58096L,58097L,
+58098L,58099L,58100L,58101L,58102L,58103L,58104L,58105L,58106L,58107L,
+58108L,58109L,58110L,58111L,58112L,58113L,58114L,58115L,58116L,58117L,
+58118L,58119L,58120L,58121L,58122L,58123L,58124L,58125L,58126L,58127L,
+58128L,58129L,58130L,58131L,58132L,58133L,58134L,58135L,58136L,58137L,
+58138L,58139L,58140L,58141L,58142L,58143L,58144L,58145L,58146L,58147L,
+58148L,58149L,58150L,58151L,58152L,58153L,58154L,58155L,58156L,58157L,
+58158L,58159L,58160L,58161L,58162L,58163L,58164L,58165L,58166L,58167L,
+58168L,58169L,58170L,58171L,58172L,58173L,58174L,58175L,58176L,58177L,
+58178L,58179L,58180L,58181L,58182L,58183L,58184L,58185L,58186L,58187L,
+58188L,58189L,58190L,58191L,58192L,58193L,58194L,58195L,58196L,58197L,
+58198L,58199L,58200L,58201L,58202L,58203L,58204L,58205L,58206L,58207L,
+58208L,58209L,58210L,58211L,58212L,58213L,58214L,58215L,58216L,58217L,
+58218L,58219L,58220L,58221L,58222L,58223L,58224L,58225L,58226L,58227L,
+58228L,58229L,58230L,58231L,58232L,58233L,58234L,58235L,58236L,58237L,
+58238L,58239L,58240L,58241L,58242L,58243L,58244L,58245L,58246L,58247L,
+58248L,58249L,58250L,58251L,58252L,58253L,58254L,58255L,58256L,58257L,
+58258L,58259L,58260L,58261L,58262L,58263L,58264L,58265L,58266L,58267L,
+58268L,58269L,58270L,58271L,58272L,58273L,58274L,58275L,58276L,58277L,
+58278L,58279L,58280L,58281L,58282L,58283L,58284L,58285L,58286L,58287L,
+58288L,58289L,58290L,58291L,58292L,58293L,58294L,58295L,58296L,58297L,
+58298L,58299L,58300L,58301L,58302L,58303L,58304L,58305L,58306L,58307L,
+58308L,58309L,58310L,58311L,58312L,58313L,58314L,58315L,58316L,58317L,
+58318L,58319L,58320L,58321L,58322L,58323L,58324L,58325L,58326L,58327L,
+58328L,58329L,58330L,58331L,58332L,58333L,58334L,58335L,58336L,58337L,
+58338L,58339L,58340L,58341L,58342L,58343L,58344L,58345L,58346L,58347L,
+58348L,58349L,58350L,58351L,58352L,58353L,58354L,58355L,58356L,58357L,
+58358L,58359L,58360L,58361L,58362L,58363L,58364L,58365L,58366L,58367L,
+58368L,58369L,58370L,58371L,58372L,58373L,58374L,58375L,58376L,58377L,
+58378L,58379L,58380L,58381L,58382L,58383L,58384L,58385L,58386L,58387L,
+58388L,58389L,58390L,58391L,58392L,58393L,58394L,58395L,58396L,58397L,
+58398L,58399L,58400L,58401L,58402L,58403L,58404L,58405L,58406L,58407L,
+58408L,58409L,58410L,58411L,58412L,58413L,58414L,58415L,58416L,58417L,
+58418L,58419L,58420L,58421L,58422L,58423L,58424L,58425L,58426L,58427L,
+58428L,58429L,58430L,58431L,58432L,58433L,58434L,58435L,58436L,58437L,
+58438L,58439L,58440L,58441L,58442L,58443L,58444L,58445L,58446L,58447L,
+58448L,58449L,58450L,58451L,58452L,58453L,58454L,58455L,58456L,58457L,
+58458L,58459L,58460L,58461L,58462L,58463L,58464L,58465L,58466L,58467L,
+58468L,58469L,58470L,58471L,58472L,58473L,58474L,58475L,58476L,58477L,
+58478L,58479L,58480L,58481L,58482L,58483L,58484L,58485L,58486L,58487L,
+58488L,58489L,58490L,58491L,58492L,58493L,58494L,58495L,58496L,58497L,
+58498L,58499L,58500L,58501L,58502L,58503L,58504L,58505L,58506L,58507L,
+58508L,58509L,58510L,58511L,58512L,58513L,58514L,58515L,58516L,58517L,
+58518L,58519L,58520L,58521L,58522L,58523L,58524L,58525L,58526L,58527L,
+58528L,58529L,58530L,58531L,58532L,58533L,58534L,58535L,58536L,58537L,
+58538L,58539L,58540L,58541L,58542L,58543L,58544L,58545L,58546L,58547L,
+58548L,58549L,58550L,58551L,58552L,58553L,58554L,58555L,58556L,58557L,
+58558L,58559L,58560L,58561L,58562L,58563L,58564L,58565L,58566L,58567L,
+58568L,58569L,58570L,58571L,58572L,58573L,58574L,58575L,58576L,58577L,
+58578L,58579L,58580L,58581L,58582L,58583L,58584L,58585L,58586L,58587L,
+58588L,58589L,58590L,58591L,58592L,58593L,58594L,58595L,58596L,58597L,
+58598L,58599L,58600L,58601L,58602L,58603L,58604L,58605L,58606L,58607L,
+58608L,58609L,58610L,58611L,58612L,58613L,58614L,58615L,58616L,58617L,
+58618L,58619L,58620L,58621L,58622L,58623L,58624L,58625L,58626L,58627L,
+58628L,58629L,58630L,58631L,58632L,58633L,58634L,58635L,58636L,58637L,
+58638L,58639L,58640L,58641L,58642L,58643L,58644L,58645L,58646L,58647L,
+58648L,58649L,58650L,58651L,58652L,58653L,58654L,58655L,58656L,58657L,
+58658L,58659L,58660L,58661L,58662L,58663L,58664L,58665L,58666L,58667L,
+58668L,58669L,58670L,58671L,58672L,58673L,58674L,58675L,58676L,58677L,
+58678L,58679L,58680L,58681L,58682L,58683L,58684L,58685L,58686L,58687L,
+58688L,58689L,58690L,58691L,58692L,58693L,58694L,58695L,58696L,58697L,
+58698L,58699L,58700L,58701L,58702L,58703L,58704L,58705L,58706L,58707L,
+58708L,58709L,58710L,58711L,58712L,58713L,58714L,58715L,58716L,58717L,
+58718L,58719L,58720L,58721L,58722L,58723L,58724L,58725L,58726L,58727L,
+58728L,58729L,58730L,58731L,58732L,58733L,58734L,58735L,58736L,58737L,
+58738L,58739L,58740L,58741L,58742L,58743L,58744L,58745L,58746L,58747L,
+58748L,58749L,58750L,58751L,58752L,58753L,58754L,58755L,58756L,58757L,
+58758L,58759L,58760L,58761L,58762L,58763L,58764L,58765L,58766L,58767L,
+58768L,58769L,58770L,58771L,58772L,58773L,58774L,58775L,58776L,58777L,
+58778L,58779L,58780L,58781L,58782L,58783L,58784L,58785L,58786L,58787L,
+58788L,58789L,58790L,58791L,58792L,58793L,58794L,58795L,58796L,58797L,
+58798L,58799L,58800L,58801L,58802L,58803L,58804L,58805L,58806L,58807L,
+58808L,58809L,58810L,58811L,58812L,58813L,58814L,58815L,58816L,58817L,
+58818L,58819L,58820L,58821L,58822L,58823L,58824L,58825L,58826L,58827L,
+58828L,58829L,58830L,58831L,58832L,58833L,58834L,58835L,58836L,58837L,
+58838L,58839L,58840L,58841L,58842L,58843L,58844L,58845L,58846L,58847L,
+58848L,58849L,58850L,58851L,58852L,58853L,58854L,58855L,58856L,58857L,
+58858L,58859L,58860L,58861L,58862L,58863L,58864L,58865L,58866L,58867L,
+58868L,58869L,58870L,58871L,58872L,58873L,58874L,58875L,58876L,58877L,
+58878L,58879L,58880L,58881L,58882L,58883L,58884L,58885L,58886L,58887L,
+58888L,58889L,58890L,58891L,58892L,58893L,58894L,58895L,58896L,58897L,
+58898L,58899L,58900L,58901L,58902L,58903L,58904L,58905L,58906L,58907L,
+58908L,58909L,58910L,58911L,58912L,58913L,58914L,58915L,58916L,58917L,
+58918L,58919L,58920L,58921L,58922L,58923L,58924L,58925L,58926L,58927L,
+58928L,58929L,58930L,58931L,58932L,58933L,58934L,58935L,58936L,58937L,
+58938L,58939L,58940L,58941L,58942L,58943L,58944L,58945L,58946L,58947L,
+58948L,58949L,58950L,58951L,58952L,58953L,58954L,58955L,58956L,58957L,
+58958L,58959L,58960L,58961L,58962L,58963L,58964L,58965L,58966L,58967L,
+58968L,58969L,58970L,58971L,58972L,58973L,58974L,58975L,58976L,58977L,
+58978L,58979L,58980L,58981L,58982L,58983L,58984L,58985L,58986L,58987L,
+58988L,58989L,58990L,58991L,58992L,58993L,58994L,58995L,58996L,58997L,
+58998L,58999L,59000L,59001L,59002L,59003L,59004L,59005L,59006L,59007L,
+59008L,59009L,59010L,59011L,59012L,59013L,59014L,59015L,59016L,59017L,
+59018L,59019L,59020L,59021L,59022L,59023L,59024L,59025L,59026L,59027L,
+59028L,59029L,59030L,59031L,59032L,59033L,59034L,59035L,59036L,59037L,
+59038L,59039L,59040L,59041L,59042L,59043L,59044L,59045L,59046L,59047L,
+59048L,59049L,59050L,59051L,59052L,59053L,59054L,59055L,59056L,59057L,
+59058L,59059L,59060L,59061L,59062L,59063L,59064L,59065L,59066L,59067L,
+59068L,59069L,59070L,59071L,59072L,59073L,59074L,59075L,59076L,59077L,
+59078L,59079L,59080L,59081L,59082L,59083L,59084L,59085L,59086L,59087L,
+59088L,59089L,59090L,59091L,59092L,59093L,59094L,59095L,59096L,59097L,
+59098L,59099L,59100L,59101L,59102L,59103L,59104L,59105L,59106L,59107L,
+59108L,59109L,59110L,59111L,59112L,59113L,59114L,59115L,59116L,59117L,
+59118L,59119L,59120L,59121L,59122L,59123L,59124L,59125L,59126L,59127L,
+59128L,59129L,59130L,59131L,59132L,59133L,59134L,59135L,59136L,59137L,
+59138L,59139L,59140L,59141L,59142L,59143L,59144L,59145L,59146L,59147L,
+59148L,59149L,59150L,59151L,59152L,59153L,59154L,59155L,59156L,59157L,
+59158L,59159L,59160L,59161L,59162L,59163L,59164L,59165L,59166L,59167L,
+59168L,59169L,59170L,59171L,59172L,59173L,59174L,59175L,59176L,59177L,
+59178L,59179L,59180L,59181L,59182L,59183L,59184L,59185L,59186L,59187L,
+59188L,59189L,59190L,59191L,59192L,59193L,59194L,59195L,59196L,59197L,
+59198L,59199L,59200L,59201L,59202L,59203L,59204L,59205L,59206L,59207L,
+59208L,59209L,59210L,59211L,59212L,59213L,59214L,59215L,59216L,59217L,
+59218L,59219L,59220L,59221L,59222L,59223L,59224L,59225L,59226L,59227L,
+59228L,59229L,59230L,59231L,59232L,59233L,59234L,59235L,59236L,59237L,
+59238L,59239L,59240L,59241L,59242L,59243L,59244L,59245L,59246L,59247L,
+59248L,59249L,59250L,59251L,59252L,59253L,59254L,59255L,59256L,59257L,
+59258L,59259L,59260L,59261L,59262L,59263L,59264L,59265L,59266L,59267L,
+59268L,59269L,59270L,59271L,59272L,59273L,59274L,59275L,59276L,59277L,
+59278L,59279L,59280L,59281L,59282L,59283L,59284L,59285L,59286L,59287L,
+59288L,59289L,59290L,59291L,59292L,59293L,59294L,59295L,59296L,59297L,
+59298L,59299L,59300L,59301L,59302L,59303L,59304L,59305L,59306L,59307L,
+59308L,59309L,59310L,59311L,59312L,59313L,59314L,59315L,59316L,59317L,
+59318L,59319L,59320L,59321L,59322L,59323L,59324L,59325L,59326L,59327L,
+59328L,59329L,59330L,59331L,59332L,59333L,59334L,59335L,59336L,59337L,
+59338L,59339L,59340L,59341L,59342L,59343L,59344L,59345L,59346L,59347L,
+59348L,59349L,59350L,59351L,59352L,59353L,59354L,59355L,59356L,59357L,
+59358L,59359L,59360L,59361L,59362L,59363L,59364L,59365L,59366L,59367L,
+59368L,59369L,59370L,59371L,59372L,59373L,59374L,59375L,59376L,59377L,
+59378L,59379L,59380L,59381L,59382L,59383L,59384L,59385L,59386L,59387L,
+59388L,59389L,59390L,59391L,59392L,59393L,59394L,59395L,59396L,59397L,
+59398L,59399L,59400L,59401L,59402L,59403L,59404L,59405L,59406L,59407L,
+59408L,59409L,59410L,59411L,59412L,59413L,59414L,59415L,59416L,59417L,
+59418L,59419L,59420L,59421L,59422L,59423L,59424L,59425L,59426L,59427L,
+59428L,59429L,59430L,59431L,59432L,59433L,59434L,59435L,59436L,59437L,
+59438L,59439L,59440L,59441L,59442L,59443L,59444L,59445L,59446L,59447L,
+59448L,59449L,59450L,59451L,59452L,59453L,59454L,59455L,59456L,59457L,
+59458L,59459L,59460L,59461L,59462L,59463L,59464L,59465L,59466L,59467L,
+59468L,59469L,59470L,59471L,59472L,59473L,59474L,59475L,59476L,59477L,
+59478L,59479L,59480L,59481L,59482L,59483L,59484L,59485L,59486L,59487L,
+59488L,59489L,59490L,59491L,59492L,59493L,59494L,59495L,59496L,59497L,
+59498L,59499L,59500L,59501L,59502L,59503L,59504L,59505L,59506L,59507L,
+59508L,59509L,59510L,59511L,59512L,59513L,59514L,59515L,59516L,59517L,
+59518L,59519L,59520L,59521L,59522L,59523L,59524L,59525L,59526L,59527L,
+59528L,59529L,59530L,59531L,59532L,59533L,59534L,59535L,59536L,59537L,
+59538L,59539L,59540L,59541L,59542L,59543L,59544L,59545L,59546L,59547L,
+59548L,59549L,59550L,59551L,59552L,59553L,59554L,59555L,59556L,59557L,
+59558L,59559L,59560L,59561L,59562L,59563L,59564L,59565L,59566L,59567L,
+59568L,59569L,59570L,59571L,59572L,59573L,59574L,59575L,59576L,59577L,
+59578L,59579L,59580L,59581L,59582L,59583L,59584L,59585L,59586L,59587L,
+59588L,59589L,59590L,59591L,59592L,59593L,59594L,59595L,59596L,59597L,
+59598L,59599L,59600L,59601L,59602L,59603L,59604L,59605L,59606L,59607L,
+59608L,59609L,59610L,59611L,59612L,59613L,59614L,59615L,59616L,59617L,
+59618L,59619L,59620L,59621L,59622L,59623L,59624L,59625L,59626L,59627L,
+59628L,59629L,59630L,59631L,59632L,59633L,59634L,59635L,59636L,59637L,
+59638L,59639L,59640L,59641L,59642L,59643L,59644L,59645L,59646L,59647L,
+59648L,59649L,59650L,59651L,59652L,59653L,59654L,59655L,59656L,59657L,
+59658L,59659L,59660L,59661L,59662L,59663L,59664L,59665L,59666L,59667L,
+59668L,59669L,59670L,59671L,59672L,59673L,59674L,59675L,59676L,59677L,
+59678L,59679L,59680L,59681L,59682L,59683L,59684L,59685L,59686L,59687L,
+59688L,59689L,59690L,59691L,59692L,59693L,59694L,59695L,59696L,59697L,
+59698L,59699L,59700L,59701L,59702L,59703L,59704L,59705L,59706L,59707L,
+59708L,59709L,59710L,59711L,59712L,59713L,59714L,59715L,59716L,59717L,
+59718L,59719L,59720L,59721L,59722L,59723L,59724L,59725L,59726L,59727L,
+59728L,59729L,59730L,59731L,59732L,59733L,59734L,59735L,59736L,59737L,
+59738L,59739L,59740L,59741L,59742L,59743L,59744L,59745L,59746L,59747L,
+59748L,59749L,59750L,59751L,59752L,59753L,59754L,59755L,59756L,59757L,
+59758L,59759L,59760L,59761L,59762L,59763L,59764L,59765L,59766L,59767L,
+59768L,59769L,59770L,59771L,59772L,59773L,59774L,59775L,59776L,59777L,
+59778L,59779L,59780L,59781L,59782L,59783L,59784L,59785L,59786L,59787L,
+59788L,59789L,59790L,59791L,59792L,59793L,59794L,59795L,59796L,59797L,
+59798L,59799L,59800L,59801L,59802L,59803L,59804L,59805L,59806L,59807L,
+59808L,59809L,59810L,59811L,59812L,59813L,59814L,59815L,59816L,59817L,
+59818L,59819L,59820L,59821L,59822L,59823L,59824L,59825L,59826L,59827L,
+59828L,59829L,59830L,59831L,59832L,59833L,59834L,59835L,59836L,59837L,
+59838L,59839L,59840L,59841L,59842L,59843L,59844L,59845L,59846L,59847L,
+59848L,59849L,59850L,59851L,59852L,59853L,59854L,59855L,59856L,59857L,
+59858L,59859L,59860L,59861L,59862L,59863L,59864L,59865L,59866L,59867L,
+59868L,59869L,59870L,59871L,59872L,59873L,59874L,59875L,59876L,59877L,
+59878L,59879L,59880L,59881L,59882L,59883L,59884L,59885L,59886L,59887L,
+59888L,59889L,59890L,59891L,59892L,59893L,59894L,59895L,59896L,59897L,
+59898L,59899L,59900L,59901L,59902L,59903L,59904L,59905L,59906L,59907L,
+59908L,59909L,59910L,59911L,59912L,59913L,59914L,59915L,59916L,59917L,
+59918L,59919L,59920L,59921L,59922L,59923L,59924L,59925L,59926L,59927L,
+59928L,59929L,59930L,59931L,59932L,59933L,59934L,59935L,59936L,59937L,
+59938L,59939L,59940L,59941L,59942L,59943L,59944L,59945L,59946L,59947L,
+59948L,59949L,59950L,59951L,59952L,59953L,59954L,59955L,59956L,59957L,
+59958L,59959L,59960L,59961L,59962L,59963L,59964L,59965L,59966L,59967L,
+59968L,59969L,59970L,59971L,59972L,59973L,59974L,59975L,59976L,59977L,
+59978L,59979L,59980L,59981L,59982L,59983L,59984L,59985L,59986L,59987L,
+59988L,59989L,59990L,59991L,59992L,59993L,59994L,59995L,59996L,59997L,
+59998L,59999L,60000L,60001L,60002L,60003L,60004L,60005L,60006L,60007L,
+60008L,60009L,60010L,60011L,60012L,60013L,60014L,60015L,60016L,60017L,
+60018L,60019L,60020L,60021L,60022L,60023L,60024L,60025L,60026L,60027L,
+60028L,60029L,60030L,60031L,60032L,60033L,60034L,60035L,60036L,60037L,
+60038L,60039L,60040L,60041L,60042L,60043L,60044L,60045L,60046L,60047L,
+60048L,60049L,60050L,60051L,60052L,60053L,60054L,60055L,60056L,60057L,
+60058L,60059L,60060L,60061L,60062L,60063L,60064L,60065L,60066L,60067L,
+60068L,60069L,60070L,60071L,60072L,60073L,60074L,60075L,60076L,60077L,
+60078L,60079L,60080L,60081L,60082L,60083L,60084L,60085L,60086L,60087L,
+60088L,60089L,60090L,60091L,60092L,60093L,60094L,60095L,60096L,60097L,
+60098L,60099L,60100L,60101L,60102L,60103L,60104L,60105L,60106L,60107L,
+60108L,60109L,60110L,60111L,60112L,60113L,60114L,60115L,60116L,60117L,
+60118L,60119L,60120L,60121L,60122L,60123L,60124L,60125L,60126L,60127L,
+60128L,60129L,60130L,60131L,60132L,60133L,60134L,60135L,60136L,60137L,
+60138L,60139L,60140L,60141L,60142L,60143L,60144L,60145L,60146L,60147L,
+60148L,60149L,60150L,60151L,60152L,60153L,60154L,60155L,60156L,60157L,
+60158L,60159L,60160L,60161L,60162L,60163L,60164L,60165L,60166L,60167L,
+60168L,60169L,60170L,60171L,60172L,60173L,60174L,60175L,60176L,60177L,
+60178L,60179L,60180L,60181L,60182L,60183L,60184L,60185L,60186L,60187L,
+60188L,60189L,60190L,60191L,60192L,60193L,60194L,60195L,60196L,60197L,
+60198L,60199L,60200L,60201L,60202L,60203L,60204L,60205L,60206L,60207L,
+60208L,60209L,60210L,60211L,60212L,60213L,60214L,60215L,60216L,60217L,
+60218L,60219L,60220L,60221L,60222L,60223L,60224L,60225L,60226L,60227L,
+60228L,60229L,60230L,60231L,60232L,60233L,60234L,60235L,60236L,60237L,
+60238L,60239L,60240L,60241L,60242L,60243L,60244L,60245L,60246L,60247L,
+60248L,60249L,60250L,60251L,60252L,60253L,60254L,60255L,60256L,60257L,
+60258L,60259L,60260L,60261L,60262L,60263L,60264L,60265L,60266L,60267L,
+60268L,60269L,60270L,60271L,60272L,60273L,60274L,60275L,60276L,60277L,
+60278L,60279L,60280L,60281L,60282L,60283L,60284L,60285L,60286L,60287L,
+60288L,60289L,60290L,60291L,60292L,60293L,60294L,60295L,60296L,60297L,
+60298L,60299L,60300L,60301L,60302L,60303L,60304L,60305L,60306L,60307L,
+60308L,60309L,60310L,60311L,60312L,60313L,60314L,60315L,60316L,60317L,
+60318L,60319L,60320L,60321L,60322L,60323L,60324L,60325L,60326L,60327L,
+60328L,60329L,60330L,60331L,60332L,60333L,60334L,60335L,60336L,60337L,
+60338L,60339L,60340L,60341L,60342L,60343L,60344L,60345L,60346L,60347L,
+60348L,60349L,60350L,60351L,60352L,60353L,60354L,60355L,60356L,60357L,
+60358L,60359L,60360L,60361L,60362L,60363L,60364L,60365L,60366L,60367L,
+60368L,60369L,60370L,60371L,60372L,60373L,60374L,60375L,60376L,60377L,
+60378L,60379L,60380L,60381L,60382L,60383L,60384L,60385L,60386L,60387L,
+60388L,60389L,60390L,60391L,60392L,60393L,60394L,60395L,60396L,60397L,
+60398L,60399L,60400L,60401L,60402L,60403L,60404L,60405L,60406L,60407L,
+60408L,60409L,60410L,60411L,60412L,60413L,60414L,60415L,60416L,60417L,
+60418L,60419L,60420L,60421L,60422L,60423L,60424L,60425L,60426L,60427L,
+60428L,60429L,60430L,60431L,60432L,60433L,60434L,60435L,60436L,60437L,
+60438L,60439L,60440L,60441L,60442L,60443L,60444L,60445L,60446L,60447L,
+60448L,60449L,60450L,60451L,60452L,60453L,60454L,60455L,60456L,60457L,
+60458L,60459L,60460L,60461L,60462L,60463L,60464L,60465L,60466L,60467L,
+60468L,60469L,60470L,60471L,60472L,60473L,60474L,60475L,60476L,60477L,
+60478L,60479L,60480L,60481L,60482L,60483L,60484L,60485L,60486L,60487L,
+60488L,60489L,60490L,60491L,60492L,60493L,60494L,60495L,60496L,60497L,
+60498L,60499L,60500L,60501L,60502L,60503L,60504L,60505L,60506L,60507L,
+60508L,60509L,60510L,60511L,60512L,60513L,60514L,60515L,60516L,60517L,
+60518L,60519L,60520L,60521L,60522L,60523L,60524L,60525L,60526L,60527L,
+60528L,60529L,60530L,60531L,60532L,60533L,60534L,60535L,60536L,60537L,
+60538L,60539L,60540L,60541L,60542L,60543L,60544L,60545L,60546L,60547L,
+60548L,60549L,60550L,60551L,60552L,60553L,60554L,60555L,60556L,60557L,
+60558L,60559L,60560L,60561L,60562L,60563L,60564L,60565L,60566L,60567L,
+60568L,60569L,60570L,60571L,60572L,60573L,60574L,60575L,60576L,60577L,
+60578L,60579L,60580L,60581L,60582L,60583L,60584L,60585L,60586L,60587L,
+60588L,60589L,60590L,60591L,60592L,60593L,60594L,60595L,60596L,60597L,
+60598L,60599L,60600L,60601L,60602L,60603L,60604L,60605L,60606L,60607L,
+60608L,60609L,60610L,60611L,60612L,60613L,60614L,60615L,60616L,60617L,
+60618L,60619L,60620L,60621L,60622L,60623L,60624L,60625L,60626L,60627L,
+60628L,60629L,60630L,60631L,60632L,60633L,60634L,60635L,60636L,60637L,
+60638L,60639L,60640L,60641L,60642L,60643L,60644L,60645L,60646L,60647L,
+60648L,60649L,60650L,60651L,60652L,60653L,60654L,60655L,60656L,60657L,
+60658L,60659L,60660L,60661L,60662L,60663L,60664L,60665L,60666L,60667L,
+60668L,60669L,60670L,60671L,60672L,60673L,60674L,60675L,60676L,60677L,
+60678L,60679L,60680L,60681L,60682L,60683L,60684L,60685L,60686L,60687L,
+60688L,60689L,60690L,60691L,60692L,60693L,60694L,60695L,60696L,60697L,
+60698L,60699L,60700L,60701L,60702L,60703L,60704L,60705L,60706L,60707L,
+60708L,60709L,60710L,60711L,60712L,60713L,60714L,60715L,60716L,60717L,
+60718L,60719L,60720L,60721L,60722L,60723L,60724L,60725L,60726L,60727L,
+60728L,60729L,60730L,60731L,60732L,60733L,60734L,60735L,60736L,60737L,
+60738L,60739L,60740L,60741L,60742L,60743L,60744L,60745L,60746L,60747L,
+60748L,60749L,60750L,60751L,60752L,60753L,60754L,60755L,60756L,60757L,
+60758L,60759L,60760L,60761L,60762L,60763L,60764L,60765L,60766L,60767L,
+60768L,60769L,60770L,60771L,60772L,60773L,60774L,60775L,60776L,60777L,
+60778L,60779L,60780L,60781L,60782L,60783L,60784L,60785L,60786L,60787L,
+60788L,60789L,60790L,60791L,60792L,60793L,60794L,60795L,60796L,60797L,
+60798L,60799L,60800L,60801L,60802L,60803L,60804L,60805L,60806L,60807L,
+60808L,60809L,60810L,60811L,60812L,60813L,60814L,60815L,60816L,60817L,
+60818L,60819L,60820L,60821L,60822L,60823L,60824L,60825L,60826L,60827L,
+60828L,60829L,60830L,60831L,60832L,60833L,60834L,60835L,60836L,60837L,
+60838L,60839L,60840L,60841L,60842L,60843L,60844L,60845L,60846L,60847L,
+60848L,60849L,60850L,60851L,60852L,60853L,60854L,60855L,60856L,60857L,
+60858L,60859L,60860L,60861L,60862L,60863L,60864L,60865L,60866L,60867L,
+60868L,60869L,60870L,60871L,60872L,60873L,60874L,60875L,60876L,60877L,
+60878L,60879L,60880L,60881L,60882L,60883L,60884L,60885L,60886L,60887L,
+60888L,60889L,60890L,60891L,60892L,60893L,60894L,60895L,60896L,60897L,
+60898L,60899L,60900L,60901L,60902L,60903L,60904L,60905L,60906L,60907L,
+60908L,60909L,60910L,60911L,60912L,60913L,60914L,60915L,60916L,60917L,
+60918L,60919L,60920L,60921L,60922L,60923L,60924L,60925L,60926L,60927L,
+60928L,60929L,60930L,60931L,60932L,60933L,60934L,60935L,60936L,60937L,
+60938L,60939L,60940L,60941L,60942L,60943L,60944L,60945L,60946L,60947L,
+60948L,60949L,60950L,60951L,60952L,60953L,60954L,60955L,60956L,60957L,
+60958L,60959L,60960L,60961L,60962L,60963L,60964L,60965L,60966L,60967L,
+60968L,60969L,60970L,60971L,60972L,60973L,60974L,60975L,60976L,60977L,
+60978L,60979L,60980L,60981L,60982L,60983L,60984L,60985L,60986L,60987L,
+60988L,60989L,60990L,60991L,60992L,60993L,60994L,60995L,60996L,60997L,
+60998L,60999L,61000L,61001L,61002L,61003L,61004L,61005L,61006L,61007L,
+61008L,61009L,61010L,61011L,61012L,61013L,61014L,61015L,61016L,61017L,
+61018L,61019L,61020L,61021L,61022L,61023L,61024L,61025L,61026L,61027L,
+61028L,61029L,61030L,61031L,61032L,61033L,61034L,61035L,61036L,61037L,
+61038L,61039L,61040L,61041L,61042L,61043L,61044L,61045L,61046L,61047L,
+61048L,61049L,61050L,61051L,61052L,61053L,61054L,61055L,61056L,61057L,
+61058L,61059L,61060L,61061L,61062L,61063L,61064L,61065L,61066L,61067L,
+61068L,61069L,61070L,61071L,61072L,61073L,61074L,61075L,61076L,61077L,
+61078L,61079L,61080L,61081L,61082L,61083L,61084L,61085L,61086L,61087L,
+61088L,61089L,61090L,61091L,61092L,61093L,61094L,61095L,61096L,61097L,
+61098L,61099L,61100L,61101L,61102L,61103L,61104L,61105L,61106L,61107L,
+61108L,61109L,61110L,61111L,61112L,61113L,61114L,61115L,61116L,61117L,
+61118L,61119L,61120L,61121L,61122L,61123L,61124L,61125L,61126L,61127L,
+61128L,61129L,61130L,61131L,61132L,61133L,61134L,61135L,61136L,61137L,
+61138L,61139L,61140L,61141L,61142L,61143L,61144L,61145L,61146L,61147L,
+61148L,61149L,61150L,61151L,61152L,61153L,61154L,61155L,61156L,61157L,
+61158L,61159L,61160L,61161L,61162L,61163L,61164L,61165L,61166L,61167L,
+61168L,61169L,61170L,61171L,61172L,61173L,61174L,61175L,61176L,61177L,
+61178L,61179L,61180L,61181L,61182L,61183L,61184L,61185L,61186L,61187L,
+61188L,61189L,61190L,61191L,61192L,61193L,61194L,61195L,61196L,61197L,
+61198L,61199L,61200L,61201L,61202L,61203L,61204L,61205L,61206L,61207L,
+61208L,61209L,61210L,61211L,61212L,61213L,61214L,61215L,61216L,61217L,
+61218L,61219L,61220L,61221L,61222L,61223L,61224L,61225L,61226L,61227L,
+61228L,61229L,61230L,61231L,61232L,61233L,61234L,61235L,61236L,61237L,
+61238L,61239L,61240L,61241L,61242L,61243L,61244L,61245L,61246L,61247L,
+61248L,61249L,61250L,61251L,61252L,61253L,61254L,61255L,61256L,61257L,
+61258L,61259L,61260L,61261L,61262L,61263L,61264L,61265L,61266L,61267L,
+61268L,61269L,61270L,61271L,61272L,61273L,61274L,61275L,61276L,61277L,
+61278L,61279L,61280L,61281L,61282L,61283L,61284L,61285L,61286L,61287L,
+61288L,61289L,61290L,61291L,61292L,61293L,61294L,61295L,61296L,61297L,
+61298L,61299L,61300L,61301L,61302L,61303L,61304L,61305L,61306L,61307L,
+61308L,61309L,61310L,61311L,61312L,61313L,61314L,61315L,61316L,61317L,
+61318L,61319L,61320L,61321L,61322L,61323L,61324L,61325L,61326L,61327L,
+61328L,61329L,61330L,61331L,61332L,61333L,61334L,61335L,61336L,61337L,
+61338L,61339L,61340L,61341L,61342L,61343L,61344L,61345L,61346L,61347L,
+61348L,61349L,61350L,61351L,61352L,61353L,61354L,61355L,61356L,61357L,
+61358L,61359L,61360L,61361L,61362L,61363L,61364L,61365L,61366L,61367L,
+61368L,61369L,61370L,61371L,61372L,61373L,61374L,61375L,61376L,61377L,
+61378L,61379L,61380L,61381L,61382L,61383L,61384L,61385L,61386L,61387L,
+61388L,61389L,61390L,61391L,61392L,61393L,61394L,61395L,61396L,61397L,
+61398L,61399L,61400L,61401L,61402L,61403L,61404L,61405L,61406L,61407L,
+61408L,61409L,61410L,61411L,61412L,61413L,61414L,61415L,61416L,61417L,
+61418L,61419L,61420L,61421L,61422L,61423L,61424L,61425L,61426L,61427L,
+61428L,61429L,61430L,61431L,61432L,61433L,61434L,61435L,61436L,61437L,
+61438L,61439L,61440L,61441L,61442L,61443L,61444L,61445L,61446L,61447L,
+61448L,61449L,61450L,61451L,61452L,61453L,61454L,61455L,61456L,61457L,
+61458L,61459L,61460L,61461L,61462L,61463L,61464L,61465L,61466L,61467L,
+61468L,61469L,61470L,61471L,61472L,61473L,61474L,61475L,61476L,61477L,
+61478L,61479L,61480L,61481L,61482L,61483L,61484L,61485L,61486L,61487L,
+61488L,61489L,61490L,61491L,61492L,61493L,61494L,61495L,61496L,61497L,
+61498L,61499L,61500L,61501L,61502L,61503L,61504L,61505L,61506L,61507L,
+61508L,61509L,61510L,61511L,61512L,61513L,61514L,61515L,61516L,61517L,
+61518L,61519L,61520L,61521L,61522L,61523L,61524L,61525L,61526L,61527L,
+61528L,61529L,61530L,61531L,61532L,61533L,61534L,61535L,61536L,61537L,
+61538L,61539L,61540L,61541L,61542L,61543L,61544L,61545L,61546L,61547L,
+61548L,61549L,61550L,61551L,61552L,61553L,61554L,61555L,61556L,61557L,
+61558L,61559L,61560L,61561L,61562L,61563L,61564L,61565L,61566L,61567L,
+61568L,61569L,61570L,61571L,61572L,61573L,61574L,61575L,61576L,61577L,
+61578L,61579L,61580L,61581L,61582L,61583L,61584L,61585L,61586L,61587L,
+61588L,61589L,61590L,61591L,61592L,61593L,61594L,61595L,61596L,61597L,
+61598L,61599L,61600L,61601L,61602L,61603L,61604L,61605L,61606L,61607L,
+61608L,61609L,61610L,61611L,61612L,61613L,61614L,61615L,61616L,61617L,
+61618L,61619L,61620L,61621L,61622L,61623L,61624L,61625L,61626L,61627L,
+61628L,61629L,61630L,61631L,61632L,61633L,61634L,61635L,61636L,61637L,
+61638L,61639L,61640L,61641L,61642L,61643L,61644L,61645L,61646L,61647L,
+61648L,61649L,61650L,61651L,61652L,61653L,61654L,61655L,61656L,61657L,
+61658L,61659L,61660L,61661L,61662L,61663L,61664L,61665L,61666L,61667L,
+61668L,61669L,61670L,61671L,61672L,61673L,61674L,61675L,61676L,61677L,
+61678L,61679L,61680L,61681L,61682L,61683L,61684L,61685L,61686L,61687L,
+61688L,61689L,61690L,61691L,61692L,61693L,61694L,61695L,61696L,61697L,
+61698L,61699L,61700L,61701L,61702L,61703L,61704L,61705L,61706L,61707L,
+61708L,61709L,61710L,61711L,61712L,61713L,61714L,61715L,61716L,61717L,
+61718L,61719L,61720L,61721L,61722L,61723L,61724L,61725L,61726L,61727L,
+61728L,61729L,61730L,61731L,61732L,61733L,61734L,61735L,61736L,61737L,
+61738L,61739L,61740L,61741L,61742L,61743L,61744L,61745L,61746L,61747L,
+61748L,61749L,61750L,61751L,61752L,61753L,61754L,61755L,61756L,61757L,
+61758L,61759L,61760L,61761L,61762L,61763L,61764L,61765L,61766L,61767L,
+61768L,61769L,61770L,61771L,61772L,61773L,61774L,61775L,61776L,61777L,
+61778L,61779L,61780L,61781L,61782L,61783L,61784L,61785L,61786L,61787L,
+61788L,61789L,61790L,61791L,61792L,61793L,61794L,61795L,61796L,61797L,
+61798L,61799L,61800L,61801L,61802L,61803L,61804L,61805L,61806L,61807L,
+61808L,61809L,61810L,61811L,61812L,61813L,61814L,61815L,61816L,61817L,
+61818L,61819L,61820L,61821L,61822L,61823L,61824L,61825L,61826L,61827L,
+61828L,61829L,61830L,61831L,61832L,61833L,61834L,61835L,61836L,61837L,
+61838L,61839L,61840L,61841L,61842L,61843L,61844L,61845L,61846L,61847L,
+61848L,61849L,61850L,61851L,61852L,61853L,61854L,61855L,61856L,61857L,
+61858L,61859L,61860L,61861L,61862L,61863L,61864L,61865L,61866L,61867L,
+61868L,61869L,61870L,61871L,61872L,61873L,61874L,61875L,61876L,61877L,
+61878L,61879L,61880L,61881L,61882L,61883L,61884L,61885L,61886L,61887L,
+61888L,61889L,61890L,61891L,61892L,61893L,61894L,61895L,61896L,61897L,
+61898L,61899L,61900L,61901L,61902L,61903L,61904L,61905L,61906L,61907L,
+61908L,61909L,61910L,61911L,61912L,61913L,61914L,61915L,61916L,61917L,
+61918L,61919L,61920L,61921L,61922L,61923L,61924L,61925L,61926L,61927L,
+61928L,61929L,61930L,61931L,61932L,61933L,61934L,61935L,61936L,61937L,
+61938L,61939L,61940L,61941L,61942L,61943L,61944L,61945L,61946L,61947L,
+61948L,61949L,61950L,61951L,61952L,61953L,61954L,61955L,61956L,61957L,
+61958L,61959L,61960L,61961L,61962L,61963L,61964L,61965L,61966L,61967L,
+61968L,61969L,61970L,61971L,61972L,61973L,61974L,61975L,61976L,61977L,
+61978L,61979L,61980L,61981L,61982L,61983L,61984L,61985L,61986L,61987L,
+61988L,61989L,61990L,61991L,61992L,61993L,61994L,61995L,61996L,61997L,
+61998L,61999L,62000L,62001L,62002L,62003L,62004L,62005L,62006L,62007L,
+62008L,62009L,62010L,62011L,62012L,62013L,62014L,62015L,62016L,62017L,
+62018L,62019L,62020L,62021L,62022L,62023L,62024L,62025L,62026L,62027L,
+62028L,62029L,62030L,62031L,62032L,62033L,62034L,62035L,62036L,62037L,
+62038L,62039L,62040L,62041L,62042L,62043L,62044L,62045L,62046L,62047L,
+62048L,62049L,62050L,62051L,62052L,62053L,62054L,62055L,62056L,62057L,
+62058L,62059L,62060L,62061L,62062L,62063L,62064L,62065L,62066L,62067L,
+62068L,62069L,62070L,62071L,62072L,62073L,62074L,62075L,62076L,62077L,
+62078L,62079L,62080L,62081L,62082L,62083L,62084L,62085L,62086L,62087L,
+62088L,62089L,62090L,62091L,62092L,62093L,62094L,62095L,62096L,62097L,
+62098L,62099L,62100L,62101L,62102L,62103L,62104L,62105L,62106L,62107L,
+62108L,62109L,62110L,62111L,62112L,62113L,62114L,62115L,62116L,62117L,
+62118L,62119L,62120L,62121L,62122L,62123L,62124L,62125L,62126L,62127L,
+62128L,62129L,62130L,62131L,62132L,62133L,62134L,62135L,62136L,62137L,
+62138L,62139L,62140L,62141L,62142L,62143L,62144L,62145L,62146L,62147L,
+62148L,62149L,62150L,62151L,62152L,62153L,62154L,62155L,62156L,62157L,
+62158L,62159L,62160L,62161L,62162L,62163L,62164L,62165L,62166L,62167L,
+62168L,62169L,62170L,62171L,62172L,62173L,62174L,62175L,62176L,62177L,
+62178L,62179L,62180L,62181L,62182L,62183L,62184L,62185L,62186L,62187L,
+62188L,62189L,62190L,62191L,62192L,62193L,62194L,62195L,62196L,62197L,
+62198L,62199L,62200L,62201L,62202L,62203L,62204L,62205L,62206L,62207L,
+62208L,62209L,62210L,62211L,62212L,62213L,62214L,62215L,62216L,62217L,
+62218L,62219L,62220L,62221L,62222L,62223L,62224L,62225L,62226L,62227L,
+62228L,62229L,62230L,62231L,62232L,62233L,62234L,62235L,62236L,62237L,
+62238L,62239L,62240L,62241L,62242L,62243L,62244L,62245L,62246L,62247L,
+62248L,62249L,62250L,62251L,62252L,62253L,62254L,62255L,62256L,62257L,
+62258L,62259L,62260L,62261L,62262L,62263L,62264L,62265L,62266L,62267L,
+62268L,62269L,62270L,62271L,62272L,62273L,62274L,62275L,62276L,62277L,
+62278L,62279L,62280L,62281L,62282L,62283L,62284L,62285L,62286L,62287L,
+62288L,62289L,62290L,62291L,62292L,62293L,62294L,62295L,62296L,62297L,
+62298L,62299L,62300L,62301L,62302L,62303L,62304L,62305L,62306L,62307L,
+62308L,62309L,62310L,62311L,62312L,62313L,62314L,62315L,62316L,62317L,
+62318L,62319L,62320L,62321L,62322L,62323L,62324L,62325L,62326L,62327L,
+62328L,62329L,62330L,62331L,62332L,62333L,62334L,62335L,62336L,62337L,
+62338L,62339L,62340L,62341L,62342L,62343L,62344L,62345L,62346L,62347L,
+62348L,62349L,62350L,62351L,62352L,62353L,62354L,62355L,62356L,62357L,
+62358L,62359L,62360L,62361L,62362L,62363L,62364L,62365L,62366L,62367L,
+62368L,62369L,62370L,62371L,62372L,62373L,62374L,62375L,62376L,62377L,
+62378L,62379L,62380L,62381L,62382L,62383L,62384L,62385L,62386L,62387L,
+62388L,62389L,62390L,62391L,62392L,62393L,62394L,62395L,62396L,62397L,
+62398L,62399L,62400L,62401L,62402L,62403L,62404L,62405L,62406L,62407L,
+62408L,62409L,62410L,62411L,62412L,62413L,62414L,62415L,62416L,62417L,
+62418L,62419L,62420L,62421L,62422L,62423L,62424L,62425L,62426L,62427L,
+62428L,62429L,62430L,62431L,62432L,62433L,62434L,62435L,62436L,62437L,
+62438L,62439L,62440L,62441L,62442L,62443L,62444L,62445L,62446L,62447L,
+62448L,62449L,62450L,62451L,62452L,62453L,62454L,62455L,62456L,62457L,
+62458L,62459L,62460L,62461L,62462L,62463L,62464L,62465L,62466L,62467L,
+62468L,62469L,62470L,62471L,62472L,62473L,62474L,62475L,62476L,62477L,
+62478L,62479L,62480L,62481L,62482L,62483L,62484L,62485L,62486L,62487L,
+62488L,62489L,62490L,62491L,62492L,62493L,62494L,62495L,62496L,62497L,
+62498L,62499L,62500L,62501L,62502L,62503L,62504L,62505L,62506L,62507L,
+62508L,62509L,62510L,62511L,62512L,62513L,62514L,62515L,62516L,62517L,
+62518L,62519L,62520L,62521L,62522L,62523L,62524L,62525L,62526L,62527L,
+62528L,62529L,62530L,62531L,62532L,62533L,62534L,62535L,62536L,62537L,
+62538L,62539L,62540L,62541L,62542L,62543L,62544L,62545L,62546L,62547L,
+62548L,62549L,62550L,62551L,62552L,62553L,62554L,62555L,62556L,62557L,
+62558L,62559L,62560L,62561L,62562L,62563L,62564L,62565L,62566L,62567L,
+62568L,62569L,62570L,62571L,62572L,62573L,62574L,62575L,62576L,62577L,
+62578L,62579L,62580L,62581L,62582L,62583L,62584L,62585L,62586L,62587L,
+62588L,62589L,62590L,62591L,62592L,62593L,62594L,62595L,62596L,62597L,
+62598L,62599L,62600L,62601L,62602L,62603L,62604L,62605L,62606L,62607L,
+62608L,62609L,62610L,62611L,62612L,62613L,62614L,62615L,62616L,62617L,
+62618L,62619L,62620L,62621L,62622L,62623L,62624L,62625L,62626L,62627L,
+62628L,62629L,62630L,62631L,62632L,62633L,62634L,62635L,62636L,62637L,
+62638L,62639L,62640L,62641L,62642L,62643L,62644L,62645L,62646L,62647L,
+62648L,62649L,62650L,62651L,62652L,62653L,62654L,62655L,62656L,62657L,
+62658L,62659L,62660L,62661L,62662L,62663L,62664L,62665L,62666L,62667L,
+62668L,62669L,62670L,62671L,62672L,62673L,62674L,62675L,62676L,62677L,
+62678L,62679L,62680L,62681L,62682L,62683L,62684L,62685L,62686L,62687L,
+62688L,62689L,62690L,62691L,62692L,62693L,62694L,62695L,62696L,62697L,
+62698L,62699L,62700L,62701L,62702L,62703L,62704L,62705L,62706L,62707L,
+62708L,62709L,62710L,62711L,62712L,62713L,62714L,62715L,62716L,62717L,
+62718L,62719L,62720L,62721L,62722L,62723L,62724L,62725L,62726L,62727L,
+62728L,62729L,62730L,62731L,62732L,62733L,62734L,62735L,62736L,62737L,
+62738L,62739L,62740L,62741L,62742L,62743L,62744L,62745L,62746L,62747L,
+62748L,62749L,62750L,62751L,62752L,62753L,62754L,62755L,62756L,62757L,
+62758L,62759L,62760L,62761L,62762L,62763L,62764L,62765L,62766L,62767L,
+62768L,62769L,62770L,62771L,62772L,62773L,62774L,62775L,62776L,62777L,
+62778L,62779L,62780L,62781L,62782L,62783L,62784L,62785L,62786L,62787L,
+62788L,62789L,62790L,62791L,62792L,62793L,62794L,62795L,62796L,62797L,
+62798L,62799L,62800L,62801L,62802L,62803L,62804L,62805L,62806L,62807L,
+62808L,62809L,62810L,62811L,62812L,62813L,62814L,62815L,62816L,62817L,
+62818L,62819L,62820L,62821L,62822L,62823L,62824L,62825L,62826L,62827L,
+62828L,62829L,62830L,62831L,62832L,62833L,62834L,62835L,62836L,62837L,
+62838L,62839L,62840L,62841L,62842L,62843L,62844L,62845L,62846L,62847L,
+62848L,62849L,62850L,62851L,62852L,62853L,62854L,62855L,62856L,62857L,
+62858L,62859L,62860L,62861L,62862L,62863L,62864L,62865L,62866L,62867L,
+62868L,62869L,62870L,62871L,62872L,62873L,62874L,62875L,62876L,62877L,
+62878L,62879L,62880L,62881L,62882L,62883L,62884L,62885L,62886L,62887L,
+62888L,62889L,62890L,62891L,62892L,62893L,62894L,62895L,62896L,62897L,
+62898L,62899L,62900L,62901L,62902L,62903L,62904L,62905L,62906L,62907L,
+62908L,62909L,62910L,62911L,62912L,62913L,62914L,62915L,62916L,62917L,
+62918L,62919L,62920L,62921L,62922L,62923L,62924L,62925L,62926L,62927L,
+62928L,62929L,62930L,62931L,62932L,62933L,62934L,62935L,62936L,62937L,
+62938L,62939L,62940L,62941L,62942L,62943L,62944L,62945L,62946L,62947L,
+62948L,62949L,62950L,62951L,62952L,62953L,62954L,62955L,62956L,62957L,
+62958L,62959L,62960L,62961L,62962L,62963L,62964L,62965L,62966L,62967L,
+62968L,62969L,62970L,62971L,62972L,62973L,62974L,62975L,62976L,62977L,
+62978L,62979L,62980L,62981L,62982L,62983L,62984L,62985L,62986L,62987L,
+62988L,62989L,62990L,62991L,62992L,62993L,62994L,62995L,62996L,62997L,
+62998L,62999L,63000L,63001L,63002L,63003L,63004L,63005L,63006L,63007L,
+63008L,63009L,63010L,63011L,63012L,63013L,63014L,63015L,63016L,63017L,
+63018L,63019L,63020L,63021L,63022L,63023L,63024L,63025L,63026L,63027L,
+63028L,63029L,63030L,63031L,63032L,63033L,63034L,63035L,63036L,63037L,
+63038L,63039L,63040L,63041L,63042L,63043L,63044L,63045L,63046L,63047L,
+63048L,63049L,63050L,63051L,63052L,63053L,63054L,63055L,63056L,63057L,
+63058L,63059L,63060L,63061L,63062L,63063L,63064L,63065L,63066L,63067L,
+63068L,63069L,63070L,63071L,63072L,63073L,63074L,63075L,63076L,63077L,
+63078L,63079L,63080L,63081L,63082L,63083L,63084L,63085L,63086L,63087L,
+63088L,63089L,63090L,63091L,63092L,63093L,63094L,63095L,63096L,63097L,
+63098L,63099L,63100L,63101L,63102L,63103L,63104L,63105L,63106L,63107L,
+63108L,63109L,63110L,63111L,63112L,63113L,63114L,63115L,63116L,63117L,
+63118L,63119L,63120L,63121L,63122L,63123L,63124L,63125L,63126L,63127L,
+63128L,63129L,63130L,63131L,63132L,63133L,63134L,63135L,63136L,63137L,
+63138L,63139L,63140L,63141L,63142L,63143L,63144L,63145L,63146L,63147L,
+63148L,63149L,63150L,63151L,63152L,63153L,63154L,63155L,63156L,63157L,
+63158L,63159L,63160L,63161L,63162L,63163L,63164L,63165L,63166L,63167L,
+63168L,63169L,63170L,63171L,63172L,63173L,63174L,63175L,63176L,63177L,
+63178L,63179L,63180L,63181L,63182L,63183L,63184L,63185L,63186L,63187L,
+63188L,63189L,63190L,63191L,63192L,63193L,63194L,63195L,63196L,63197L,
+63198L,63199L,63200L,63201L,63202L,63203L,63204L,63205L,63206L,63207L,
+63208L,63209L,63210L,63211L,63212L,63213L,63214L,63215L,63216L,63217L,
+63218L,63219L,63220L,63221L,63222L,63223L,63224L,63225L,63226L,63227L,
+63228L,63229L,63230L,63231L,63232L,63233L,63234L,63235L,63236L,63237L,
+63238L,63239L,63240L,63241L,63242L,63243L,63244L,63245L,63246L,63247L,
+63248L,63249L,63250L,63251L,63252L,63253L,63254L,63255L,63256L,63257L,
+63258L,63259L,63260L,63261L,63262L,63263L,63264L,63265L,63266L,63267L,
+63268L,63269L,63270L,63271L,63272L,63273L,63274L,63275L,63276L,63277L,
+63278L,63279L,63280L,63281L,63282L,63283L,63284L,63285L,63286L,63287L,
+63288L,63289L,63290L,63291L,63292L,63293L,63294L,63295L,63296L,63297L,
+63298L,63299L,63300L,63301L,63302L,63303L,63304L,63305L,63306L,63307L,
+63308L,63309L,63310L,63311L,63312L,63313L,63314L,63315L,63316L,63317L,
+63318L,63319L,63320L,63321L,63322L,63323L,63324L,63325L,63326L,63327L,
+63328L,63329L,63330L,63331L,63332L,63333L,63334L,63335L,63336L,63337L,
+63338L,63339L,63340L,63341L,63342L,63343L,63344L,63345L,63346L,63347L,
+63348L,63349L,63350L,63351L,63352L,63353L,63354L,63355L,63356L,63357L,
+63358L,63359L,63360L,63361L,63362L,63363L,63364L,63365L,63366L,63367L,
+63368L,63369L,63370L,63371L,63372L,63373L,63374L,63375L,63376L,63377L,
+63378L,63379L,63380L,63381L,63382L,63383L,63384L,63385L,63386L,63387L,
+63388L,63389L,63390L,63391L,63392L,63393L,63394L,63395L,63396L,63397L,
+63398L,63399L,63400L,63401L,63402L,63403L,63404L,63405L,63406L,63407L,
+63408L,63409L,63410L,63411L,63412L,63413L,63414L,63415L,63416L,63417L,
+63418L,63419L,63420L,63421L,63422L,63423L,63424L,63425L,63426L,63427L,
+63428L,63429L,63430L,63431L,63432L,63433L,63434L,63435L,63436L,63437L,
+63438L,63439L,63440L,63441L,63442L,63443L,63444L,63445L,63446L,63447L,
+63448L,63449L,63450L,63451L,63452L,63453L,63454L,63455L,63456L,63457L,
+63458L,63459L,63460L,63461L,63462L,63463L,63464L,63465L,63466L,63467L,
+63468L,63469L,63470L,63471L,63472L,63473L,63474L,63475L,63476L,63477L,
+63478L,63479L,63480L,63481L,63482L,63483L,63484L,63485L,63486L,63487L,
+63488L,63489L,63490L,63491L,63492L,63493L,63494L,63495L,63496L,63497L,
+63498L,63499L,63500L,63501L,63502L,63503L,63504L,63505L,63506L,63507L,
+63508L,63509L,63510L,63511L,63512L,63513L,63514L,63515L,63516L,63517L,
+63518L,63519L,63520L,63521L,63522L,63523L,63524L,63525L,63526L,63527L,
+63528L,63529L,63530L,63531L,63532L,63533L,63534L,63535L,63536L,63537L,
+63538L,63539L,63540L,63541L,63542L,63543L,63544L,63545L,63546L,63547L,
+63548L,63549L,63550L,63551L,63552L,63553L,63554L,63555L,63556L,63557L,
+63558L,63559L,63560L,63561L,63562L,63563L,63564L,63565L,63566L,63567L,
+63568L,63569L,63570L,63571L,63572L,63573L,63574L,63575L,63576L,63577L,
+63578L,63579L,63580L,63581L,63582L,63583L,63584L,63585L,63586L,63587L,
+63588L,63589L,63590L,63591L,63592L,63593L,63594L,63595L,63596L,63597L,
+63598L,63599L,63600L,63601L,63602L,63603L,63604L,63605L,63606L,63607L,
+63608L,63609L,63610L,63611L,63612L,63613L,63614L,63615L,63616L,63617L,
+63618L,63619L,63620L,63621L,63622L,63623L,63624L,63625L,63626L,63627L,
+63628L,63629L,63630L,63631L,63632L,63633L,63634L,63635L,63636L,63637L,
+63638L,63639L,63640L,63641L,63642L,63643L,63644L,63645L,63646L,63647L,
+63648L,63649L,63650L,63651L,63652L,63653L,63654L,63655L,63656L,63657L,
+63658L,63659L,63660L,63661L,63662L,63663L,63664L,63665L,63666L,63667L,
+63668L,63669L,63670L,63671L,63672L,63673L,63674L,63675L,63676L,63677L,
+63678L,63679L,63680L,63681L,63682L,63683L,63684L,63685L,63686L,63687L,
+63688L,63689L,63690L,63691L,63692L,63693L,63694L,63695L,63696L,63697L,
+63698L,63699L,63700L,63701L,63702L,63703L,63704L,63705L,63706L,63707L,
+63708L,63709L,63710L,63711L,63712L,63713L,63714L,63715L,63716L,63717L,
+63718L,63719L,63720L,63721L,63722L,63723L,63724L,63725L,63726L,63727L,
+63728L,63729L,63730L,63731L,63732L,63733L,63734L,63735L,63736L,63737L,
+63738L,63739L,63740L,63741L,63742L,63743L,63744L,63745L,63746L,63747L,
+63748L,63749L,63750L,63751L,63752L,63753L,63754L,63755L,63756L,63757L,
+63758L,63759L,63760L,63761L,63762L,63763L,63764L,63765L,63766L,63767L,
+63768L,63769L,63770L,63771L,63772L,63773L,63774L,63775L,63776L,63777L,
+63778L,63779L,63780L,63781L,63782L,63783L,63784L,63785L,63786L,63787L,
+63788L,63789L,63790L,63791L,63792L,63793L,63794L,63795L,63796L,63797L,
+63798L,63799L,63800L,63801L,63802L,63803L,63804L,63805L,63806L,63807L,
+63808L,63809L,63810L,63811L,63812L,63813L,63814L,63815L,63816L,63817L,
+63818L,63819L,63820L,63821L,63822L,63823L,63824L,63825L,63826L,63827L,
+63828L,63829L,63830L,63831L,63832L,63833L,63834L,63835L,63836L,63837L,
+63838L,63839L,63840L,63841L,63842L,63843L,63844L,63845L,63846L,63847L,
+63848L,63849L,63850L,63851L,63852L,63853L,63854L,63855L,63856L,63857L,
+63858L,63859L,63860L,63861L,63862L,63863L,63864L,63865L,63866L,63867L,
+63868L,63869L,63870L,63871L,63872L,63873L,63874L,63875L,63876L,63877L,
+63878L,63879L,63880L,63881L,63882L,63883L,63884L,63885L,63886L,63887L,
+63888L,63889L,63890L,63891L,63892L,63893L,63894L,63895L,63896L,63897L,
+63898L,63899L,63900L,63901L,63902L,63903L,63904L,63905L,63906L,63907L,
+63908L,63909L,63910L,63911L,63912L,63913L,63914L,63915L,63916L,63917L,
+63918L,63919L,63920L,63921L,63922L,63923L,63924L,63925L,63926L,63927L,
+63928L,63929L,63930L,63931L,63932L,63933L,63934L,63935L,63936L,63937L,
+63938L,63939L,63940L,63941L,63942L,63943L,63944L,63945L,63946L,63947L,
+63948L,63949L,63950L,63951L,63952L,63953L,63954L,63955L,63956L,63957L,
+63958L,63959L,63960L,63961L,63962L,63963L,63964L,63965L,63966L,63967L,
+63968L,63969L,63970L,63971L,63972L,63973L,63974L,63975L,63976L,63977L,
+63978L,63979L,63980L,63981L,63982L,63983L,63984L,63985L,63986L,63987L,
+63988L,63989L,63990L,63991L,63992L,63993L,63994L,63995L,63996L,63997L,
+63998L,63999L,64000L,64001L,64002L,64003L,64004L,64005L,64006L,64007L,
+64008L,64009L,64010L,64011L,64012L,64013L,64014L,64015L,64016L,64017L,
+64018L,64019L,64020L,64021L,64022L,64023L,64024L,64025L,64026L,64027L,
+64028L,64029L,64030L,64031L,64032L,64033L,64034L,64035L,64036L,64037L,
+64038L,64039L,64040L,64041L,64042L,64043L,64044L,64045L,64046L,64047L,
+64048L,64049L,64050L,64051L,64052L,64053L,64054L,64055L,64056L,64057L,
+64058L,64059L,64060L,64061L,64062L,64063L,64064L,64065L,64066L,64067L,
+64068L,64069L,64070L,64071L,64072L,64073L,64074L,64075L,64076L,64077L,
+64078L,64079L,64080L,64081L,64082L,64083L,64084L,64085L,64086L,64087L,
+64088L,64089L,64090L,64091L,64092L,64093L,64094L,64095L,64096L,64097L,
+64098L,64099L,64100L,64101L,64102L,64103L,64104L,64105L,64106L,64107L,
+64108L,64109L,64110L,64111L,64112L,64113L,64114L,64115L,64116L,64117L,
+64118L,64119L,64120L,64121L,64122L,64123L,64124L,64125L,64126L,64127L,
+64128L,64129L,64130L,64131L,64132L,64133L,64134L,64135L,64136L,64137L,
+64138L,64139L,64140L,64141L,64142L,64143L,64144L,64145L,64146L,64147L,
+64148L,64149L,64150L,64151L,64152L,64153L,64154L,64155L,64156L,64157L,
+64158L,64159L,64160L,64161L,64162L,64163L,64164L,64165L,64166L,64167L,
+64168L,64169L,64170L,64171L,64172L,64173L,64174L,64175L,64176L,64177L,
+64178L,64179L,64180L,64181L,64182L,64183L,64184L,64185L,64186L,64187L,
+64188L,64189L,64190L,64191L,64192L,64193L,64194L,64195L,64196L,64197L,
+64198L,64199L,64200L,64201L,64202L,64203L,64204L,64205L,64206L,64207L,
+64208L,64209L,64210L,64211L,64212L,64213L,64214L,64215L,64216L,64217L,
+64218L,64219L,64220L,64221L,64222L,64223L,64224L,64225L,64226L,64227L,
+64228L,64229L,64230L,64231L,64232L,64233L,64234L,64235L,64236L,64237L,
+64238L,64239L,64240L,64241L,64242L,64243L,64244L,64245L,64246L,64247L,
+64248L,64249L,64250L,64251L,64252L,64253L,64254L,64255L,64256L,64257L,
+64258L,64259L,64260L,64261L,64262L,64263L,64264L,64265L,64266L,64267L,
+64268L,64269L,64270L,64271L,64272L,64273L,64274L,64275L,64276L,64277L,
+64278L,64279L,64280L,64281L,64282L,64283L,64284L,64285L,64286L,64287L,
+64288L,64289L,64290L,64291L,64292L,64293L,64294L,64295L,64296L,64297L,
+64298L,64299L,64300L,64301L,64302L,64303L,64304L,64305L,64306L,64307L,
+64308L,64309L,64310L,64311L,64312L,64313L,64314L,64315L,64316L,64317L,
+64318L,64319L,64320L,64321L,64322L,64323L,64324L,64325L,64326L,64327L,
+64328L,64329L,64330L,64331L,64332L,64333L,64334L,64335L,64336L,64337L,
+64338L,64339L,64340L,64341L,64342L,64343L,64344L,64345L,64346L,64347L,
+64348L,64349L,64350L,64351L,64352L,64353L,64354L,64355L,64356L,64357L,
+64358L,64359L,64360L,64361L,64362L,64363L,64364L,64365L,64366L,64367L,
+64368L,64369L,64370L,64371L,64372L,64373L,64374L,64375L,64376L,64377L,
+64378L,64379L,64380L,64381L,64382L,64383L,64384L,64385L,64386L,64387L,
+64388L,64389L,64390L,64391L,64392L,64393L,64394L,64395L,64396L,64397L,
+64398L,64399L,64400L,64401L,64402L,64403L,64404L,64405L,64406L,64407L,
+64408L,64409L,64410L,64411L,64412L,64413L,64414L,64415L,64416L,64417L,
+64418L,64419L,64420L,64421L,64422L,64423L,64424L,64425L,64426L,64427L,
+64428L,64429L,64430L,64431L,64432L,64433L,64434L,64435L,64436L,64437L,
+64438L,64439L,64440L,64441L,64442L,64443L,64444L,64445L,64446L,64447L,
+64448L,64449L,64450L,64451L,64452L,64453L,64454L,64455L,64456L,64457L,
+64458L,64459L,64460L,64461L,64462L,64463L,64464L,64465L,64466L,64467L,
+64468L,64469L,64470L,64471L,64472L,64473L,64474L,64475L,64476L,64477L,
+64478L,64479L,64480L,64481L,64482L,64483L,64484L,64485L,64486L,64487L,
+64488L,64489L,64490L,64491L,64492L,64493L,64494L,64495L,64496L,64497L,
+64498L,64499L,64500L,64501L,64502L,64503L,64504L,64505L,64506L,64507L,
+64508L,64509L,64510L,64511L,64512L,64513L,64514L,64515L,64516L,64517L,
+64518L,64519L,64520L,64521L,64522L,64523L,64524L,64525L,64526L,64527L,
+64528L,64529L,64530L,64531L,64532L,64533L,64534L,64535L,64536L,64537L,
+64538L,64539L,64540L,64541L,64542L,64543L,64544L,64545L,64546L,64547L,
+64548L,64549L,64550L,64551L,64552L,64553L,64554L,64555L,64556L,64557L,
+64558L,64559L,64560L,64561L,64562L,64563L,64564L,64565L,64566L,64567L,
+64568L,64569L,64570L,64571L,64572L,64573L,64574L,64575L,64576L,64577L,
+64578L,64579L,64580L,64581L,64582L,64583L,64584L,64585L,64586L,64587L,
+64588L,64589L,64590L,64591L,64592L,64593L,64594L,64595L,64596L,64597L,
+64598L,64599L,64600L,64601L,64602L,64603L,64604L,64605L,64606L,64607L,
+64608L,64609L,64610L,64611L,64612L,64613L,64614L,64615L,64616L,64617L,
+64618L,64619L,64620L,64621L,64622L,64623L,64624L,64625L,64626L,64627L,
+64628L,64629L,64630L,64631L,64632L,64633L,64634L,64635L,64636L,64637L,
+64638L,64639L,64640L,64641L,64642L,64643L,64644L,64645L,64646L,64647L,
+64648L,64649L,64650L,64651L,64652L,64653L,64654L,64655L,64656L,64657L,
+64658L,64659L,64660L,64661L,64662L,64663L,64664L,64665L,64666L,64667L,
+64668L,64669L,64670L,64671L,64672L,64673L,64674L,64675L,64676L,64677L,
+64678L,64679L,64680L,64681L,64682L,64683L,64684L,64685L,64686L,64687L,
+64688L,64689L,64690L,64691L,64692L,64693L,64694L,64695L,64696L,64697L,
+64698L,64699L,64700L,64701L,64702L,64703L,64704L,64705L,64706L,64707L,
+64708L,64709L,64710L,64711L,64712L,64713L,64714L,64715L,64716L,64717L,
+64718L,64719L,64720L,64721L,64722L,64723L,64724L,64725L,64726L,64727L,
+64728L,64729L,64730L,64731L,64732L,64733L,64734L,64735L,64736L,64737L,
+64738L,64739L,64740L,64741L,64742L,64743L,64744L,64745L,64746L,64747L,
+64748L,64749L,64750L,64751L,64752L,64753L,64754L,64755L,64756L,64757L,
+64758L,64759L,64760L,64761L,64762L,64763L,64764L,64765L,64766L,64767L,
+64768L,64769L,64770L,64771L,64772L,64773L,64774L,64775L,64776L,64777L,
+64778L,64779L,64780L,64781L,64782L,64783L,64784L,64785L,64786L,64787L,
+64788L,64789L,64790L,64791L,64792L,64793L,64794L,64795L,64796L,64797L,
+64798L,64799L,64800L,64801L,64802L,64803L,64804L,64805L,64806L,64807L,
+64808L,64809L,64810L,64811L,64812L,64813L,64814L,64815L,64816L,64817L,
+64818L,64819L,64820L,64821L,64822L,64823L,64824L,64825L,64826L,64827L,
+64828L,64829L,64830L,64831L,64832L,64833L,64834L,64835L,64836L,64837L,
+64838L,64839L,64840L,64841L,64842L,64843L,64844L,64845L,64846L,64847L,
+64848L,64849L,64850L,64851L,64852L,64853L,64854L,64855L,64856L,64857L,
+64858L,64859L,64860L,64861L,64862L,64863L,64864L,64865L,64866L,64867L,
+64868L,64869L,64870L,64871L,64872L,64873L,64874L,64875L,64876L,64877L,
+64878L,64879L,64880L,64881L,64882L,64883L,64884L,64885L,64886L,64887L,
+64888L,64889L,64890L,64891L,64892L,64893L,64894L,64895L,64896L,64897L,
+64898L,64899L,64900L,64901L,64902L,64903L,64904L,64905L,64906L,64907L,
+64908L,64909L,64910L,64911L,64912L,64913L,64914L,64915L,64916L,64917L,
+64918L,64919L,64920L,64921L,64922L,64923L,64924L,64925L,64926L,64927L,
+64928L,64929L,64930L,64931L,64932L,64933L,64934L,64935L,64936L,64937L,
+64938L,64939L,64940L,64941L,64942L,64943L,64944L,64945L,64946L,64947L,
+64948L,64949L,64950L,64951L,64952L,64953L,64954L,64955L,64956L,64957L,
+64958L,64959L,64960L,64961L,64962L,64963L,64964L,64965L,64966L,64967L,
+64968L,64969L,64970L,64971L,64972L,64973L,64974L,64975L,64976L,64977L,
+64978L,64979L,64980L,64981L,64982L,64983L,64984L,64985L,64986L,64987L,
+64988L,64989L,64990L,64991L,64992L,64993L,64994L,64995L,64996L,64997L,
+64998L,64999L,65000L,65001L,65002L,65003L,65004L,65005L,65006L,65007L,
+65008L,65009L,65010L,65011L,65012L,65013L,65014L,65015L,65016L,65017L,
+65018L,65019L,65020L,65021L,65022L,65023L,65024L,65025L,65026L,65027L,
+65028L,65029L,65030L,65031L,65032L,65033L,65034L,65035L,65036L,65037L,
+65038L,65039L,65040L,65041L,65042L,65043L,65044L,65045L,65046L,65047L,
+65048L,65049L,65050L,65051L,65052L,65053L,65054L,65055L,65056L,65057L,
+65058L,65059L,65060L,65061L,65062L,65063L,65064L,65065L,65066L,65067L,
+65068L,65069L,65070L,65071L,65072L,65073L,65074L,65075L,65076L,65077L,
+65078L,65079L,65080L,65081L,65082L,65083L,65084L,65085L,65086L,65087L,
+65088L,65089L,65090L,65091L,65092L,65093L,65094L,65095L,65096L,65097L,
+65098L,65099L,65100L,65101L,65102L,65103L,65104L,65105L,65106L,65107L,
+65108L,65109L,65110L,65111L,65112L,65113L,65114L,65115L,65116L,65117L,
+65118L,65119L,65120L,65121L,65122L,65123L,65124L,65125L,65126L,65127L,
+65128L,65129L,65130L,65131L,65132L,65133L,65134L,65135L,65136L,65137L,
+65138L,65139L,65140L,65141L,65142L,65143L,65144L,65145L,65146L,65147L,
+65148L,65149L,65150L,65151L,65152L,65153L,65154L,65155L,65156L,65157L,
+65158L,65159L,65160L,65161L,65162L,65163L,65164L,65165L,65166L,65167L,
+65168L,65169L,65170L,65171L,65172L,65173L,65174L,65175L,65176L,65177L,
+65178L,65179L,65180L,65181L,65182L,65183L,65184L,65185L,65186L,65187L,
+65188L,65189L,65190L,65191L,65192L,65193L,65194L,65195L,65196L,65197L,
+65198L,65199L,65200L,65201L,65202L,65203L,65204L,65205L,65206L,65207L,
+65208L,65209L,65210L,65211L,65212L,65213L,65214L,65215L,65216L,65217L,
+65218L,65219L,65220L,65221L,65222L,65223L,65224L,65225L,65226L,65227L,
+65228L,65229L,65230L,65231L,65232L,65233L,65234L,65235L,65236L,65237L,
+65238L,65239L,65240L,65241L,65242L,65243L,65244L,65245L,65246L,65247L,
+65248L,65249L,65250L,65251L,65252L,65253L,65254L,65255L,65256L,65257L,
+65258L,65259L,65260L,65261L,65262L,65263L,65264L,65265L,65266L,65267L,
+65268L,65269L,65270L,65271L,65272L,65273L,65274L,65275L,65276L,65277L,
+65278L,65279L,65280L,65281L,65282L,65283L,65284L,65285L,65286L,65287L,
+65288L,65289L,65290L,65291L,65292L,65293L,65294L,65295L,65296L,65297L,
+65298L,65299L,65300L,65301L,65302L,65303L,65304L,65305L,65306L,65307L,
+65308L,65309L,65310L,65311L,65312L,65313L,65314L,65315L,65316L,65317L,
+65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,65326L,65327L,
+65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,65336L,65337L,
+65338L,65339L,65340L,65341L,65342L,65343L,65344L,65313L,65314L,65315L,
+65316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,
+65326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,
+65336L,65337L,65338L,65371L,65372L,65373L,65374L,65375L,65376L,65377L,
+65378L,65379L,65380L,65381L,65382L,65383L,65384L,65385L,65386L,65387L,
+65388L,65389L,65390L,65391L,65392L,65393L,65394L,65395L,65396L,65397L,
+65398L,65399L,65400L,65401L,65402L,65403L,65404L,65405L,65406L,65407L,
+65408L,65409L,65410L,65411L,65412L,65413L,65414L,65415L,65416L,65417L,
+65418L,65419L,65420L,65421L,65422L,65423L,65424L,65425L,65426L,65427L,
+65428L,65429L,65430L,65431L,65432L,65433L,65434L,65435L,65436L,65437L,
+65438L,65439L,65440L,65441L,65442L,65443L,65444L,65445L,65446L,65447L,
+65448L,65449L,65450L,65451L,65452L,65453L,65454L,65455L,65456L,65457L,
+65458L,65459L,65460L,65461L,65462L,65463L,65464L,65465L,65466L,65467L,
+65468L,65469L,65470L,65471L,65472L,65473L,65474L,65475L,65476L,65477L,
+65478L,65479L,65480L,65481L,65482L,65483L,65484L,65485L,65486L,65487L,
+65488L,65489L,65490L,65491L,65492L,65493L,65494L,65495L,65496L,65497L,
+65498L,65499L,65500L,65501L,65502L,65503L,65504L,65505L,65506L,65507L,
+65508L,65509L,65510L,65511L,65512L,65513L,65514L,65515L,65516L,65517L,
+65518L,65519L,65520L,65521L,65522L,65523L,65524L,65525L,65526L,65527L,
+65528L,65529L,65530L,65531L,65532L,65533L,65534L,65535L,
+};
+#endif
+
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/*
+ * Automatically generated by extract_caseconv.py, do not edit!
+ */
+
+const duk_uint8_t duk_unicode_re_canon_bitmap[256] = {
+23,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,255,255,255,127,
+255,255,255,255,255,255,255,255,231,247,0,16,255,227,255,255,63,255,255,
+255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+227,193,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251,
};
#endif
-#line 1 "duk_util_bitdecoder.c"
/*
* Bitstream decoder.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Decode 'bits' bits from the input stream (bits must be 1...24).
* When reading past bitstream end, zeroes are shifted in. The result
* is signed to match duk_bd_decode_flagged.
*/
-DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
+DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
duk_small_int_t shift;
duk_uint32_t mask;
duk_uint32_t tmp;
@@ -86201,7 +94322,7 @@ DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t
* to be cleared, we just ignore them on next round.
*/
shift = ctx->currbits - bits;
- mask = (1 << bits) - 1;
+ mask = (((duk_uint32_t) 1U) << bits) - 1U;
tmp = (ctx->currval >> shift) & mask;
ctx->currbits = shift; /* remaining */
@@ -86213,27 +94334,122 @@ DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t
return tmp;
}
-DUK_INTERNAL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
- return (duk_small_int_t) duk_bd_decode(ctx, 1);
+DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
+ return (duk_small_uint_t) duk_bd_decode(ctx, 1);
}
/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
- * default value. Return value is signed so that negative marker value can be
- * used by caller as a "not present" value.
+ * default value.
*/
-DUK_INTERNAL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
+DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) {
if (duk_bd_decode_flag(ctx)) {
- return (duk_int32_t) duk_bd_decode(ctx, bits);
+ return duk_bd_decode(ctx, bits);
} else {
return def_value;
}
}
-#line 1 "duk_util_bitencoder.c"
+
+/* Signed variant, allows negative marker value. */
+DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
+ return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value);
+}
+
+/* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */
+DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) {
+ duk_small_uint_t t;
+
+ /* The bit encoding choices here are based on manual testing against
+ * the actual varuints generated by genbuiltins.py.
+ */
+ switch (duk_bd_decode(ctx, 2)) {
+ case 0:
+ return 0; /* [0,0] */
+ case 1:
+ return duk_bd_decode(ctx, 2) + 1; /* [1,4] */
+ case 2:
+ return duk_bd_decode(ctx, 5) + 5; /* [5,36] */
+ default:
+ t = duk_bd_decode(ctx, 7);
+ if (t == 0) {
+ return duk_bd_decode(ctx, 20);
+ }
+ return (t - 1) + 37; /* [37,163] */
+ }
+}
+
+/* Decode a bit packed string from a custom format used by genbuiltins.py.
+ * This function is here because it's used for both heap and thread inits.
+ * Caller must supply the output buffer whose size is NOT checked!
+ */
+
+#define DUK__BITPACK_LETTER_LIMIT 26
+#define DUK__BITPACK_LOOKUP1 26
+#define DUK__BITPACK_LOOKUP2 27
+#define DUK__BITPACK_SWITCH1 28
+#define DUK__BITPACK_SWITCH 29
+#define DUK__BITPACK_UNUSED1 30
+#define DUK__BITPACK_EIGHTBIT 31
+
+DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = {
+ DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
+ DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
+ DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE,
+ 0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
+};
+
+DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) {
+ duk_small_uint_t len;
+ duk_small_uint_t mode;
+ duk_small_uint_t t;
+ duk_small_uint_t i;
+
+ len = duk_bd_decode(bd, 5);
+ if (len == 31) {
+ len = duk_bd_decode(bd, 8); /* Support up to 256 bytes; rare. */
+ }
+
+ mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
+ for (i = 0; i < len; i++) {
+ t = duk_bd_decode(bd, 5);
+ if (t < DUK__BITPACK_LETTER_LIMIT) {
+ t = t + DUK_ASC_UC_A + mode;
+ } else if (t == DUK__BITPACK_LOOKUP1) {
+ t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)];
+ } else if (t == DUK__BITPACK_LOOKUP2) {
+ t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)];
+ } else if (t == DUK__BITPACK_SWITCH1) {
+ t = duk_bd_decode(bd, 5);
+ DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
+ DUK_ASSERT(t <= 25);
+ t = t + DUK_ASC_UC_A + (mode ^ 32);
+ } else if (t == DUK__BITPACK_SWITCH) {
+ mode = mode ^ 32;
+ t = duk_bd_decode(bd, 5);
+ DUK_ASSERT_DISABLE(t >= 0);
+ DUK_ASSERT(t <= 25);
+ t = t + DUK_ASC_UC_A + mode;
+ } else if (t == DUK__BITPACK_EIGHTBIT) {
+ t = duk_bd_decode(bd, 8);
+ }
+ out[i] = (duk_uint8_t) t;
+ }
+
+ return len;
+}
+
+/* automatic undefs */
+#undef DUK__BITPACK_EIGHTBIT
+#undef DUK__BITPACK_LETTER_LIMIT
+#undef DUK__BITPACK_LOOKUP1
+#undef DUK__BITPACK_LOOKUP2
+#undef DUK__BITPACK_SWITCH
+#undef DUK__BITPACK_SWITCH1
+#undef DUK__BITPACK_UNUSED1
/*
* Bitstream encoder.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
duk_uint8_t tmp;
@@ -86272,12 +94488,11 @@ DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
}
DUK_ASSERT(ctx->currbits == 0);
}
-#line 1 "duk_util_bufwriter.c"
/*
- * Fast buffer writer with spare management.
+ * Fast buffer writer with slack management.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Macro support functions (use only macros in calling code)
@@ -86302,21 +94517,17 @@ DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_h
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw_ctx != NULL);
DUK_ASSERT(h_buf != NULL);
- DUK_UNREF(thr);
bw_ctx->buf = h_buf;
duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
}
DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
- duk_context *ctx;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw_ctx != NULL);
- ctx = (duk_context *) thr;
- (void) duk_push_dynamic_buffer(ctx, buf_size);
- bw_ctx->buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
+ (void) duk_push_dynamic_buffer(thr, buf_size);
+ bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
}
@@ -86336,9 +94547,9 @@ DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_
*/
curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
- add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
+ add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD;
new_sz = curr_off + sz + add_sz;
- if (new_sz < curr_off) {
+ if (DUK_UNLIKELY(new_sz < curr_off)) {
/* overflow */
DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
return NULL; /* not reachable */
@@ -86396,7 +94607,6 @@ DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
duk_bw_write_raw_slice(thr, bw, src_off, len);
@@ -86413,7 +94623,7 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b
DUK_UNREF(thr);
p_base = bw->p_base;
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base); /* constrained by maximum buffer size */
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
@@ -86431,7 +94641,6 @@ DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(bw != NULL);
DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(buf != NULL);
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
@@ -86461,7 +94670,7 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
src_off += len;
}
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base);
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
@@ -86481,7 +94690,6 @@ DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
/* Don't support "straddled" source now. */
DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
@@ -86500,7 +94708,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter
DUK_UNREF(thr);
p_base = bw->p_base;
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base);
move_sz = buf_sz - off;
p_dst = p_base + off + len;
p_src = p_base + off;
@@ -86512,7 +94720,6 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwri
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw != NULL);
DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
return duk_bw_insert_raw_area(thr, bw, off, len);
@@ -86633,7 +94840,6 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk
DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
*p += 8;
}
-#line 1 "duk_util_hashbytes.c"
/*
* Hash function duk_util_hashbytes().
*
@@ -86643,7 +94849,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk
* dependent, for instance.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_STRHASH_DENSE)
/* 'magic' constants for Murmurhash2 */
@@ -86659,7 +94865,7 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t
* endian access even on big endian architectures, which is
* OK as long as it is consistent for a build.
*/
-#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
+#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
#else
duk_uint32_t k = ((duk_uint32_t) data[0]) |
@@ -86691,40 +94897,42 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t
return h;
}
#endif /* DUK_USE_STRHASH_DENSE */
-#line 1 "duk_util_tinyrandom.c"
+
+/* automatic undefs */
+#undef DUK__MAGIC_M
+#undef DUK__MAGIC_R
/*
- * A tiny random number generator.
+ * A tiny random number generator used for Math.random() and other internals.
*
- * Currently used for Math.random().
+ * Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c
+ * with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c.
+ *
+ * Low memory targets and targets without 64-bit types use a slightly smaller
+ * (but slower) algorithm by Adi Shamir:
+ * http://www.woodmann.com/forum/archive/index.php/t-3100.html.
*
- * http://www.woodmann.com/forum/archive/index.php/t-3100.html
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
+
+#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
+#define DUK__RANDOM_SHAMIR3OP
+#else
+#define DUK__RANDOM_XOROSHIRO128PLUS
+#endif
+#if defined(DUK__RANDOM_SHAMIR3OP)
#define DUK__UPDATE_RND(rnd) do { \
- (rnd) += ((rnd) * (rnd)) | 0x05; \
- (rnd) = ((rnd) & 0xffffffffU); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
+ (rnd) += ((rnd) * (rnd)) | 0x05UL; \
+ (rnd) = ((rnd) & 0xffffffffUL); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
} while (0)
#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
-DUK_INTERNAL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
- duk_small_int_t i;
- duk_uint32_t res = 0;
- duk_uint32_t rnd;
-
- rnd = thr->heap->rnd_state;
-
- for (i = 0; i < n; i++) {
- DUK__UPDATE_RND(rnd);
- res <<= 1;
- res += DUK__RND_BIT(rnd);
- }
-
- thr->heap->rnd_state = rnd;
-
- return res;
+DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
+ DUK_UNREF(thr); /* Nothing now. */
}
DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
@@ -86732,11 +94940,6 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
duk_small_int_t n;
duk_uint32_t rnd;
- /*
- * XXX: could make this a lot faster if we create the double memory
- * representation directly. Feasible easily (must be uniform random).
- */
-
rnd = thr->heap->rnd_state;
n = 53; /* enough to cover the whole mantissa */
@@ -86755,4 +94958,78 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
+#endif /* DUK__RANDOM_SHAMIR3OP */
+
+#if defined(DUK__RANDOM_XOROSHIRO128PLUS)
+DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) {
+ duk_uint64_t z;
+ z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15));
+ z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9);
+ z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB);
+ return z ^ (z >> 31U);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) {
+ return (x << k) | (x >> (64U - k));
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) {
+ duk_uint64_t s0;
+ duk_uint64_t s1;
+ duk_uint64_t res;
+
+ s0 = s[0];
+ s1 = s[1];
+ res = s0 + s1;
+ s1 ^= s0;
+ s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U);
+ s[1] = duk__rnd_rotl(s1, 36);
+
+ return res;
+}
+
+DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
+ duk_small_uint_t i;
+ duk_uint64_t x;
+
+ /* Mix both halves of the initial seed with SplitMix64. The intent
+ * is to ensure that very similar raw seeds (which is usually the case
+ * because current seed is Date.now()) result in different xoroshiro128+
+ * seeds.
+ */
+ x = thr->heap->rnd_state[0]; /* Only [0] is used as input here. */
+ for (i = 0; i < 64; i++) {
+ thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x); /* Keep last 2 values. */
+ }
+}
+
+DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
+ duk_uint64_t v;
+ duk_double_union du;
+
+ /* For big and little endian the integer and IEEE double byte order
+ * is the same so a direct assignment works. For mixed endian the
+ * 32-bit parts must be swapped.
+ */
+ v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
+ du.ull[0] = v;
+#if defined(DUK_USE_DOUBLE_ME)
+ do {
+ duk_uint32_t tmp;
+ tmp = du.ui[0];
+ du.ui[0] = du.ui[1];
+ du.ui[1] = tmp;
+ } while (0);
+#endif
+ return du.d - 1.0;
+}
+#endif /* DUK__RANDOM_XOROSHIRO128PLUS */
+
+#endif /* !DUK_USE_GET_RANDOM_DOUBLE */
+
+/* automatic undefs */
+#undef DUK__RANDOM_SHAMIR3OP
+#undef DUK__RANDOM_XOROSHIRO128PLUS
+#undef DUK__RND_BIT
+#undef DUK__UPDATE_RND
#endif
diff --git a/content/handlers/javascript/duktape/duktape.h b/content/handlers/javascript/duktape/duktape.h
index eb47a707b..e97e46269 100644
--- a/content/handlers/javascript/duktape/duktape.h
+++ b/content/handlers/javascript/duktape/duktape.h
@@ -1,13 +1,13 @@
/*
- * Duktape public API for Duktape 1.6.0.
+ * Duktape public API for Duktape 2.2.1.
*
- * See the API reference for documentation on call semantics.
- * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED
- * include guard. Other parts of the header are Duktape
- * internal and related to platform/compiler/feature detection.
+ * See the API reference for documentation on call semantics. The exposed,
+ * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API"
+ * comments. Other parts of the header are Duktape internal and related to
+ * e.g. platform/compiler/feature detection.
*
- * Git commit 17e3d86cf8b4788bd0d37658f833ab440ce43a1c (v1.6.0).
- * Git branch HEAD.
+ * Git commit external (external).
+ * Git branch external.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -21,7 +21,7 @@
*
* (http://opensource.org/licenses/MIT)
*
- * Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
+ * Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -75,6 +75,23 @@
* * Ren\u00e9 Hollander <rene@rene8888.at>
* * Julien Hamaide (https://github.com/crazyjul)
* * Sebastian G\u00f6tte (https://github.com/jaseg)
+ * * Tomasz Magulski (https://github.com/magul)
+ * * \D. Bohdan (https://github.com/dbohdan)
+ * * Ond\u0159ej Jirman (https://github.com/megous)
+ * * Sa\u00fal Ibarra Corretg\u00e9 <saghul@gmail.com>
+ * * Jeremy HU <huxingyi@msn.com>
+ * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+ * * Harold Brenes (https://github.com/harold-b)
+ * * Oliver Crow (https://github.com/ocrow)
+ * * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski)
+ * * Brett Vickers (https://github.com/beevik)
+ * * Dominik Okwieka (https://github.com/okitec)
+ * * Remko Tron\u00e7on (https://el-tramo.be)
+ * * Romero Malaquias (rbsm@ic.ufal.br)
+ * * Michael Drake <michael.drake@codethink.co.uk>
+ * * Steven Don (https://github.com/shdon)
+ * * Simon Stone (https://github.com/sstone1)
+ * * \J. McC. (https://github.com/jmhmccr)
*
* Other contributions
* ===================
@@ -112,35 +129,55 @@
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
* * Laurent Zubiaur (https://github.com/lzubiaur)
- * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+ * * Neil Kolban (https://github.com/nkolban)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala@iki.fi``) and I'll fix the omission.
*/
-#ifndef DUKTAPE_H_INCLUDED
+#if !defined(DUKTAPE_H_INCLUDED)
#define DUKTAPE_H_INCLUDED
#define DUK_SINGLE_FILE
-/* External duk_config.h provides platform/compiler/OS dependent
- * typedefs and macros, and DUK_USE_xxx config options so that
- * the rest of Duktape doesn't need to do any feature detection.
+/*
+ * BEGIN PUBLIC API
*/
-#include "duk_config.h"
/*
- * BEGIN PUBLIC API
+ * Version and Git commit identification
*/
-#ifndef DUK_API_PUBLIC_H_INCLUDED
-#define DUK_API_PUBLIC_H_INCLUDED
+/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code
+ * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value
+ * is also available to Ecmascript code in Duktape.version. Unofficial
+ * development snapshots have 99 for patch level (e.g. 0.10.99 would be a
+ * development version after 0.10.0 but before the next official release).
+ */
+#define DUK_VERSION 20201L
+
+/* Git commit, describe, and branch for Duktape build. Useful for
+ * non-official snapshot builds so that application code can easily log
+ * which Duktape snapshot was used. Not available in the Ecmascript
+ * environment.
+ */
+#define DUK_GIT_COMMIT "external"
+#define DUK_GIT_DESCRIBE "external"
+#define DUK_GIT_BRANCH "external"
+
+/* External duk_config.h provides platform/compiler/OS dependent
+ * typedefs and macros, and DUK_USE_xxx config options so that
+ * the rest of Duktape doesn't need to do any feature detection.
+ * DUK_VERSION is defined before including so that configuration
+ * snippets can react to it.
+ */
+#include "duk_config.h"
/*
* Avoid C++ name mangling
*/
-#ifdef __cplusplus
+#if defined(__cplusplus)
extern "C" {
#endif
@@ -149,7 +186,7 @@ extern "C" {
*/
#undef DUK_API_VARIADIC_MACROS
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
#define DUK_API_VARIADIC_MACROS
#endif
@@ -167,6 +204,7 @@ struct duk_thread_state;
struct duk_memory_functions;
struct duk_function_list_entry;
struct duk_number_list_entry;
+struct duk_time_components;
/* duk_context is now defined in duk_config.h because it may also be
* referenced there by prototypes.
@@ -175,22 +213,23 @@ typedef struct duk_thread_state duk_thread_state;
typedef struct duk_memory_functions duk_memory_functions;
typedef struct duk_function_list_entry duk_function_list_entry;
typedef struct duk_number_list_entry duk_number_list_entry;
+typedef struct duk_time_components duk_time_components;
typedef duk_ret_t (*duk_c_function)(duk_context *ctx);
typedef void *(*duk_alloc_function) (void *udata, duk_size_t size);
typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size);
typedef void (*duk_free_function) (void *udata, void *ptr);
-typedef void (*duk_fatal_function) (duk_context *ctx, duk_errcode_t code, const char *msg);
+typedef void (*duk_fatal_function) (void *udata, const char *msg);
typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint);
typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint);
-typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx);
+typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx, void *udata);
typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length);
typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length);
typedef duk_size_t (*duk_debug_peek_function) (void *udata);
typedef void (*duk_debug_read_flush_function) (void *udata);
typedef void (*duk_debug_write_flush_function) (void *udata);
typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues);
-typedef void (*duk_debug_detached_function) (void *udata);
+typedef void (*duk_debug_detached_function) (duk_context *ctx, void *udata);
struct duk_thread_state {
/* XXX: Enough space to hold internal suspend/resume structure.
@@ -218,29 +257,23 @@ struct duk_number_list_entry {
duk_double_t value;
};
+struct duk_time_components {
+ duk_double_t year; /* year, e.g. 2016, Ecmascript year range */
+ duk_double_t month; /* month: 1-12 */
+ duk_double_t day; /* day: 1-31 */
+ duk_double_t hours; /* hour: 0-59 */
+ duk_double_t minutes; /* minute: 0-59 */
+ duk_double_t seconds; /* second: 0-59 (in POSIX time no leap second) */
+ duk_double_t milliseconds; /* may contain sub-millisecond fractions */
+ duk_double_t weekday; /* weekday: 0-6, 0=Sunday, 1=Monday, ..., 6=Saturday */
+};
+
/*
* Constants
*/
-/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code
- * to #ifdef against Duktape API version. The same value is also available
- * to Ecmascript code in Duktape.version. Unofficial development snapshots
- * have 99 for patch level (e.g. 0.10.99 would be a development version
- * after 0.10.0 but before the next official release).
- */
-#define DUK_VERSION 10600L
-
-/* Git commit, describe, and branch for Duktape build. Useful for
- * non-official snapshot builds so that application code can easily log
- * which Duktape snapshot was used. Not available in the Ecmascript
- * environment.
- */
-#define DUK_GIT_COMMIT "17e3d86cf8b4788bd0d37658f833ab440ce43a1c"
-#define DUK_GIT_DESCRIBE "v1.6.0"
-#define DUK_GIT_BRANCH "HEAD"
-
/* Duktape debug protocol version used by this build. */
-#define DUK_DEBUG_PROTOCOL_VERSION 1
+#define DUK_DEBUG_PROTOCOL_VERSION 2
/* Used to represent invalid index; if caller uses this without checking,
* this index will map to a non-existent stack entry. Also used in some
@@ -256,34 +289,35 @@ struct duk_number_list_entry {
/* Number of value stack entries (in addition to actual call arguments)
* guaranteed to be allocated on entry to a Duktape/C function.
*/
-#define DUK_API_ENTRY_STACK 64
+#define DUK_API_ENTRY_STACK 64U
/* Value types, used by e.g. duk_get_type() */
-#define DUK_TYPE_MIN 0
-#define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */
-#define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */
-#define DUK_TYPE_NULL 2 /* Ecmascript null */
-#define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */
-#define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */
-#define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */
-#define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */
-#define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */
-#define DUK_TYPE_POINTER 8 /* raw void pointer */
-#define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */
-#define DUK_TYPE_MAX 9
+#define DUK_TYPE_MIN 0U
+#define DUK_TYPE_NONE 0U /* no value, e.g. invalid index */
+#define DUK_TYPE_UNDEFINED 1U /* Ecmascript undefined */
+#define DUK_TYPE_NULL 2U /* Ecmascript null */
+#define DUK_TYPE_BOOLEAN 3U /* Ecmascript boolean: 0 or 1 */
+#define DUK_TYPE_NUMBER 4U /* Ecmascript number: double */
+#define DUK_TYPE_STRING 5U /* Ecmascript string: CESU-8 / extended UTF-8 encoded */
+#define DUK_TYPE_OBJECT 6U /* Ecmascript object: includes objects, arrays, functions, threads */
+#define DUK_TYPE_BUFFER 7U /* fixed or dynamic, garbage collected byte buffer */
+#define DUK_TYPE_POINTER 8U /* raw void pointer */
+#define DUK_TYPE_LIGHTFUNC 9U /* lightweight function pointer */
+#define DUK_TYPE_MAX 9U
/* Value mask types, used by e.g. duk_get_type_mask() */
-#define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE)
-#define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED)
-#define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL)
-#define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN)
-#define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER)
-#define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING)
-#define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT)
-#define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER)
-#define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER)
-#define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC)
-#define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */
+#define DUK_TYPE_MASK_NONE (1U << DUK_TYPE_NONE)
+#define DUK_TYPE_MASK_UNDEFINED (1U << DUK_TYPE_UNDEFINED)
+#define DUK_TYPE_MASK_NULL (1U << DUK_TYPE_NULL)
+#define DUK_TYPE_MASK_BOOLEAN (1U << DUK_TYPE_BOOLEAN)
+#define DUK_TYPE_MASK_NUMBER (1U << DUK_TYPE_NUMBER)
+#define DUK_TYPE_MASK_STRING (1U << DUK_TYPE_STRING)
+#define DUK_TYPE_MASK_OBJECT (1U << DUK_TYPE_OBJECT)
+#define DUK_TYPE_MASK_BUFFER (1U << DUK_TYPE_BUFFER)
+#define DUK_TYPE_MASK_POINTER (1U << DUK_TYPE_POINTER)
+#define DUK_TYPE_MASK_LIGHTFUNC (1U << DUK_TYPE_LIGHTFUNC)
+#define DUK_TYPE_MASK_THROW (1U << 10) /* internal flag value: throw if mask doesn't match */
+#define DUK_TYPE_MASK_PROMOTE (1U << 11) /* internal flag value: promote to object if mask matches */
/* Coercion hints */
#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which
@@ -293,78 +327,95 @@ struct duk_number_list_entry {
#define DUK_HINT_NUMBER 2 /* prefer number */
/* Enumeration flags for duk_enum() */
-#define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */
-#define DUK_ENUM_INCLUDE_INTERNAL (1 << 1) /* enumerate internal properties (regardless of enumerability) */
-#define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 2) /* don't walk prototype chain, only check own properties */
-#define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 3) /* only enumerate array indices */
-#define DUK_ENUM_SORT_ARRAY_INDICES (1 << 4) /* sort array indices, use with DUK_ENUM_ARRAY_INDICES_ONLY */
-#define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 5) /* enumerate a proxy object itself without invoking proxy behavior */
+#define DUK_ENUM_INCLUDE_NONENUMERABLE (1U << 0) /* enumerate non-numerable properties in addition to enumerable */
+#define DUK_ENUM_INCLUDE_HIDDEN (1U << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */
+#define DUK_ENUM_INCLUDE_SYMBOLS (1U << 2) /* enumerate symbols */
+#define DUK_ENUM_EXCLUDE_STRINGS (1U << 3) /* exclude strings */
+#define DUK_ENUM_OWN_PROPERTIES_ONLY (1U << 4) /* don't walk prototype chain, only check own properties */
+#define DUK_ENUM_ARRAY_INDICES_ONLY (1U << 5) /* only enumerate array indices */
+/* XXX: misleading name */
+#define DUK_ENUM_SORT_ARRAY_INDICES (1U << 6) /* sort array indices (applied to full enumeration result, including inherited array indices); XXX: misleading name */
+#define DUK_ENUM_NO_PROXY_BEHAVIOR (1U << 7) /* enumerate a proxy object itself without invoking proxy behavior */
/* Compilation flags for duk_compile() and duk_eval() */
-/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument
- * (the nargs value passed is direct stack arguments + 1 to account for an
- * internal extra argument).
- */
-#define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */
-#define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */
-#define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */
-#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */
-#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */
-#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */
-#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */
-#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */
-
-/* Flags for duk_def_prop() and its variants */
-#define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */
-#define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */
-#define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */
-#define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */
-#define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */
-#define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */
-#define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */
-#define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */
-#define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */
-#define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */
+/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument.
+ */
+#define DUK_COMPILE_EVAL (1U << 3) /* compile eval code (instead of global code) */
+#define DUK_COMPILE_FUNCTION (1U << 4) /* compile function code (instead of global code) */
+#define DUK_COMPILE_STRICT (1U << 5) /* use strict (outer) context for global, eval, or function code */
+#define DUK_COMPILE_SHEBANG (1U << 6) /* allow shebang ('#! ...') comment on first line of source */
+#define DUK_COMPILE_SAFE (1U << 7) /* (internal) catch compilation errors */
+#define DUK_COMPILE_NORESULT (1U << 8) /* (internal) omit eval result */
+#define DUK_COMPILE_NOSOURCE (1U << 9) /* (internal) no source string on stack */
+#define DUK_COMPILE_STRLEN (1U << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */
+#define DUK_COMPILE_NOFILENAME (1U << 11) /* (internal) no filename on stack */
+#define DUK_COMPILE_FUNCEXPR (1U << 12) /* (internal) source is a function expression (used for Function constructor) */
+
+/* Flags for duk_def_prop() and its variants; base flags + a lot of convenience shorthands */
+#define DUK_DEFPROP_WRITABLE (1U << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */
+#define DUK_DEFPROP_ENUMERABLE (1U << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */
+#define DUK_DEFPROP_CONFIGURABLE (1U << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */
+#define DUK_DEFPROP_HAVE_WRITABLE (1U << 3) /* set/clear writable */
+#define DUK_DEFPROP_HAVE_ENUMERABLE (1U << 4) /* set/clear enumerable */
+#define DUK_DEFPROP_HAVE_CONFIGURABLE (1U << 5) /* set/clear configurable */
+#define DUK_DEFPROP_HAVE_VALUE (1U << 6) /* set value (given on value stack) */
+#define DUK_DEFPROP_HAVE_GETTER (1U << 7) /* set getter (given on value stack) */
+#define DUK_DEFPROP_HAVE_SETTER (1U << 8) /* set setter (given on value stack) */
+#define DUK_DEFPROP_FORCE (1U << 9) /* force change if possible, may still fail for e.g. virtual properties */
#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE)
#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE
#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE)
#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE
#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE)
#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE
+#define DUK_DEFPROP_W DUK_DEFPROP_WRITABLE
+#define DUK_DEFPROP_E DUK_DEFPROP_ENUMERABLE
+#define DUK_DEFPROP_C DUK_DEFPROP_CONFIGURABLE
+#define DUK_DEFPROP_WE (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE)
+#define DUK_DEFPROP_WC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_CONFIGURABLE)
+#define DUK_DEFPROP_WEC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_CONFIGURABLE)
+#define DUK_DEFPROP_HAVE_W DUK_DEFPROP_HAVE_WRITABLE
+#define DUK_DEFPROP_HAVE_E DUK_DEFPROP_HAVE_ENUMERABLE
+#define DUK_DEFPROP_HAVE_C DUK_DEFPROP_HAVE_CONFIGURABLE
+#define DUK_DEFPROP_HAVE_WE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE)
+#define DUK_DEFPROP_HAVE_WC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_CONFIGURABLE)
+#define DUK_DEFPROP_HAVE_WEC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE)
+#define DUK_DEFPROP_SET_W DUK_DEFPROP_SET_WRITABLE
+#define DUK_DEFPROP_SET_E DUK_DEFPROP_SET_ENUMERABLE
+#define DUK_DEFPROP_SET_C DUK_DEFPROP_SET_CONFIGURABLE
+#define DUK_DEFPROP_SET_WE (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE)
+#define DUK_DEFPROP_SET_WC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE)
+#define DUK_DEFPROP_SET_WEC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_SET_CONFIGURABLE)
+#define DUK_DEFPROP_CLEAR_W DUK_DEFPROP_CLEAR_WRITABLE
+#define DUK_DEFPROP_CLEAR_E DUK_DEFPROP_CLEAR_ENUMERABLE
+#define DUK_DEFPROP_CLEAR_C DUK_DEFPROP_CLEAR_CONFIGURABLE
+#define DUK_DEFPROP_CLEAR_WE (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE)
+#define DUK_DEFPROP_CLEAR_WC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE)
+#define DUK_DEFPROP_CLEAR_WEC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE)
+#define DUK_DEFPROP_ATTR_W (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_W)
+#define DUK_DEFPROP_ATTR_E (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_E)
+#define DUK_DEFPROP_ATTR_C (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_C)
+#define DUK_DEFPROP_ATTR_WE (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WE)
+#define DUK_DEFPROP_ATTR_WC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WC)
+#define DUK_DEFPROP_ATTR_WEC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WEC)
/* Flags for duk_push_thread_raw() */
-#define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */
+#define DUK_THREAD_NEW_GLOBAL_ENV (1U << 0) /* create a new global environment */
-/* Flags for duk_push_string_file_raw() */
-#define DUK_STRING_PUSH_SAFE (1 << 0) /* no error if file does not exist */
+/* Flags for duk_gc() */
+#define DUK_GC_COMPACT (1U << 0) /* compact heap objects */
-/* Duktape specific error codes (must be 8 bits at most, see duk_error.h) */
+/* Error codes (must be 8 bits at most, see duk_error.h) */
#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */
-#define DUK_ERR_UNIMPLEMENTED_ERROR 50 /* UnimplementedError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_UNSUPPORTED_ERROR 51 /* UnsupportedError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_INTERNAL_ERROR 52 /* InternalError */ /* XXX: replace with plain Error? */
-#define DUK_ERR_ALLOC_ERROR 53 /* AllocError */ /* XXX: replace with RangeError? */
-#define DUK_ERR_ASSERTION_ERROR 54 /* AssertionError */ /* XXX: to be removed? */
-#define DUK_ERR_API_ERROR 55 /* APIError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_UNCAUGHT_ERROR 56 /* UncaughtError */ /* XXX: to be removed? */
-
-/* Ecmascript E5 specification error codes */
-#define DUK_ERR_ERROR 100 /* Error */
-#define DUK_ERR_EVAL_ERROR 101 /* EvalError */
-#define DUK_ERR_RANGE_ERROR 102 /* RangeError */
-#define DUK_ERR_REFERENCE_ERROR 103 /* ReferenceError */
-#define DUK_ERR_SYNTAX_ERROR 104 /* SyntaxError */
-#define DUK_ERR_TYPE_ERROR 105 /* TypeError */
-#define DUK_ERR_URI_ERROR 106 /* URIError */
+#define DUK_ERR_ERROR 1 /* Error */
+#define DUK_ERR_EVAL_ERROR 2 /* EvalError */
+#define DUK_ERR_RANGE_ERROR 3 /* RangeError */
+#define DUK_ERR_REFERENCE_ERROR 4 /* ReferenceError */
+#define DUK_ERR_SYNTAX_ERROR 5 /* SyntaxError */
+#define DUK_ERR_TYPE_ERROR 6 /* TypeError */
+#define DUK_ERR_URI_ERROR 7 /* URIError */
/* Return codes for C functions (shortcut for throwing an error) */
-#define DUK_RET_UNIMPLEMENTED_ERROR (-DUK_ERR_UNIMPLEMENTED_ERROR)
-#define DUK_RET_UNSUPPORTED_ERROR (-DUK_ERR_UNSUPPORTED_ERROR)
-#define DUK_RET_INTERNAL_ERROR (-DUK_ERR_INTERNAL_ERROR)
-#define DUK_RET_ALLOC_ERROR (-DUK_ERR_ALLOC_ERROR)
-#define DUK_RET_ASSERTION_ERROR (-DUK_ERR_ASSERTION_ERROR)
-#define DUK_RET_API_ERROR (-DUK_ERR_API_ERROR)
-#define DUK_RET_UNCAUGHT_ERROR (-DUK_ERR_UNCAUGHT_ERROR)
#define DUK_RET_ERROR (-DUK_ERR_ERROR)
#define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR)
#define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR)
@@ -377,20 +428,34 @@ struct duk_number_list_entry {
#define DUK_EXEC_SUCCESS 0
#define DUK_EXEC_ERROR 1
-/* Log levels */
-#define DUK_LOG_TRACE 0
-#define DUK_LOG_DEBUG 1
-#define DUK_LOG_INFO 2
-#define DUK_LOG_WARN 3
-#define DUK_LOG_ERROR 4
-#define DUK_LOG_FATAL 5
+/* Debug levels for DUK_USE_DEBUG_WRITE(). */
+#define DUK_LEVEL_DEBUG 0
+#define DUK_LEVEL_DDEBUG 1
+#define DUK_LEVEL_DDDEBUG 2
+
+/*
+ * Macros to create Symbols as C statically constructed strings.
+ *
+ * Call e.g. as DUK_HIDDEN_SYMBOL("myProperty") <=> ("\xFF" "myProperty").
+ * Local symbols have a unique suffix, caller should take care to avoid
+ * conflicting with the Duktape internal representation by e.g. prepending
+ * a '!' character: DUK_LOCAL_SYMBOL("myLocal", "!123").
+ *
+ * Note that these can only be used for string constants, not dynamically
+ * created strings.
+ */
+
+#define DUK_HIDDEN_SYMBOL(x) ("\xFF" x)
+#define DUK_GLOBAL_SYMBOL(x) ("\x80" x)
+#define DUK_LOCAL_SYMBOL(x,uniq) ("\x81" x "\xff" uniq)
+#define DUK_WELLKNOWN_SYMBOL(x) ("\x81" x "\xff")
/*
* If no variadic macros, __FILE__ and __LINE__ are passed through globals
* which is ugly and not thread safe.
*/
-#ifndef DUK_API_VARIADIC_MACROS
+#if !defined(DUK_API_VARIADIC_MACROS)
DUK_EXTERNAL_DECL const char *duk_api_global_filename;
DUK_EXTERNAL_DECL duk_int_t duk_api_global_line;
#endif
@@ -432,29 +497,100 @@ DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags);
* Error handling
*/
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw(duk_context *ctx));
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg));
-
+DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw_raw(duk_context *ctx));
+#define duk_throw(ctx) \
+ (duk_throw_raw((ctx)), (duk_ret_t) 0)
+DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal_raw(duk_context *ctx, const char *err_msg));
+#define duk_fatal(ctx,err_msg) \
+ (duk_fatal_raw((ctx), (err_msg)), (duk_ret_t) 0)
DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...));
-#ifdef DUK_API_VARIADIC_MACROS
+#if defined(DUK_API_VARIADIC_MACROS)
#define duk_error(ctx,err_code,...) \
- duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__)
-#else
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...));
-/* One problem with this macro is that expressions like the following fail
- * to compile: "(void) duk_error(...)". But because duk_error() is noreturn,
- * they make little sense anyway.
- */
+ (duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_generic_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_eval_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_range_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_reference_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_syntax_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_type_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#define duk_uri_error(ctx,...) \
+ (duk_error_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__), (duk_ret_t) 0)
+#else /* DUK_API_VARIADIC_MACROS */
+/* For legacy compilers without variadic macros a macro hack is used to allow
+ * variable arguments. While the macro allows "return duk_error(...)", it
+ * will fail with e.g. "(void) duk_error(...)". The calls are noreturn but
+ * with a return value to allow the "return duk_error(...)" idiom. This may
+ * cause some compiler warnings, but without noreturn the generated code is
+ * often worse. The same approach as with variadic macros (using
+ * "(duk_error(...), 0)") won't work due to the macro hack structure.
+ */
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...));
+DUK_API_NORETURN(DUK_EXTERNAL_DECL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...));
#define duk_error \
(duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
duk_error_stash) /* last value is func pointer, arguments follow in parens */
-#endif
+#define duk_generic_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_generic_error_stash)
+#define duk_eval_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_eval_error_stash)
+#define duk_range_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_range_error_stash)
+#define duk_reference_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_reference_error_stash)
+#define duk_syntax_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_syntax_error_stash)
+#define duk_type_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_type_error_stash)
+#define duk_uri_error \
+ (duk_api_global_filename = (const char *) (DUK_FILE_MACRO), \
+ duk_api_global_line = (duk_int_t) (DUK_LINE_MACRO), \
+ duk_uri_error_stash)
+#endif /* DUK_API_VARIADIC_MACROS */
DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap));
+
#define duk_error_va(ctx,err_code,fmt,ap) \
- duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap))
+ (duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_generic_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_eval_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_EVAL_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_range_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_RANGE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_reference_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_REFERENCE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_syntax_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_SYNTAX_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_type_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_TYPE_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
+#define duk_uri_error_va(ctx,fmt,ap) \
+ (duk_error_va_raw((ctx), (duk_errcode_t) DUK_ERR_URI_ERROR, (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), (fmt), (ap)), (duk_ret_t) 0)
/*
* Other state related functions
@@ -467,13 +603,13 @@ DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx);
* Stack management
*/
-DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx);
DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx);
@@ -493,14 +629,14 @@ DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top);
* Stack manipulation (other than push/pop)
*/
-DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_index);
+DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2);
+DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_idx);
DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_idx);
+DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_idx);
+DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx);
+DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy);
#define duk_xmove_top(to_ctx,from_ctx,count) \
@@ -532,10 +668,6 @@ DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p);
DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...);
DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap);
-DUK_EXTERNAL_DECL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags);
-#define duk_push_string_file(ctx,path) \
- duk_push_string_file_raw((ctx), (path), 0)
-
DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx);
@@ -545,10 +677,12 @@ DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx);
DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx);
+DUK_EXTERNAL_DECL duk_idx_t duk_push_bare_object(duk_context *ctx);
DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx);
DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs);
DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic);
DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags);
+DUK_EXTERNAL_DECL duk_idx_t duk_push_proxy(duk_context *ctx, duk_uint_t proxy_flags);
#define duk_push_thread(ctx) \
duk_push_thread_raw((ctx), 0 /*flags*/)
@@ -558,7 +692,7 @@ DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t fla
DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...);
-#ifdef DUK_API_VARIADIC_MACROS
+#if defined(DUK_API_VARIADIC_MACROS)
#define duk_push_error_object(ctx,err_code,...) \
duk_push_error_object_raw((ctx), (err_code), (const char *) (DUK_FILE_MACRO), (duk_int_t) (DUK_LINE_MACRO), __VA_ARGS__)
#else
@@ -589,20 +723,18 @@ DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, d
#define duk_push_external_buffer(ctx) \
((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL))
-#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */
-#define DUK_BUFOBJ_DUKTAPE_BUFFER 0
+#define DUK_BUFOBJ_ARRAYBUFFER 0
#define DUK_BUFOBJ_NODEJS_BUFFER 1
-#define DUK_BUFOBJ_ARRAYBUFFER 2
-#define DUK_BUFOBJ_DATAVIEW (3 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT8ARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT16ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_FLOAT32ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_FLOAT64ARRAY (12 | DUK_BUFOBJ_CREATE_ARRBUF)
+#define DUK_BUFOBJ_DATAVIEW 2
+#define DUK_BUFOBJ_INT8ARRAY 3
+#define DUK_BUFOBJ_UINT8ARRAY 4
+#define DUK_BUFOBJ_UINT8CLAMPEDARRAY 5
+#define DUK_BUFOBJ_INT16ARRAY 6
+#define DUK_BUFOBJ_UINT16ARRAY 7
+#define DUK_BUFOBJ_INT32ARRAY 8
+#define DUK_BUFOBJ_UINT32ARRAY 9
+#define DUK_BUFOBJ_FLOAT32ARRAY 10
+#define DUK_BUFOBJ_FLOAT64ARRAY 11
DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags);
@@ -624,70 +756,79 @@ DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx);
* is not needed; duk_is_valid_index() gives the same information.
*/
-DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type);
-DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask);
-
-DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index);
-
-DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index);
-
-#define duk_is_callable(ctx,index) \
- duk_is_function((ctx), (index))
-DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index);
-
-#define duk_is_primitive(ctx,index) \
- duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_UNDEFINED | \
- DUK_TYPE_MASK_NULL | \
- DUK_TYPE_MASK_BOOLEAN | \
- DUK_TYPE_MASK_NUMBER | \
- DUK_TYPE_MASK_STRING | \
- DUK_TYPE_MASK_BUFFER | \
- DUK_TYPE_MASK_POINTER | \
- DUK_TYPE_MASK_LIGHTFUNC)
-
-#define duk_is_object_coercible(ctx,index) \
- duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \
- DUK_TYPE_MASK_NUMBER | \
- DUK_TYPE_MASK_STRING | \
- DUK_TYPE_MASK_OBJECT | \
- DUK_TYPE_MASK_BUFFER | \
- DUK_TYPE_MASK_POINTER | \
- DUK_TYPE_MASK_LIGHTFUNC)
-
-DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index);
-#define duk_is_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) != 0)
-#define duk_is_eval_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_EVAL_ERROR)
-#define duk_is_range_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_RANGE_ERROR)
-#define duk_is_reference_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_REFERENCE_ERROR)
-#define duk_is_syntax_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_SYNTAX_ERROR)
-#define duk_is_type_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_TYPE_ERROR)
-#define duk_is_uri_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_URI_ERROR)
+DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type);
+DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask);
+
+DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx);
+#define duk_is_null_or_undefined(ctx, idx) \
+ ((duk_get_type_mask((ctx), (idx)) & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) ? 1 : 0)
+
+DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx);
+
+DUK_EXTERNAL_DECL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx);
+
+#define duk_is_callable(ctx,idx) \
+ duk_is_function((ctx), (idx))
+DUK_EXTERNAL_DECL duk_bool_t duk_is_constructable(duk_context *ctx, duk_idx_t idx);
+
+DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx);
+
+/* Buffers and lightfuncs are not considered primitive because they mimic
+ * objects and e.g. duk_to_primitive() will coerce them instead of returning
+ * them as is. Symbols are represented as strings internally.
+ */
+#define duk_is_primitive(ctx,idx) \
+ duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_UNDEFINED | \
+ DUK_TYPE_MASK_NULL | \
+ DUK_TYPE_MASK_BOOLEAN | \
+ DUK_TYPE_MASK_NUMBER | \
+ DUK_TYPE_MASK_STRING | \
+ DUK_TYPE_MASK_POINTER)
+
+/* Symbols are object coercible, covered by DUK_TYPE_MASK_STRING. */
+#define duk_is_object_coercible(ctx,idx) \
+ duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \
+ DUK_TYPE_MASK_NUMBER | \
+ DUK_TYPE_MASK_STRING | \
+ DUK_TYPE_MASK_OBJECT | \
+ DUK_TYPE_MASK_BUFFER | \
+ DUK_TYPE_MASK_POINTER | \
+ DUK_TYPE_MASK_LIGHTFUNC)
+
+DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx);
+#define duk_is_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) != 0)
+#define duk_is_eval_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_EVAL_ERROR)
+#define duk_is_range_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_RANGE_ERROR)
+#define duk_is_reference_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_REFERENCE_ERROR)
+#define duk_is_syntax_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_SYNTAX_ERROR)
+#define duk_is_type_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_TYPE_ERROR)
+#define duk_is_uri_error(ctx,idx) \
+ (duk_get_error_code((ctx), (idx)) == DUK_ERR_URI_ERROR)
/*
* Get operations: no coercion, returns default value for invalid
@@ -697,48 +838,86 @@ DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t i
* are not included.
*/
-DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
+DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
+DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
+DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx);
+
+/*
+ * Get-with-explicit default operations: like get operations but with an
+ * explicit default value.
+ */
+
+DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value);
+DUK_EXTERNAL_DECL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value);
+DUK_EXTERNAL_DECL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value);
+DUK_EXTERNAL_DECL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value);
+DUK_EXTERNAL_DECL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value);
+DUK_EXTERNAL_DECL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len);
+DUK_EXTERNAL_DECL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len);
+DUK_EXTERNAL_DECL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len);
+DUK_EXTERNAL_DECL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value);
+DUK_EXTERNAL_DECL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value);
+DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value);
+DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value);
+
+/*
+ * Opt operations: like require operations but with an explicit default value
+ * when value is undefined or index is invalid, null and non-matching types
+ * cause a TypeError.
+ */
+
+DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value);
+DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value);
+DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value);
+DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value);
+DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr);
+DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len);
+DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size);
+DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size);
+DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value);
+DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value);
+DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value);
+DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value);
/*
* Require operations: no coercion, throw error if index or type
* is incorrect. No defaulting.
*/
-#define duk_require_type_mask(ctx,index,mask) \
- ((void) duk_check_type_mask((ctx), (index), (mask) | DUK_TYPE_MASK_THROW))
-
-DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t index);
-#define duk_require_callable(ctx,index) \
- duk_require_function((ctx), (index))
-DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index);
-
-#define duk_require_object_coercible(ctx,index) \
- ((void) duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \
+#define duk_require_type_mask(ctx,idx,mask) \
+ ((void) duk_check_type_mask((ctx), (idx), (mask) | DUK_TYPE_MASK_THROW))
+
+DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
+DUK_EXTERNAL_DECL void duk_require_object(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
+DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
+DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t idx);
+#define duk_require_callable(ctx,idx) \
+ duk_require_function((ctx), (idx))
+DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx);
+
+/* Symbols are object coercible and covered by DUK_TYPE_MASK_STRING. */
+#define duk_require_object_coercible(ctx,idx) \
+ ((void) duk_check_type_mask((ctx), (idx), DUK_TYPE_MASK_BOOLEAN | \
DUK_TYPE_MASK_NUMBER | \
DUK_TYPE_MASK_STRING | \
DUK_TYPE_MASK_OBJECT | \
@@ -754,57 +933,69 @@ DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index);
* or an internal error (e.g. from out of memory).
*/
-DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t flags);
-DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint);
-DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint);
+DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
+DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t flags);
+DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint);
#define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */
#define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */
#define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */
-#define duk_to_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DONTCARE)
-#define duk_to_fixed_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_FIXED)
-#define duk_to_dynamic_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DYNAMIC)
+#define duk_to_buffer(ctx,idx,out_size) \
+ duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DONTCARE)
+#define duk_to_fixed_buffer(ctx,idx,out_size) \
+ duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_FIXED)
+#define duk_to_dynamic_buffer(ctx,idx,out_size) \
+ duk_to_buffer_raw((ctx), (idx), (out_size), DUK_BUF_MODE_DYNAMIC)
/* safe variants of a few coercion operations */
-DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-#define duk_safe_to_string(ctx,index) \
- duk_safe_to_lstring((ctx), (index), NULL)
+DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
+#define duk_safe_to_string(ctx,idx) \
+ duk_safe_to_lstring((ctx), (idx), NULL)
+
+/*
+ * Value length
+ */
+
+DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len);
+#if 0
+/* duk_require_length()? */
+/* duk_opt_length()? */
+#endif
/*
* Misc conversion
*/
-DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t idx);
+
+DUK_EXTERNAL_DECL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx);
/*
* Buffer
*/
-DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size);
-DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len);
+DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size);
+DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
+DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len);
/*
* Property access
@@ -814,36 +1005,55 @@ DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void
* index as a property name (e.g. 123 is equivalent to the key "123").
*/
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
+
+DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
+DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len);
+
+/*
+ * Inspection
+ */
+
+DUK_EXTERNAL_DECL void duk_inspect_value(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level);
/*
* Object prototype
*/
-DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t idx);
/*
* Object finalizer
*/
-DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t index);
+DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx);
/*
* Global object
@@ -855,36 +1065,26 @@ DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx);
* Duktape/C function magic value
*/
-DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic);
+DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic);
DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx);
/*
* Module helpers: put multiple function or constant properties
*/
-DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs);
-DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers);
-
-/*
- * Variable access
- */
-
-/* XXX: These calls are incomplete and not usable now. They are not (yet)
- * part of the public API.
- */
-DUK_EXTERNAL_DECL void duk_get_var(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_put_var(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_var(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_var(duk_context *ctx);
+DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs);
+DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers);
/*
* Object operations
*/
-DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags);
-DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value);
+DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags);
+DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_idx, duk_bool_t get_value);
+DUK_EXTERNAL_DECL void duk_seal(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL void duk_freeze(duk_context *ctx, duk_idx_t obj_idx);
/*
* String manipulation
@@ -892,19 +1092,20 @@ DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, du
DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count);
DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count);
-DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata);
-DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata);
-DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_char_offset, duk_size_t end_char_offset);
-DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset);
+DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata);
+DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata);
+DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_char_offset, duk_size_t end_char_offset);
+DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t idx);
+DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset);
/*
* Ecmascript operators
*/
-DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
+DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2);
+DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2);
+DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2);
+DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2);
/*
* Function (method) calls
@@ -912,13 +1113,13 @@ DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1,
DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs);
DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs);
+DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs);
DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs);
DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs);
+DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs);
DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs);
DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets);
+DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets);
/*
* Thread management
@@ -937,103 +1138,72 @@ DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_bu
/* plain */
#define duk_eval(ctx) \
- ((void) duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME))
#define duk_eval_noresult(ctx) \
- ((void) duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_peval(ctx) \
- (duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
#define duk_peval_noresult(ctx) \
- (duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), NULL, 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_compile(ctx,flags) \
- ((void) duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags)))
+ ((void) duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags)))
#define duk_pcompile(ctx,flags) \
- (duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags) | DUK_COMPILE_SAFE))
+ (duk_compile_raw((ctx), NULL, 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE))
/* string */
#define duk_eval_string(ctx,src) \
- ((void) duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
#define duk_eval_string_noresult(ctx,src) \
- ((void) duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_peval_string(ctx,src) \
- (duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
#define duk_peval_string_noresult(ctx,src) \
- (duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), (src), 0, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_compile_string(ctx,flags,src) \
- ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
+ ((void) duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
#define duk_compile_string_filename(ctx,flags,src) \
- ((void) duk_compile_raw((ctx), (src), 0, 2 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
+ ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
#define duk_pcompile_string(ctx,flags,src) \
- (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
+ (duk_compile_raw((ctx), (src), 0, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
#define duk_pcompile_string_filename(ctx,flags,src) \
- (duk_compile_raw((ctx), (src), 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
+ (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
/* lstring */
#define duk_eval_lstring(ctx,buf,len) \
- ((void) duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
#define duk_eval_lstring_noresult(ctx,buf,len) \
- ((void) duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ ((void) duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_peval_lstring(ctx,buf,len) \
- (duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
#define duk_peval_lstring_noresult(ctx,buf,len) \
- (duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
+ (duk_eval_raw((ctx), buf, len, 0 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
#define duk_compile_lstring(ctx,flags,buf,len) \
- ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
+ ((void) duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
#define duk_compile_lstring_filename(ctx,flags,buf,len) \
- ((void) duk_compile_raw((ctx), buf, len, 2 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE))
+ ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE))
#define duk_pcompile_lstring(ctx,flags,buf,len) \
- (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
+ (duk_compile_raw((ctx), buf, len, 0 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
#define duk_pcompile_lstring_filename(ctx,flags,buf,len) \
- (duk_compile_raw((ctx), buf, len, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE))
-
-/* file */
-#define duk_eval_file(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL))
-
-#define duk_eval_file_noresult(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT))
-
-#define duk_peval_file(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE))
-
-#define duk_peval_file_noresult(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT))
-
-#define duk_compile_file(ctx,flags,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags)))
-
-#define duk_pcompile_file(ctx,flags,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags) | DUK_COMPILE_SAFE))
+ (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE))
/*
* Bytecode load/dump
@@ -1043,58 +1213,38 @@ DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx);
/*
- * Logging
- */
-
-DUK_EXTERNAL_DECL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...);
-DUK_EXTERNAL_DECL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap);
-
-/*
* Debugging
*/
DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx);
-#if defined(DUK_USE_FILE_IO)
-/* internal use */
-#define duk_dump_context_filehandle(ctx,fh) \
- (duk_push_context_dump((ctx)), \
- DUK_FPRINTF((fh), "%s\n", duk_safe_to_string(ctx, -1)), \
- duk_pop(ctx))
-
-/* external use */
-#define duk_dump_context_stdout(ctx) \
- duk_dump_context_filehandle((ctx), DUK_STDOUT)
-#define duk_dump_context_stderr(ctx) \
- duk_dump_context_filehandle((ctx), DUK_STDERR)
-#else /* DUK_USE_FILE_IO */
-#define duk_dump_context_stdout(ctx) ((void) 0)
-#define duk_dump_context_stderr(ctx) ((void) 0)
-#endif /* DUK_USE_FILE_IO */
-
/*
* Debugger (debug protocol)
*/
-#define duk_debugger_attach(ctx,read_cb,write_cb,peek_cb,read_flush_cb,write_flush_cb,detached_cb,udata) \
- duk_debugger_attach_custom((ctx), (read_cb), (write_cb), (peek_cb), (read_flush_cb), (write_flush_cb), \
- NULL, (detached_cb), (udata))
-
-DUK_EXTERNAL_DECL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata);
+DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx,
+ duk_debug_read_function read_cb,
+ duk_debug_write_function write_cb,
+ duk_debug_peek_function peek_cb,
+ duk_debug_read_flush_function read_flush_cb,
+ duk_debug_write_flush_function write_flush_cb,
+ duk_debug_request_function request_cb,
+ duk_debug_detached_function detached_cb,
+ void *udata);
DUK_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx);
DUK_EXTERNAL_DECL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues);
DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx);
/*
+ * Time handling
+ */
+
+DUK_EXTERNAL_DECL duk_double_t duk_get_now(duk_context *ctx);
+DUK_EXTERNAL_DECL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp);
+DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp);
+
+/*
* Date provider related constants
*
* NOTE: These are "semi public" - you should only use these if you write
@@ -1130,7 +1280,7 @@ DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx);
* depend on the specific ordering, so change with care. 16 bits are not
* enough for all parts (year, specifically).
*
- * (Must be in-sync with genbuiltins.py.)
+ * Must be in-sync with genbuiltins.py.
*/
#define DUK_DATE_IDX_YEAR 0 /* year */
#define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */
@@ -1142,7 +1292,7 @@ DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx);
#define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */
#define DUK_DATE_IDX_NUM_PARTS 8
-/* Internal API call flags, used for various functions in this file.
+/* Internal API call flags, used for various functions in duk_bi_date.c.
* Certain flags are used by only certain functions, but since the flags
* don't overlap, a single flags value can be passed around to multiple
* functions.
@@ -1150,7 +1300,7 @@ DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx);
* The unused top bits of the flags field are also used to pass values
* to helpers (duk__get_part_helper() and duk__set_part_helper()).
*
- * (Must be in-sync with genbuiltins.py.)
+ * Must be in-sync with genbuiltins.py.
*/
/* NOTE: when writing a Date provider you only need a few specific
@@ -1187,394 +1337,13 @@ DUK_EXTERNAL_DECL const void * const duk_rom_compressed_pointers[];
* C++ name mangling
*/
-#ifdef __cplusplus
+#if defined(__cplusplus)
/* end 'extern "C"' wrapper */
}
#endif
-#endif /* DUK_API_PUBLIC_H_INCLUDED */
-
/*
* END PUBLIC API
*/
-/*
- * Union to access IEEE double memory representation, indexes for double
- * memory representation, and some macros for double manipulation.
- *
- * Also used by packed duk_tval. Use a union for bit manipulation to
- * minimize aliasing issues in practice. The C99 standard does not
- * guarantee that this should work, but it's a very widely supported
- * practice for low level manipulation.
- *
- * IEEE double format summary:
- *
- * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
- * A B C D E F G H
- *
- * s sign bit
- * eee... exponent field
- * fff... fraction
- *
- * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
- *
- * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
- * signaling NaN when the highest bit of the mantissa is zero, and a quiet
- * NaN when the highest bit is set.
- *
- * At least three memory layouts are relevant here:
- *
- * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
- * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
- * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME
- *
- * ARM is a special case: ARM double values are in mixed/cross endian
- * format while ARM duk_uint64_t values are in standard little endian
- * format (H G F E D C B A). When a double is read as a duk_uint64_t
- * from memory, the register will contain the (logical) value
- * E F G H A B C D. This requires some special handling below.
- *
- * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
- * the logical (big endian) order:
- *
- * byte order duk_uint8_t duk_uint16_t duk_uint32_t
- * BE 01234567 0123 01
- * LE 76543210 3210 10
- * ME (ARM) 32107654 1032 01
- *
- * Some processors may alter NaN values in a floating point load+store.
- * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
- * quiet one. This is catastrophic when NaN space is used in packed
- * duk_tval values. See: misc/clang_aliasing.c.
- */
-
-#ifndef DUK_DBLUNION_H_INCLUDED
-#define DUK_DBLUNION_H_INCLUDED
-
-/*
- * Union for accessing double parts, also serves as packed duk_tval
- */
-
-union duk_double_union {
- double d;
- float f[2];
-#if defined(DUK_USE_64BIT_OPS)
- duk_uint64_t ull[1];
-#endif
- duk_uint32_t ui[2];
- duk_uint16_t us[4];
- duk_uint8_t uc[8];
-#if defined(DUK_USE_PACKED_TVAL)
- void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
-#endif
-};
-
-typedef union duk_double_union duk_double_union;
-
-/*
- * Indexes of various types with respect to big endian (logical) layout
- */
-
-#if defined(DUK_USE_DOUBLE_LE)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0
-#endif
-#define DUK_DBL_IDX_UI0 1
-#define DUK_DBL_IDX_UI1 0
-#define DUK_DBL_IDX_US0 3
-#define DUK_DBL_IDX_US1 2
-#define DUK_DBL_IDX_US2 1
-#define DUK_DBL_IDX_US3 0
-#define DUK_DBL_IDX_UC0 7
-#define DUK_DBL_IDX_UC1 6
-#define DUK_DBL_IDX_UC2 5
-#define DUK_DBL_IDX_UC3 4
-#define DUK_DBL_IDX_UC4 3
-#define DUK_DBL_IDX_UC5 2
-#define DUK_DBL_IDX_UC6 1
-#define DUK_DBL_IDX_UC7 0
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#elif defined(DUK_USE_DOUBLE_BE)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0
-#endif
-#define DUK_DBL_IDX_UI0 0
-#define DUK_DBL_IDX_UI1 1
-#define DUK_DBL_IDX_US0 0
-#define DUK_DBL_IDX_US1 1
-#define DUK_DBL_IDX_US2 2
-#define DUK_DBL_IDX_US3 3
-#define DUK_DBL_IDX_UC0 0
-#define DUK_DBL_IDX_UC1 1
-#define DUK_DBL_IDX_UC2 2
-#define DUK_DBL_IDX_UC3 3
-#define DUK_DBL_IDX_UC4 4
-#define DUK_DBL_IDX_UC5 5
-#define DUK_DBL_IDX_UC6 6
-#define DUK_DBL_IDX_UC7 7
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#elif defined(DUK_USE_DOUBLE_ME)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
-#endif
-#define DUK_DBL_IDX_UI0 0
-#define DUK_DBL_IDX_UI1 1
-#define DUK_DBL_IDX_US0 1
-#define DUK_DBL_IDX_US1 0
-#define DUK_DBL_IDX_US2 3
-#define DUK_DBL_IDX_US3 2
-#define DUK_DBL_IDX_UC0 3
-#define DUK_DBL_IDX_UC1 2
-#define DUK_DBL_IDX_UC2 1
-#define DUK_DBL_IDX_UC3 0
-#define DUK_DBL_IDX_UC4 7
-#define DUK_DBL_IDX_UC5 6
-#define DUK_DBL_IDX_UC6 5
-#define DUK_DBL_IDX_UC7 4
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#else
-#error internal error
-#endif
-
-/*
- * Helper macros for reading/writing memory representation parts, used
- * by duk_numconv.c and duk_tval.h.
- */
-
-#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
- (u)->d = (v); \
- } while (0)
-
-#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
- } while (0)
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
- } while (0)
-#else
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK_DBLUNION_SET_LOW32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
- } while (0)
-
-#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
-#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
-#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK_DBLUNION_SET_UINT64(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
- } while (0)
-#define DUK_DBLUNION_GET_UINT64(u) \
- ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
- ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
-#else
-#define DUK_DBLUNION_SET_UINT64(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
- } while (0)
-#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
-#endif
-#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
-#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
-#endif /* DUK_USE_64BIT_OPS */
-
-/*
- * Double NaN manipulation macros related to NaN normalization needed when
- * using the packed duk_tval representation. NaN normalization is necessary
- * to keep double values compatible with the duk_tval format.
- *
- * When packed duk_tval is used, the NaN space is used to store pointers
- * and other tagged values in addition to NaNs. Actual NaNs are normalized
- * to a specific quiet NaN. The macros below are used by the implementation
- * to check and normalize NaN values when they might be created. The macros
- * are essentially NOPs when the non-packed duk_tval representation is used.
- *
- * A FULL check is exact and checks all bits. A NOTFULL check is used by
- * the packed duk_tval and works correctly for all NaNs except those that
- * begin with 0x7ff0. Since the 'normalized NaN' values used with packed
- * duk_tval begin with 0x7ff8, the partial check is reliable when packed
- * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
- * quiet NaN regardless of its remaining lower bits.
- *
- * The ME variant below is specifically for ARM byte order, which has the
- * feature that while doubles have a mixed byte order (32107654), unsigned
- * long long values has a little endian byte order (76543210). When writing
- * a logical double value through a ULL pointer, the 32-bit words need to be
- * swapped; hence the #ifdefs below for ULL writes with DUK_USE_DOUBLE_ME.
- * This is not full ARM support but suffices for some environments.
- */
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x000000007ff80000ULL; \
- } while (0)
-#else
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
- (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
- } while (0)
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0))
-#else
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0))
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
- (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
- (u)->ui[DUK_DBL_IDX_UI1] != 0))
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
- /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL)
-#else
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
- ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
- /* E == 0x7ff, F == 8 => normalized NaN */ \
- ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
-
-#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
- if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
- DUK__DBLUNION_SET_NAN_FULL((u)); \
- } \
- } while (0)
-
-#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
- if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
- DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
- } \
- } while (0)
-
-/* Concrete macros for NaN handling used by the implementation internals.
- * Chosen so that they match the duk_tval representation: with a packed
- * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
- * these are essentially NOPs.
- */
-
-#if defined(DUK_USE_PACKED_TVAL)
-#if defined(DUK_USE_FULL_TVAL)
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
-#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
-#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
-#else
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
-#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
-#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
-#endif
-#define DUK_DBLUNION_IS_NORMALIZED(u) \
- (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
- DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
-#else /* DUK_USE_PACKED_TVAL */
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
-#define DUK_DBLUNION_IS_NAN(u) (DUK_ISNAN((u)->d))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) (DUK_ISNAN((u)->d))
-#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
-#define DUK_DBLUNION_SET_NAN(u) do { \
- /* in non-packed representation we don't care about which NaN is used */ \
- (u)->d = DUK_DOUBLE_NAN; \
- } while (0)
-#endif /* DUK_USE_PACKED_TVAL */
-
-/* XXX: native 64-bit byteswaps when available */
-
-/* 64-bit byteswap, same operation independent of target endianness. */
-#define DUK_DBLUNION_BSWAP64(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp2; \
- (u)->ui[1] = duk__bswaptmp1; \
- } while (0)
-
-/* Byteswap an IEEE double in the duk_double_union from host to network
- * order. For a big endian target this is a no-op.
- */
-#if defined(DUK_USE_DOUBLE_LE)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp2; \
- (u)->ui[1] = duk__bswaptmp1; \
- } while (0)
-#elif defined(DUK_USE_DOUBLE_ME)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp1; \
- (u)->ui[1] = duk__bswaptmp2; \
- } while (0)
-#elif defined(DUK_USE_DOUBLE_BE)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
-#else
-#error internal error, double endianness insane
-#endif
-
-/* Reverse operation is the same. */
-#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
-
-#endif /* DUK_DBLUNION_H_INCLUDED */
-
#endif /* DUKTAPE_H_INCLUDED */
diff --git a/content/handlers/text/Makefile b/content/handlers/text/Makefile
new file mode 100644
index 000000000..83d5dbd1e
--- /dev/null
+++ b/content/handlers/text/Makefile
@@ -0,0 +1,3 @@
+# text content handler sources
+
+S_TEXT := textplain.c
diff --git a/render/textplain.c b/content/handlers/text/textplain.c
index ae148697e..af990d1d7 100644
--- a/render/textplain.c
+++ b/content/handlers/text/textplain.c
@@ -17,8 +17,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for text/plain (implementation).
+/**
+ * \file
+ *
+ * plain text content handling implementation.
*/
#include <assert.h>
@@ -50,10 +52,8 @@
#include "desktop/selection.h"
#include "desktop/gui_internal.h"
-#include "render/search.h"
-#include "render/textplain.h"
-#include "render/html.h"
-#include "render/search.h"
+#include "html/search.h"
+#include "text/textplain.h"
struct textplain_line {
size_t start;
@@ -85,9 +85,8 @@ typedef struct textplain_content {
#define CHUNK 32768 /* Must be a power of 2 */
#define MARGIN 4
-
#define TAB_WIDTH 8 /* must be power of 2 currently */
-#define TEXT_SIZE 10 * FONT_SIZE_SCALE /* Unscaled text size in pt */
+#define TEXT_SIZE 10 * PLOT_STYLE_SCALE /* Unscaled text size in pt */
static plot_font_style_t textplain_style = {
.family = PLOT_FONT_FAMILY_MONOSPACE,
@@ -100,129 +99,125 @@ static plot_font_style_t textplain_style = {
static int textplain_tab_width = 256; /* try for a sensible default */
-static void textplain_fini(void);
-static nserror textplain_create(const content_handler *handler,
- lwc_string *imime_type, const http_parameter *params,
- llcache_handle *llcache, const char *fallback_charset,
- bool quirks, struct content **c);
-static nserror textplain_create_internal(textplain_content *c,
- lwc_string *charset);
-static bool textplain_process_data(struct content *c,
- const char *data, unsigned int size);
-static bool textplain_convert(struct content *c);
-static void textplain_mouse_track(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
-static void textplain_mouse_action(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
-static bool textplain_keypress(struct content *c, uint32_t key);
-static void textplain_search(struct content *c, void *gui_data,
- search_flags_t flags, const char *string);
-static void textplain_search_clear(struct content *c);
-static void textplain_reformat(struct content *c, int width, int height);
-static void textplain_destroy(struct content *c);
-static bool textplain_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx);
-static void textplain_open(struct content *c, struct browser_window *bw,
- struct content *page, struct object_params *params);
-void textplain_close(struct content *c);
-char *textplain_get_selection(struct content *c);
-static nserror textplain_clone(const struct content *old,
- struct content **newc);
-static content_type textplain_content_type(void);
-
-static parserutils_error textplain_charset_hack(const uint8_t *data, size_t len,
- uint16_t *mibenum, uint32_t *source);
-static bool textplain_drain_input(textplain_content *c,
- parserutils_inputstream *stream, parserutils_error terminator);
-static bool textplain_copy_utf8_data(textplain_content *c,
- const uint8_t *buf, size_t len);
-static int textplain_coord_from_offset(const char *text, size_t offset,
- size_t length);
-static float textplain_line_height(void);
-
-static const content_handler textplain_content_handler = {
- .fini = textplain_fini,
- .create = textplain_create,
- .process_data = textplain_process_data,
- .data_complete = textplain_convert,
- .reformat = textplain_reformat,
- .destroy = textplain_destroy,
- .mouse_track = textplain_mouse_track,
- .mouse_action = textplain_mouse_action,
- .keypress = textplain_keypress,
- .search = textplain_search,
- .search_clear = textplain_search_clear,
- .redraw = textplain_redraw,
- .open = textplain_open,
- .close = textplain_close,
- .get_selection = textplain_get_selection,
- .clone = textplain_clone,
- .type = textplain_content_type,
- .no_share = true,
-};
-
static lwc_string *textplain_default_charset;
+
/**
- * Initialise the text content handler
+ * Clean up after the text content handler
*/
-nserror textplain_init(void)
+static void textplain_fini(void)
{
- lwc_error lerror;
- nserror error;
-
- lerror = lwc_intern_string("Windows-1252", SLEN("Windows-1252"),
- &textplain_default_charset);
- if (lerror != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- error = content_factory_register_handler("text/plain",
- &textplain_content_handler);
- if (error != NSERROR_OK) {
+ if (textplain_default_charset != NULL) {
lwc_string_unref(textplain_default_charset);
+ textplain_default_charset = NULL;
}
+}
- return error;
+
+/**
+ * Work around feature in libparserutils
+ *
+ * if the client provides an encoding up front, but does not provide a
+ * charset detection callback, then libparserutils will replace the
+ * provided encoding with UTF-8. This breaks our input handling.
+ *
+ * Avoid this by providing a callback that does precisely nothing,
+ * thus preserving whatever charset information we decided on in
+ * textplain_create.
+ */
+static parserutils_error
+textplain_charset_hack(const uint8_t *data,
+ size_t len,
+ uint16_t *mibenum,
+ uint32_t *source)
+{
+ return PARSERUTILS_OK;
}
+
/**
- * Clean up after the text content handler
+ * setup plain text render.
+ *
+ * \param[in] c content object.
+ * \param[in] encoding the encoding of the content.
+ * \return NSERROR_OK else appropriate error code.
*/
-void textplain_fini(void)
+static nserror
+textplain_create_internal(textplain_content *c, lwc_string *encoding)
{
- if (textplain_default_charset != NULL) {
- lwc_string_unref(textplain_default_charset);
- textplain_default_charset = NULL;
+ char *utf8_data;
+ parserutils_inputstream *stream;
+ parserutils_error error;
+
+ textplain_style.size = (nsoption_int(font_size) * PLOT_STYLE_SCALE) / 10;
+
+ utf8_data = malloc(CHUNK);
+ if (utf8_data == NULL)
+ goto no_memory;
+
+ error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
+ textplain_charset_hack, &stream);
+ if (error == PARSERUTILS_BADENCODING) {
+ /* Fall back to Windows-1252 */
+ error = parserutils_inputstream_create("Windows-1252", 0,
+ textplain_charset_hack, &stream);
}
+ if (error != PARSERUTILS_OK) {
+ free(utf8_data);
+ goto no_memory;
+ }
+
+ c->encoding = lwc_string_ref(encoding);
+ c->inputstream = stream;
+ c->utf8_data = utf8_data;
+ c->utf8_data_size = 0;
+ c->utf8_data_allocated = CHUNK;
+ c->physical_line = 0;
+ c->physical_line_count = 0;
+ c->formatted_width = 0;
+ c->bw = NULL;
+
+ selection_prepare(&c->sel, (struct content *)c, false);
+
+ return NSERROR_OK;
+
+no_memory:
+ content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
+
+ return NSERROR_NOMEM;
}
+
/**
* Create a CONTENT_TEXTPLAIN.
*/
-
-nserror textplain_create(const content_handler *handler,
- lwc_string *imime_type, const http_parameter *params,
- llcache_handle *llcache, const char *fallback_charset,
- bool quirks, struct content **c)
+static nserror
+textplain_create(const content_handler *handler,
+ lwc_string *imime_type,
+ const http_parameter *params,
+ llcache_handle *llcache,
+ const char *fallback_charset,
+ bool quirks,
+ struct content **c)
{
textplain_content *text;
nserror error;
lwc_string *encoding;
text = calloc(1, sizeof(textplain_content));
- if (text == NULL)
+ if (text == NULL) {
return NSERROR_NOMEM;
+ }
error = content__init(&text->base, handler, imime_type, params,
- llcache, fallback_charset, quirks);
+ llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(text);
return error;
}
error = http_parameter_list_find_item(params, corestring_lwc_charset,
- &encoding);
+ &encoding);
if (error != NSERROR_OK) {
encoding = lwc_string_ref(textplain_default_charset);
}
@@ -241,86 +236,57 @@ nserror textplain_create(const content_handler *handler,
return NSERROR_OK;
}
-/*
- * Hack around bug in libparserutils: if the client provides an
- * encoding up front, but does not provide a charset detection
- * callback, then libparserutils will replace the provided encoding
- * with UTF-8. This breaks our input handling.
- *
- * We avoid this by providing a callback that does precisely nothing,
- * thus preserving whatever charset information we decided on in
- * textplain_create.
- */
-parserutils_error textplain_charset_hack(const uint8_t *data, size_t len,
- uint16_t *mibenum, uint32_t *source)
-{
- return PARSERUTILS_OK;
-}
-nserror textplain_create_internal(textplain_content *c, lwc_string *encoding)
+/**
+ * copy utf8 encoded data
+ */
+static bool
+textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
{
- char *utf8_data;
- parserutils_inputstream *stream;
- parserutils_error error;
- union content_msg_data msg_data;
-
- textplain_style.size = (nsoption_int(font_size) * FONT_SIZE_SCALE) / 10;
+ if (c->utf8_data_size + len >= c->utf8_data_allocated) {
+ /* Compute next multiple of chunk above the required space */
+ size_t allocated;
+ char *utf8_data;
- utf8_data = malloc(CHUNK);
- if (utf8_data == NULL)
- goto no_memory;
+ allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
+ utf8_data = realloc(c->utf8_data, allocated);
+ if (utf8_data == NULL)
+ return false;
- error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
- textplain_charset_hack, &stream);
- if (error == PARSERUTILS_BADENCODING) {
- /* Fall back to Windows-1252 */
- error = parserutils_inputstream_create("Windows-1252", 0,
- textplain_charset_hack, &stream);
- }
- if (error != PARSERUTILS_OK) {
- free(utf8_data);
- goto no_memory;
+ c->utf8_data = utf8_data;
+ c->utf8_data_allocated = allocated;
}
-
- c->encoding = lwc_string_ref(encoding);
- c->inputstream = stream;
- c->utf8_data = utf8_data;
- c->utf8_data_size = 0;
- c->utf8_data_allocated = CHUNK;
- c->physical_line = 0;
- c->physical_line_count = 0;
- c->formatted_width = 0;
- c->bw = NULL;
- selection_prepare(&c->sel, (struct content *)c, false);
-
- return NSERROR_OK;
+ memcpy(c->utf8_data + c->utf8_data_size, buf, len);
+ c->utf8_data_size += len;
-no_memory:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
- return NSERROR_NOMEM;
+ return true;
}
-bool textplain_drain_input(textplain_content *c,
- parserutils_inputstream *stream,
- parserutils_error terminator)
+
+/**
+ * drain input
+ */
+static bool
+textplain_drain_input(textplain_content *c,
+ parserutils_inputstream *stream,
+ parserutils_error terminator)
{
static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xfd";
const uint8_t *ch;
size_t chlen, offset = 0;
- while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
- terminator) {
+ while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
+ terminator) {
/* Replace all instances of NUL with U+FFFD */
if (chlen == 1 && *ch == 0) {
if (offset > 0) {
/* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0,
- &ch, &chlen);
+ parserutils_inputstream_peek(stream, 0,
+ &ch, &chlen);
/* Copy from it up to the start of the NUL */
- if (textplain_copy_utf8_data(c, ch,
- offset) == false)
+ if (textplain_copy_utf8_data(c, ch,
+ offset) == false)
return false;
}
@@ -338,12 +304,12 @@ bool textplain_drain_input(textplain_content *c,
if (offset > CHUNK) {
/* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0,
- &ch, &chlen);
+ parserutils_inputstream_peek(stream, 0,
+ &ch, &chlen);
/* Emit the data we've read */
- if (textplain_copy_utf8_data(c, ch,
- offset) == false)
+ if (textplain_copy_utf8_data(c, ch,
+ offset) == false)
return false;
/* Advance the inputstream */
@@ -356,7 +322,7 @@ bool textplain_drain_input(textplain_content *c,
if (offset > 0) {
/* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0, &ch, &chlen);
+ parserutils_inputstream_peek(stream, 0, &ch, &chlen);
/* Emit any data remaining */
if (textplain_copy_utf8_data(c, ch, offset) == false)
return false;
@@ -368,44 +334,19 @@ bool textplain_drain_input(textplain_content *c,
return true;
}
-bool textplain_copy_utf8_data(textplain_content *c,
- const uint8_t *buf, size_t len)
-{
- if (c->utf8_data_size + len >= c->utf8_data_allocated) {
- /* Compute next multiple of chunk above the required space */
- size_t allocated;
- char *utf8_data;
-
- allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
- utf8_data = realloc(c->utf8_data, allocated);
- if (utf8_data == NULL)
- return false;
-
- c->utf8_data = utf8_data;
- c->utf8_data_allocated = allocated;
- }
-
- memcpy(c->utf8_data + c->utf8_data_size, buf, len);
- c->utf8_data_size += len;
-
- return true;
-}
-
/**
* Process data for CONTENT_TEXTPLAIN.
*/
-
-bool textplain_process_data(struct content *c,
- const char *data, unsigned int size)
+static bool
+textplain_process_data(struct content *c, const char *data, unsigned int size)
{
textplain_content *text = (textplain_content *) c;
parserutils_inputstream *stream = text->inputstream;
- union content_msg_data msg_data;
parserutils_error error;
- error = parserutils_inputstream_append(stream,
- (const uint8_t *) data, size);
+ error = parserutils_inputstream_append(stream,
+ (const uint8_t *) data, size);
if (error != PARSERUTILS_OK) {
goto no_memory;
}
@@ -416,8 +357,7 @@ bool textplain_process_data(struct content *c,
return true;
no_memory:
- msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast_errorcode(c, NSERROR_NOMEM);
return false;
}
@@ -425,8 +365,7 @@ no_memory:
/**
* Convert a CONTENT_TEXTPLAIN for display.
*/
-
-bool textplain_convert(struct content *c)
+static bool textplain_convert(struct content *c)
{
textplain_content *text = (textplain_content *) c;
parserutils_inputstream *stream = text->inputstream;
@@ -452,10 +391,23 @@ bool textplain_convert(struct content *c)
/**
- * Reformat a CONTENT_TEXTPLAIN to a new width.
+ * Calculate the line height, in pixels
+ *
+ * \return Line height, in pixels
*/
+static float textplain_line_height(void)
+{
+ /* Size is in points, so convert to pixels.
+ * Then use a constant line height of 1.2 x font size.
+ */
+ return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, INTTOFIX((textplain_style.size / PLOT_STYLE_SCALE))))), F_72));
+}
+
-void textplain_reformat(struct content *c, int width, int height)
+/**
+ * Reformat a CONTENT_TEXTPLAIN to a new width.
+ */
+static void textplain_reformat(struct content *c, int width, int height)
{
textplain_content *text = (textplain_content *) c;
char *utf8_data = text->utf8_data;
@@ -469,7 +421,7 @@ void textplain_reformat(struct content *c, int width, int height)
size_t line_start;
nserror res;
- LOG("content %p w:%d h:%d", c, width, height);
+ NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height);
/* compute available columns (assuming monospaced font) - use 8
* characters for better accuracy
@@ -521,23 +473,25 @@ void textplain_reformat(struct content *c, int width, int height)
if (term || next_col >= columns) {
if (line_count % 1024 == 0) {
- line1 = realloc(line,
- sizeof(struct textplain_line) *
+ line1 = realloc(line,
+ sizeof(struct textplain_line) *
(line_count + 1024 + 3));
if (!line1)
goto no_memory;
text->physical_line = line = line1;
}
+
if (term) {
line[line_count-1].length = i - line_start;
/* skip second char of CR/LF or LF/CR pair */
if (i + 1 < utf8_data_size &&
- utf8_data[i+1] != utf8_data[i] &&
- (utf8_data[i+1] == '\n' || utf8_data[i+1] == '\r'))
+ utf8_data[i+1] != utf8_data[i] &&
+ (utf8_data[i+1] == '\n' ||
+ utf8_data[i+1] == '\r')) {
i++;
- }
- else {
+ }
+ } else {
if (space) {
/* break at last space in line */
i = space;
@@ -545,6 +499,7 @@ void textplain_reformat(struct content *c, int width, int height)
} else
line[line_count-1].length = i - line_start;
}
+
line[line_count++].start = line_start = i + 1;
col = 0;
space = 0;
@@ -565,7 +520,7 @@ void textplain_reformat(struct content *c, int width, int height)
return;
no_memory:
- LOG("out of memory (line_count %lu)", line_count);
+ NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count);
return;
}
@@ -574,7 +529,7 @@ no_memory:
* Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
*/
-void textplain_destroy(struct content *c)
+static void textplain_destroy(struct content *c)
{
textplain_content *text = (textplain_content *) c;
@@ -594,7 +549,7 @@ void textplain_destroy(struct content *c)
}
-nserror textplain_clone(const struct content *old, struct content **newc)
+static nserror textplain_clone(const struct content *old, struct content **newc)
{
const textplain_content *old_text = (textplain_content *) old;
textplain_content *text;
@@ -628,7 +583,7 @@ nserror textplain_clone(const struct content *old, struct content **newc)
}
if (old->status == CONTENT_STATUS_READY ||
- old->status == CONTENT_STATUS_DONE) {
+ old->status == CONTENT_STATUS_DONE) {
if (textplain_convert(&text->base) == false) {
content_destroy(&text->base);
return NSERROR_CLONE_FAILED;
@@ -638,71 +593,27 @@ nserror textplain_clone(const struct content *old, struct content **newc)
return NSERROR_OK;
}
-content_type textplain_content_type(void)
-{
- return CONTENT_TEXTPLAIN;
-}
-/**
- * Handle mouse tracking (including drags) in a TEXTPLAIN content window.
- *
- * \param c content of type textplain
- * \param bw browser window
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-
-void textplain_mouse_track(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y)
+static content_type textplain_content_type(void)
{
- textplain_content *text = (textplain_content *) c;
-
- if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) {
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&text->sel))
- dir = 1;
-
- idx = textplain_offset_from_coords(c, x, y, dir);
- selection_track(&text->sel, mouse, idx);
-
- browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
- }
-
- switch (browser_window_get_drag_type(bw)) {
-
- case DRAGGING_SELECTION: {
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&text->sel)) dir = 1;
-
- idx = textplain_offset_from_coords(c, x, y, dir);
- selection_track(&text->sel, mouse, idx);
- }
- break;
-
- default:
- textplain_mouse_action(c, bw, mouse, x, y);
- break;
- }
+ return CONTENT_TEXTPLAIN;
}
/**
* Handle mouse clicks and movements in a TEXTPLAIN content window.
*
- * \param c content of type textplain
- * \param bw browser window
- * \param mouse mouse state on action
- * \param x coordinate of mouse
- * \param y coordinate of mouse
+ * \param c content of type textplain
+ * \param bw browser window
+ * \param mouse mouse state on action
+ * \param x coordinate of mouse
+ * \param y coordinate of mouse
*/
-
-void textplain_mouse_action(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y)
+static void
+textplain_mouse_action(struct content *c,
+ struct browser_window *bw,
+ browser_mouse_state mouse,
+ int x, int y)
{
textplain_content *text = (textplain_content *) c;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
@@ -718,7 +629,7 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw,
if (selection_dragging(&text->sel)) {
browser_window_set_drag_type(bw,
- DRAGGING_SELECTION, NULL);
+ DRAGGING_SELECTION, NULL);
status = messages_get("Selecting");
}
@@ -730,10 +641,60 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw,
}
msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
+ content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
msg_data.pointer = pointer;
- content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
+ content_broadcast(c, CONTENT_MSG_POINTER, &msg_data);
+}
+
+
+/**
+ * Handle mouse tracking (including drags) in a TEXTPLAIN content window.
+ *
+ * \param c content of type textplain
+ * \param bw browser window
+ * \param mouse state of mouse buttons and modifier keys
+ * \param x coordinate of mouse
+ * \param y coordinate of mouse
+ */
+static void
+textplain_mouse_track(struct content *c,
+ struct browser_window *bw,
+ browser_mouse_state mouse,
+ int x, int y)
+{
+ textplain_content *text = (textplain_content *) c;
+
+ if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) {
+ int dir = -1;
+ size_t idx;
+
+ if (selection_dragging_start(&text->sel))
+ dir = 1;
+
+ idx = textplain_offset_from_coords(c, x, y, dir);
+ selection_track(&text->sel, mouse, idx);
+
+ browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
+ }
+
+ switch (browser_window_get_drag_type(bw)) {
+
+ case DRAGGING_SELECTION: {
+ int dir = -1;
+ size_t idx;
+
+ if (selection_dragging_start(&text->sel)) dir = 1;
+
+ idx = textplain_offset_from_coords(c, x, y, dir);
+ selection_track(&text->sel, mouse, idx);
+ }
+ break;
+
+ default:
+ textplain_mouse_action(c, bw, mouse, x, y);
+ break;
+ }
}
@@ -744,8 +705,7 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw,
* \param key The UCS4 character codepoint
* \return true if key handled, false otherwise
*/
-
-bool textplain_keypress(struct content *c, uint32_t key)
+static bool textplain_keypress(struct content *c, uint32_t key)
{
textplain_content *text = (textplain_content *) c;
struct selection *sel = &text->sel;
@@ -778,6 +738,27 @@ bool textplain_keypress(struct content *c, uint32_t key)
/**
+ * Terminate a search.
+ *
+ * \param c content of type text
+ */
+static void textplain_search_clear(struct content *c)
+{
+ textplain_content *text = (textplain_content *) c;
+
+ assert(c != NULL);
+
+ free(text->search_string);
+ text->search_string = NULL;
+
+ if (text->search != NULL) {
+ search_destroy_context(text->search);
+ }
+ text->search = NULL;
+}
+
+
+/**
* Handle search.
*
* \param c content of type text
@@ -785,16 +766,16 @@ bool textplain_keypress(struct content *c, uint32_t key)
* \param flags search flags
* \param string search string
*/
-void textplain_search(struct content *c, void *gui_data,
- search_flags_t flags, const char *string)
+static void textplain_search(struct content *c, void *gui_data,
+ search_flags_t flags, const char *string)
{
textplain_content *text = (textplain_content *) c;
assert(c != NULL);
if (string != NULL && text->search_string != NULL &&
- strcmp(string, text->search_string) == 0 &&
- text->search != NULL) {
+ strcmp(string, text->search_string) == 0 &&
+ text->search != NULL) {
/* Continue prev. search */
search_step(text->search, flags, string);
@@ -811,7 +792,7 @@ void textplain_search(struct content *c, void *gui_data,
}
text->search = search_create_context(c, CONTENT_TEXTPLAIN,
- gui_data);
+ gui_data);
if (text->search == NULL)
return;
@@ -829,43 +810,241 @@ void textplain_search(struct content *c, void *gui_data,
/**
- * Terminate a search.
+ * Redraw a text string with highlighting
+ * (for selection/search)
*
- * \param c content of type text
+ * \param utf8_text pointer to UTF-8 text string
+ * \param utf8_len length of string, in bytes
+ * \param offset byte offset within textual representation
+ * \param x x ordinate at which to plot text
+ * \param y y ordinate at which to plot text
+ * \param clip pointer to current clip rectangle
+ * \param height height of text string
+ * \param scale current display scale (1.0 = 100%)
+ * \param text Content being redrawn.
+ * \param sel Selection context
+ * \param search Search context
+ * \param ctx current redraw context
+ * \return true iff successful and redraw should proceed
*/
-void textplain_search_clear(struct content *c)
+static bool
+text_draw(const char *utf8_text,
+ size_t utf8_len,
+ size_t offset,
+ int x,
+ int y,
+ const struct rect *clip,
+ int height,
+ float scale,
+ textplain_content *text,
+ const struct selection *sel,
+ struct search_context *search,
+ const struct redraw_context *ctx)
{
- textplain_content *text = (textplain_content *) c;
+ bool highlighted = false;
+ plot_font_style_t plot_fstyle;
+ nserror res;
- assert(c != NULL);
+ /* Need scaled text size to pass to plotters */
+ plot_fstyle = textplain_style;
+ plot_fstyle.size *= scale;
+
+ /* is this box part of a selection? */
+ if (ctx->interactive == true) {
+ unsigned len = utf8_len;
+ unsigned start_idx;
+ unsigned end_idx;
+
+ /* first try the browser window's current selection */
+ if (selection_defined(sel) &&
+ selection_highlighted(sel,
+ offset,
+ offset + len,
+ &start_idx,
+ &end_idx)) {
+ highlighted = true;
+ }
- free(text->search_string);
- text->search_string = NULL;
+ /* what about the current search operation, if any? */
+ if (!highlighted &&
+ (search != NULL) &&
+ search_term_highlighted((struct content *)text,
+ offset,
+ offset + len,
+ &start_idx,
+ &end_idx,
+ search)) {
+ highlighted = true;
+ }
- if (text->search != NULL)
- search_destroy_context(text->search);
- text->search = NULL;
+ /* \todo make search terms visible within selected text */
+ if (highlighted) {
+ struct rect r;
+ unsigned endtxt_idx = end_idx;
+ bool clip_changed = false;
+ bool text_visible = true;
+ int startx, endx;
+ plot_style_t pstyle_fill_hback = *plot_style_fill_white;
+ plot_font_style_t fstyle_hback = plot_fstyle;
+
+ if (end_idx > utf8_len) {
+ /* adjust for trailing space, not present in
+ * utf8_text
+ */
+ assert(end_idx == utf8_len + 1);
+ endtxt_idx = utf8_len;
+ }
+
+ res = guit->layout->width(&textplain_style,
+ utf8_text,
+ start_idx,
+ &startx);
+ if (res != NSERROR_OK) {
+ startx = 0;
+ }
+
+ res = guit->layout->width(&textplain_style,
+ utf8_text,
+ endtxt_idx,
+ &endx);
+ if (res != NSERROR_OK) {
+ endx = 0;
+ }
+
+ if (scale != 1.0) {
+ startx *= scale;
+ endx *= scale;
+ }
+
+ /* draw any text preceding highlighted portion */
+ if (start_idx > 0) {
+ res = ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ start_idx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ pstyle_fill_hback.fill_colour = textplain_style.foreground;
+
+ /* highlighted portion */
+ r.x0 = x + startx;
+ r.y0 = y;
+ r.x1 = x + endx;
+ r.y1 = y + height * scale;
+ res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ if (start_idx > 0) {
+ int px0 = max(x + startx, clip->x0);
+ int px1 = min(x + endx, clip->x1);
+
+ if (px0 < px1) {
+ r.x0 = px0;
+ r.y0 = clip->y0;
+ r.x1 = px1;
+ r.y1 = clip->y1;
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ clip_changed = true;
+ } else {
+ text_visible = false;
+ }
+ }
+
+ fstyle_hback.background =
+ pstyle_fill_hback.fill_colour;
+ fstyle_hback.foreground = colour_to_bw_furthest(
+ pstyle_fill_hback.fill_colour);
+
+ if (text_visible &&
+ (ctx->plot->text(ctx,
+ &fstyle_hback,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ endtxt_idx) != NSERROR_OK)) {
+ return false;
+ }
+
+ /* draw any text succeeding highlighted portion */
+ if (endtxt_idx < utf8_len) {
+ int px0 = max(x + endx, clip->x0);
+ if (px0 < clip->x1) {
+
+ r.x0 = px0;
+ r.y0 = clip->y0;
+ r.x1 = clip->x1;
+ r.y1 = clip->y1;
+ res = ctx->plot->clip(ctx, &r);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+
+ clip_changed = true;
+
+ res = ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int)(height * 0.75 * scale),
+ utf8_text,
+ utf8_len);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+ }
+
+ if (clip_changed &&
+ (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
+ return false;
+ }
+ }
+ }
+
+ if (!highlighted) {
+ res = ctx->plot->text(ctx,
+ &plot_fstyle,
+ x,
+ y + (int) (height * 0.75 * scale),
+ utf8_text,
+ utf8_len);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+ return true;
}
/**
* Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
*
+ * x, y, clip_[xy][01] are in target coordinates.
+ *
* \param c content of type CONTENT_TEXTPLAIN
* \param data redraw data for this content redraw
* \param clip current clip region
* \param ctx current redraw context
* \return true if successful, false otherwise
- *
- * x, y, clip_[xy][01] are in target coordinates.
*/
-
-bool textplain_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx)
+static bool
+textplain_redraw(struct content *c,
+ struct content_redraw_data *data,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
{
textplain_content *text = (textplain_content *) c;
struct browser_window *bw = text->bw;
- const struct plotter_table *plot = ctx->plot;
char *utf8_data = text->utf8_data;
long lineno;
int x = data->x;
@@ -878,6 +1057,7 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
struct textplain_line *line = text->physical_line;
size_t length;
plot_style_t *plot_style_highlight;
+ nserror res;
if (line0 < 0)
line0 = 0;
@@ -890,9 +1070,10 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
if (line1 < line0)
line1 = line0;
- if (!plot->rectangle(clip->x0, clip->y0, clip->x1, clip->y1,
- plot_style_fill_white))
+ res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip);
+ if (res != NSERROR_OK) {
return false;
+ }
if (!line)
return true;
@@ -926,24 +1107,34 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
int ntx;
nserror res;
- while (next_offset < length && text_d[next_offset] != '\t')
- next_offset = utf8_next(text_d, length, next_offset);
+ while ((next_offset < length) &&
+ (text_d[next_offset] != '\t')) {
+ next_offset = utf8_next(text_d,
+ length,
+ next_offset);
+ }
- if (!text_redraw(text_d + offset, next_offset - offset,
- line[lineno].start + offset, 0,
- &textplain_style,
- tx, y + (lineno * scaled_line_height),
- clip, line_height, data->scale, false,
- (struct content *)text, &text->sel,
- text->search, ctx))
+ if (!text_draw(text_d + offset,
+ next_offset - offset,
+ line[lineno].start + offset,
+ tx,
+ y + (lineno * scaled_line_height),
+ clip,
+ line_height,
+ data->scale,
+ text,
+ &text->sel,
+ text->search,
+ ctx)) {
return false;
+ }
if (next_offset >= length)
break;
res = guit->layout->width(&textplain_style,
- &text_d[offset],
- next_offset - offset,
+ &text_d[offset],
+ next_offset - offset,
&width);
/* locate end of string and align to next tab position */
if (res == NSERROR_OK) {
@@ -952,9 +1143,11 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
ntx = x + ((1 + (tx - x) / tab_width) * tab_width);
- /* if the tab character lies within the selection, if any,
- then we must draw it as a filled rectangle so that it's
- consistent with background of the selected text */
+ /* if the tab character lies within the
+ * selection, if any, then we must draw it as
+ * a filled rectangle so that it's consistent
+ * with background of the selected text
+ */
if (bw) {
unsigned tab_ofst = line[lineno].start + next_offset;
@@ -964,26 +1157,36 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
if (selection_defined(sel)) {
unsigned start_idx, end_idx;
if (selection_highlighted(sel,
- tab_ofst, tab_ofst + 1,
- &start_idx, &end_idx))
+ tab_ofst,
+ tab_ofst + 1,
+ &start_idx,
+ &end_idx))
highlighted = true;
}
if (!highlighted && (text->search != NULL)) {
unsigned start_idx, end_idx;
if (search_term_highlighted(c,
- tab_ofst, tab_ofst + 1,
- &start_idx, &end_idx,
- text->search))
+ tab_ofst,
+ tab_ofst + 1,
+ &start_idx,
+ &end_idx,
+ text->search))
highlighted = true;
}
if (highlighted) {
- int sy = y + (lineno * scaled_line_height);
- if (!plot->rectangle(tx, sy,
- ntx, sy + scaled_line_height,
- plot_style_highlight))
+ struct rect rect;
+ rect.x0 = tx;
+ rect.y0 = y + (lineno * scaled_line_height);
+ rect.x1 = ntx;
+ rect.y1 = rect.y0 + scaled_line_height;
+ res = ctx->plot->rectangle(ctx,
+ plot_style_highlight,
+ &rect);
+ if (res != NSERROR_OK) {
return false;
+ }
}
}
@@ -999,29 +1202,31 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data,
/**
* Handle a window containing a CONTENT_TEXTPLAIN being opened.
*/
-
-void textplain_open(struct content *c, struct browser_window *bw,
- struct content *page, struct object_params *params)
+static void
+textplain_open(struct content *c,
+ struct browser_window *bw,
+ struct content *page,
+ struct object_params *params)
{
textplain_content *text = (textplain_content *) c;
text->bw = bw;
/* text selection */
- selection_init(&text->sel, NULL);
+ selection_init(&text->sel, NULL, NULL);
}
/**
* Handle a window containing a CONTENT_TEXTPLAIN being closed.
*/
-
-void textplain_close(struct content *c)
+static void textplain_close(struct content *c)
{
textplain_content *text = (textplain_content *) c;
- if (text->search != NULL)
+ if (text->search != NULL) {
search_destroy_context(text->search);
+ }
text->bw = NULL;
}
@@ -1030,20 +1235,107 @@ void textplain_close(struct content *c)
/**
* Return an textplain content's selection context
*/
-
-char *textplain_get_selection(struct content *c)
+static char *textplain_get_selection(struct content *c)
{
textplain_content *text = (textplain_content *) c;
return selection_get_copy(&text->sel);
}
+
/**
- * Retrieve number of lines in content
+ * Convert a character offset within a line of text into the
+ * horizontal co-ordinate
+ *
+ * The conversion takes into account the font being used and any tabs
+ * in the text
*
- * \param c Content to retrieve line count from
- * \return Number of lines
+ * \param text line of text
+ * \param offset char offset within text
+ * \param length line length
+ * \return x ordinate
*/
+static int
+textplain_coord_from_offset(const char *text, size_t offset, size_t length)
+{
+ int x = 0;
+
+ while (offset > 0) {
+ size_t next_offset = 0;
+ int tx;
+
+ while (next_offset < offset && text[next_offset] != '\t') {
+ next_offset = utf8_next(text, length, next_offset);
+ }
+
+ guit->layout->width(&textplain_style, text, next_offset, &tx);
+
+ x += tx;
+
+ if (next_offset >= offset)
+ break;
+
+ /* align to next tab boundary */
+ next_offset++;
+ x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
+ offset -= next_offset;
+ text += next_offset;
+ length -= next_offset;
+ }
+
+ return x;
+}
+
+
+/**
+ * plain text content handler table
+ */
+static const content_handler textplain_content_handler = {
+ .fini = textplain_fini,
+ .create = textplain_create,
+ .process_data = textplain_process_data,
+ .data_complete = textplain_convert,
+ .reformat = textplain_reformat,
+ .destroy = textplain_destroy,
+ .mouse_track = textplain_mouse_track,
+ .mouse_action = textplain_mouse_action,
+ .keypress = textplain_keypress,
+ .search = textplain_search,
+ .search_clear = textplain_search_clear,
+ .redraw = textplain_redraw,
+ .open = textplain_open,
+ .close = textplain_close,
+ .get_selection = textplain_get_selection,
+ .clone = textplain_clone,
+ .type = textplain_content_type,
+ .no_share = true,
+};
+
+
+/* exported interface documented in html/textplain.h */
+nserror textplain_init(void)
+{
+ lwc_error lerror;
+ nserror error;
+
+ lerror = lwc_intern_string("Windows-1252",
+ SLEN("Windows-1252"),
+ &textplain_default_charset);
+ if (lerror != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+
+ error = content_factory_register_handler("text/plain",
+ &textplain_content_handler);
+ if (error != NSERROR_OK) {
+ lwc_string_unref(textplain_default_charset);
+ }
+
+ return error;
+}
+
+
+/* exported interface documented in html/textplain.h */
unsigned long textplain_line_count(struct content *c)
{
textplain_content *text = (textplain_content *) c;
@@ -1053,12 +1345,8 @@ unsigned long textplain_line_count(struct content *c)
return text->physical_line_count;
}
-/**
- * Retrieve the size (in bytes) of text data
- *
- * \param c Content to retrieve size of
- * \return Size, in bytes, of data
- */
+
+/* exported interface documented in html/textplain.h */
size_t textplain_size(struct content *c)
{
textplain_content *text = (textplain_content *) c;
@@ -1068,21 +1356,8 @@ size_t textplain_size(struct content *c)
return text->utf8_data_size;
}
-/**
-
- * Return byte offset within UTF8 textplain content.
- *
- * given the co-ordinates of a point within a textplain content. 'dir'
- * specifies the direction in which to search (-1 = above-left, +1 =
- * below-right) if the co-ordinates are not contained within a line.
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param x x ordinate of point
- * \param y y ordinate of point
- * \param dir direction of search if not within line
- * \return byte offset of character containing (or nearest to) point
- */
+/* exported interface documented in html/textplain.h */
size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
{
textplain_content *textc = (textplain_content *) c;
@@ -1115,8 +1390,9 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
size_t next_offset = 0;
int width = INT_MAX;
- while (next_offset < length && text[next_offset] != '\t')
+ while (next_offset < length && text[next_offset] != '\t') {
next_offset = utf8_next(text, length, next_offset);
+ }
if (next_offset < length) {
guit->layout->width(&textplain_style,
@@ -1156,94 +1432,12 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
}
-/**
- * Given a byte offset within the text, return the line number
- * of the line containing that offset (or -1 if offset invalid)
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param offset byte offset within textual representation
- * \return line number, or -1 if offset invalid (larger than size)
- */
-
-int textplain_find_line(struct content *c, unsigned offset)
-{
- textplain_content *text = (textplain_content *) c;
- struct textplain_line *line;
- int nlines;
- int lineno = 0;
-
- assert(c != NULL);
-
- line = text->physical_line;
- nlines = text->physical_line_count;
-
- if (offset > text->utf8_data_size)
- return -1;
-
-/* \todo - implement binary search here */
- while (lineno < nlines && line[lineno].start < offset)
- lineno++;
- if (line[lineno].start > offset)
- lineno--;
-
- return lineno;
-}
-
-
-/**
- * Convert a character offset within a line of text into the
- * horizontal co-ordinate, taking into account the font being
- * used and any tabs in the text
- *
- * \param text line of text
- * \param offset char offset within text
- * \param length line length
- * \return x ordinate
- */
-
-int textplain_coord_from_offset(const char *text, size_t offset, size_t length)
-{
- int x = 0;
-
- while (offset > 0) {
- size_t next_offset = 0;
- int tx;
-
- while (next_offset < offset && text[next_offset] != '\t') {
- next_offset = utf8_next(text, length, next_offset);
- }
-
- guit->layout->width(&textplain_style, text, next_offset, &tx);
-
- x += tx;
-
- if (next_offset >= offset)
- break;
-
- /* align to next tab boundary */
- next_offset++;
- x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
- offset -= next_offset;
- text += next_offset;
- length -= next_offset;
- }
-
- return x;
-}
-
-
-/**
- * Given a range of byte offsets within a UTF8 textplain content,
- * return a box that fully encloses the text
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param start byte offset of start of text range
- * \param end byte offset of end
- * \param r rectangle to be completed
- */
-
-void textplain_coords_from_range(struct content *c, unsigned start,
- unsigned end, struct rect *r)
+/* exported interface documented in html/textplain.h */
+void
+textplain_coords_from_range(struct content *c,
+ unsigned start,
+ unsigned end,
+ struct rect *r)
{
textplain_content *text = (textplain_content *) c;
float line_height = textplain_line_height();
@@ -1266,42 +1460,38 @@ void textplain_coords_from_range(struct content *c, unsigned start,
r->y0 = (int)(MARGIN + lineno * line_height);
if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
- /* \todo - it may actually be more efficient just to run
- forwards most of the time */
+ /* \todo - it may actually be more efficient just to
+ * run forwards most of the time
+ */
/* find end */
lineno = textplain_find_line(c, end);
r->x0 = 0;
r->x1 = text->formatted_width;
- }
- else {
+ } else {
/* single line */
const char *text = utf8_data + line[lineno].start;
- r->x0 = textplain_coord_from_offset(text, start - line[lineno].start,
- line[lineno].length);
+ r->x0 = textplain_coord_from_offset(text,
+ start - line[lineno].start,
+ line[lineno].length);
- r->x1 = textplain_coord_from_offset(text, end - line[lineno].start,
- line[lineno].length);
+ r->x1 = textplain_coord_from_offset(text,
+ end - line[lineno].start,
+ line[lineno].length);
}
r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
}
-/**
- * Return a pointer to the requested line of text.
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param lineno line number
- * \param poffset receives byte offset of line start within text
- * \param plen receives length of returned line
- * \return pointer to text, or NULL if invalid line number
- */
-
-char *textplain_get_line(struct content *c, unsigned lineno,
- size_t *poffset, size_t *plen)
+/* exported interface documented in html/textplain.h */
+char *
+textplain_get_line(struct content *c,
+ unsigned lineno,
+ size_t *poffset,
+ size_t *plen)
{
textplain_content *text = (textplain_content *) c;
struct textplain_line *line;
@@ -1318,20 +1508,41 @@ char *textplain_get_line(struct content *c, unsigned lineno,
}
-/**
- * Return a pointer to the raw UTF-8 data, as opposed to the reformatted
- * text to fit the window width. Thus only hard newlines are preserved
- * in the saved/copied text of a selection.
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param start starting byte offset within UTF-8 text
- * \param end ending byte offset
- * \param plen receives validated length
- * \return pointer to text, or NULL if no text
- */
+/* exported interface documented in html/textplain.h */
+int textplain_find_line(struct content *c, unsigned offset)
+{
+ textplain_content *text = (textplain_content *) c;
+ struct textplain_line *line;
+ int nlines;
+ int lineno = 0;
+
+ assert(c != NULL);
+
+ line = text->physical_line;
+ nlines = text->physical_line_count;
+
+ if (offset > text->utf8_data_size) {
+ return -1;
+ }
+
+/* \todo - implement binary search here */
+ while (lineno < nlines && line[lineno].start < offset) {
+ lineno++;
+ }
+ if (line[lineno].start > offset) {
+ lineno--;
+ }
+
+ return lineno;
+}
+
-char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
- size_t *plen)
+/* exported interface documented in html/textplain.h */
+char *
+textplain_get_raw_data(struct content *c,
+ unsigned start,
+ unsigned end,
+ size_t *plen)
{
textplain_content *text = (textplain_content *) c;
size_t utf8_size;
@@ -1352,26 +1563,8 @@ char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
return text->utf8_data + start;
}
-/**
- * Calculate the line height, in pixels
- *
- * \return Line height, in pixels
- */
-float textplain_line_height(void)
-{
- /* Size is in points, so convert to pixels.
- * Then use a constant line height of 1.2 x font size.
- */
- return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi,
- INTTOFIX((textplain_style.size / FONT_SIZE_SCALE))))), F_72));
-}
-/**
- * Get the browser window containing a textplain content
- *
- * \param c text/plain content
- * \return the browser window
- */
+/* exported interface documented in html/textplain.h */
struct browser_window *textplain_get_browser_window(struct content *c)
{
textplain_content *text = (textplain_content *) c;
@@ -1381,4 +1574,3 @@ struct browser_window *textplain_get_browser_window(struct content *c)
return text->bw;
}
-
diff --git a/content/handlers/text/textplain.h b/content/handlers/text/textplain.h
new file mode 100644
index 000000000..23917fb6c
--- /dev/null
+++ b/content/handlers/text/textplain.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * Interface to content handler for plain text.
+ */
+
+#ifndef NETSURF_HTML_TEXTPLAIN_H
+#define NETSURF_HTML_TEXTPLAIN_H
+
+#include <stddef.h>
+#include "netsurf/mouse.h"
+
+struct content;
+struct hlcache_handle;
+struct http_parameter;
+struct rect;
+
+/**
+ * Initialise the text content handler
+ *
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+nserror textplain_init(void);
+
+
+/**
+ * Retrieve number of lines in content
+ *
+ * \param[in] c Content to retrieve line count from
+ * \return Number of lines
+ */
+unsigned long textplain_line_count(struct content *c);
+
+
+/**
+ * Retrieve the size (in bytes) of text data
+ *
+ * \param[in] c Content to retrieve size of
+ * \return Size, in bytes, of data
+ */
+size_t textplain_size(struct content *c);
+
+
+/**
+ * Return byte offset within UTF8 textplain content.
+ *
+ * given the co-ordinates of a point within a textplain content. 'dir'
+ * specifies the direction in which to search (-1 = above-left, +1 =
+ * below-right) if the co-ordinates are not contained within a line.
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] x x ordinate of point
+ * \param[in] y y ordinate of point
+ * \param[in] dir direction of search if not within line
+ * \return byte offset of character containing (or nearest to) point
+ */
+size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
+
+
+/**
+ * Given a range of byte offsets within a UTF8 textplain content,
+ * return a box that fully encloses the text
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] start byte offset of start of text range
+ * \param[in] end byte offset of end
+ * \param[out] r rectangle to be completed
+ */
+void textplain_coords_from_range(struct content *c,
+ unsigned start, unsigned end, struct rect *r);
+
+/**
+ * Return a pointer to the requested line of text.
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] lineno line number
+ * \param[out] poffset receives byte offset of line start within text
+ * \param[out] plen receives length of returned line
+ * \return pointer to text, or NULL if invalid line number
+ */
+char *textplain_get_line(struct content *c, unsigned lineno,
+ size_t *poffset, size_t *plen);
+
+
+/**
+ * Find line number of byte in text
+ *
+ * Given a byte offset within the text, return the line number
+ * of the line containing that offset.
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] offset byte offset within textual representation
+ * \return line number, or -1 if offset invalid (larger than size)
+ */
+int textplain_find_line(struct content *c, unsigned offset);
+
+
+/**
+ * Return a pointer to the raw UTF-8 data, as opposed to the reformatted
+ * text to fit the window width. Thus only hard newlines are preserved
+ * in the saved/copied text of a selection.
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] start starting byte offset within UTF-8 text
+ * \param[in] end ending byte offset
+ * \param[out] plen receives validated length
+ * \return pointer to text, or NULL if no text
+ */
+char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end, size_t *plen);
+
+
+/**
+ * Get the browser window containing a textplain content
+ *
+ * \param[in] c text/plain content
+ * \return the browser window
+ */
+struct browser_window *textplain_get_browser_window(struct content *c);
+
+#endif
diff --git a/content/hlcache.c b/content/hlcache.c
index 95edd2120..33436f7ed 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -179,20 +179,23 @@ static bool hlcache_type_is_acceptable(lwc_string *mime_type,
* \param pw Pointer to private data (hlcache_handle)
*/
static void hlcache_content_callback(struct content *c, content_msg msg,
- union content_msg_data data, void *pw)
+ const union content_msg_data *data, void *pw)
{
hlcache_handle *handle = pw;
- hlcache_event event;
nserror error = NSERROR_OK;
+ hlcache_event event = {
+ .type = msg,
+ };
- event.type = msg;
- event.data = data;
+ if (data != NULL) {
+ event.data = *data;
+ }
if (handle->cb != NULL)
error = handle->cb(handle, &event, handle->pw);
if (error != NSERROR_OK)
- LOG("Error in callback: %d", error);
+ NSLOG(netsurf, INFO, "Error in callback: %d", error);
}
/**
@@ -421,7 +424,7 @@ static nserror hlcache_llcache_callback(llcache_handle *handle,
switch (event->type) {
case LLCACHE_EVENT_HAD_HEADERS:
- error = mimesniff_compute_effective_type(handle, NULL, 0,
+ error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"), NULL, 0,
ctx->flags & HLCACHE_RETRIEVE_SNIFF_TYPE,
ctx->accepted_types == CONTENT_IMAGE,
&effective_type);
@@ -444,7 +447,7 @@ static nserror hlcache_llcache_callback(llcache_handle *handle,
break;
case LLCACHE_EVENT_HAD_DATA:
- error = mimesniff_compute_effective_type(handle,
+ error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"),
event->data.data.buf, event->data.data.len,
ctx->flags & HLCACHE_RETRIEVE_SNIFF_TYPE,
ctx->accepted_types == CONTENT_IMAGE,
@@ -463,7 +466,7 @@ static nserror hlcache_llcache_callback(llcache_handle *handle,
case LLCACHE_EVENT_DONE:
/* DONE event before we could determine the effective MIME type.
*/
- error = mimesniff_compute_effective_type(handle,
+ error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"),
NULL, 0, false, false, &effective_type);
if (error == NSERROR_OK || error == NSERROR_NOT_FOUND) {
error = hlcache_migrate_ctx(ctx, effective_type);
@@ -563,7 +566,8 @@ void hlcache_finalise(void)
num_contents++;
}
- LOG("%d contents remain before cache drain", num_contents);
+ NSLOG(netsurf, INFO, "%d contents remain before cache drain",
+ num_contents);
/* Drain cache */
do {
@@ -577,14 +581,17 @@ void hlcache_finalise(void)
}
} while (num_contents > 0 && num_contents != prev_contents);
- LOG("%d contents remaining:", num_contents);
+ NSLOG(netsurf, INFO, "%d contents remaining:", num_contents);
for (entry = hlcache->content_list; entry != NULL; entry = entry->next) {
hlcache_handle entry_handle = { entry, NULL, NULL };
if (entry->content != NULL) {
- LOG(" %p : %s (%d users)", entry, nsurl_access(hlcache_handle_get_url(&entry_handle)), content_count_users(entry->content));
+ NSLOG(netsurf, INFO, " %p : %s (%d users)",
+ entry,
+ nsurl_access(hlcache_handle_get_url(&entry_handle)),
+ content_count_users(entry->content));
} else {
- LOG(" %p", entry);
+ NSLOG(netsurf, INFO, " %p", entry);
}
}
@@ -612,12 +619,13 @@ void hlcache_finalise(void)
hlcache->retrieval_ctx_ring = NULL;
}
- LOG("hit/miss %d/%d", hlcache->hit_count, hlcache->miss_count);
+ NSLOG(netsurf, INFO, "hit/miss %d/%d", hlcache->hit_count,
+ hlcache->miss_count);
free(hlcache);
hlcache = NULL;
- LOG("Finalising low-level cache");
+ NSLOG(netsurf, INFO, "Finalising low-level cache");
llcache_finalise();
}
diff --git a/content/llcache.c b/content/llcache.c
index eb300534d..29b42a1c0 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -52,16 +52,6 @@
#include "content/backing_store.h"
#include "content/urldb.h"
-/** Define to enable tracing of llcache operations. */
-#undef LLCACHE_TRACE
-//#define LLCACHE_TRACE 1
-
-#ifdef LLCACHE_TRACE
-#define LLCACHE_LOG(x...) LOG(x)
-#else
-#define LLCACHE_LOG(x...) ((void) 0)
-#endif
-
/**
* State of a low-level cache object fetch.
*/
@@ -96,7 +86,7 @@ struct llcache_handle {
typedef struct llcache_object_user {
llcache_handle *handle; /**< Handle data for client */
- bool iterator_target; /**< This is the an iterator target */
+ bool iterator_target; /**< This is the iterator target */
bool queued_for_delete; /**< This user is queued for deletion */
struct llcache_object_user *prev; /**< Previous in list */
@@ -119,11 +109,15 @@ typedef struct {
uint32_t retries_remaining; /**< Number of times to retry on timeout */
+ bool hsts_in_use; /**< Whether HSTS applies to this fetch */
+
bool tried_with_auth; /**< Whether we've tried with auth */
bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */
bool outstanding_query; /**< Waiting for a query response */
+
+ bool tainted_tls; /**< Whether the TLS transport is tainted */
} llcache_fetch_ctx;
/**
@@ -136,7 +130,7 @@ typedef enum {
} llcache_validate;
/**
- * cache control value for invalid age.
+ * Cache control value for invalid age.
*/
#define INVALID_AGE -1
@@ -160,7 +154,7 @@ typedef struct {
char *value; /**< Header value */
} llcache_header;
-/** Current status of objects data */
+/** Current status of an object's data */
typedef enum {
LLCACHE_STATE_RAM = 0, /**< source data is stored in RAM only */
LLCACHE_STATE_DISC, /**< source data is stored on disc */
@@ -201,7 +195,7 @@ struct llcache_object {
/* Instrumentation. These elements are strictly for information
* to improve the cache performance and to provide performance
- * metrics. The values are non-authorative and must not be used to
+ * metrics. The values are non-authoritative and must not be used to
* determine object lifetime etc.
*/
time_t last_used; /**< time the last user was removed from the object */
@@ -316,7 +310,8 @@ static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
u->handle = h;
- LLCACHE_LOG("Created user %p (%p, %p, %p)", u, h, (void *) cb, pw);
+ NSLOG(llcache, DEBUG,
+ "Created user %p (%p, %p, %p)", u, h, (void *) cb, pw);
*user = u;
@@ -333,7 +328,7 @@ static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
*/
static nserror llcache_object_user_destroy(llcache_object_user *user)
{
- LLCACHE_LOG("Destroyed user %p", user);
+ NSLOG(llcache, DEBUG, "Destroyed user %p", user);
assert(user->next == NULL);
assert(user->prev == NULL);
@@ -377,7 +372,7 @@ static nserror llcache_object_remove_user(llcache_object *object,
object->last_used = time(NULL);
}
- LLCACHE_LOG("Removing user %p from %p", user, object);
+ NSLOG(llcache, DEBUG, "Removing user %p from %p", user, object);
return NSERROR_OK;
}
@@ -433,7 +428,7 @@ static nserror llcache_object_new(nsurl *url, llcache_object **result)
if (obj == NULL)
return NSERROR_NOMEM;
- LLCACHE_LOG("Created object %p (%s)", obj, nsurl_access(url));
+ NSLOG(llcache, DEBUG, "Created object %p (%s)", obj, nsurl_access(url));
obj->url = nsurl_ref(url);
@@ -800,7 +795,7 @@ static nserror llcache_fetch_process_header(llcache_object *object,
/**
* (Re)fetch an object
*
- * sets up headers and attempts to start an actual fetch from the
+ * Sets up headers and attempts to start an actual fetch from the
* fetchers system updating the llcache object with the new fetch on
* successful start.
*
@@ -874,7 +869,7 @@ static nserror llcache_object_refetch(llcache_object *object)
/* Reset fetch state */
object->fetch.state = LLCACHE_FETCH_INIT;
- LLCACHE_LOG("Re-fetching %p", object);
+ NSLOG(llcache, DEBUG, "Re-fetching %p", object);
/* Kick off fetch */
res = fetch_start(object->url,
@@ -911,17 +906,18 @@ static nserror llcache_object_refetch(llcache_object *object)
* \param referer Referring URL, or NULL for none
* \param post POST data, or NULL for GET
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count)
+ uint32_t redirect_count, bool hsts_in_use)
{
nserror error;
nsurl *referer_clone = NULL;
llcache_post_data *post_clone = NULL;
- LLCACHE_LOG("Starting fetch for %p", object);
+ NSLOG(llcache, DEBUG, "Starting fetch for %p", object);
if (post != NULL) {
error = llcache_post_data_clone(post, &post_clone);
@@ -937,6 +933,7 @@ static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
object->fetch.post = post_clone;
object->fetch.redirect_count = redirect_count;
object->fetch.retries_remaining = llcache->fetch_attempts;
+ object->fetch.hsts_in_use = hsts_in_use;
return llcache_object_refetch(object);
}
@@ -955,8 +952,8 @@ static nserror llcache_object_destroy(llcache_object *object)
{
size_t i;
- LLCACHE_LOG("Destroying object %p, %s", object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG, "Destroying object %p, %s", object,
+ nsurl_access(object->url));
if (object->source_data != NULL) {
if (object->store_state == LLCACHE_STATE_DISC) {
@@ -1038,16 +1035,17 @@ llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
current_age += cd->res_time - cd->req_time + now - cd->res_time;
/* Determine freshness lifetime of this object */
- if (cd->max_age != INVALID_AGE)
+ if (cd->max_age != INVALID_AGE) {
freshness_lifetime = cd->max_age;
- else if (cd->expires != 0)
+ } else if (cd->expires != 0) {
freshness_lifetime = cd->expires - cd->date;
- else if (cd->last_modified != 0)
+ } else if (cd->last_modified != 0) {
freshness_lifetime = (now - cd->last_modified) / 10;
- else
+ } else {
freshness_lifetime = 0;
+ }
- /* LLCACHE_LOG("%d:%d", freshness_lifetime, current_age); */
+ NSLOG(llcache, DEBUG, "%d:%d", freshness_lifetime, current_age);
if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
(freshness_lifetime > current_age)) {
@@ -1076,7 +1074,7 @@ static bool llcache_object_is_fresh(const llcache_object *object)
remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(cd);
- LLCACHE_LOG("%p: (%d > 0 || %d != %d)", object,
+ NSLOG(llcache, DEBUG, "%p: (%d > 0 || %d != %d)", object,
remaining_lifetime,
object->fetch.state, LLCACHE_FETCH_COMPLETE);
@@ -1173,14 +1171,14 @@ llcache_object_remove_from_list(llcache_object *object, llcache_object **list)
/**
* Retrieve source data for an object from persistent store if necessary.
*
- * If an objects source data has been placed in the persistent store
- * and the in memory copy released this will attempt to retrieve the
- * source data.
+ * If an object's source data has been placed in the persistent store
+ * and there is no in-memory copy, then attempt to retrieve the source
+ * data.
*
* \param object the object to operate on.
* \return appropriate error code.
*/
-static nserror llcache_persist_retrieve(llcache_object *object)
+static nserror llcache_retrieve_persisted_data(llcache_object *object)
{
/* ensure the source data is present if necessary */
if ((object->source_data != NULL) ||
@@ -1199,7 +1197,7 @@ static nserror llcache_persist_retrieve(llcache_object *object)
}
/**
- * Generate a serialised version of an objects metadata
+ * Generate a serialised version of an object's metadata
*
* The metadata includes object headers.
*
@@ -1322,7 +1320,7 @@ llcache_serialise_metadata(llcache_object *object,
datasize -= use;
}
- LLCACHE_LOG("Filled buffer with %d spare", datasize);
+ NSLOG(llcache, DEBUG, "Filled buffer with %d spare", datasize);
*data_out = data;
*datasize_out = allocsize - datasize;
@@ -1331,19 +1329,19 @@ llcache_serialise_metadata(llcache_object *object,
overflow:
/* somehow we overflowed the buffer - hth? */
- LOG("Overflowed metadata buffer");
+ NSLOG(llcache, INFO, "Overflowed metadata buffer");
free(data);
return NSERROR_INVALID;
operror:
/* output error */
- LOG("Output error");
+ NSLOG(llcache, INFO, "Output error");
free(data);
return NSERROR_INVALID;
}
/**
- * Deserialisation of an objects metadata.
+ * Deserialisation of an object's metadata.
*
* Attempt to retrieve and deserialise the metadata for an object from
* the backing store.
@@ -1369,12 +1367,12 @@ llcache_process_metadata(llcache_object *object)
size_t source_length;
time_t request_time;
- time_t reponse_time;
+ time_t response_time;
time_t completion_time;
size_t num_headers;
size_t hloop;
- LOG("Retrieving metadata");
+ NSLOG(llcache, INFO, "Retrieving metadata");
/* attempt to retrieve object metadata from the backing store */
res = guit->llcache->fetch(object->url,
@@ -1385,7 +1383,7 @@ llcache_process_metadata(llcache_object *object)
return res;
}
- LOG("Processing retrieved data");
+ NSLOG(llcache, INFO, "Processing retrieved data");
/* metadata line 1 is the url the metadata referrs to */
line = 1;
@@ -1408,8 +1406,8 @@ llcache_process_metadata(llcache_object *object)
* by simply skipping caching of this object.
*/
- LOG("Got metadata for %s instead of %s",
- nsurl_access(metadataurl), nsurl_access(object->url));
+ NSLOG(llcache, INFO, "Got metadata for %s instead of %s",
+ nsurl_access(metadataurl), nsurl_access(object->url));
nsurl_unref(metadataurl);
@@ -1420,7 +1418,7 @@ llcache_process_metadata(llcache_object *object)
nsurl_unref(metadataurl);
- /* metadata line 2 is the objects length */
+ /* metadata line 2 is the object's length */
line = 2;
ln += lnsize + 1;
lnsize = strlen(ln);
@@ -1446,7 +1444,7 @@ llcache_process_metadata(llcache_object *object)
ln += lnsize + 1;
lnsize = strlen(ln);
- res = nsc_snptimet(ln, lnsize, &reponse_time);
+ res = nsc_snptimet(ln, lnsize, &response_time);
if (res != NSERROR_OK)
goto format_error;
@@ -1493,7 +1491,7 @@ llcache_process_metadata(llcache_object *object)
object->source_alloc = metadatalen;
object->cache.req_time = request_time;
- object->cache.res_time = reponse_time;
+ object->cache.res_time = response_time;
object->cache.fin_time = completion_time;
/* object stored in backing store */
@@ -1502,7 +1500,9 @@ llcache_process_metadata(llcache_object *object)
return NSERROR_OK;
format_error:
- LOG("metadata error on line %d error code %d\n", line, res);
+ NSLOG(llcache, INFO,
+ "metadata error on line %d error code %d\n",
+ line, res);
guit->llcache->release(object->url, BACKING_STORE_META);
return res;
@@ -1520,7 +1520,7 @@ format_error:
* cache else appropriate error code.
*/
static nserror
-llcache_object_fetch_persistant(llcache_object *object,
+llcache_object_fetch_persistent(llcache_object *object,
uint32_t flags,
nsurl *referer,
const llcache_post_data *post,
@@ -1570,6 +1570,7 @@ llcache_object_fetch_persistant(llcache_object *object,
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \param result Pointer to location to receive retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
@@ -1579,12 +1580,13 @@ llcache_object_retrieve_from_cache(nsurl *url,
nsurl *referer,
const llcache_post_data *post,
uint32_t redirect_count,
+ bool hsts_in_use,
llcache_object **result)
{
nserror error;
llcache_object *obj, *newest = NULL;
- LLCACHE_LOG("Searching cache for %s flags:%x referer:%s post:%p",
+ NSLOG(llcache, DEBUG, "Searching cache for %s flags:%x referer:%s post:%p",
nsurl_access(url), flags,
referer==NULL?"":nsurl_access(referer), post);
@@ -1603,16 +1605,16 @@ llcache_object_retrieve_from_cache(nsurl *url,
* pull from persistent store.
*/
if (newest == NULL) {
- LLCACHE_LOG("No viable object found in llcache");
+ NSLOG(llcache, DEBUG, "No viable object found in llcache");
error = llcache_object_new(url, &obj);
if (error != NSERROR_OK)
return error;
/* attempt to retrieve object from persistent store */
- error = llcache_object_fetch_persistant(obj, flags, referer, post, redirect_count);
+ error = llcache_object_fetch_persistent(obj, flags, referer, post, redirect_count);
if (error == NSERROR_OK) {
- LLCACHE_LOG("retrieved object from persistent store");
+ NSLOG(llcache, DEBUG, "retrieved object from persistent store");
/* set newest object from persistent store which
* will cause the normal object handling to be used.
@@ -1630,14 +1632,14 @@ llcache_object_retrieve_from_cache(nsurl *url,
if ((newest != NULL) && (llcache_object_is_fresh(newest))) {
/* Found a suitable object, and it's still fresh */
- LLCACHE_LOG("Found fresh %p", newest);
+ NSLOG(llcache, DEBUG, "Found fresh %p", newest);
/* The client needs to catch up with the object's state.
* This will occur the next time that llcache_poll is called.
*/
/* ensure the source data is present */
- error = llcache_persist_retrieve(newest);
+ error = llcache_retrieve_persisted_data(newest);
if (error == NSERROR_OK) {
/* source data was successfully retrieved from
* persistent store
@@ -1651,7 +1653,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
* failed, destroy cache object and fall though to
* cache miss to re-fetch
*/
- LLCACHE_LOG("Persistent retrieval failed for %p", newest);
+ NSLOG(llcache, DEBUG, "Persistent retrieval failed for %p", newest);
llcache_object_remove_from_list(newest, &llcache->cached_objects);
llcache_object_destroy(newest);
@@ -1664,7 +1666,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
/* Found a candidate object but it needs freshness validation */
/* ensure the source data is present */
- error = llcache_persist_retrieve(newest);
+ error = llcache_retrieve_persisted_data(newest);
if (error == NSERROR_OK) {
/* Create a new object */
@@ -1672,7 +1674,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
if (error != NSERROR_OK)
return error;
- LLCACHE_LOG("Found candidate %p (%p)", obj, newest);
+ NSLOG(llcache, DEBUG, "Found candidate %p (%p)", obj, newest);
/* Clone candidate's cache data */
error = llcache_object_clone_cache_data(newest, obj, true);
@@ -1687,7 +1689,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
newest->candidate_count--;
llcache_object_destroy(obj);
@@ -1702,7 +1704,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
return NSERROR_OK;
}
- LLCACHE_LOG("Persistent retrieval failed for %p", newest);
+ NSLOG(llcache, DEBUG, "Persistent retrieval failed for %p", newest);
/* retrieval of source data from persistent store
* failed, destroy cache object and fall though to
@@ -1719,7 +1721,8 @@ llcache_object_retrieve_from_cache(nsurl *url,
}
/* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post, redirect_count);
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
return error;
@@ -1741,6 +1744,7 @@ llcache_object_retrieve_from_cache(nsurl *url,
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
+ * \param hsts_in_use Whether HSTS applies to this fetch
* \param result Pointer to location to receive retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
@@ -1750,6 +1754,7 @@ llcache_object_retrieve(nsurl *url,
nsurl *referer,
const llcache_post_data *post,
uint32_t redirect_count,
+ bool hsts_in_use,
llcache_object **result)
{
nserror error;
@@ -1757,7 +1762,7 @@ llcache_object_retrieve(nsurl *url,
nsurl *defragmented_url;
bool uncachable = false;
- LLCACHE_LOG("Retrieve %s (%x, %s, %p)", nsurl_access(url), flags,
+ NSLOG(llcache, DEBUG, "Retrieve %s (%x, %s, %p)", nsurl_access(url), flags,
referer==NULL?"":nsurl_access(referer), post);
@@ -1804,7 +1809,7 @@ llcache_object_retrieve(nsurl *url,
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
+ redirect_count, hsts_in_use);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
nsurl_unref(defragmented_url);
@@ -1815,7 +1820,8 @@ llcache_object_retrieve(nsurl *url,
llcache_object_add_to_list(obj, &llcache->uncached_objects);
} else {
error = llcache_object_retrieve_from_cache(defragmented_url,
- flags, referer, post, redirect_count, &obj);
+ flags, referer, post, redirect_count,
+ hsts_in_use, &obj);
if (error != NSERROR_OK) {
nsurl_unref(defragmented_url);
return error;
@@ -1824,7 +1830,7 @@ llcache_object_retrieve(nsurl *url,
/* Returned object is already in the cached list */
}
- LLCACHE_LOG("Retrieved %p", obj);
+ NSLOG(llcache, DEBUG, "Retrieved %p", obj);
*result = obj;
@@ -1857,7 +1863,87 @@ static nserror llcache_object_add_user(llcache_object *object,
object->users->prev = user;
object->users = user;
- LLCACHE_LOG("Adding user %p to %p", user, object);
+ NSLOG(llcache, DEBUG, "Adding user %p to %p", user, object);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Transform a request-URI based on HSTS policy
+ *
+ * \param url URL to transform
+ * \param result Pointer to location to receive transformed URL
+ * \param hsts_in_use Pointer to location to receive HSTS in-use flag
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result,
+ bool *hsts_in_use)
+{
+ lwc_string *scheme = NULL;
+ bool match;
+ nserror error = NSERROR_OK;
+
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
+ &match) != lwc_error_ok || match == false) {
+ /* Non-HTTP fetch: ignore */
+ lwc_string_unref(scheme);
+ *result = nsurl_ref(url);
+ *hsts_in_use = false;
+ return error;
+ }
+ lwc_string_unref(scheme);
+
+ if (urldb_get_hsts_enabled(url)) {
+ /* Only need to force HTTPS. If original port was explicitly
+ * specified as 80, nsurl_create/join will remove it (as
+ * it's redundant) */
+ error = nsurl_replace_scheme(url, corestring_lwc_https,
+ result);
+ *hsts_in_use = (error == NSERROR_OK);
+ } else {
+ *result = nsurl_ref(url);
+ *hsts_in_use = false;
+ }
+
+ return error;
+}
+
+/**
+ * Update HSTS policy for target domain.
+ *
+ * \param object Newly-fetched cache object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_hsts_update_policy(llcache_object *object)
+{
+ size_t i;
+ lwc_string *scheme = NULL;
+ bool match = false;
+
+ scheme = nsurl_get_component(object->url, NSURL_SCHEME);
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
+ &match) != lwc_error_ok || match == false) {
+ /* Non-HTTPS fetch: ignore */
+ lwc_string_unref(scheme);
+ return NSERROR_OK;
+ }
+ lwc_string_unref(scheme);
+
+ if (object->fetch.tainted_tls) {
+ /* Transport is tainted: ignore */
+ return NSERROR_OK;
+ }
+
+ for (i = 0; i < object->num_headers; i++) {
+ if (strcasecmp("Strict-Transport-Security",
+ object->headers[i].name) == 0) {
+ urldb_set_hsts_policy(object->url,
+ object->headers[i].value);
+ /* Only process the first one we find */
+ break;
+ }
+ }
return NSERROR_OK;
}
@@ -1877,10 +1963,10 @@ static nserror llcache_fetch_redirect(llcache_object *object,
llcache_object *dest;
llcache_object_user *user, *next;
const llcache_post_data *post = object->fetch.post;
- nsurl *url;
+ nsurl *url, *hsts_url;
lwc_string *scheme;
lwc_string *object_scheme;
- bool match;
+ bool match, hsts_in_use;
/* Extract HTTP response code from the fetch object */
long http_code = fetch_http_code(object->fetch.fetch);
llcache_event event;
@@ -1895,10 +1981,12 @@ static nserror llcache_fetch_redirect(llcache_object *object,
/* And mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ (void) llcache_hsts_update_policy(object);
+
/* Forcibly stop redirecting if we've followed too many redirects */
#define REDIRECT_LIMIT 10
if (object->fetch.redirect_count > REDIRECT_LIMIT) {
- LOG("Too many nested redirects");
+ NSLOG(llcache, INFO, "Too many nested redirects");
event.type = LLCACHE_EVENT_ERROR;
event.data.msg = messages_get("BadRedirect");
@@ -1912,15 +2000,23 @@ static nserror llcache_fetch_redirect(llcache_object *object,
if (error != NSERROR_OK)
return error;
+ /* Perform HSTS transform */
+ error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+ if (error != NSERROR_OK) {
+ nsurl_unref(url);
+ return error;
+ }
+ nsurl_unref(url);
+
/* Inform users of redirect */
event.type = LLCACHE_EVENT_REDIRECT;
event.data.redirect.from = object->url;
- event.data.redirect.to = url;
+ event.data.redirect.to = hsts_url;
error = llcache_send_event_to_users(object, &event);
if (error != NSERROR_OK) {
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return error;
}
@@ -1928,7 +2024,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
* A "validated" scheme is one over which we have some guarantee that
* the source is trustworthy. */
object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
- scheme = nsurl_get_component(url, NSURL_SCHEME);
+ scheme = nsurl_get_component(hsts_url, NSURL_SCHEME);
/* resource: and about: are allowed to redirect anywhere */
if ((lwc_string_isequal(object_scheme, corestring_lwc_resource,
@@ -1944,7 +2040,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
&match) == lwc_error_ok && match == true)) {
lwc_string_unref(object_scheme);
lwc_string_unref(scheme);
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
}
@@ -1953,8 +2049,8 @@ static nserror llcache_fetch_redirect(llcache_object *object,
lwc_string_unref(object_scheme);
/* Bail out if we've no way of handling this URL */
- if (fetch_can_fetch(url) == false) {
- nsurl_unref(url);
+ if (fetch_can_fetch(hsts_url) == false) {
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
@@ -1963,17 +2059,18 @@ static nserror llcache_fetch_redirect(llcache_object *object,
post = NULL;
} else if (http_code != 307 || post != NULL) {
/** \todo 300, 305, 307 with POST */
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
return NSERROR_OK;
}
/* Attempt to fetch target URL */
- error = llcache_object_retrieve(url, object->fetch.flags,
+ error = llcache_object_retrieve(hsts_url, object->fetch.flags,
object->fetch.referer, post,
- object->fetch.redirect_count + 1, &dest);
+ object->fetch.redirect_count + 1,
+ hsts_in_use, &dest);
/* No longer require url */
- nsurl_unref(url);
+ nsurl_unref(hsts_url);
if (error != NSERROR_OK)
return error;
@@ -2065,6 +2162,8 @@ static nserror llcache_fetch_notmodified(llcache_object *object,
/* Mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ (void) llcache_hsts_update_policy(object);
+
/* Old object will be flushed from the cache on the next poll */
return NSERROR_OK;
@@ -2259,7 +2358,11 @@ static nserror llcache_fetch_cert_error(llcache_object *object,
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
- if (llcache->query_cb != NULL) {
+ /* Consider the TLS transport tainted */
+ object->fetch.tainted_tls = true;
+
+ /* Only give the user a chance if HSTS isn't in use for this fetch */
+ if (object->fetch.hsts_in_use == false && llcache->query_cb != NULL) {
llcache_query query;
/* Emit query for TLS */
@@ -2309,7 +2412,13 @@ static nserror llcache_fetch_ssl_error(llcache_object *object)
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
- if (object->fetch.tried_with_tls_downgrade == true) {
+ /* Consider the TLS transport tainted */
+ object->fetch.tainted_tls = true;
+
+ /* Make no attempt to downgrade if HSTS is in use
+ * (i.e. assume server does TLS properly) */
+ if (object->fetch.hsts_in_use ||
+ object->fetch.tried_with_tls_downgrade) {
/* Have already tried to downgrade, so give up */
llcache_event event;
@@ -2493,8 +2602,10 @@ static void llcache_persist_slowcheck(void *p)
total_bandwidth = (llcache->total_written * 1000) / llcache->total_elapsed;
if (total_bandwidth < llcache->minimum_bandwidth) {
- LOG("Current bandwidth %" PRIu64 " less than minimum %" PRIsizet,
- total_bandwidth, llcache->minimum_bandwidth);
+ NSLOG(llcache, INFO,
+ "Current bandwidth %"PRIu64" less than minimum %"PRIsizet,
+ total_bandwidth,
+ llcache->minimum_bandwidth);
guit->llcache->finalise();
}
}
@@ -2524,7 +2635,7 @@ static void llcache_persist(void *p)
ret = build_candidate_list(&lst, &lst_count);
if (ret != NSERROR_OK) {
- LLCACHE_LOG("Unable to construct candidate list for persistent writeout");
+ NSLOG(llcache, DEBUG, "Unable to construct candidate list for persistent writeout");
return;
}
@@ -2542,7 +2653,7 @@ static void llcache_persist(void *p)
total_elapsed += elapsed;
total_bandwidth = (total_written * 1000) / total_elapsed;
- LLCACHE_LOG("Wrote %zd bytes in %lums bw:%lu %s",
+ NSLOG(llcache, DEBUG, "Wrote %zd bytes in %lums bw:%lu %s",
written, elapsed, (written * 1000) / elapsed,
nsurl_access(lst[idx]->url) );
@@ -2550,7 +2661,7 @@ static void llcache_persist(void *p)
* (bandwidth) for this run being exceeded.
*/
if (total_elapsed > llcache->time_quantum) {
- LOG("Overran timeslot");
+ NSLOG(llcache, INFO, "Overran timeslot");
/* writeout has exhausted the available time.
* Either the writeout is slow or the last
* object was very large.
@@ -2609,10 +2720,10 @@ static void llcache_persist(void *p)
llcache->total_written += total_written;
llcache->total_elapsed += total_elapsed;
- LLCACHE_LOG("writeout size:%zd time:%lu bandwidth:%lubytes/s",
+ NSLOG(llcache, DEBUG, "writeout size:%zd time:%lu bandwidth:%lubytes/s",
total_written, total_elapsed, total_bandwidth);
- LLCACHE_LOG("Rescheduling writeout in %dms", next);
+ NSLOG(llcache, DEBUG, "Rescheduling writeout in %dms", next);
guit->misc->schedule(next, llcache_persist, NULL);
}
@@ -2629,7 +2740,7 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
llcache_object *object = p;
llcache_event event;
- LLCACHE_LOG("Fetch event %d for %p", msg->type, object);
+ NSLOG(llcache, DEBUG, "Fetch event %d for %p", msg->type, object);
switch (msg->type) {
case FETCH_HEADER:
@@ -2688,6 +2799,8 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
/* record when the fetch finished */
object->cache.fin_time = time(NULL);
+ (void) llcache_hsts_update_policy(object);
+
guit->misc->schedule(5000, llcache_persist, NULL);
}
break;
@@ -2702,9 +2815,7 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
error = llcache_object_refetch(object);
break;
}
- /* Otherwise fall through to error, setting the message to
- * a timeout
- */
+ /* Fall through */
case FETCH_ERROR:
/* An error occurred while fetching */
/* The fetch has has already been cleaned up by the fetcher */
@@ -2853,10 +2964,7 @@ static nserror llcache_object_notify_users(llcache_object *object)
nserror error;
llcache_object_user *user, *next_user;
llcache_event event;
-
-#ifdef LLCACHE_TRACE
bool emitted_notify = false;
-#endif
/**
* State transitions and event emission for users.
@@ -2917,17 +3025,20 @@ static nserror llcache_object_notify_users(llcache_object *object)
* continue is used)
*/
-#ifdef LLCACHE_TRACE
if (handle->state != objstate) {
if (emitted_notify == false) {
- LOG("Notifying users of %p", object);
+ NSLOG(llcache, DEBUG,
+ "Notifying users of %p",
+ object);
emitted_notify = true;
}
- LOG("User %p state: %d Object state: %d", user,
- handle->state, objstate);
+ NSLOG(llcache, DEBUG,
+ "User %p state: %d Object state: %d",
+ user,
+ handle->state,
+ objstate);
}
-#endif
/* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
if (handle->state == LLCACHE_FETCH_INIT &&
@@ -3184,7 +3295,7 @@ void llcache_clean(bool purge)
int remaining_lifetime;
uint32_t limit;
- LLCACHE_LOG("Attempting cache clean");
+ NSLOG(llcache, DEBUG, "Attempting cache clean");
/* If the cache is being purged set the size limit to zero. */
if (purge) {
@@ -3204,7 +3315,7 @@ void llcache_clean(bool purge)
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
- LLCACHE_LOG("Discarding uncachable object with no users (%p) %s",
+ NSLOG(llcache, DEBUG, "Discarding uncachable object with no users (%p) %s",
object, nsurl_access(object->url));
llcache_object_remove_from_list(object,
@@ -3231,7 +3342,7 @@ void llcache_clean(bool purge)
(object->fetch.outstanding_query == false) &&
(remaining_lifetime <= 0)) {
/* object is stale */
- LLCACHE_LOG("discarding stale cacheable object with no "
+ NSLOG(llcache, DEBUG, "discarding stale cacheable object with no "
"users or pending fetches (%p) %s",
object, nsurl_access(object->url));
@@ -3277,7 +3388,7 @@ void llcache_clean(bool purge)
llcache_size -= object->source_len;
- LLCACHE_LOG("Freeing source data for %p len:%zd",
+ NSLOG(llcache, DEBUG, "Freeing source data for %p len:%zd",
object,
object->source_len);
}
@@ -3297,12 +3408,12 @@ void llcache_clean(bool purge)
(object->fetch.outstanding_query == false) &&
(object->store_state == LLCACHE_STATE_DISC) &&
(object->source_data == NULL)) {
- LLCACHE_LOG("discarding backed object len:%zd "
- "age:%d (%p) %s",
- object->source_len,
- time(NULL) - object->last_used,
- object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG,
+ "discarding backed object len:%zd age:%ld (%p) %s",
+ object->source_len,
+ (long)(time(NULL) - object->last_used),
+ object,
+ nsurl_access(object->url));
llcache_size -= total_object_size(object);
@@ -3328,11 +3439,12 @@ void llcache_clean(bool purge)
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false) &&
(object->store_state == LLCACHE_STATE_RAM)) {
- LLCACHE_LOG("discarding fresh object len:%zd age:%d (%p) %s",
- object->source_len,
- time(NULL) - object->last_used,
- object,
- nsurl_access(object->url));
+ NSLOG(llcache, DEBUG,
+ "discarding fresh object len:%zd age:%ld (%p) %s",
+ object->source_len,
+ (long)(time(NULL) - object->last_used),
+ object,
+ nsurl_access(object->url));
llcache_size -= object->source_len + sizeof(*object);
@@ -3342,7 +3454,7 @@ void llcache_clean(bool purge)
}
}
- LLCACHE_LOG("Size: %u (limit: %u)", llcache_size, limit);
+ NSLOG(llcache, DEBUG, "Size: %u (limit: %u)", llcache_size, limit);
}
/* Exported interface documented in content/llcache.h */
@@ -3364,7 +3476,9 @@ llcache_initialise(const struct llcache_parameters *prm)
llcache->fetch_attempts = prm->fetch_attempts;
llcache->all_caught_up = true;
- LOG("llcache initialising with a limit of %d bytes", llcache->limit);
+ NSLOG(llcache, INFO,
+ "llcache initialising with a limit of %d bytes",
+ llcache->limit);
/* backing store initialisation */
return guit->llcache->initialise(&prm->store);
@@ -3427,10 +3541,11 @@ void llcache_finalise(void)
llcache->total_elapsed;
}
- LOG("Backing store wrote %"PRIu64" bytes in %"PRIu64" ms "
- "(average %"PRIu64" bytes/second)",
- llcache->total_written, llcache->total_elapsed,
- total_bandwidth);
+ NSLOG(llcache, INFO,
+ "Backing store wrote %"PRIu64" bytes in %"PRIu64" ms ""(average %"PRIu64" bytes/second)",
+ llcache->total_written,
+ llcache->total_elapsed,
+ total_bandwidth);
free(llcache);
llcache = NULL;
@@ -3446,8 +3561,8 @@ static void llcache_catch_up_all_users(void *ignored)
llcache_object *object;
/* Assume after this we'll be all caught up. If any user of a handle
- * defers then we'll end up set not caught up and we'll
- * reschedule at that point via llcache_users_not_caught_up()
+ * defers then we'll invalidate all_caught_up and reschedule via
+ * llcache_users_not_caught_up()
*/
llcache->all_caught_up = true;
@@ -3485,23 +3600,35 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
nserror error;
llcache_object_user *user;
llcache_object *object;
+ nsurl *hsts_url;
+ bool hsts_in_use;
+
+ /* Perform HSTS transform */
+ error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
+ if (error != NSERROR_OK) {
+ return error;
+ }
/* Can we fetch this URL at all? */
- if (fetch_can_fetch(url) == false) {
+ if (fetch_can_fetch(hsts_url) == false) {
+ nsurl_unref(hsts_url);
return NSERROR_NO_FETCH_HANDLER;
}
/* Create a new object user */
error = llcache_object_user_new(cb, pw, &user);
if (error != NSERROR_OK) {
+ nsurl_unref(hsts_url);
return error;
}
/* Retrieve a suitable object from the cache,
* creating a new one if needed. */
- error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
+ error = llcache_object_retrieve(hsts_url, flags, referer, post, 0,
+ hsts_in_use, &object);
if (error != NSERROR_OK) {
llcache_object_user_destroy(user);
+ nsurl_unref(hsts_url);
return error;
}
@@ -3513,6 +3640,8 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
/* Users exist which are now not caught up! */
llcache_users_not_caught_up();
+ nsurl_unref(hsts_url);
+
return NSERROR_OK;
}
diff --git a/content/mimesniff.c b/content/mimesniff.c
index b24448861..9a11834f9 100644
--- a/content/mimesniff.c
+++ b/content/mimesniff.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * MIME type sniffer (implementation)
+/**
+ * \file
+ * MIME type sniffer implementation
*
* Spec version: 2011-11-27
*/
@@ -25,11 +26,12 @@
#include <string.h>
#include <strings.h>
-#include "content/content_factory.h"
-#include "content/llcache.h"
-#include "content/mimesniff.h"
#include "utils/http.h"
#include "utils/utils.h"
+#include "utils/corestrings.h"
+
+#include "content/content_factory.h"
+#include "content/mimesniff.h"
struct map_s {
const uint8_t *sig;
@@ -38,103 +40,6 @@ struct map_s {
lwc_string **type;
};
-static lwc_string *unknown_unknown;
-static lwc_string *application_unknown;
-static lwc_string *any;
-static lwc_string *text_xml;
-static lwc_string *application_xml;
-static lwc_string *text_html;
-static lwc_string *text_plain;
-static lwc_string *application_octet_stream;
-static lwc_string *image_gif;
-static lwc_string *image_png;
-static lwc_string *image_jpeg;
-static lwc_string *image_bmp;
-static lwc_string *image_vnd_microsoft_icon;
-static lwc_string *image_webp;
-static lwc_string *application_rss_xml;
-static lwc_string *application_atom_xml;
-static lwc_string *audio_wave;
-static lwc_string *application_ogg;
-static lwc_string *video_webm;
-static lwc_string *application_x_rar_compressed;
-static lwc_string *application_zip;
-static lwc_string *application_x_gzip;
-static lwc_string *application_postscript;
-static lwc_string *application_pdf;
-static lwc_string *video_mp4;
-static lwc_string *image_svg;
-
-nserror mimesniff_init(void)
-{
- lwc_error lerror;
-
-#define SINIT(v, s) \
- lerror = lwc_intern_string(s, SLEN(s), &v); \
- if (lerror != lwc_error_ok) \
- return NSERROR_NOMEM
-
- SINIT(unknown_unknown, "unknown/unknown");
- SINIT(application_unknown, "application/unknown");
- SINIT(any, "*/*");
- SINIT(text_xml, "text/xml");
- SINIT(application_xml, "application/xml");
- SINIT(text_html, "text/html");
- SINIT(text_plain, "text/plain");
- SINIT(application_octet_stream, "application/octet-stream");
- SINIT(image_gif, "image/gif");
- SINIT(image_png, "image/png");
- SINIT(image_jpeg, "image/jpeg");
- SINIT(image_bmp, "image/bmp");
- SINIT(image_vnd_microsoft_icon, "image/vnd.microsoft.icon");
- SINIT(image_webp, "image/webp");
- SINIT(application_rss_xml, "application/rss+xml");
- SINIT(application_atom_xml, "application/atom+xml");
- SINIT(audio_wave, "audio/wave");
- SINIT(application_ogg, "application/ogg");
- SINIT(video_webm, "video/webm");
- SINIT(application_x_rar_compressed, "application/x-rar-compressed");
- SINIT(application_zip, "application/zip");
- SINIT(application_x_gzip, "application/x-gzip");
- SINIT(application_postscript, "application/postscript");
- SINIT(application_pdf, "application/pdf");
- SINIT(video_mp4, "video/mp4");
- SINIT(image_svg, "image/svg+xml");
-#undef SINIT
-
- return NSERROR_OK;
-}
-
-void mimesniff_fini(void)
-{
- lwc_string_unref(image_svg);
- lwc_string_unref(video_mp4);
- lwc_string_unref(application_pdf);
- lwc_string_unref(application_postscript);
- lwc_string_unref(application_x_gzip);
- lwc_string_unref(application_zip);
- lwc_string_unref(application_x_rar_compressed);
- lwc_string_unref(video_webm);
- lwc_string_unref(application_ogg);
- lwc_string_unref(audio_wave);
- lwc_string_unref(application_atom_xml);
- lwc_string_unref(application_rss_xml);
- lwc_string_unref(image_webp);
- lwc_string_unref(image_vnd_microsoft_icon);
- lwc_string_unref(image_bmp);
- lwc_string_unref(image_jpeg);
- lwc_string_unref(image_png);
- lwc_string_unref(image_gif);
- lwc_string_unref(application_octet_stream);
- lwc_string_unref(text_plain);
- lwc_string_unref(text_html);
- lwc_string_unref(application_xml);
- lwc_string_unref(text_xml);
- lwc_string_unref(any);
- lwc_string_unref(application_unknown);
- lwc_string_unref(unknown_unknown);
-}
-
static bool mimesniff__has_binary_octets(const uint8_t *data, size_t len)
{
const uint8_t *end = data + len;
@@ -143,7 +48,7 @@ static bool mimesniff__has_binary_octets(const uint8_t *data, size_t len)
const uint8_t c = *data;
/* Binary iff in C0 and not ESC, CR, FF, LF, HT */
- if (c <= 0x1f && c != 0x1b && c != '\r' && c != '\f' &&
+ if (c <= 0x1f && c != 0x1b && c != '\r' && c != '\f' &&
c != '\n' && c != '\t')
break;
@@ -168,19 +73,19 @@ static nserror mimesniff__match_mp4(const uint8_t *data, size_t len,
* uint32_t compatible_brands[];
* }
*
- * Note 1: A size of 0 implies that the length of the box is designated
- * by the remaining input data (and thus may only occur in the last
- * box in the input). We'll reject this below, as it's pointless
+ * Note 1: A size of 0 implies that the length of the box is designated
+ * by the remaining input data (and thus may only occur in the last
+ * box in the input). We'll reject this below, as it's pointless
* sniffing input that contains no boxes other than 'ftyp'.
*
- * Note 2: A size of 1 implies an additional uint64_t field after
- * the type which contains the extended box size. We'll reject this,
- * too, as it implies a minimum of (2^32 - 24) / 4 compatible brands,
+ * Note 2: A size of 1 implies an additional uint64_t field after
+ * the type which contains the extended box size. We'll reject this,
+ * too, as it implies a minimum of (2^32 - 24) / 4 compatible brands,
* which is decidely unlikely.
*/
- /* 12 reflects the minimum number of octets needed to sniff useful
- * information out of an 'ftyp' box (i.e. the size, type,
+ /* 12 reflects the minimum number of octets needed to sniff useful
+ * information out of an 'ftyp' box (i.e. the size, type,
* and major_brand words). */
if (len < 12)
return NSERROR_NOT_FOUND;
@@ -193,22 +98,22 @@ static nserror mimesniff__match_mp4(const uint8_t *data, size_t len,
return NSERROR_NOT_FOUND;
/* Ensure this is an 'ftyp' box */
- if (data[4] != 'f' || data[5] != 't' ||
+ if (data[4] != 'f' || data[5] != 't' ||
data[6] != 'y' || data[7] != 'p')
return NSERROR_NOT_FOUND;
/* Check if major brand begins with 'mp4' */
if (data[8] == 'm' && data[9] == 'p' && data[10] == '4') {
- *effective_type = lwc_string_ref(video_mp4);
+ *effective_type = lwc_string_ref(corestring_lwc_video_mp4);
return NSERROR_OK;
}
/* Search each compatible brand in the box for "mp4" */
for (i = 16; i <= box_size - 4; i += 4) {
- if (data[i] == 'm' &&
- data[i+1] == 'p' &&
+ if (data[i] == 'm' &&
+ data[i+1] == 'p' &&
data[i+2] == '4') {
- *effective_type = lwc_string_ref(video_mp4);
+ *effective_type = lwc_string_ref(corestring_lwc_video_mp4);
return NSERROR_OK;
}
}
@@ -221,28 +126,28 @@ static nserror mimesniff__match_unknown_ws(const uint8_t *data, size_t len,
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s ws_exact_match_types[] = {
- SIG(&text_xml, "<?xml", false),
+ SIG(&corestring_lwc_text_xml, "<?xml", false),
{ NULL, 0, false, NULL }
};
static const struct map_s ws_inexact_match_types[] = {
- SIG(&text_html, "<!DOCTYPE HTML", false),
- SIG(&text_html, "<HTML", false),
- SIG(&text_html, "<HEAD", false),
- SIG(&text_html, "<SCRIPT", false),
- SIG(&text_html, "<IFRAME", false),
- SIG(&text_html, "<H1", false),
- SIG(&text_html, "<DIV", false),
- SIG(&text_html, "<FONT", false),
- SIG(&text_html, "<TABLE", false),
- SIG(&text_html, "<A", false),
- SIG(&text_html, "<STYLE", false),
- SIG(&text_html, "<TITLE", false),
- SIG(&text_html, "<B", false),
- SIG(&text_html, "<BODY", false),
- SIG(&text_html, "<BR", false),
- SIG(&text_html, "<P", false),
- SIG(&text_html, "<!--", false),
+ SIG(&corestring_lwc_text_html, "<!DOCTYPE HTML", false),
+ SIG(&corestring_lwc_text_html, "<HTML", false),
+ SIG(&corestring_lwc_text_html, "<HEAD", false),
+ SIG(&corestring_lwc_text_html, "<SCRIPT", false),
+ SIG(&corestring_lwc_text_html, "<IFRAME", false),
+ SIG(&corestring_lwc_text_html, "<H1", false),
+ SIG(&corestring_lwc_text_html, "<DIV", false),
+ SIG(&corestring_lwc_text_html, "<FONT", false),
+ SIG(&corestring_lwc_text_html, "<TABLE", false),
+ SIG(&corestring_lwc_text_html, "<A", false),
+ SIG(&corestring_lwc_text_html, "<STYLE", false),
+ SIG(&corestring_lwc_text_html, "<TITLE", false),
+ SIG(&corestring_lwc_text_html, "<B", false),
+ SIG(&corestring_lwc_text_html, "<BODY", false),
+ SIG(&corestring_lwc_text_html, "<BR", false),
+ SIG(&corestring_lwc_text_html, "<P", false),
+ SIG(&corestring_lwc_text_html, "<!--", false),
{ NULL, 0, false, NULL }
};
#undef SIG
@@ -253,7 +158,7 @@ static nserror mimesniff__match_unknown_ws(const uint8_t *data, size_t len,
while (data != end) {
const uint8_t c = *data;
- if (c != '\t' && c != '\n' && c != '\f' &&
+ if (c != '\t' && c != '\n' && c != '\f' &&
c != '\r' && c != ' ')
break;
@@ -277,9 +182,9 @@ static nserror mimesniff__match_unknown_ws(const uint8_t *data, size_t len,
if (len < it->len + 1)
continue;
- if (strncasecmp((const char *) data,
- (const char *) it->sig, it->len) == 0 &&
- (data[it->len] == ' ' ||
+ if (strncasecmp((const char *) data,
+ (const char *) it->sig, it->len) == 0 &&
+ (data[it->len] == ' ' ||
data[it->len] == '>')) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
@@ -294,9 +199,9 @@ static nserror mimesniff__match_unknown_bom(const uint8_t *data, size_t len,
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s bom_match_types[] = {
- SIG(&text_plain, "\xfe\xff", false),
- SIG(&text_plain, "\xff\xfe", false),
- SIG(&text_plain, "\xef\xbb\xbf", false),
+ SIG(&corestring_lwc_text_plain, "\xfe\xff", false),
+ SIG(&corestring_lwc_text_plain, "\xff\xfe", false),
+ SIG(&corestring_lwc_text_plain, "\xef\xbb\xbf", false),
{ NULL, 0, false, NULL }
};
#undef SIG
@@ -317,17 +222,17 @@ static nserror mimesniff__match_unknown_riff(const uint8_t *data, size_t len,
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s riff_match_types[] = {
- SIG(&image_webp, "WEBPVP", true),
- SIG(&audio_wave, "WAVE", true),
+ SIG(&corestring_lwc_image_webp, "WEBPVP", true),
+ SIG(&corestring_lwc_audio_wave, "WAVE", true),
{ NULL, 0, false, NULL }
};
#undef SIG
const struct map_s *it;
for (it = riff_match_types; it->sig != NULL; it++) {
- if (it->len + SLEN("RIFF????") <= len &&
+ if (it->len + SLEN("RIFF????") <= len &&
memcmp(data, "RIFF", SLEN("RIFF")) == 0 &&
- memcmp(data + SLEN("RIFF????"),
+ memcmp(data + SLEN("RIFF????"),
it->sig, it->len) == 0) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
@@ -342,19 +247,19 @@ static nserror mimesniff__match_unknown_exact(const uint8_t *data, size_t len,
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s exact_match_types[] = {
- SIG(&image_gif, "GIF87a", true),
- SIG(&image_gif, "GIF89a", true),
- SIG(&image_png, "\x89PNG\r\n\x1a\n", true),
- SIG(&image_jpeg, "\xff\xd8\xff", true),
- SIG(&image_bmp, "BM", true),
- SIG(&image_vnd_microsoft_icon, "\x00\x00\x01\x00", true),
- SIG(&application_ogg, "OggS\x00", true),
- SIG(&video_webm, "\x1a\x45\xdf\xa3", true),
- SIG(&application_x_rar_compressed, "Rar \x1a\x07\x00", true),
- SIG(&application_zip, "PK\x03\x04", true),
- SIG(&application_x_gzip, "\x1f\x8b\x08", true),
- SIG(&application_postscript, "%!PS-Adobe-", true),
- SIG(&application_pdf, "%PDF-", false),
+ SIG(&corestring_lwc_image_gif, "GIF87a", true),
+ SIG(&corestring_lwc_image_gif, "GIF89a", true),
+ SIG(&corestring_lwc_image_png, "\x89PNG\r\n\x1a\n", true),
+ SIG(&corestring_lwc_image_jpeg, "\xff\xd8\xff", true),
+ SIG(&corestring_lwc_image_bmp, "BM", true),
+ SIG(&corestring_lwc_image_vnd_microsoft_icon, "\x00\x00\x01\x00", true),
+ SIG(&corestring_lwc_application_ogg, "OggS\x00", true),
+ SIG(&corestring_lwc_video_webm, "\x1a\x45\xdf\xa3", true),
+ SIG(&corestring_lwc_application_x_rar_compressed, "Rar \x1a\x07\x00", true),
+ SIG(&corestring_lwc_application_zip, "PK\x03\x04", true),
+ SIG(&corestring_lwc_application_x_gzip, "\x1f\x8b\x08", true),
+ SIG(&corestring_lwc_application_postscript, "%!PS-Adobe-",true),
+ SIG(&corestring_lwc_application_pdf, "%PDF-", false),
{ NULL, 0, false, NULL }
};
#undef SIG
@@ -374,11 +279,11 @@ static nserror mimesniff__match_unknown_exact(const uint8_t *data, size_t len,
static nserror mimesniff__match_unknown(const uint8_t *data, size_t len,
bool allow_unsafe, lwc_string **effective_type)
{
- if (mimesniff__match_unknown_exact(data, len, allow_unsafe,
+ if (mimesniff__match_unknown_exact(data, len, allow_unsafe,
effective_type) == NSERROR_OK)
return NSERROR_OK;
- if (mimesniff__match_unknown_riff(data, len,
+ if (mimesniff__match_unknown_riff(data, len,
effective_type) == NSERROR_OK)
return NSERROR_OK;
@@ -407,49 +312,51 @@ static nserror mimesniff__compute_unknown(const uint8_t *data, size_t len,
len = min(len, 512);
- if (mimesniff__match_unknown(data, len, true,
- effective_type) == NSERROR_OK)
+ if (mimesniff__match_unknown(data, len, true,
+ effective_type) == NSERROR_OK) {
return NSERROR_OK;
+ }
if (mimesniff__has_binary_octets(data, len) == false) {
/* No binary octets => text/plain */
- *effective_type = lwc_string_ref(text_plain);
+ *effective_type = lwc_string_ref(corestring_lwc_text_plain);
return NSERROR_OK;
}
- *effective_type = lwc_string_ref(application_octet_stream);
+ *effective_type = lwc_string_ref(corestring_lwc_application_octet_stream);
return NSERROR_OK;
}
-static nserror mimesniff__compute_text_or_binary(const uint8_t *data,
+static nserror mimesniff__compute_text_or_binary(const uint8_t *data,
size_t len, lwc_string **effective_type)
{
- if (data == NULL)
+ if (data == NULL) {
return NSERROR_NEED_DATA;
+ }
len = min(len, 512);
if (len >= 3 && ((data[0] == 0xfe && data[1] == 0xff) ||
(data[0] == 0xff && data[1] == 0xfe) ||
- (data[0] == 0xef && data[1] == 0xbb &&
+ (data[0] == 0xef && data[1] == 0xbb &&
data[2] == 0xbf))) {
/* Found a BOM => text/plain */
- *effective_type = lwc_string_ref(text_plain);
+ *effective_type = lwc_string_ref(corestring_lwc_text_plain);
return NSERROR_OK;
}
if (mimesniff__has_binary_octets(data, len) == false) {
/* No binary octets => text/plain */
- *effective_type = lwc_string_ref(text_plain);
+ *effective_type = lwc_string_ref(corestring_lwc_text_plain);
return NSERROR_OK;
}
- if (mimesniff__match_unknown(data, len, false,
+ if (mimesniff__match_unknown(data, len, false,
effective_type) == NSERROR_OK)
return NSERROR_OK;
- *effective_type = lwc_string_ref(application_octet_stream);
+ *effective_type = lwc_string_ref(corestring_lwc_application_octet_stream);
return NSERROR_OK;
}
@@ -463,12 +370,12 @@ static nserror mimesniff__compute_image(lwc_string *official_type,
size_t len;
lwc_string **type;
} image_types[] = {
- SIG(&image_gif, "GIF87a"),
- SIG(&image_gif, "GIF89a"),
- SIG(&image_png, "\x89PNG\r\n\x1a\n"),
- SIG(&image_jpeg, "\xff\xd8\xff"),
- SIG(&image_bmp, "BM"),
- SIG(&image_vnd_microsoft_icon, "\x00\x00\x01\x00"),
+ SIG(&corestring_lwc_image_gif, "GIF87a"),
+ SIG(&corestring_lwc_image_gif, "GIF89a"),
+ SIG(&corestring_lwc_image_png, "\x89PNG\r\n\x1a\n"),
+ SIG(&corestring_lwc_image_jpeg, "\xff\xd8\xff"),
+ SIG(&corestring_lwc_image_bmp, "BM"),
+ SIG(&corestring_lwc_image_vnd_microsoft_icon, "\x00\x00\x01\x00"),
{ NULL, 0, NULL }
};
#undef SIG
@@ -489,12 +396,12 @@ static nserror mimesniff__compute_image(lwc_string *official_type,
}
/* WebP has a signature that doesn't fit into the above table */
- if (SLEN("RIFF????WEBPVP") <= len &&
- memcmp(data, "RIFF", SLEN("RIFF")) == 0 &&
- memcmp(data + SLEN("RIFF????"),
+ if (SLEN("RIFF????WEBPVP") <= len &&
+ memcmp(data, "RIFF", SLEN("RIFF")) == 0 &&
+ memcmp(data + SLEN("RIFF????"),
"WEBPVP", SLEN("WEBPVP")) == 0 ) {
lwc_string_unref(official_type);
- *effective_type = lwc_string_ref(image_webp);
+ *effective_type = lwc_string_ref(corestring_lwc_image_webp);
return NSERROR_OK;
}
@@ -537,7 +444,7 @@ static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
switch (state) {
case BEFORE_BOM:
- if (3 <= end - data && c == 0xef && data[1] == 0xbb &&
+ if (3 <= end - data && c == 0xef && data[1] == 0xbb &&
data[2] == 0xbf) {
data += 3;
}
@@ -597,12 +504,12 @@ static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
break;
case IN_TAG:
if (MATCH("rss")) {
- *effective_type =
- lwc_string_ref(application_rss_xml);
+ *effective_type =
+ lwc_string_ref(corestring_lwc_application_rss_xml);
return NSERROR_OK;
} else if (MATCH("feed")) {
- *effective_type =
- lwc_string_ref(application_atom_xml);
+ *effective_type =
+ lwc_string_ref(corestring_lwc_application_atom_xml);
return NSERROR_OK;
} else if (MATCH("rdf:RDF")) {
state = IN_RDF;
@@ -621,8 +528,7 @@ static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
data++;
if (rdf && rss) {
- *effective_type =
- lwc_string_ref(application_rss_xml);
+ *effective_type = lwc_string_ref(corestring_lwc_application_rss_xml);
return NSERROR_OK;
}
@@ -631,7 +537,7 @@ static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
#undef MATCH
}
- *effective_type = lwc_string_ref(text_html);
+ *effective_type = lwc_string_ref(corestring_lwc_text_html);
return NSERROR_OK;
@@ -640,9 +546,13 @@ static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
}
/* See mimesniff.h for documentation */
-nserror mimesniff_compute_effective_type(llcache_handle *handle,
- const uint8_t *data, size_t len, bool sniff_allowed,
- bool image_only, lwc_string **effective_type)
+nserror
+mimesniff_compute_effective_type(const char *content_type_header,
+ const uint8_t *data,
+ size_t len,
+ bool sniff_allowed,
+ bool image_only,
+ lwc_string **effective_type)
{
#define S(s) { s, SLEN(s) }
static const struct tt_s {
@@ -657,18 +567,16 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
};
#undef S
- const char *content_type_header;
size_t content_type_header_len;
http_content_type *ct;
const struct tt_s *tt;
bool match;
nserror error;
- content_type_header =
- llcache_handle_get_header(handle, "Content-Type");
if (content_type_header == NULL) {
- if (sniff_allowed == false)
+ if (sniff_allowed == false) {
return NSERROR_NOT_FOUND;
+ }
/* No official type => unknown */
return mimesniff__compute_unknown(data, len, effective_type);
@@ -692,9 +600,10 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
if (image_only) {
lwc_string *official_type;
- if (lwc_string_caseless_isequal(ct->media_type, image_svg,
- &match) == lwc_error_ok && match) {
- *effective_type = lwc_string_ref(image_svg);
+ if (lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_image_svg,
+ &match) == lwc_error_ok && match) {
+ *effective_type = lwc_string_ref(corestring_lwc_image_svg);
http_content_type_destroy(ct);
return NSERROR_OK;
}
@@ -710,8 +619,9 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
/* Look for text types */
for (tt = text_types; tt->data != NULL; tt++) {
if (tt->len == content_type_header_len &&
- memcmp(tt->data, content_type_header,
- content_type_header_len) == 0) {
+ memcmp(tt->data,
+ content_type_header,
+ content_type_header_len) == 0) {
http_content_type_destroy(ct);
return mimesniff__compute_text_or_binary(data, len,
effective_type);
@@ -719,22 +629,24 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
}
/* unknown/unknown, application/unknown, * / * */
- if ((lwc_string_caseless_isequal(ct->media_type, unknown_unknown,
- &match) == lwc_error_ok && match) ||
- (lwc_string_caseless_isequal(ct->media_type,
- application_unknown, &match) == lwc_error_ok &&
- match) ||
- (lwc_string_caseless_isequal(ct->media_type, any,
- &match) == lwc_error_ok && match)) {
+ if ((lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_unknown_unknown,
+ &match) == lwc_error_ok && match) ||
+ (lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_application_unknown,
+ &match) == lwc_error_ok && match) ||
+ (lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_any,
+ &match) == lwc_error_ok && match)) {
http_content_type_destroy(ct);
return mimesniff__compute_unknown(data, len, effective_type);
}
/* +xml */
if (lwc_string_length(ct->media_type) > SLEN("+xml") &&
- strncasecmp(lwc_string_data(ct->media_type) +
- lwc_string_length(ct->media_type) -
- SLEN("+xml"),
+ strncasecmp(lwc_string_data(ct->media_type) +
+ lwc_string_length(ct->media_type) -
+ SLEN("+xml"),
"+xml", SLEN("+xml")) == 0) {
/* Use official type */
*effective_type = lwc_string_ref(ct->media_type);
@@ -743,19 +655,20 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
}
/* text/xml, application/xml */
- if ((lwc_string_caseless_isequal(ct->media_type, text_xml,
- &match) == lwc_error_ok && match) ||
- (lwc_string_caseless_isequal(ct->media_type,
- application_xml, &match) == lwc_error_ok &&
- match)) {
+ if ((lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_text_xml,
+ &match) == lwc_error_ok && match) ||
+ (lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_application_xml,
+ &match) == lwc_error_ok && match)) {
/* Use official type */
*effective_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return NSERROR_OK;
}
-
+
/* Image types */
- if (content_factory_type_from_mime_type(ct->media_type) ==
+ if (content_factory_type_from_mime_type(ct->media_type) ==
CONTENT_IMAGE) {
lwc_string *official_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
@@ -764,11 +677,12 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
}
/* text/html */
- if ((lwc_string_caseless_isequal(ct->media_type, text_html,
- &match) == lwc_error_ok && match)) {
+ if ((lwc_string_caseless_isequal(ct->media_type,
+ corestring_lwc_text_html,
+ &match) == lwc_error_ok && match)) {
http_content_type_destroy(ct);
return mimesniff__compute_feed_or_html(data, len,
- effective_type);
+ effective_type);
}
/* Use official type */
@@ -778,4 +692,3 @@ nserror mimesniff_compute_effective_type(llcache_handle *handle,
return NSERROR_OK;
}
-
diff --git a/content/mimesniff.h b/content/mimesniff.h
index bf3e493f3..faecab865 100644
--- a/content/mimesniff.h
+++ b/content/mimesniff.h
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * MIME type sniffer (interface)
+/**
+ * \file
+ * MIME type sniffer interface
*/
#ifndef NETSURF_CONTENT_MIMESNIFF_H_
@@ -31,10 +32,12 @@
struct llcache_handle;
/**
- * Compute the effective MIME type for an object using the sniffing
- * algorithm described in http://mimesniff.spec.whatwg.org/
+ * Compute the effective MIME type for an object
+ *
+ * The implementation uses the sniffing algorithm described in
+ * http://mimesniff.spec.whatwg.org/
*
- * \param handle Source data handle to sniff
+ * \param content_type_header Source content type header
* \param data First data chunk, or NULL
* \param len Length of \a data, in bytes
* \param sniff_allowed Whether MIME type sniffing is allowed
@@ -45,11 +48,8 @@ struct llcache_handle;
* NSERROR_NOT_FOUND if sniffing is prohibited and no
* Content-Type header was found
*/
-nserror mimesniff_compute_effective_type(struct llcache_handle *handle,
+nserror mimesniff_compute_effective_type(const char *content_type_header,
const uint8_t *data, size_t len, bool sniff_allowed,
bool image_only, lwc_string **effective_type);
-nserror mimesniff_init(void);
-void mimesniff_fini(void);
-
#endif
diff --git a/content/urldb.c b/content/urldb.c
index b6eaf630b..4bdb10e66 100644
--- a/content/urldb.c
+++ b/content/urldb.c
@@ -32,14 +32,14 @@
*
* This provides something looking like:
*
- * root (a sentinel)
- * |
- * -------------------------------------------------
- * | | | | | | |
+ * root (a sentinel)
+ * |
+ * -------------------------------------------------
+ * | | | | | | |
* com edu gov 127.0.0.1 net org uk TLDs
- * | | | | | |
+ * | | | | | |
* google ... ... ... ... co 2LDs
- * | |
+ * | |
* www bbc Hosts/Subdomains
* |
* www ...
@@ -62,11 +62,11 @@
*
* (sentinel)
* |
- * path
- * |
- * to
- * |
- * resource.html
+ * path
+ * |
+ * to
+ * |
+ * resource.html
*
* This represents the absolute path "/path/to/resource.html". The leaf node
* "resource.html" contains the last visited time of the resource.
@@ -108,6 +108,7 @@
#include "utils/time.h"
#include "utils/nsurl.h"
#include "utils/ascii.h"
+#include "utils/http.h"
#include "netsurf/bitmap.h"
#include "desktop/cookie_manager.h"
#include "desktop/gui_internal.h"
@@ -118,7 +119,7 @@
/**
* cookie entry.
*
- * \warn This *must* be kept in sync with the public interface in
+ * \warning This *must* be kept in sync with the public interface in
* netsurf/cookie_db.h
*/
struct cookie_internal_data {
@@ -143,28 +144,43 @@ struct cookie_internal_data {
};
-/* A protection space is defined as a tuple canonical_root_url and realm.
- * This structure lives as linked list element in a leaf host_part struct
- * so we need additional scheme and port to have a canonical_root_url. */
+
+/**
+ * A protection space
+ *
+ * This is defined as a tuple canonical_root_url and realm. This
+ * structure lives as linked list element in a leaf host_part struct
+ * so we need additional scheme and port to have a canonical_root_url.
+ */
struct prot_space_data {
- lwc_string *scheme; /**< URL scheme of canonical hostname of this
- * protection space. */
- unsigned int port; /**< Port number of canonical hostname of this
- * protection space. When 0, it means the
- * default port for given scheme, i.e. 80
- * (http), 443 (https). */
- char *realm; /**< Protection realm */
-
- char *auth; /**< Authentication details for this
- * protection space in form
- * username:password */
- struct prot_space_data *next; /**< Next sibling */
-};
+ /**
+ * URL scheme of canonical hostname of this protection space.
+ */
+ lwc_string *scheme;
+ /**
+ * Port number of canonical hostname of this protection
+ * space. When 0, it means the default port for given scheme,
+ * i.e. 80 (http), 443 (https).
+ */
+ unsigned int port;
+ /** Protection realm */
+ char *realm;
-struct cache_internal_data {
- char filename[12]; /**< Cached filename, or first byte 0 for none */
+ /**
+ * Authentication details for this protection space in form
+ * username:password
+ */
+ char *auth;
+ /** Next sibling */
+ struct prot_space_data *next;
};
+
+/**
+ * meta data about a url
+ *
+ * \warning must be kept in sync with url_data structure in netsurf/url_db.h
+ */
struct url_internal_data {
char *title; /**< Resource title */
unsigned int visits; /**< Visit count */
@@ -172,6 +188,10 @@ struct url_internal_data {
content_type type; /**< Type of resource */
};
+
+/**
+ * data entry for url
+ */
struct path_data {
nsurl *url; /**< Full URL */
lwc_string *scheme; /**< URL scheme for data */
@@ -183,45 +203,66 @@ struct path_data {
char **fragment; /**< Array of fragments */
bool persistent; /**< This entry should persist */
- struct bitmap *thumb; /**< Thumbnail image of resource */
struct url_internal_data urld; /**< URL data for resource */
- struct cache_internal_data cache; /**< Cache data for resource */
- const struct prot_space_data *prot_space; /**< Protection space
- * to which this resource belongs too. Can be
- * NULL when it does not belong to a protection
- * space or when it is not known. No
- * ownership (is with struct host_part::prot_space). */
- struct cookie_internal_data *cookies; /**< Cookies associated with resource */
- struct cookie_internal_data *cookies_end; /**< Last cookie in list */
+
+ /**
+ * Protection space to which this resource belongs too. Can be
+ * NULL when it does not belong to a protection space or when
+ * it is not known. No ownership (is with struct host_part::prot_space).
+ */
+ const struct prot_space_data *prot_space;
+ /** Cookies associated with resource */
+ struct cookie_internal_data *cookies;
+ /** Last cookie in list */
+ struct cookie_internal_data *cookies_end;
struct path_data *next; /**< Next sibling */
struct path_data *prev; /**< Previous sibling */
- struct path_data *parent; /**< Parent path segment */
- struct path_data *children; /**< Child path segments */
- struct path_data *last; /**< Last child */
+ struct path_data *parent; /**< Parent path segment */
+ struct path_data *children; /**< Child path segments */
+ struct path_data *last; /**< Last child */
+};
+
+struct hsts_data {
+ time_t expires; /**< Expiry time */
+ bool include_sub_domains; /**< Whether to include subdomains */
};
struct host_part {
- /**< Known paths on this host. This _must_ be first so that
- * struct host_part *h = (struct host_part *)mypath; works */
+ /**
+ * Known paths on this host. This _must_ be first so that
+ * struct host_part *h = (struct host_part *)mypath; works
+ */
struct path_data paths;
- bool permit_invalid_certs; /**< Allow access to SSL protected
- * resources on this host without
- * verifying certificate authenticity
- */
+ /**
+ * Allow access to SSL protected resources on this host
+ * without verifying certificate authenticity
+ */
+ bool permit_invalid_certs;
+ /* HSTS data */
+ struct hsts_data hsts;
- char *part; /**< Part of host string */
+ /**
+ * Part of host string
+ */
+ char *part;
- struct prot_space_data *prot_space; /**< Linked list of all known
- * proctection spaces known for his host and
- * all its schems and ports. */
+ /**
+ * Linked list of all known proctection spaces known for this
+ * host and all its schems and ports.
+ */
+ struct prot_space_data *prot_space;
struct host_part *next; /**< Next sibling */
struct host_part *prev; /**< Previous sibling */
- struct host_part *parent; /**< Parent host part */
- struct host_part *children; /**< Child host parts */
+ struct host_part *parent; /**< Parent host part */
+ struct host_part *children; /**< Child host parts */
};
+
+/**
+ * search index node
+ */
struct search_node {
const struct host_part *data; /**< Host tree entry */
@@ -247,26 +288,56 @@ static struct search_node *search_trees[NUM_SEARCH_TREES] = {
&empty, &empty, &empty, &empty
};
+/** Minimum cookie database file version */
#define MIN_COOKIE_FILE_VERSION 100
+/** Current cookie database file version */
#define COOKIE_FILE_VERSION 102
+/** loaded cookie file version */
static int loaded_cookie_file_version;
-#define MIN_URL_FILE_VERSION 106
-/** URL database file version */
-#define URL_FILE_VERSION 106
+/** Minimum URL database file version */
+#define MIN_URL_FILE_VERSION 106
+/** Current URL database file version */
+#define URL_FILE_VERSION 107
-/* Bloom filter used for short-circuting the false case of "is this
+/**
+ * filter for url presence in database
+ *
+ * Bloom filter used for short-circuting the false case of "is this
* URL in the database?". BLOOM_SIZE controls how large the filter is
* in bytes. Primitive experimentation shows that for a filter of X
* bytes filled with X items, searching for X items not in the filter
* has a 5% false-positive rate. We set it to 32kB, which should be
- * enough for all but the largest databases, while not being shockingly
- * wasteful on memory.
+ * enough for all but the largest databases, while not being
+ * shockingly wasteful on memory.
*/
static struct bloom_filter *url_bloom;
+/**
+ * Size of url filter
+ */
#define BLOOM_SIZE (1024 * 32)
+/**
+ * write a time_t to a file portably
+ *
+ * \param fp File to write to
+ * \param val the unix time value to output
+ * \return NSERROR_OK on success
+ */
+static nserror urldb_write_timet(FILE *fp, time_t val)
+{
+ int use;
+ char op[32];
+
+ use = nsc_sntimet(op, 32, &val);
+ if (use == 0) {
+ fprintf(fp, "%i\n", (int)val);
+ } else {
+ fprintf(fp, "%.*s\n", use, op);
+ }
+ return NSERROR_OK;
+}
/**
* Write paths associated with a host
@@ -279,9 +350,14 @@ static struct bloom_filter *url_bloom;
* \param path_used Used size of path
* \param expiry Expiry time of URLs
*/
-static void urldb_write_paths(const struct path_data *parent, const char *host,
- FILE *fp, char **path, int *path_alloc, int *path_used,
- time_t expiry)
+static void
+urldb_write_paths(const struct path_data *parent,
+ const char *host,
+ FILE *fp,
+ char **path,
+ int *path_alloc,
+ int *path_used,
+ time_t expiry)
{
const struct path_data *p = parent;
int i;
@@ -291,16 +367,19 @@ static void urldb_write_paths(const struct path_data *parent, const char *host,
int len = *path_used + seglen + 1;
if (*path_alloc < len) {
- char *temp = realloc(*path,
- (len > 64) ? len : *path_alloc + 64);
- if (!temp)
+ char *temp;
+ temp = realloc(*path,
+ (len > 64) ? len : *path_alloc + 64);
+ if (!temp) {
return;
+ }
*path = temp;
*path_alloc = (len > 64) ? len : *path_alloc + 64;
}
- if (p->segment != NULL)
+ if (p->segment != NULL) {
memcpy(*path + *path_used - 1, p->segment, seglen);
+ }
if (p->children != NULL) {
(*path)[*path_used + seglen - 1] = '/';
@@ -317,22 +396,29 @@ static void urldb_write_paths(const struct path_data *parent, const char *host,
p = p->children;
} else {
/* leaf node */
- if (p->persistent ||((p->urld.last_visit > expiry) &&
- (p->urld.visits > 0))) {
+ if (p->persistent ||
+ ((p->urld.last_visit > expiry) &&
+ (p->urld.visits > 0))) {
fprintf(fp, "%s\n", lwc_string_data(p->scheme));
- if (p->port)
+ if (p->port) {
fprintf(fp,"%d\n", p->port);
- else
+ } else {
fprintf(fp, "\n");
+ }
fprintf(fp, "%s\n", *path);
/** \todo handle fragments? */
- fprintf(fp, "%i\n%i\n%i\n", p->urld.visits,
- (int)p->urld.last_visit,
- (int)p->urld.type);
+ /* number of visits */
+ fprintf(fp, "%i\n", p->urld.visits);
+
+ /* time entry was last used */
+ urldb_write_timet(fp, p->urld.last_visit);
+
+ /* entry type */
+ fprintf(fp, "%i\n", (int)p->urld.type);
fprintf(fp, "\n");
@@ -346,8 +432,9 @@ static void urldb_write_paths(const struct path_data *parent, const char *host,
i--)
s[i] = '\0';
fprintf(fp, "%s\n", p->urld.title);
- } else
+ } else {
fprintf(fp, "\n");
+ }
}
/* Now, find next node to process. */
@@ -384,8 +471,10 @@ static void urldb_write_paths(const struct path_data *parent, const char *host,
* \param expiry Expiry time for URLs
* \param count Pointer to count
*/
-static void urldb_count_urls(const struct path_data *root, time_t expiry,
- unsigned int *count)
+static void
+urldb_count_urls(const struct path_data *root,
+ time_t expiry,
+ unsigned int *count)
{
const struct path_data *p = root;
@@ -395,8 +484,9 @@ static void urldb_count_urls(const struct path_data *root, time_t expiry,
p = p->children;
} else {
/* No more children, increment count if required */
- if (p->persistent || ((p->urld.last_visit > expiry) &&
- (p->urld.visits > 0))) {
+ if (p->persistent ||
+ ((p->urld.last_visit > expiry) &&
+ (p->urld.visits > 0))) {
(*count)++;
}
@@ -429,7 +519,8 @@ static void urldb_save_search_tree(struct search_node *parent, FILE *fp)
unsigned int path_count = 0;
char *path, *p, *end;
int path_alloc = 64, path_used = 1;
- time_t expiry;
+ time_t expiry, hsts_expiry = 0;
+ int hsts_include_subdomains = 0;
expiry = time(NULL) - ((60 * 60 * 24) * nsoption_int(expire_url));
@@ -445,9 +536,9 @@ static void urldb_save_search_tree(struct search_node *parent, FILE *fp)
path[0] = '\0';
for (h = parent->data, p = host, end = host + sizeof host;
- h && h != &db_root && p < end; h = h->parent) {
+ h && h != &db_root && p < end; h = h->parent) {
int written = snprintf(p, end - p, "%s%s", h->part,
- (h->parent && h->parent->parent) ? "." : "");
+ (h->parent && h->parent->parent) ? "." : "");
if (written < 0) {
free(path);
return;
@@ -455,13 +546,25 @@ static void urldb_save_search_tree(struct search_node *parent, FILE *fp)
p += written;
}
+ h = parent->data;
+ if (h && h->hsts.expires > expiry) {
+ hsts_expiry = h->hsts.expires;
+ hsts_include_subdomains = h->hsts.include_sub_domains;
+ }
+
urldb_count_urls(&parent->data->paths, expiry, &path_count);
if (path_count > 0) {
- fprintf(fp, "%s\n%i\n", host, path_count);
+ fprintf(fp, "%s %i ", host, hsts_include_subdomains);
+ urldb_write_timet(fp, hsts_expiry);
+ fprintf(fp, "%i\n", path_count);
urldb_write_paths(&parent->data->paths, host, fp,
- &path, &path_alloc, &path_used, expiry);
+ &path, &path_alloc, &path_used, expiry);
+ } else if (hsts_expiry) {
+ fprintf(fp, "%s %i ", host, hsts_include_subdomains);
+ urldb_write_timet(fp, hsts_expiry);
+ fprintf(fp, "0\n");
}
free(path);
@@ -478,7 +581,8 @@ static void urldb_save_search_tree(struct search_node *parent, FILE *fp)
* \param cookie_callback Callback function
* \return true to continue, false otherwise
*/
-static bool urldb_iterate_entries_path(const struct path_data *parent,
+static bool
+urldb_iterate_entries_path(const struct path_data *parent,
bool (*url_callback)(nsurl *url, const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data))
{
@@ -503,7 +607,7 @@ static bool urldb_iterate_entries_path(const struct path_data *parent,
assert(p->url);
if (!url_callback(p->url,
- (const struct url_data *) u))
+ (const struct url_data *) u))
return false;
} else {
c = (const struct cookie_data *)p->cookies;
@@ -550,8 +654,10 @@ static bool urldb__host_is_ip_address(const char *host)
#ifndef NO_IPV6
struct in6_addr ipv6;
char ipv6_addr[64];
+ unsigned int ipv6_addr_len;
#endif
- /** @todo FIXME Some parts of urldb.c make confusions between hosts
+ /**
+ * @todo FIXME Some parts of urldb.c make confusions between hosts
* and "prefixes", we can sometimes be erroneously passed more than
* just a host. Sometimes we may be passed trailing slashes, or even
* whole path segments. A specific criminal in this class is
@@ -575,8 +681,9 @@ static bool urldb__host_is_ip_address(const char *host)
char *c = strdup(host);
c[slash - host] = '\0';
sane_host = c;
- host_len = slash - host - 1;
- LOG("WARNING: called with non-host '%s'", host);
+ host_len = slash - host;
+ NSLOG(netsurf, INFO, "WARNING: called with non-host '%s'",
+ host);
}
if (strspn(sane_host, "0123456789abcdefABCDEF[].:") < host_len)
@@ -603,11 +710,18 @@ static bool urldb__host_is_ip_address(const char *host)
}
#ifndef NO_IPV6
- if (sane_host[0] != '[' || sane_host[host_len] != ']')
+ if ((host_len < 6) ||
+ (sane_host[0] != '[') ||
+ (sane_host[host_len - 1] != ']')) {
goto out_false;
+ }
- strncpy(ipv6_addr, sane_host + 1, sizeof(ipv6_addr));
- ipv6_addr[sizeof(ipv6_addr) - 1] = '\0';
+ ipv6_addr_len = host_len - 2;
+ if (ipv6_addr_len >= sizeof(ipv6_addr)) {
+ ipv6_addr_len = sizeof(ipv6_addr) - 1;
+ }
+ strncpy(ipv6_addr, sane_host + 1, ipv6_addr_len);
+ ipv6_addr[ipv6_addr_len] = '\0';
if (inet_pton(AF_INET6, ipv6_addr, &ipv6) == 1)
goto out_true;
@@ -626,8 +740,8 @@ out_true:
/**
* Compare host_part with prefix
*
- * \param a
- * \param b
+ * \param a host part
+ * \param b prefix
* \return 0 if match, non-zero, otherwise
*/
static int urldb_search_match_prefix(const struct host_part *a, const char *b)
@@ -661,12 +775,13 @@ static int urldb_search_match_prefix(const struct host_part *a, const char *b)
/* Consider segment lengths only in the case
* where the prefix contains segments */
plen = strlen(a->part);
- if (plen > dot - b)
+ if (plen > dot - b) {
/* len(a) > len(b) */
return 1;
- else if (plen < dot - b)
+ } else if (plen < dot - b) {
/* len(a) < len(b) */
return -1;
+ }
}
b = dot + 1;
@@ -677,12 +792,13 @@ static int urldb_search_match_prefix(const struct host_part *a, const char *b)
* a) The path lengths differ
* or b) The hosts are identical
*/
- if (a && a != &db_root && b >= end)
+ if (a && a != &db_root && b >= end) {
/* len(a) > len(b) => prefix matches */
return 0;
- else if ((!a || a == &db_root) && b < end)
+ } else if ((!a || a == &db_root) && b < end) {
/* len(a) < len(b) => prefix does not match */
return -1;
+ }
/* Identical */
return 0;
@@ -711,31 +827,38 @@ urldb_iterate_partial_host(struct search_node *root,
c = urldb_search_match_prefix(root->data, prefix);
- if (c > 0)
+ if (c > 0) {
/* No match => look in left subtree */
- return urldb_iterate_partial_host(root->left, prefix,
- callback);
- else if (c < 0)
+ return urldb_iterate_partial_host(root->left,
+ prefix,
+ callback);
+ } else if (c < 0) {
/* No match => look in right subtree */
- return urldb_iterate_partial_host(root->right, prefix,
- callback);
- else {
+ return urldb_iterate_partial_host(root->right,
+ prefix,
+ callback);
+ } else {
/* Match => iterate over l/r subtrees & process this node */
- if (!urldb_iterate_partial_host(root->left, prefix,
- callback))
+ if (!urldb_iterate_partial_host(root->left,
+ prefix,
+ callback)) {
return false;
+ }
if (root->data->paths.children) {
/* and extract all paths attached to this host */
if (!urldb_iterate_entries_path(&root->data->paths,
- callback, NULL)) {
+ callback,
+ NULL)) {
return false;
}
}
- if (!urldb_iterate_partial_host(root->right, prefix,
- callback))
+ if (!urldb_iterate_partial_host(root->right,
+ prefix,
+ callback)) {
return false;
+ }
}
return true;
@@ -745,54 +868,54 @@ urldb_iterate_partial_host(struct search_node *root,
/**
* Partial path iterator (internal)
*
+ * Given: http://www.example.org/a/b/c/d//e
+ * and assuming a path tree:
+ * ^
+ * / \
+ * a1 b1
+ * / \
+ * a2 b2
+ * /|\
+ * a b c
+ * 3 3 |
+ * d
+ * |
+ * e
+ * / \
+ * f g
+ *
+ * Prefix will be: p will be:
+ *
+ * a/b/c/d//e a1
+ * b/c/d//e a2
+ * b/c/d//e b3
+ * c/d//e a3
+ * c/d//e b3
+ * c/d//e c
+ * d//e d
+ * /e e (skip /)
+ * e e
+ *
+ * I.E. perform a breadth-first search of the tree.
+ *
* \param parent Root of (sub)tree to traverse
* \param prefix Prefix to match
* \param callback Callback function
* \return true to continue, false otherwise
*/
-static bool urldb_iterate_partial_path(const struct path_data *parent,
- const char *prefix, bool (*callback)(nsurl *url,
- const struct url_data *data))
+static bool
+urldb_iterate_partial_path(const struct path_data *parent,
+ const char *prefix,
+ bool (*callback)(nsurl *url, const struct url_data *data))
{
const struct path_data *p = parent->children;
const char *slash, *end = prefix + strlen(prefix);
- /*
- * Given: http://www.example.org/a/b/c/d//e
- * and assuming a path tree:
- * .
- * / \
- * a1 b1
- * / \
- * a2 b2
- * /|\
- * a b c
- * 3 3 |
- * d
- * |
- * e
- * / \
- * f g
- *
- * Prefix will be: p will be:
- *
- * a/b/c/d//e a1
- * b/c/d//e a2
- * b/c/d//e b3
- * c/d//e a3
- * c/d//e b3
- * c/d//e c
- * d//e d
- * /e e (skip /)
- * e e
- *
- * I.E. we perform a breadth-first search of the tree.
- */
-
do {
slash = strchr(prefix, '/');
- if (!slash)
+ if (!slash) {
slash = end;
+ }
if (slash == prefix && *prefix == '/') {
/* Ignore "//" */
@@ -805,9 +928,11 @@ static bool urldb_iterate_partial_path(const struct path_data *parent,
if (slash == end) {
/* we've run out of prefix, so all
* paths below this one match */
- if (!urldb_iterate_entries_path(p, callback,
- NULL))
+ if (!urldb_iterate_entries_path(p,
+ callback,
+ NULL)) {
return false;
+ }
/* Progress to next sibling */
p = p->next;
@@ -835,30 +960,37 @@ static bool urldb_iterate_partial_path(const struct path_data *parent,
* \param cookie_callback Callback function
* \return true to continue, false otherwise
*/
-static bool urldb_iterate_entries_host(struct search_node *parent,
- bool (*url_callback)(nsurl *url,
- const struct url_data *data),
+static bool
+urldb_iterate_entries_host(struct search_node *parent,
+ bool (*url_callback)(nsurl *url, const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data))
{
- if (parent == &empty)
+ if (parent == &empty) {
return true;
+ }
if (!urldb_iterate_entries_host(parent->left,
- url_callback, cookie_callback))
+ url_callback,
+ cookie_callback)) {
return false;
+ }
- if ((parent->data->paths.children) || ((cookie_callback) &&
- (parent->data->paths.cookies))) {
+ if ((parent->data->paths.children) ||
+ ((cookie_callback) &&
+ (parent->data->paths.cookies))) {
/* We have paths (or domain cookies), so iterate them */
if (!urldb_iterate_entries_path(&parent->data->paths,
- url_callback, cookie_callback)) {
+ url_callback,
+ cookie_callback)) {
return false;
}
}
if (!urldb_iterate_entries_host(parent->right,
- url_callback, cookie_callback))
+ url_callback,
+ cookie_callback)) {
return false;
+ }
return true;
}
@@ -871,16 +1003,17 @@ static bool urldb_iterate_entries_host(struct search_node *parent,
* \param parent Parent node to add to
* \return Pointer to added node, or NULL on memory exhaustion
*/
-static struct host_part *urldb_add_host_node(const char *part,
- struct host_part *parent)
+static struct host_part *
+urldb_add_host_node(const char *part, struct host_part *parent)
{
struct host_part *d;
assert(part && parent);
d = calloc(1, sizeof(struct host_part));
- if (!d)
+ if (!d) {
return NULL;
+ }
d->part = strdup(part);
if (!d->part) {
@@ -889,8 +1022,9 @@ static struct host_part *urldb_add_host_node(const char *part,
}
d->next = parent->children;
- if (parent->children)
+ if (parent->children) {
parent->children->prev = d;
+ }
d->parent = parent;
parent->children = d;
@@ -900,6 +1034,10 @@ static struct host_part *urldb_add_host_node(const char *part,
/**
* Fragment comparator callback for qsort
+ *
+ * \param a first value
+ * \param b second value
+ * \return 0 for equal else positive or negative value on comparison
*/
static int urldb_add_path_fragment_cmp(const void *a, const void *b)
{
@@ -928,13 +1066,13 @@ urldb_add_path_fragment(struct path_data *segment, lwc_string *fragment)
return segment;
temp = realloc(segment->fragment,
- (segment->frag_cnt + 1) * sizeof(char *));
+ (segment->frag_cnt + 1) * sizeof(char *));
if (!temp)
return NULL;
segment->fragment = temp;
segment->fragment[segment->frag_cnt] =
- strdup(lwc_string_data(fragment));
+ strdup(lwc_string_data(fragment));
if (!segment->fragment[segment->frag_cnt]) {
/* Don't free temp - it's now our buffer */
return NULL;
@@ -944,8 +1082,10 @@ urldb_add_path_fragment(struct path_data *segment, lwc_string *fragment)
/* We want fragments in alphabetical order, so sort them
* It may prove better to insert in alphabetical order instead */
- qsort(segment->fragment, segment->frag_cnt, sizeof (char *),
- urldb_add_path_fragment_cmp);
+ qsort(segment->fragment,
+ segment->frag_cnt,
+ sizeof (char *),
+ urldb_add_path_fragment_cmp);
return segment;
}
@@ -962,9 +1102,11 @@ urldb_add_path_fragment(struct path_data *segment, lwc_string *fragment)
* \return Pointer to added node, or NULL on memory exhaustion
*/
static struct path_data *
-urldb_add_path_node(lwc_string *scheme, unsigned int port,
- const char *segment, lwc_string *fragment,
- struct path_data *parent)
+urldb_add_path_node(lwc_string *scheme,
+ unsigned int port,
+ const char *segment,
+ lwc_string *fragment,
+ struct path_data *parent)
{
struct path_data *d, *e;
@@ -1025,7 +1167,7 @@ urldb_add_path_node(lwc_string *scheme, unsigned int port,
/**
* Get the search tree for a particular host
*
- * \param host the host to lookup
+ * \param host the host to lookup
* \return the corresponding search tree
*/
static struct search_node **urldb_get_search_tree_direct(const char *host)
@@ -1044,7 +1186,7 @@ static struct search_node **urldb_get_search_tree_direct(const char *host)
/**
* Get the search tree for a particular host
*
- * \param host the host to lookup
+ * \param host the host to lookup
* \return the corresponding search tree
*/
static struct search_node *urldb_get_search_tree(const char *host)
@@ -1054,10 +1196,10 @@ static struct search_node *urldb_get_search_tree(const char *host)
/**
- * Compare host_part with a string
+ * Compare host part with a string
*
- * \param a
- * \param b
+ * \param a host part
+ * \param b string to compare
* \return 0 if match, non-zero, otherwise
*/
static int urldb_search_match_string(const struct host_part *a, const char *b)
@@ -1089,12 +1231,13 @@ static int urldb_search_match_string(const struct host_part *a, const char *b)
/* The strings matched, now check that the lengths do, too */
plen = strlen(a->part);
- if (plen > dot - b)
+ if (plen > dot - b) {
/* len(a) > len(b) */
return 1;
- else if (plen < dot - b)
+ } else if (plen < dot - b) {
/* len(a) < len(b) */
return -1;
+ }
b = dot + 1;
a = a->parent;
@@ -1104,12 +1247,13 @@ static int urldb_search_match_string(const struct host_part *a, const char *b)
* a) The path lengths differ
* or b) The hosts are identical
*/
- if (a && a != &db_root && b >= end)
+ if (a && a != &db_root && b >= end) {
/* len(a) > len(b) */
return 1;
- else if ((!a || a == &db_root) && b < end)
+ } else if ((!a || a == &db_root) && b < end) {
/* len(a) < len(b) */
return -1;
+ }
/* Identical */
return 0;
@@ -1136,12 +1280,13 @@ urldb_search_find(struct search_node *root, const char *host)
c = urldb_search_match_string(root->data, host);
- if (c > 0)
+ if (c > 0) {
return urldb_search_find(root->left, host);
- else if (c < 0)
+ } else if (c < 0) {
return urldb_search_find(root->right, host);
- else
- return root->data;
+ }
+
+ return root->data;
}
@@ -1154,8 +1299,11 @@ urldb_search_find(struct search_node *root, const char *host)
* \param port The port associated with the path
* \return Pointer to path data or NULL if not found.
*/
-static struct path_data *urldb_match_path(const struct path_data *parent,
- const char *path, lwc_string *scheme, unsigned short port)
+static struct path_data *
+urldb_match_path(const struct path_data *parent,
+ const char *path,
+ lwc_string *scheme,
+ unsigned short port)
{
const struct path_data *p;
const char *slash;
@@ -1165,7 +1313,7 @@ static struct path_data *urldb_match_path(const struct path_data *parent,
assert(parent->segment == NULL);
if (path[0] != '/') {
- LOG("path is %s", path);
+ NSLOG(netsurf, INFO, "path is %s", path);
}
assert(path[0] == '/');
@@ -1175,14 +1323,14 @@ static struct path_data *urldb_match_path(const struct path_data *parent,
while (p != NULL) {
slash = strchr(path + 1, '/');
- if (!slash)
+ if (!slash) {
slash = path + strlen(path);
+ }
if (strncmp(p->segment, path + 1, slash - path - 1) == 0 &&
- lwc_string_isequal(p->scheme, scheme, &match) ==
- lwc_error_ok &&
- match == true &&
- p->port == port) {
+ lwc_string_isequal(p->scheme, scheme, &match) == lwc_error_ok &&
+ match == true &&
+ p->port == port) {
if (*slash == '\0') {
/* Complete match */
return (struct path_data *) p;
@@ -1233,7 +1381,7 @@ static struct path_data *urldb_find_url(nsurl *url)
return NULL;
if (lwc_string_isequal(scheme, corestring_lwc_mailto, &match) ==
- lwc_error_ok && match == true) {
+ lwc_error_ok && match == true) {
lwc_string_unref(scheme);
return NULL;
}
@@ -1244,7 +1392,7 @@ static struct path_data *urldb_find_url(nsurl *url)
lwc_string_unref(host);
} else if (lwc_string_isequal(scheme, corestring_lwc_file, &match) ==
- lwc_error_ok && match == true) {
+ lwc_error_ok && match == true) {
host_str = "localhost";
} else {
@@ -1260,8 +1408,7 @@ static struct path_data *urldb_find_url(nsurl *url)
}
/* generate plq (path, leaf, query) */
- if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &plq, &len) !=
- NSERROR_OK) {
+ if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &plq, &len) != NSERROR_OK) {
lwc_string_unref(scheme);
return NULL;
}
@@ -1296,12 +1443,15 @@ static void urldb_dump_paths(struct path_data *parent)
do {
if (p->segment != NULL) {
- LOG("\t%s : %u", lwc_string_data(p->scheme), p->port);
+ NSLOG(netsurf, INFO, "\t%s : %u",
+ lwc_string_data(p->scheme), p->port);
- LOG("\t\t'%s'", p->segment);
+ NSLOG(netsurf, INFO, "\t\t'%s'", p->segment);
- for (i = 0; i != p->frag_cnt; i++)
- LOG("\t\t\t#%s", p->fragment[i]);
+ for (i = 0; i != p->frag_cnt; i++) {
+ NSLOG(netsurf, INFO, "\t\t\t#%s",
+ p->fragment[i]);
+ }
}
if (p->children != NULL) {
@@ -1330,17 +1480,19 @@ static void urldb_dump_hosts(struct host_part *parent)
struct host_part *h;
if (parent->part) {
- LOG("%s", parent->part);
+ NSLOG(netsurf, INFO, "%s", parent->part);
- LOG("\t%s invalid SSL certs", parent->permit_invalid_certs ? "Permits" : "Denies");
+ NSLOG(netsurf, INFO, "\t%s invalid SSL certs",
+ parent->permit_invalid_certs ? "Permits" : "Denies");
}
/* Dump path data */
urldb_dump_paths(&parent->paths);
/* and recurse */
- for (h = parent->children; h; h = h->next)
+ for (h = parent->children; h; h = h->next) {
urldb_dump_hosts(h);
+ }
}
@@ -1357,7 +1509,7 @@ static void urldb_dump_search(struct search_node *parent, int depth)
char s[1024];
int r;
int sl = sizeof(s) - 2;
-
+
if (parent == &empty)
return;
@@ -1383,17 +1535,17 @@ static void urldb_dump_search(struct search_node *parent, int depth)
}
s[i]= 0;
- LOG("%s", s);
+ NSLOG(netsurf, INFO, "%s", s);
urldb_dump_search(parent->right, depth + 1);
}
/**
- * Compare a pair of host_parts
+ * Compare a pair of host parts
*
- * \param a
- * \param b
+ * \param a first host part
+ * \param b second host part
* \return 0 if match, non-zero, otherwise
*/
static int
@@ -1405,21 +1557,24 @@ urldb_search_match_host(const struct host_part *a, const struct host_part *b)
/* traverse up tree to root, comparing parts as we go. */
for (; a && a != &db_root && b && b != &db_root;
- a = a->parent, b = b->parent)
- if ((ret = strcasecmp(a->part, b->part)) != 0)
+ a = a->parent, b = b->parent) {
+ if ((ret = strcasecmp(a->part, b->part)) != 0) {
/* They differ => return the difference here */
return ret;
+ }
+ }
/* If we get here then either:
* a) The path lengths differ
* or b) The hosts are identical
*/
- if (a && a != &db_root && (!b || b == &db_root))
+ if (a && a != &db_root && (!b || b == &db_root)) {
/* len(a) > len(b) */
return 1;
- else if ((!a || a == &db_root) && b && b != &db_root)
+ } else if ((!a || a == &db_root) && b && b != &db_root) {
/* len(a) < len(b) */
return -1;
+ }
/* identical */
return 0;
@@ -1434,11 +1589,11 @@ urldb_search_match_host(const struct host_part *a, const struct host_part *b)
*/
static struct search_node *urldb_search_skew(struct search_node *root)
{
- struct search_node *temp;
-
assert(root);
if (root->left->level == root->level) {
+ struct search_node *temp;
+
temp = root->left;
root->left = temp->right;
temp->right = root;
@@ -1457,11 +1612,11 @@ static struct search_node *urldb_search_skew(struct search_node *root)
*/
static struct search_node *urldb_search_split(struct search_node *root)
{
- struct search_node *temp;
-
assert(root);
if (root->right->right->level == root->level) {
+ struct search_node *temp;
+
temp = root->right;
root->right = temp->left;
temp->left = root;
@@ -1493,10 +1648,10 @@ urldb_search_insert_internal(struct search_node *root, struct search_node *n)
if (c > 0) {
root->left = urldb_search_insert_internal(
- root->left, n);
+ root->left, n);
} else if (c < 0) {
root->right = urldb_search_insert_internal(
- root->right, n);
+ root->right, n);
} else {
/* exact match */
free(n);
@@ -1548,8 +1703,11 @@ urldb_search_insert(struct search_node *root, const struct host_part *data)
* \param was_quoted Whether \a v was quoted in the input
* \return true on success, false on memory exhaustion
*/
-static bool urldb_parse_avpair(struct cookie_internal_data *c, char *n,
- char *v, bool was_quoted)
+static bool
+urldb_parse_avpair(struct cookie_internal_data *c,
+ char *n,
+ char *v,
+ bool was_quoted)
{
int vlen;
@@ -1623,7 +1781,7 @@ static bool urldb_parse_avpair(struct cookie_internal_data *c, char *n,
/* do nothing */
}
- res = nsc_strntimet(datenoday, strlen(datenoday), &expires);
+ res = nsc_strntimet(datenoday, strlen(datenoday), &expires);
if (res != NSERROR_OK) {
/* assume we have an unrepresentable date =>
* force it to the maximum possible value of a
@@ -1640,8 +1798,9 @@ static bool urldb_parse_avpair(struct cookie_internal_data *c, char *n,
c->name = strdup(n);
c->value = strdup(v);
c->value_was_quoted = was_quoted;
- if (!c->name || !c->value)
+ if (!c->name || !c->value) {
return false;
+ }
}
return true;
@@ -1911,6 +2070,180 @@ urldb_parse_cookie(nsurl *url, const char **cookie)
/**
+ * Add a path to the database, creating any intermediate entries
+ *
+ * \param scheme URL scheme associated with path
+ * \param port Port number on host associated with path
+ * \param host Host tree node to attach to
+ * \param path_query Absolute path plus query to add (freed)
+ * \param fragment URL fragment, or NULL
+ * \param url URL (fragment ignored)
+ * \return Pointer to leaf node, or NULL on memory exhaustion
+ */
+static struct path_data *
+urldb_add_path(lwc_string *scheme,
+ unsigned int port,
+ const struct host_part *host,
+ char *path_query,
+ lwc_string *fragment,
+ nsurl *url)
+{
+ struct path_data *d, *e;
+ char *buf = path_query;
+ char *segment, *slash;
+ bool match;
+
+ assert(scheme && host && url);
+
+ d = (struct path_data *) &host->paths;
+
+ /* skip leading '/' */
+ segment = buf;
+ if (*segment == '/')
+ segment++;
+
+ /* Process path segments */
+ do {
+ slash = strchr(segment, '/');
+ if (!slash) {
+ /* last segment */
+ /* look for existing entry */
+ for (e = d->children; e; e = e->next)
+ if (strcmp(segment, e->segment) == 0 &&
+ lwc_string_isequal(scheme,
+ e->scheme, &match) ==
+ lwc_error_ok &&
+ match == true &&
+ e->port == port)
+ break;
+
+ d = e ? urldb_add_path_fragment(e, fragment) :
+ urldb_add_path_node(scheme, port,
+ segment, fragment, d);
+ break;
+ }
+
+ *slash = '\0';
+
+ /* look for existing entry */
+ for (e = d->children; e; e = e->next)
+ if (strcmp(segment, e->segment) == 0 &&
+ lwc_string_isequal(scheme, e->scheme,
+ &match) == lwc_error_ok &&
+ match == true &&
+ e->port == port)
+ break;
+
+ d = e ? e : urldb_add_path_node(scheme, port, segment, NULL, d);
+ if (!d)
+ break;
+
+ segment = slash + 1;
+ } while (1);
+
+ free(path_query);
+
+ if (d && !d->url) {
+ /* Insert defragmented URL */
+ if (nsurl_defragment(url, &d->url) != NSERROR_OK)
+ return NULL;
+ }
+
+ return d;
+}
+
+
+/**
+ * Add a host to the database, creating any intermediate entries
+ *
+ * \param host Hostname to add
+ * \return Pointer to leaf node, or NULL on memory exhaustion
+ */
+static struct host_part *urldb_add_host(const char *host)
+{
+ struct host_part *d = (struct host_part *) &db_root, *e;
+ struct search_node *s;
+ char buf[256]; /* 256 bytes is sufficient - domain names are
+ * limited to 255 chars. */
+ char *part;
+
+ assert(host);
+
+ if (urldb__host_is_ip_address(host)) {
+ /* Host is an IP, so simply add as TLD */
+
+ /* Check for existing entry */
+ for (e = d->children; e; e = e->next)
+ if (strcasecmp(host, e->part) == 0)
+ /* found => return it */
+ return e;
+
+ d = urldb_add_host_node(host, d);
+
+ s = urldb_search_insert(search_trees[ST_IP], d);
+ if (!s) {
+ /* failed */
+ d = NULL;
+ } else {
+ search_trees[ST_IP] = s;
+ }
+
+ return d;
+ }
+
+ /* Copy host string, so we can corrupt it */
+ strncpy(buf, host, sizeof buf);
+ buf[sizeof buf - 1] = '\0';
+
+ /* Process FQDN segments backwards */
+ do {
+ part = strrchr(buf, '.');
+ if (!part) {
+ /* last segment */
+ /* Check for existing entry */
+ for (e = d->children; e; e = e->next)
+ if (strcasecmp(buf, e->part) == 0)
+ break;
+
+ if (e) {
+ d = e;
+ } else {
+ d = urldb_add_host_node(buf, d);
+ }
+
+ /* And insert into search tree */
+ if (d) {
+ struct search_node **r;
+
+ r = urldb_get_search_tree_direct(buf);
+ s = urldb_search_insert(*r, d);
+ if (!s) {
+ /* failed */
+ d = NULL;
+ } else {
+ *r = s;
+ }
+ }
+ break;
+ }
+
+ /* Check for existing entry */
+ for (e = d->children; e; e = e->next)
+ if (strcasecmp(part + 1, e->part) == 0)
+ break;
+
+ d = e ? e : urldb_add_host_node(part + 1, d);
+ if (!d)
+ break;
+
+ *part = '\0';
+ } while (1);
+
+ return d;
+}
+
+
+/**
* Insert a cookie into the database
*
* \param c The cookie to insert
@@ -1918,8 +2251,10 @@ urldb_parse_cookie(nsurl *url, const char **cookie)
* \param url URL (sans fragment) associated with cookie
* \return true on success, false on memory exhaustion (c will be freed)
*/
-static bool urldb_insert_cookie(struct cookie_internal_data *c,
- lwc_string *scheme, nsurl *url)
+static bool
+urldb_insert_cookie(struct cookie_internal_data *c,
+ lwc_string *scheme,
+ nsurl *url)
{
struct cookie_internal_data *d;
const struct host_part *h;
@@ -1947,8 +2282,8 @@ static bool urldb_insert_cookie(struct cookie_internal_data *c,
assert(scheme != NULL);
h = urldb_search_find(
- urldb_get_search_tree(c->domain),
- c->domain);
+ urldb_get_search_tree(c->domain),
+ c->domain);
if (!h) {
h = urldb_add_host(c->domain);
@@ -1960,7 +2295,7 @@ static bool urldb_insert_cookie(struct cookie_internal_data *c,
/* find path */
p = urldb_add_path(scheme, 0, h,
- strdup(c->path), NULL, url);
+ strdup(c->path), NULL, url);
if (!p) {
urldb_free_cookie(c);
return false;
@@ -1970,8 +2305,8 @@ static bool urldb_insert_cookie(struct cookie_internal_data *c,
/* add cookie */
for (d = p->cookies; d; d = d->next) {
if (!strcmp(d->domain, c->domain) &&
- !strcmp(d->path, c->path) &&
- !strcmp(d->name, c->name))
+ !strcmp(d->path, c->path) &&
+ !strcmp(d->name, c->name))
break;
}
@@ -2035,8 +2370,12 @@ static bool urldb_insert_cookie(struct cookie_internal_data *c,
* \param buf Pointer to Pointer to buffer (updated)
* \return true on success, false on memory exhaustion
*/
-static bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
- int *used, int *alloc, char **buf)
+static bool
+urldb_concat_cookie(struct cookie_internal_data *c,
+ int version,
+ int *used,
+ int *alloc,
+ char **buf)
{
/* Combined (A)BNF for the Cookie: request header:
*
@@ -2100,10 +2439,10 @@ static bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
* We allow for the possibility that values are quoted
*/
max_len = 2 + strlen(c->name) + 1 + strlen(c->value) + 2 +
- (c->path_from_set ?
- 8 + strlen(c->path) + 2 : 0) +
- (c->domain_from_set ?
- 10 + strlen(c->domain) + 2 : 0);
+ (c->path_from_set ?
+ 8 + strlen(c->path) + 2 : 0) +
+ (c->domain_from_set ?
+ 10 + strlen(c->domain) + 2 : 0);
if (*used + max_len >= *alloc) {
char *temp = realloc(*buf, *alloc + 4096);
@@ -2144,7 +2483,7 @@ static bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
/* Value needs quoting if it contains any separator or if
* it needs preserving from the Set-Cookie header */
if (c->value_was_quoted ||
- strpbrk(c->value, separators) != NULL) {
+ strpbrk(c->value, separators) != NULL) {
sprintf(*buf + *used - 1, "\"%s\"", c->value);
*used += 1 + strlen(c->value) + 1;
} else {
@@ -2187,9 +2526,17 @@ static bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
/**
* deletes paths from a cookie.
+ *
+ * \param domain the cookie domain
+ * \param path the cookie path
+ * \param name The cookie name
+ * \param parent The url data of the cookie
*/
-static void urldb_delete_cookie_paths(const char *domain, const char *path,
- const char *name, struct path_data *parent)
+static void
+urldb_delete_cookie_paths(const char *domain,
+ const char *path,
+ const char *name,
+ struct path_data *parent)
{
struct cookie_internal_data *c;
struct path_data *p = parent;
@@ -2199,17 +2546,19 @@ static void urldb_delete_cookie_paths(const char *domain, const char *path,
do {
for (c = p->cookies; c; c = c->next) {
if (strcmp(c->domain, domain) == 0 &&
- strcmp(c->path, path) == 0 &&
- strcmp(c->name, name) == 0) {
- if (c->prev)
+ strcmp(c->path, path) == 0 &&
+ strcmp(c->name, name) == 0) {
+ if (c->prev) {
c->prev->next = c->next;
- else
+ } else {
p->cookies = c->next;
+ }
- if (c->next)
+ if (c->next) {
c->next->prev = c->prev;
- else
+ } else {
p->cookies_end = c->prev;
+ }
urldb_free_cookie(c);
@@ -2235,17 +2584,26 @@ static void urldb_delete_cookie_paths(const char *domain, const char *path,
/**
* Deletes cookie hosts and their assoicated paths
+ *
+ * \param domain the cookie domain
+ * \param path the cookie path
+ * \param name The cookie name
+ * \param parent The url data of the cookie
*/
-static void urldb_delete_cookie_hosts(const char *domain, const char *path,
- const char *name, struct host_part *parent)
+static void
+urldb_delete_cookie_hosts(const char *domain,
+ const char *path,
+ const char *name,
+ struct host_part *parent)
{
struct host_part *h;
assert(parent);
urldb_delete_cookie_paths(domain, path, name, &parent->paths);
- for (h = parent->children; h; h = h->next)
+ for (h = parent->children; h; h = h->next) {
urldb_delete_cookie_hosts(domain, path, name, h);
+ }
}
@@ -2267,9 +2625,10 @@ static void urldb_save_cookie_paths(FILE *fp, struct path_data *parent)
struct cookie_internal_data *c;
for (c = p->cookies; c != NULL; c = c->next) {
- if (c->expires == -1 || c->expires < now)
+ if (c->expires == -1 || c->expires < now) {
/* Skip expired & session cookies */
continue;
+ }
fprintf(fp,
"%d\t%s\t%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t"
@@ -2282,9 +2641,9 @@ static void urldb_save_cookie_paths(FILE *fp, struct path_data *parent)
c->no_destroy, c->name, c->value,
c->value_was_quoted,
p->scheme ? lwc_string_data(p->scheme) :
- "unused",
+ "unused",
p->url ? nsurl_access(p->url) :
- "unused",
+ "unused",
c->comment ? c->comment : "");
}
}
@@ -2350,21 +2709,19 @@ static void urldb_destroy_path_node_content(struct path_data *node)
struct cookie_internal_data *a, *b;
unsigned int i;
- if (node->url != NULL)
+ if (node->url != NULL) {
nsurl_unref(node->url);
+ }
- if (node->scheme != NULL)
+ if (node->scheme != NULL) {
lwc_string_unref(node->scheme);
+ }
free(node->segment);
for (i = 0; i < node->frag_cnt; i++)
free(node->fragment[i]);
free(node->fragment);
- if (node->thumb) {
- guit->bitmap->destroy(node->thumb);
- }
-
free(node->urld.title);
for (a = node->cookies; a; a = b) {
@@ -2513,7 +2870,7 @@ void urldb_destroy(void)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
nserror urldb_load(const char *filename)
{
#define MAXIMUM_URL_LENGTH 4096
@@ -2528,14 +2885,15 @@ nserror urldb_load(const char *filename)
assert(filename);
- LOG("Loading URL file %s", filename);
+ NSLOG(netsurf, INFO, "Loading URL file %s", filename);
if (url_bloom == NULL)
url_bloom = bloom_create(BLOOM_SIZE);
fp = fopen(filename, "r");
if (!fp) {
- LOG("Failed to open file '%s' for reading", filename);
+ NSLOG(netsurf, INFO, "Failed to open file '%s' for reading",
+ filename);
return NSERROR_NOT_FOUND;
}
@@ -2546,17 +2904,20 @@ nserror urldb_load(const char *filename)
version = atoi(s);
if (version < MIN_URL_FILE_VERSION) {
- LOG("Unsupported URL file version.");
+ NSLOG(netsurf, INFO, "Unsupported URL file version.");
fclose(fp);
return NSERROR_INVALID;
}
if (version > URL_FILE_VERSION) {
- LOG("Unknown URL file version.");
+ NSLOG(netsurf, INFO, "Unknown URL file version.");
fclose(fp);
return NSERROR_INVALID;
}
while (fgets(host, sizeof host, fp)) {
+ time_t hsts_expiry = 0;
+ int hsts_include_sub_domains = 0;
+
/* get the hostname */
length = strlen(host) - 1;
host[length] = '\0';
@@ -2574,6 +2935,25 @@ nserror urldb_load(const char *filename)
continue;
}
+ if (version >= 107) {
+ char *p = host;
+ while (*p && *p != ' ') p++;
+ while (*p && *p == ' ') { *p = '\0'; p++; }
+ hsts_include_sub_domains = (*p == '1');
+ while (*p && *p != ' ') p++;
+ while (*p && *p == ' ') p++;
+ nsc_snptimet(p, strlen(p), &hsts_expiry);
+ }
+
+ h = urldb_add_host(host);
+ if (!h) {
+ NSLOG(netsurf, INFO, "Failed adding host: '%s'", host);
+ fclose(fp);
+ return NSERROR_NOMEM;
+ }
+ h->hsts.expires = hsts_expiry;
+ h->hsts.include_sub_domains = hsts_include_sub_domains;
+
/* read number of URLs */
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
@@ -2581,17 +2961,10 @@ nserror urldb_load(const char *filename)
/* no URLs => try next host */
if (urls == 0) {
- LOG("No URLs for '%s'", host);
+ NSLOG(netsurf, INFO, "No URLs for '%s'", host);
continue;
}
- h = urldb_add_host(host);
- if (!h) {
- LOG("Failed adding host: '%s'", host);
- fclose(fp);
- return NSERROR_NOMEM;
- }
-
/* load the non-corrupt data */
for (i = 0; i < urls; i++) {
struct path_data *p = NULL;
@@ -2621,16 +2994,16 @@ nserror urldb_load(const char *filename)
s[length] = '\0';
if (!strcasecmp(host, "localhost") &&
- !strcasecmp(scheme, "file"))
+ !strcasecmp(scheme, "file"))
is_file = true;
snprintf(url, sizeof url, "%s://%s%s%s%s",
- scheme,
- /* file URLs have no host */
- (is_file ? "" : host),
- (port ? ":" : ""),
- (port ? ports : ""),
- s);
+ scheme,
+ /* file URLs have no host */
+ (is_file ? "" : host),
+ (port ? ":" : ""),
+ (port ? ports : ""),
+ s);
/* TODO: store URLs in pre-parsed state, and make
* a nsurl_load to generate the nsurl more
@@ -2638,7 +3011,8 @@ nserror urldb_load(const char *filename)
* Need a nsurl_save too.
*/
if (nsurl_create(url, &nsurl) != NSERROR_OK) {
- LOG("Failed inserting '%s'", url);
+ NSLOG(netsurf, INFO, "Failed inserting '%s'",
+ url);
fclose(fp);
return NSERROR_NOMEM;
}
@@ -2650,19 +3024,21 @@ nserror urldb_load(const char *filename)
/* Copy and merge path/query strings */
if (nsurl_get(nsurl, NSURL_PATH | NSURL_QUERY,
- &path_query, &len) != NSERROR_OK) {
- LOG("Failed inserting '%s'", url);
+ &path_query, &len) != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Failed inserting '%s'",
+ url);
fclose(fp);
return NSERROR_NOMEM;
}
scheme_lwc = nsurl_get_component(nsurl, NSURL_SCHEME);
fragment_lwc = nsurl_get_component(nsurl,
- NSURL_FRAGMENT);
+ NSURL_FRAGMENT);
p = urldb_add_path(scheme_lwc, port, h, path_query,
- fragment_lwc, nsurl);
+ fragment_lwc, nsurl);
if (!p) {
- LOG("Failed inserting '%s'", url);
+ NSLOG(netsurf, INFO, "Failed inserting '%s'",
+ url);
fclose(fp);
return NSERROR_NOMEM;
}
@@ -2676,10 +3052,13 @@ nserror urldb_load(const char *filename)
if (p)
p->urld.visits = (unsigned int)atoi(s);
- if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
+ /* entry last use time */
+ if (!fgets(s, MAXIMUM_URL_LENGTH, fp)) {
break;
- if (p)
- p->urld.last_visit = (time_t)atoi(s);
+ }
+ if (p) {
+ nsc_snptimet(s, strlen(s) - 1, &p->urld.last_visit);
+ }
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
@@ -2703,13 +3082,13 @@ nserror urldb_load(const char *filename)
}
fclose(fp);
- LOG("Successfully loaded URL file");
+ NSLOG(netsurf, INFO, "Successfully loaded URL file");
#undef MAXIMUM_URL_LENGTH
return NSERROR_OK;
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
nserror urldb_save(const char *filename)
{
FILE *fp;
@@ -2719,7 +3098,8 @@ nserror urldb_save(const char *filename)
fp = fopen(filename, "w");
if (!fp) {
- LOG("Failed to open file '%s' for writing", filename);
+ NSLOG(netsurf, INFO, "Failed to open file '%s' for writing",
+ filename);
return NSERROR_SAVE_FAILED;
}
@@ -2737,17 +3117,20 @@ nserror urldb_save(const char *filename)
/* exported interface documented in content/urldb.h */
-void urldb_set_url_persistence(nsurl *url, bool persist)
+nserror urldb_set_url_persistence(nsurl *url, bool persist)
{
struct path_data *p;
assert(url);
p = urldb_find_url(url);
- if (!p)
- return;
+ if (!p) {
+ return NSERROR_NOT_FOUND;
+ }
p->persistent = persist;
+
+ return NSERROR_OK;
}
@@ -2778,7 +3161,7 @@ bool urldb_add_url(nsurl *url)
/* Copy and merge path/query strings */
if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &path_query, &len) !=
- NSERROR_OK) {
+ NSERROR_OK) {
return false;
}
assert(path_query != NULL);
@@ -2795,7 +3178,7 @@ bool urldb_add_url(nsurl *url)
lwc_string_unref(host);
} else if (lwc_string_isequal(scheme, corestring_lwc_file, &match) ==
- lwc_error_ok && match == true) {
+ lwc_error_ok && match == true) {
host_str = "localhost";
} else {
@@ -2838,54 +3221,69 @@ bool urldb_add_url(nsurl *url)
/* exported interface documented in content/urldb.h */
-void urldb_set_url_title(nsurl *url, const char *title)
+nserror urldb_set_url_title(nsurl *url, const char *title)
{
struct path_data *p;
char *temp;
- assert(url && title);
+ assert(url);
p = urldb_find_url(url);
- if (!p)
- return;
+ if (p == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
- temp = strdup(title);
- if (!temp)
- return;
+ /* copy the parameter if necessary */
+ if (title != NULL) {
+ temp = strdup(title);
+ if (temp == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ temp = NULL;
+ }
free(p->urld.title);
p->urld.title = temp;
+
+ return NSERROR_OK;
}
/* exported interface documented in content/urldb.h */
-void urldb_set_url_content_type(nsurl *url, content_type type)
+nserror urldb_set_url_content_type(nsurl *url, content_type type)
{
struct path_data *p;
assert(url);
p = urldb_find_url(url);
- if (!p)
- return;
+ if (!p) {
+ return NSERROR_NOT_FOUND;
+ }
p->urld.type = type;
+
+ return NSERROR_OK;
}
/* exported interface documented in content/urldb.h */
-void urldb_update_url_visit_data(nsurl *url)
+nserror urldb_update_url_visit_data(nsurl *url)
{
struct path_data *p;
assert(url);
p = urldb_find_url(url);
- if (!p)
- return;
+ if (!p) {
+ return NSERROR_NOT_FOUND;
+ }
p->urld.last_visit = time(NULL);
p->urld.visits++;
+
+ return NSERROR_OK;
}
@@ -2905,7 +3303,7 @@ void urldb_reset_url_visit_data(nsurl *url)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
const struct url_data *urldb_get_url_data(nsurl *url)
{
struct path_data *p;
@@ -2938,7 +3336,7 @@ nsurl *urldb_get_url(nsurl *url)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
void urldb_set_auth_details(nsurl *url, const char *realm, const char *auth)
{
struct path_data *p, *pi;
@@ -2965,10 +3363,10 @@ void urldb_set_auth_details(nsurl *url, const char *realm, const char *auth)
/* Search if given URL belongs to a protection space we already know of. */
for (space = h->prot_space; space; space = space->next) {
if (!strcmp(space->realm, realm) &&
- lwc_string_isequal(space->scheme, p->scheme,
- &match) == lwc_error_ok &&
- match == true &&
- space->port == p->port)
+ lwc_string_isequal(space->scheme, p->scheme,
+ &match) == lwc_error_ok &&
+ match == true &&
+ space->port == p->port)
break;
}
@@ -3001,7 +3399,7 @@ void urldb_set_auth_details(nsurl *url, const char *realm, const char *auth)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
const char *urldb_get_auth_details(nsurl *url, const char *realm)
{
struct path_data *p, *p_cur, *p_top;
@@ -3051,7 +3449,7 @@ const char *urldb_get_auth_details(nsurl *url, const char *realm)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
void urldb_set_cert_permissions(nsurl *url, bool permit)
{
struct path_data *p;
@@ -3099,51 +3497,141 @@ bool urldb_get_cert_permissions(nsurl *url)
/* exported interface documented in content/urldb.h */
-bool urldb_set_thumbnail(nsurl *url, struct bitmap *bitmap)
+bool urldb_set_hsts_policy(struct nsurl *url, const char *header)
{
struct path_data *p;
+ struct host_part *h;
+ lwc_string *host;
+ time_t now = time(NULL);
+ http_strict_transport_security *sts;
+ uint32_t max_age = 0;
+ nserror error;
assert(url);
+ host = nsurl_get_component(url, NSURL_HOST);
+ if (host != NULL) {
+ if (urldb__host_is_ip_address(lwc_string_data(host))) {
+ /* Host is IP: ignore */
+ lwc_string_unref(host);
+ return true;
+ } else if (lwc_string_length(host) == 0) {
+ /* Host is blank: ignore */
+ lwc_string_unref(host);
+ return true;
+ }
+
+ lwc_string_unref(host);
+ } else {
+ /* No host part: ignore */
+ return true;
+ }
+
/* add url, in case it's missing */
urldb_add_url(url);
p = urldb_find_url(url);
- if (p == NULL) {
+ if (!p)
return false;
+
+ for (; p && p->parent; p = p->parent)
+ /* do nothing */;
+ assert(p);
+
+ h = (struct host_part *)p;
+ if (h->permit_invalid_certs) {
+ /* Transport is tainted: ignore */
+ return true;
+ }
+
+ error = http_parse_strict_transport_security(header, &sts);
+ if (error != NSERROR_OK) {
+ /* Parse failed: ignore */
+ return true;
}
- LOG("Setting bitmap on %s", nsurl_access(url));
+ h->hsts.include_sub_domains =
+ http_strict_transport_security_include_subdomains(sts);
- if ((p->thumb) && (p->thumb != bitmap)) {
- guit->bitmap->destroy(p->thumb);
+ max_age = http_strict_transport_security_max_age(sts);
+ if (max_age == 0) {
+ h->hsts.expires = 0;
+ h->hsts.include_sub_domains = false;
+ } else if ((time_t) (now + max_age) > h->hsts.expires) {
+ h->hsts.expires = now + max_age;
}
- p->thumb = bitmap;
+ http_strict_transport_security_destroy(sts);
return true;
}
/* exported interface documented in content/urldb.h */
-struct bitmap *urldb_get_thumbnail(nsurl *url)
+bool urldb_get_hsts_enabled(struct nsurl *url)
{
struct path_data *p;
+ const struct host_part *h;
+ lwc_string *host;
+ time_t now = time(NULL);
assert(url);
+ host = nsurl_get_component(url, NSURL_HOST);
+ if (host != NULL) {
+ if (urldb__host_is_ip_address(lwc_string_data(host))) {
+ /* Host is IP: not enabled */
+ lwc_string_unref(host);
+ return false;
+ } else if (lwc_string_length(host) == 0) {
+ /* Host is blank: not enabled */
+ lwc_string_unref(host);
+ return false;
+ }
+
+ lwc_string_unref(host);
+ } else {
+ /* No host part: not enabled */
+ return false;
+ }
+
+ /* The URL must exist in the db in order to find HSTS policy, since
+ * we search up the tree from the URL node, and policy from further
+ * up may also apply. */
+ urldb_add_url(url);
+
p = urldb_find_url(url);
if (!p)
- return NULL;
+ return false;
+
+ for (; p && p->parent; p = p->parent)
+ /* do nothing */;
+ assert(p);
- return p->thumb;
+ h = (const struct host_part *)p;
+
+ /* Consult record for this host */
+ if (h->hsts.expires > now) {
+ /* Not expired */
+ return true;
+ }
+
+ /* Consult parent domains */
+ for (h = h->parent; h && h != &db_root; h = h->parent) {
+ if (h->hsts.expires > now && h->hsts.include_sub_domains) {
+ /* Not expired and subdomains included */
+ return true;
+ }
+ }
+
+ return false;
}
-/* exported interface documented in content/urldb.h */
-void urldb_iterate_partial(const char *prefix,
- bool (*callback)(nsurl *url,
- const struct url_data *data))
+/* exported interface documented in netsurf/url_db.h */
+void
+urldb_iterate_partial(const char *prefix,
+ bool (*callback)(nsurl *url, const struct url_data *data))
{
char host[256];
char buf[260]; /* max domain + "www." */
@@ -3165,7 +3653,7 @@ void urldb_iterate_partial(const char *prefix,
/* if there's a slash in the input, then we can
* assume that we're looking for a path */
snprintf(host, sizeof host, "%.*s",
- (int) (slash - prefix), prefix);
+ (int) (slash - prefix), prefix);
h = urldb_search_find(tree, host);
if (!h) {
@@ -3185,7 +3673,7 @@ void urldb_iterate_partial(const char *prefix,
if (h->paths.children) {
/* Have paths, iterate them */
urldb_iterate_partial_path(&h->paths, slash + 1,
- callback);
+ callback);
}
} else {
@@ -3199,17 +3687,17 @@ void urldb_iterate_partial(const char *prefix,
/* now look for www.prefix */
snprintf(buf, sizeof buf, "www.%s", prefix);
if(!urldb_iterate_partial_host(
- search_trees[ST_DN + 'w' - 'a'],
- buf, callback))
+ search_trees[ST_DN + 'w' - 'a'],
+ buf, callback))
return;
}
}
}
-/* exported interface documented in content/urldb.h */
-void urldb_iterate_entries(bool (*callback)(nsurl *url,
- const struct url_data *data))
+/* exported interface documented in netsurf/url_db.h */
+void
+urldb_iterate_entries(bool (*callback)(nsurl *url, const struct url_data *data))
{
int i;
@@ -3217,8 +3705,10 @@ void urldb_iterate_entries(bool (*callback)(nsurl *url,
for (i = 0; i < NUM_SEARCH_TREES; i++) {
if (!urldb_iterate_entries_host(search_trees[i],
- callback, NULL))
+ callback,
+ NULL)) {
break;
+ }
}
}
@@ -3232,7 +3722,7 @@ void urldb_iterate_cookies(bool (*callback)(const struct cookie_data *data))
for (i = 0; i < NUM_SEARCH_TREES; i++) {
if (!urldb_iterate_entries_host(search_trees[i],
- NULL, callback))
+ NULL, callback))
break;
}
}
@@ -3285,7 +3775,7 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
/* Domain match host names */
if (lwc_string_isequal(host, rhost, &match) == lwc_error_ok &&
- match == false) {
+ match == false) {
const char *hptr;
const char *rptr;
const char *dot;
@@ -3294,7 +3784,7 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
/* Ensure neither host nor rhost are IP addresses */
if (urldb__host_is_ip_address(host_data) ||
- urldb__host_is_ip_address(rhost_data)) {
+ urldb__host_is_ip_address(rhost_data)) {
/* IP address, so no partial match */
lwc_string_unref(rhost);
goto error;
@@ -3342,8 +3832,8 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
/* 3 */
if (*hptr == '\0' ||
- (dot = strchr(hptr + 1, '.')) == NULL ||
- *(dot + 1) == '\0') {
+ (dot = strchr(hptr + 1, '.')) == NULL ||
+ *(dot + 1) == '\0') {
lwc_string_unref(rhost);
goto error;
}
@@ -3356,9 +3846,11 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
do {
struct cookie_internal_data *c;
- const char *suffix;
char *dot;
size_t len;
+#ifdef WITH_NSPSL
+ const char *suffix;
+#endif
c = urldb_parse_cookie(url, &cur);
if (!c) {
@@ -3377,8 +3869,8 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
/* 4.3.2:i Cookie path must be a prefix of URL path */
len = strlen(c->path);
if (len > lwc_string_length(path) ||
- strncmp(c->path, lwc_string_data(path),
- len) != 0) {
+ strncmp(c->path, lwc_string_data(path),
+ len) != 0) {
urldb_free_cookie(c);
goto error;
}
@@ -3391,7 +3883,8 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
}
suffix = nspsl_getpublicsuffix(dot);
if (suffix == NULL) {
- LOG("domain %s was a public suffix domain", dot);
+ NSLOG(netsurf, INFO,
+ "domain %s was a public suffix domain", dot);
urldb_free_cookie(c);
goto error;
}
@@ -3448,7 +3941,7 @@ bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
}
if (strcasecmp(lwc_string_data(host) + (hlen - dlen),
- domain)) {
+ domain)) {
urldb_free_cookie(c);
goto error;
}
@@ -3530,7 +4023,7 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
scheme = p->scheme;
matched_cookies = malloc(matched_cookies_size *
- sizeof(struct cookie_internal_data *));
+ sizeof(struct cookie_internal_data *));
if (!matched_cookies)
return NULL;
@@ -3539,8 +4032,8 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
if (count == matched_cookies_size) { \
struct cookie_internal_data **temp; \
temp = realloc(matched_cookies, \
- (matched_cookies_size + 20) * \
- sizeof(struct cookie_internal_data *)); \
+ (matched_cookies_size + 20) * \
+ sizeof(struct cookie_internal_data *)); \
\
if (temp == NULL) { \
free(ret); \
@@ -3587,10 +4080,10 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
continue;
if (c->secure && lwc_string_isequal(
- q->scheme,
- corestring_lwc_https,
- &match) &&
- match == false)
+ q->scheme,
+ corestring_lwc_https,
+ &match) &&
+ match == false)
/* secure cookie for insecure host.
* ignore */
continue;
@@ -3627,10 +4120,10 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
continue;
if (c->secure && lwc_string_isequal(
- q->scheme,
- corestring_lwc_https,
- &match) &&
- match == false)
+ q->scheme,
+ corestring_lwc_https,
+ &match) &&
+ match == false)
/* Secure cookie for insecure server
* => ignore */
continue;
@@ -3672,9 +4165,9 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
continue;
if (c->secure && lwc_string_isequal(p->scheme,
- corestring_lwc_https,
- &match) &&
- match == false)
+ corestring_lwc_https,
+ &match) &&
+ match == false)
/* Secure cookie for insecure server
* => ignore */
continue;
@@ -3695,7 +4188,7 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
/* Finally consider domain cookies for hosts which domain match ours */
for (h = (const struct host_part *)p; h && h != &db_root;
- h = h->parent) {
+ h = h->parent) {
for (c = h->paths.cookies; c; c = c->next) {
if (c->expires != -1 && c->expires < now)
/* cookie has expired => ignore */
@@ -3707,9 +4200,9 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
continue;
if (c->secure && lwc_string_isequal(scheme,
- corestring_lwc_https,
- &match) &&
- match == false)
+ corestring_lwc_https,
+ &match) &&
+ match == false)
/* secure cookie for insecure host. ignore */
continue;
@@ -3741,7 +4234,7 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
for (i = 0; i < count; i++) {
if (!urldb_concat_cookie(matched_cookies[i], version,
- &ret_used, &ret_alloc, &ret)) {
+ &ret_used, &ret_alloc, &ret)) {
free(ret);
free(matched_cookies);
return NULL;
@@ -3776,7 +4269,7 @@ char *urldb_get_cookie(nsurl *url, bool include_http_only)
/* exported interface documented in content/urldb.h */
void urldb_delete_cookie(const char *domain, const char *path,
- const char *name)
+ const char *name)
{
urldb_delete_cookie_hosts(domain, path, name, &db_root);
}
@@ -3794,24 +4287,24 @@ void urldb_load_cookies(const char *filename)
if (!fp)
return;
-#define FIND_T { \
- for (; *p && *p != '\t'; p++) \
- ; /* do nothing */ \
- if (p >= end) { \
- LOG("Overran input"); \
- continue; \
- } \
- *p++ = '\0'; \
-}
+#define FIND_T { \
+ for (; *p && *p != '\t'; p++) \
+ ; /* do nothing */ \
+ if (p >= end) { \
+ NSLOG(netsurf, INFO, "Overran input"); \
+ continue; \
+ } \
+ *p++ = '\0'; \
+ }
-#define SKIP_T { \
- for (; *p && *p == '\t'; p++) \
- ; /* do nothing */ \
- if (p >= end) { \
- LOG("Overran input"); \
- continue; \
- } \
-}
+#define SKIP_T { \
+ for (; *p && *p == '\t'; p++) \
+ ; /* do nothing */ \
+ if (p >= end) { \
+ NSLOG(netsurf, INFO, "Overran input"); \
+ continue; \
+ } \
+ }
while (fgets(s, sizeof s, fp)) {
char *p = s, *end = 0,
@@ -3836,8 +4329,9 @@ void urldb_load_cookies(const char *filename)
FIND_T; SKIP_T; loaded_cookie_file_version = atoi(p);
if (loaded_cookie_file_version <
- MIN_COOKIE_FILE_VERSION) {
- LOG("Unsupported Cookie file version");
+ MIN_COOKIE_FILE_VERSION) {
+ NSLOG(netsurf, INFO,
+ "Unsupported Cookie file version");
break;
}
@@ -3905,7 +4399,7 @@ void urldb_load_cookies(const char *filename)
c->no_destroy = no_destroy;
if (!(c->name && c->value && c->comment &&
- c->domain && c->path)) {
+ c->domain && c->path)) {
urldb_free_cookie(c);
break;
}
@@ -3921,7 +4415,7 @@ void urldb_load_cookies(const char *filename)
break;
}
scheme_lwc = nsurl_get_component(url_nsurl,
- NSURL_SCHEME);
+ NSURL_SCHEME);
/* And insert it into database */
if (!urldb_insert_cookie(c, scheme_lwc, url_nsurl)) {
@@ -3953,7 +4447,7 @@ void urldb_save_cookies(const char *filename)
{
FILE *fp;
int cookie_file_version = max(loaded_cookie_file_version,
- COOKIE_FILE_VERSION);
+ COOKIE_FILE_VERSION);
assert(filename);
@@ -3961,19 +4455,18 @@ void urldb_save_cookies(const char *filename)
if (!fp)
return;
- fprintf(fp, "# >%s\n", filename);
fprintf(fp, "# NetSurf cookies file.\n"
- "#\n"
- "# Lines starting with a '#' are comments, "
- "blank lines are ignored.\n"
- "#\n"
- "# All lines prior to \"Version:\t%d\" are discarded.\n"
- "#\n"
- "# Version\tDomain\tDomain from Set-Cookie\tPath\t"
- "Path from Set-Cookie\tSecure\tHTTP-Only\tExpires\tLast used\t"
- "No destroy\tName\tValue\tValue was quoted\tScheme\t"
- "URL\tComment\n",
- cookie_file_version);
+ "#\n"
+ "# Lines starting with a '#' are comments, "
+ "blank lines are ignored.\n"
+ "#\n"
+ "# All lines prior to \"Version:\t%d\" are discarded.\n"
+ "#\n"
+ "# Version\tDomain\tDomain from Set-Cookie\tPath\t"
+ "Path from Set-Cookie\tSecure\tHTTP-Only\tExpires\tLast used\t"
+ "No destroy\tName\tValue\tValue was quoted\tScheme\t"
+ "URL\tComment\n",
+ cookie_file_version);
fprintf(fp, "Version:\t%d\n", cookie_file_version);
urldb_save_cookie_hosts(fp, &db_root);
@@ -3982,172 +4475,18 @@ void urldb_save_cookies(const char *filename)
}
-/* exported interface documented in content/urldb.h */
+/* exported interface documented in netsurf/url_db.h */
void urldb_dump(void)
{
int i;
urldb_dump_hosts(&db_root);
- for (i = 0; i != NUM_SEARCH_TREES; i++)
+ for (i = 0; i != NUM_SEARCH_TREES; i++) {
urldb_dump_search(search_trees[i], 0);
-}
-
-
-/* exported interface documented in content/urldb.h */
-struct host_part *urldb_add_host(const char *host)
-{
- struct host_part *d = (struct host_part *) &db_root, *e;
- struct search_node *s;
- char buf[256]; /* 256 bytes is sufficient - domain names are
- * limited to 255 chars. */
- char *part;
-
- assert(host);
-
- if (urldb__host_is_ip_address(host)) {
- /* Host is an IP, so simply add as TLD */
-
- /* Check for existing entry */
- for (e = d->children; e; e = e->next)
- if (strcasecmp(host, e->part) == 0)
- /* found => return it */
- return e;
-
- d = urldb_add_host_node(host, d);
-
- s = urldb_search_insert(search_trees[ST_IP], d);
- if (!s) {
- /* failed */
- d = NULL;
- } else {
- search_trees[ST_IP] = s;
- }
-
- return d;
}
-
- /* Copy host string, so we can corrupt it */
- strncpy(buf, host, sizeof buf);
- buf[sizeof buf - 1] = '\0';
-
- /* Process FQDN segments backwards */
- do {
- part = strrchr(buf, '.');
- if (!part) {
- /* last segment */
- /* Check for existing entry */
- for (e = d->children; e; e = e->next)
- if (strcasecmp(buf, e->part) == 0)
- break;
-
- if (e) {
- d = e;
- } else {
- d = urldb_add_host_node(buf, d);
- }
-
- /* And insert into search tree */
- if (d) {
- struct search_node **r;
-
- r = urldb_get_search_tree_direct(buf);
- s = urldb_search_insert(*r, d);
- if (!s) {
- /* failed */
- d = NULL;
- } else {
- *r = s;
- }
- }
- break;
- }
-
- /* Check for existing entry */
- for (e = d->children; e; e = e->next)
- if (strcasecmp(part + 1, e->part) == 0)
- break;
-
- d = e ? e : urldb_add_host_node(part + 1, d);
- if (!d)
- break;
-
- *part = '\0';
- } while (1);
-
- return d;
}
-/* exported interface documented in content/urldb.h */
-struct path_data *
-urldb_add_path(lwc_string *scheme,
- unsigned int port,
- const struct host_part *host,
- char *path_query,
- lwc_string *fragment,
- nsurl *url)
-{
- struct path_data *d, *e;
- char *buf = path_query;
- char *segment, *slash;
- bool match;
-
- assert(scheme && host && url);
-
- d = (struct path_data *) &host->paths;
-
- /* skip leading '/' */
- segment = buf;
- if (*segment == '/')
- segment++;
-
- /* Process path segments */
- do {
- slash = strchr(segment, '/');
- if (!slash) {
- /* last segment */
- /* look for existing entry */
- for (e = d->children; e; e = e->next)
- if (strcmp(segment, e->segment) == 0 &&
- lwc_string_isequal(scheme,
- e->scheme, &match) ==
- lwc_error_ok &&
- match == true &&
- e->port == port)
- break;
-
- d = e ? urldb_add_path_fragment(e, fragment) :
- urldb_add_path_node(scheme, port,
- segment, fragment, d);
- break;
- }
-
- *slash = '\0';
-
- /* look for existing entry */
- for (e = d->children; e; e = e->next)
- if (strcmp(segment, e->segment) == 0 &&
- lwc_string_isequal(scheme, e->scheme,
- &match) == lwc_error_ok &&
- match == true &&
- e->port == port)
- break;
-
- d = e ? e : urldb_add_path_node(scheme, port, segment, NULL, d);
- if (!d)
- break;
-
- segment = slash + 1;
- } while (1);
- free(path_query);
- if (d && !d->url) {
- /* Insert defragmented URL */
- if (nsurl_defragment(url, &d->url) != NSERROR_OK)
- return NULL;
- }
-
- return d;
-}
diff --git a/content/urldb.h b/content/urldb.h
index 9ff3a8d37..0ad64267f 100644
--- a/content/urldb.h
+++ b/content/urldb.h
@@ -21,8 +21,8 @@
* Unified URL information database internal interface.
*/
-#ifndef _NETSURF_CONTENT_URLDB_H_
-#define _NETSURF_CONTENT_URLDB_H_
+#ifndef NETSURF_CONTENT_URLDB_H
+#define NETSURF_CONTENT_URLDB_H
#include <libwapcaplet/libwapcaplet.h>
@@ -40,8 +40,9 @@ void urldb_destroy(void);
*
* \param url Absolute URL to persist
* \param persist True to persist, false otherwise
+ * \return NSERROR_OK on success or NSERROR_NOT_FOUND if url not in database
*/
-void urldb_set_url_persistence(struct nsurl *url, bool persist);
+nserror urldb_set_url_persistence(struct nsurl *url, bool persist);
/**
@@ -58,8 +59,9 @@ bool urldb_add_url(struct nsurl *url);
*
* \param url The URL to look for
* \param title The title string to use (copied)
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
-void urldb_set_url_title(struct nsurl *url, const char *title);
+nserror urldb_set_url_title(struct nsurl *url, const char *title);
/**
@@ -67,16 +69,18 @@ void urldb_set_url_title(struct nsurl *url, const char *title);
*
* \param url The URL to look for
* \param type The type to set
+ * \return NSERROR_OK on success or NSERROR_NOT_FOUND if url not in database
*/
-void urldb_set_url_content_type(struct nsurl *url, content_type type);
+nserror urldb_set_url_content_type(struct nsurl *url, content_type type);
/**
* Update an URL's visit data
*
* \param url The URL to update
+ * \return NSERROR_OK on success or NSERROR_NOT_FOUND if url not in database
*/
-void urldb_update_url_visit_data(struct nsurl *url);
+nserror urldb_update_url_visit_data(struct nsurl *url);
/**
@@ -107,24 +111,14 @@ bool urldb_get_cert_permissions(struct nsurl *url);
/**
- * Set thumbnail for url, replacing any existing thumbnail
- *
- * \param url Absolute URL to consider
- * \param bitmap Opaque pointer to thumbnail data, or NULL to invalidate
- * \return true on sucessful setting else false
- */
-bool urldb_set_thumbnail(struct nsurl *url, struct bitmap *bitmap);
-
-
-/**
* Parse Set-Cookie header and insert cookie(s) into database
*
* \param header Header to parse, with Set-Cookie: stripped
* \param url URL being fetched
- * \param referer Referring resource, or 0 for verifiable transaction
+ * \param referrer Referring resource, or 0 for verifiable transaction
* \return true on success, false otherwise
*/
-bool urldb_set_cookie(const char *header, struct nsurl *url, struct nsurl *referer);
+bool urldb_set_cookie(const char *header, struct nsurl *url, struct nsurl *referrer);
/**
@@ -138,28 +132,21 @@ char *urldb_get_cookie(struct nsurl *url, bool include_http_only);
/**
- * Add a host to the database, creating any intermediate entries
+ * Set HSTS policy for an URL
*
- * \param host Hostname to add
- * \return Pointer to leaf node, or NULL on memory exhaustion
+ * \param url URL being fetched
+ * \param header Strict-Transport-Security header value
+ * \return true on success, false otherwise
*/
-struct host_part *urldb_add_host(const char *host);
+bool urldb_set_hsts_policy(struct nsurl *url, const char *header);
/**
- * Add a path to the database, creating any intermediate entries
- *
- * \param scheme URL scheme associated with path
- * \param port Port number on host associated with path
- * \param host Host tree node to attach to
- * \param path_query Absolute path plus query to add (freed)
- * \param fragment URL fragment, or NULL
- * \param url URL (fragment ignored)
- * \return Pointer to leaf node, or NULL on memory exhaustion
+ * Determine if HSTS policy is enabled for an URL
+ *
+ * \param url URL being fetched
+ * \return true if HSTS policy is enabled, false otherwise
*/
-struct path_data *urldb_add_path(lwc_string *scheme, unsigned int port,
- const struct host_part *host, char *path_query,
- lwc_string *fragment, struct nsurl *url);
-
+bool urldb_get_hsts_enabled(struct nsurl *url);
#endif
diff --git a/desktop/Makefile b/desktop/Makefile
index 2dcd61611..ffd932177 100644
--- a/desktop/Makefile
+++ b/desktop/Makefile
@@ -3,7 +3,7 @@
S_DESKTOP := cookie_manager.c knockout.c hotlist.c mouse.c \
plot_style.c print.c search.c searchweb.c scrollbar.c \
sslcert_viewer.c textarea.c version.c system_colour.c \
- global_history.c treeview.c
+ local_history.c global_history.c treeview.c
S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP))
diff --git a/desktop/browser.c b/desktop/browser.c
index d3648d76a..1c8aa95fa 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -56,9 +56,9 @@
#include "content/hlcache.h"
#include "content/urldb.h"
#include "css/utils.h"
-#include "render/form_internal.h"
-#include "render/html.h"
-#include "render/box.h"
+#include "html/form_internal.h"
+#include "html/html.h"
+#include "html/box.h"
#include "javascript/js.h"
#include "desktop/browser_history.h"
@@ -87,7 +87,6 @@
* \param x Updated to x-coord of top left of scrollbar widget
* \param y Updated to y-coord of top left of scrollbar widget
*/
-
static inline void browser_window_get_scrollbar_pos(struct browser_window *bw,
bool horizontal, int *x, int *y)
{
@@ -129,6 +128,7 @@ browser_window_get_name(struct browser_window *bw, const char **out_name)
return NSERROR_OK;
}
+
/* exported interface, documented in browser.h */
nserror
browser_window_set_name(struct browser_window *bw, const char *name)
@@ -153,9 +153,13 @@ browser_window_set_name(struct browser_window *bw, const char *name)
return NSERROR_OK;
}
+
/* exported interface, documented in browser.h */
-bool browser_window_redraw(struct browser_window *bw, int x, int y,
- const struct rect *clip, const struct redraw_context *ctx)
+bool
+browser_window_redraw(struct browser_window *bw,
+ int x, int y,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
{
struct redraw_context new_ctx = *ctx;
int width = 0;
@@ -164,29 +168,28 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
content_type content_type;
struct content_redraw_data data;
struct rect content_clip;
+ nserror res;
if (bw == NULL) {
- LOG("NULL browser window");
+ NSLOG(netsurf, INFO, "NULL browser window");
return false;
}
- if (bw->current_content == NULL && bw->children == NULL) {
+ if ((bw->current_content == NULL) &&
+ (bw->children == NULL)) {
/* Browser window has no content, render blank fill */
- ctx->plot->clip(clip);
- return ctx->plot->rectangle(clip->x0, clip->y0,
- clip->x1, clip->y1,
- plot_style_fill_white);
+ ctx->plot->clip(ctx, clip);
+ return (ctx->plot->rectangle(ctx, plot_style_fill_white, clip) == NSERROR_OK);
}
/* Browser window has content OR children (frames) */
-
if ((bw->window != NULL) &&
(ctx->plot->option_knockout)) {
/* Root browser window: start knockout */
knockout_plot_start(ctx, &new_ctx);
}
- new_ctx.plot->clip(clip);
+ new_ctx.plot->clip(ctx, clip);
/* Handle redraw of any browser window children */
if (bw->children) {
@@ -194,11 +197,12 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
int cur_child;
int children = bw->rows * bw->cols;
- if (bw->window != NULL)
+ if (bw->window != NULL) {
/* Root browser window; start with blank fill */
- plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0,
- clip->x1, clip->y1,
- plot_style_fill_white);
+ plot_ok &= (new_ctx.plot->rectangle(ctx,
+ plot_style_fill_white,
+ clip) == NSERROR_OK);
+ }
/* Loop through all children of bw */
for (cur_child = 0; cur_child < children; cur_child++) {
@@ -225,7 +229,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
/* Skip this frame if it lies outside clip rectangle */
if (content_clip.x0 >= content_clip.x1 ||
- content_clip.y0 >= content_clip.y1)
+ content_clip.y0 >= content_clip.y1)
continue;
/* Redraw frame */
@@ -235,10 +239,11 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
}
/* Nothing else to redraw for browser windows with children;
- * cleanup and return */
+ * cleanup and return
+ */
if (bw->window != NULL && ctx->plot->option_knockout) {
/* Root browser window: knockout end */
- knockout_plot_end();
+ knockout_plot_end(ctx);
}
return plot_ok;
@@ -254,8 +259,9 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
/* Non-HTML may not fill viewport to extents, so plot white
* background fill */
- plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0,
- clip->x1, clip->y1, plot_style_fill_white);
+ plot_ok &= (new_ctx.plot->rectangle(&new_ctx,
+ plot_style_fill_white,
+ clip) == NSERROR_OK);
}
/* Set up content redraw data */
@@ -290,7 +296,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
&content_clip, &new_ctx);
/* Back to full clip rect */
- new_ctx.plot->clip(clip);
+ new_ctx.plot->clip(&new_ctx, clip);
if (!bw->window) {
/* Render scrollbars */
@@ -298,32 +304,39 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
if (bw->scroll_x != NULL) {
browser_window_get_scrollbar_pos(bw, true,
&off_x, &off_y);
- plot_ok &= scrollbar_redraw(bw->scroll_x,
+ res = scrollbar_redraw(bw->scroll_x,
x + off_x, y + off_y, clip,
bw->scale, &new_ctx);
+ if (res != NSERROR_OK) {
+ plot_ok = false;
+ }
}
if (bw->scroll_y != NULL) {
browser_window_get_scrollbar_pos(bw, false,
&off_x, &off_y);
- plot_ok &= scrollbar_redraw(bw->scroll_y,
+ res = scrollbar_redraw(bw->scroll_y,
x + off_x, y + off_y, clip,
bw->scale, &new_ctx);
+ if (res != NSERROR_OK) {
+ plot_ok = false;
+ }
}
}
if (bw->window != NULL && ctx->plot->option_knockout) {
/* Root browser window: end knockout */
- knockout_plot_end();
+ knockout_plot_end(ctx);
}
return plot_ok;
}
+
/* exported interface, documented in browser.h */
bool browser_window_redraw_ready(struct browser_window *bw)
{
if (bw == NULL) {
- LOG("NULL browser window");
+ NSLOG(netsurf, INFO, "NULL browser window");
return false;
} else if (bw->current_content != NULL) {
/* Can't render locked contents */
@@ -333,6 +346,7 @@ bool browser_window_redraw_ready(struct browser_window *bw)
return true;
}
+
/* exported interface, documented in browser_private.h */
void browser_window_update_extent(struct browser_window *bw)
{
@@ -344,9 +358,13 @@ void browser_window_update_extent(struct browser_window *bw)
browser_window_handle_scrollbars(bw);
}
+
/* exported interface, documented in browser.h */
-void browser_window_get_position(struct browser_window *bw, bool root,
- int *pos_x, int *pos_y)
+void
+browser_window_get_position(struct browser_window *bw,
+ bool root,
+ int *pos_x,
+ int *pos_y)
{
*pos_x = 0;
*pos_y = 0;
@@ -386,6 +404,7 @@ void browser_window_get_position(struct browser_window *bw, bool root,
}
}
+
/* exported interface, documented in browser.h */
void browser_window_set_position(struct browser_window *bw, int x, int y)
{
@@ -396,28 +415,31 @@ void browser_window_set_position(struct browser_window *bw, int x, int y)
bw->x = x;
bw->y = y;
} else {
- LOG("Asked to set position of front end window.");
+ NSLOG(netsurf, INFO,
+ "Asked to set position of front end window.");
assert(0);
}
}
/* exported interface, documented in browser.h */
-void browser_window_set_drag_type(struct browser_window *bw,
- browser_drag_type type, const struct rect *rect)
+void
+browser_window_set_drag_type(struct browser_window *bw,
+ browser_drag_type type,
+ const struct rect *rect)
{
struct browser_window *top_bw = browser_window_get_root(bw);
gui_drag_type gtype;
- bw->drag_type = type;
+ bw->drag.type = type;
if (type == DRAGGING_NONE) {
- top_bw->drag_window = NULL;
+ top_bw->drag.window = NULL;
} else {
- top_bw->drag_window = bw;
+ top_bw->drag.window = bw;
switch (type) {
case DRAGGING_SELECTION:
- /* TODO: tell front end */
+ /** \todo tell front end */
return;
case DRAGGING_SCR_X:
case DRAGGING_SCR_Y:
@@ -436,7 +458,7 @@ void browser_window_set_drag_type(struct browser_window *bw,
/* exported interface, documented in browser.h */
browser_drag_type browser_window_get_drag_type(struct browser_window *bw)
{
- return bw->drag_type;
+ return bw->drag.type;
}
/* exported interface, documented in browser.h */
@@ -565,36 +587,33 @@ static void browser_window_set_selection(struct browser_window *bw,
top->selection.read_only = read_only;
}
-/* exported interface, documented in browser.h */
-void browser_window_scroll_visible(struct browser_window *bw,
- const struct rect *rect)
-{
- assert(bw != NULL);
+/**
+ * Set the scroll position of a browser window.
+ *
+ * scrolls the viewport to ensure the specified rectangle of the
+ * content is shown.
+ *
+ * \param bw window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+browser_window_set_scroll(struct browser_window *bw,
+ const struct rect *rect)
+{
if (bw->window != NULL) {
- /* Front end window */
- guit->window->scroll_visible(bw->window,
- rect->x0, rect->y0, rect->x1, rect->y1);
- } else {
- /* Core managed browser window */
- if (bw->scroll_x != NULL)
- scrollbar_set(bw->scroll_x, rect->x0, false);
- if (bw->scroll_y != NULL)
- scrollbar_set(bw->scroll_y, rect->y0, false);
+ return guit->window->set_scroll(bw->window, rect);
}
-}
-/* exported interface, documented in browser.h */
-void browser_window_set_scroll(struct browser_window *bw, int x, int y)
-{
- if (bw->window != NULL) {
- guit->window->set_scroll(bw->window, x, y);
- } else {
- if (bw->scroll_x != NULL)
- scrollbar_set(bw->scroll_x, x, false);
- if (bw->scroll_y != NULL)
- scrollbar_set(bw->scroll_y, y, false);
+ if (bw->scroll_x != NULL) {
+ scrollbar_set(bw->scroll_x, rect->x0, false);
+ }
+ if (bw->scroll_y != NULL) {
+ scrollbar_set(bw->scroll_y, rect->y0, false);
}
+
+ return NSERROR_OK;
}
/**
@@ -793,7 +812,7 @@ nserror browser_window_debug(struct browser_window *bw, enum content_debug op)
static bool slow_script(void *ctx)
{
static int count = 0;
- LOG("Continuing execution %d", count);
+ NSLOG(netsurf, INFO, "Continuing execution %d", count);
count++;
if (count > 1) {
count = 0;
@@ -868,7 +887,7 @@ nserror browser_window_create(enum browser_window_create_flags flags,
}
if (url != NULL) {
- enum browser_window_nav_flags nav_flags = BW_NAVIGATE_NONE;
+ enum browser_window_nav_flags nav_flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE;
if (flags & BW_CREATE_UNVERIFIABLE)
nav_flags |= BW_NAVIGATE_UNVERIFIABLE;
if (flags & BW_CREATE_HISTORY)
@@ -920,7 +939,7 @@ nserror browser_window_initialise_common(enum browser_window_create_flags flags,
/* window characteristics */
bw->refresh_interval = -1;
- bw->drag_type = DRAGGING_NONE;
+ bw->drag.type = DRAGGING_NONE;
bw->scroll_x = NULL;
bw->scroll_y = NULL;
@@ -928,10 +947,10 @@ nserror browser_window_initialise_common(enum browser_window_create_flags flags,
bw->focus = NULL;
/* initialise status text cache */
- bw->status_text = NULL;
- bw->status_text_len = 0;
- bw->status_match = 0;
- bw->status_miss = 0;
+ bw->status.text = NULL;
+ bw->status.text_len = 0;
+ bw->status.match = 0;
+ bw->status.miss = 0;
return NSERROR_OK;
}
@@ -964,11 +983,12 @@ browser_window_download(struct browser_window *bw,
/* no internal handler for this type, call out to frontend */
error = guit->misc->launch_url(url);
} else if (error != NSERROR_OK) {
- LOG("Failed to fetch download: %d", error);
+ NSLOG(netsurf, INFO, "Failed to fetch download: %d", error);
} else {
error = download_context_create(l, root->window);
if (error != NSERROR_OK) {
- LOG("Failed creating download context: %d", error);
+ NSLOG(netsurf, INFO,
+ "Failed creating download context: %d", error);
llcache_handle_abort(l);
llcache_handle_release(l);
}
@@ -1040,63 +1060,71 @@ static void browser_window_stop_throbber(struct browser_window *bw)
/**
* Callback for fetchcache() for browser window favicon fetches.
+ *
+ * \param c content handle of favicon
+ * \param event The event to process
+ * \param pw a context containing the browser window
+ * \return NSERROR_OK on success else appropriate error code.
*/
-static nserror browser_window_favicon_callback(hlcache_handle *c,
- const hlcache_event *event, void *pw)
+static nserror
+browser_window_favicon_callback(hlcache_handle *c,
+ const hlcache_event *event,
+ void *pw)
{
struct browser_window *bw = pw;
switch (event->type) {
case CONTENT_MSG_DONE:
- if (bw->current_favicon != NULL) {
+ if (bw->favicon.current != NULL) {
content_status status =
- content_get_status(bw->current_favicon);
+ content_get_status(bw->favicon.current);
if ((status == CONTENT_STATUS_READY) ||
(status == CONTENT_STATUS_DONE))
- content_close(bw->current_favicon);
+ content_close(bw->favicon.current);
- hlcache_handle_release(bw->current_favicon);
+ hlcache_handle_release(bw->favicon.current);
}
- bw->current_favicon = c;
- bw->loading_favicon = NULL;
+ bw->favicon.current = c;
+ bw->favicon.loading = NULL;
/* content_get_bitmap on the hlcache_handle should give
- * us the favicon bitmap at this point
+ * the favicon bitmap at this point
*/
guit->window->set_icon(bw->window, c);
break;
case CONTENT_MSG_ERROR:
+ case CONTENT_MSG_ERRORCODE:
/* clean up after ourselves */
- if (c == bw->loading_favicon)
- bw->loading_favicon = NULL;
- else if (c == bw->current_favicon) {
- bw->current_favicon = NULL;
+ if (c == bw->favicon.loading) {
+ bw->favicon.loading = NULL;
+ } else if (c == bw->favicon.current) {
+ bw->favicon.current = NULL;
}
hlcache_handle_release(c);
- if (bw->failed_favicon == false) {
+ if (bw->favicon.failed == false) {
nsurl *nsref = NULL;
nsurl *nsurl;
nserror error;
- bw->failed_favicon = true;
+ bw->favicon.failed = true;
error = nsurl_create("resource:favicon.ico", &nsurl);
if (error != NSERROR_OK) {
- LOG("Unable to create default location url");
+ NSLOG(netsurf, INFO,
+ "Unable to create default location url");
} else {
-
hlcache_handle_retrieve(nsurl,
HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref, NULL,
browser_window_favicon_callback,
bw, NULL, CONTENT_IMAGE,
- &bw->loading_favicon);
+ &bw->favicon.loading);
nsurl_unref(nsurl);
}
@@ -1110,8 +1138,18 @@ static nserror browser_window_favicon_callback(hlcache_handle *c,
return NSERROR_OK;
}
-static void browser_window_update_favicon(hlcache_handle *c,
- struct browser_window *bw, struct content_rfc5988_link *link)
+
+/**
+ * update the favicon associated with the browser window
+ *
+ * \param c the page content handle.
+ * \param bw A top level browser window.
+ * \param link A link context or NULL to attempt fallback scanning.
+ */
+static void
+browser_window_update_favicon(hlcache_handle *c,
+ struct browser_window *bw,
+ struct content_rfc5988_link *link)
{
nsurl *nsref = NULL;
nsurl *nsurl;
@@ -1125,10 +1163,10 @@ static void browser_window_update_favicon(hlcache_handle *c,
return;
/* already fetching the favicon - use that */
- if (bw->loading_favicon != NULL)
+ if (bw->favicon.loading != NULL)
return;
- bw->failed_favicon = false;
+ bw->favicon.failed = false;
if (link == NULL) {
/* Look for "icon" */
@@ -1165,11 +1203,12 @@ static void browser_window_update_favicon(hlcache_handle *c,
/* no favicon via link, try for the default location */
error = nsurl_join(nsurl, "/favicon.ico", &nsurl);
} else {
- bw->failed_favicon = true;
+ bw->favicon.failed = true;
error = nsurl_create("resource:favicon.ico", &nsurl);
}
if (error != NSERROR_OK) {
- LOG("Unable to create default location url");
+ NSLOG(netsurf, INFO,
+ "Unable to create default location url");
return;
}
} else {
@@ -1177,14 +1216,16 @@ static void browser_window_update_favicon(hlcache_handle *c,
}
if (link == NULL) {
- LOG("fetching general favicon from '%s'", nsurl_access(nsurl));
+ NSLOG(netsurf, INFO, "fetching general favicon from '%s'",
+ nsurl_access(nsurl));
} else {
- LOG("fetching favicon rel:%s '%s'", lwc_string_data(link->rel), nsurl_access(nsurl));
+ NSLOG(netsurf, INFO, "fetching favicon rel:%s '%s'",
+ lwc_string_data(link->rel), nsurl_access(nsurl));
}
hlcache_handle_retrieve(nsurl, HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref, NULL, browser_window_favicon_callback,
- bw, NULL, CONTENT_IMAGE, &bw->loading_favicon);
+ bw, NULL, CONTENT_IMAGE, &bw->favicon.loading);
nsurl_unref(nsurl);
}
@@ -1307,11 +1348,14 @@ static void browser_window_convert_to_download(struct browser_window *bw,
/**
* Browser window content event callback handler.
*/
-static nserror browser_window_callback(hlcache_handle *c,
- const hlcache_event *event, void *pw)
+static nserror
+browser_window_callback(hlcache_handle *c,
+ const hlcache_event *event,
+ void *pw)
{
struct browser_window *bw = pw;
nserror res = NSERROR_OK;
+ float sx, sy;
switch (event->type) {
case CONTENT_MSG_DOWNLOAD:
@@ -1365,19 +1409,6 @@ static nserror browser_window_callback(hlcache_handle *c,
browser_window_get_dimensions(bw, &width, &height, true);
content_reformat(c, false, width, height);
- browser_window_remove_caret(bw, false);
-
- if (bw->window != NULL) {
- guit->window->new_content(bw->window);
-
- browser_window_refresh_url_bar(bw);
- }
-
- /* new content; set scroll_to_top */
- browser_window_update(bw, true);
- content_open(c, bw, 0, 0);
- browser_window_set_status(bw, content_get_status_message(c));
-
/* history */
if (bw->history_add && bw->history) {
nsurl *url = hlcache_handle_get_url(c);
@@ -1410,10 +1441,27 @@ static nserror browser_window_callback(hlcache_handle *c,
* all newly visited URLs. With the history_add call
* after, we only leak the thumbnails when urldb does
* not add the URL.
+ *
+ * Also, since browser_window_history_add can create
+ * a thumbnail (content_redraw), we need to do it after
+ * content_reformat.
*/
browser_window_history_add(bw, c, bw->frag_id);
}
+ browser_window_remove_caret(bw, false);
+
+ if (bw->window != NULL) {
+ guit->window->new_content(bw->window);
+
+ browser_window_refresh_url_bar(bw);
+ }
+
+ /* new content; set scroll_to_top */
+ browser_window_update(bw, true);
+ content_open(c, bw, 0, 0);
+ browser_window_set_status(bw, content_get_status_message(c));
+
/* frames */
if ((content_get_type(c) == CONTENT_HTML) &&
(html_get_frameset(c) != NULL)) {
@@ -1442,6 +1490,19 @@ static nserror browser_window_callback(hlcache_handle *c,
browser_window_stop_throbber(bw);
browser_window_update_favicon(c, bw, NULL);
+ if (browser_window_history_get_scroll(bw, &sx, &sy) == NSERROR_OK) {
+ int scrollx = (int)((float)content_get_width(bw->current_content) * sx);
+ int scrolly = (int)((float)content_get_height(bw->current_content) * sy);
+ struct rect rect;
+ rect.x0 = rect.x1 = scrollx;
+ rect.y0 = rect.y1 = scrolly;
+ if (browser_window_set_scroll(bw, &rect) != NSERROR_OK) {
+ NSLOG(netsurf, WARNING,
+ "Unable to set browser scroll offsets to %d by %d",
+ scrollx, scrolly);
+ }
+ }
+
browser_window_history_update(bw, c);
hotlist_update_url(hlcache_handle_get_url(c));
@@ -1571,25 +1632,28 @@ static nserror browser_window_callback(hlcache_handle *c,
break;
case CONTENT_MSG_SCROLL:
+ {
+ struct rect rect = {
+ .x0 = event->data.scroll.x0,
+ .y0 = event->data.scroll.y0,
+ };
+
/* Content wants to be scrolled */
- if (bw->current_content != c)
+ if (bw->current_content != c) {
break;
+ }
if (event->data.scroll.area) {
- struct rect rect = {
- .x0 = event->data.scroll.x0,
- .y0 = event->data.scroll.y0,
- .x1 = event->data.scroll.x1,
- .y1 = event->data.scroll.y1
- };
- browser_window_scroll_visible(bw, &rect);
+ rect.x1 = event->data.scroll.x1;
+ rect.y1 = event->data.scroll.y1;
} else {
- browser_window_set_scroll(bw,
- event->data.scroll.x0,
- event->data.scroll.y0);
+ rect.x1 = event->data.scroll.x0;
+ rect.y1 = event->data.scroll.y0;
}
+ browser_window_set_scroll(bw, &rect);
break;
+ }
case CONTENT_MSG_DRAGSAVE:
{
@@ -1742,6 +1806,27 @@ static void browser_window_destroy_children(struct browser_window *bw)
/**
+ * internal scheduled reformat callback.
+ *
+ * scheduled reformat callback to allow reformats from unthreaded context.
+ *
+ * \param vbw The browser window to be reformatted
+ */
+static void scheduled_reformat(void *vbw)
+{
+ struct browser_window *bw = vbw;
+ int width;
+ int height;
+ nserror res;
+
+ res = guit->window->get_dimensions(bw->window, &width, &height, false);
+ if (res == NSERROR_OK) {
+ browser_window_reformat(bw, false, width, height);
+ }
+}
+
+
+/**
* Release all memory associated with a browser window.
*
* \param bw browser window
@@ -1750,7 +1835,7 @@ static void browser_window_destroy_internal(struct browser_window *bw)
{
assert(bw);
- LOG("Destroying window");
+ NSLOG(netsurf, INFO, "Destroying window");
if (bw->children != NULL || bw->iframes != NULL) {
browser_window_destroy_children(bw);
@@ -1770,8 +1855,9 @@ static void browser_window_destroy_internal(struct browser_window *bw)
/* The ugly cast here is so the reformat function can be
* passed a gui window pointer in its API rather than void*
*/
- LOG("Clearing schedule %p(%p)", guit->window->reformat, bw->window);
- guit->misc->schedule(-1, (void(*)(void*))guit->window->reformat, bw->window);
+ NSLOG(netsurf, INFO,
+ "Clearing reformat schedule for browser window %p", bw);
+ guit->misc->schedule(-1, scheduled_reformat, bw);
/* If this brower window is not the root window, and has focus, unset
* the root browser window's focus pointer. */
@@ -1812,21 +1898,22 @@ static void browser_window_destroy_internal(struct browser_window *bw)
bw->current_content = NULL;
}
- if (bw->loading_favicon != NULL) {
- hlcache_handle_abort(bw->loading_favicon);
- hlcache_handle_release(bw->loading_favicon);
- bw->loading_favicon = NULL;
+ if (bw->favicon.loading != NULL) {
+ hlcache_handle_abort(bw->favicon.loading);
+ hlcache_handle_release(bw->favicon.loading);
+ bw->favicon.loading = NULL;
}
- if (bw->current_favicon != NULL) {
- content_status status = content_get_status(bw->current_favicon);
+ if (bw->favicon.current != NULL) {
+ content_status status = content_get_status(bw->favicon.current);
if (status == CONTENT_STATUS_READY ||
- status == CONTENT_STATUS_DONE)
- content_close(bw->current_favicon);
+ status == CONTENT_STATUS_DONE) {
+ content_close(bw->favicon.current);
+ }
- hlcache_handle_release(bw->current_favicon);
- bw->current_favicon = NULL;
+ hlcache_handle_release(bw->favicon.current);
+ bw->favicon.current = NULL;
}
if (bw->box != NULL) {
@@ -1840,15 +1927,17 @@ static void browser_window_destroy_internal(struct browser_window *bw)
/* These simply free memory, so are safe here */
- if (bw->frag_id != NULL)
+ if (bw->frag_id != NULL) {
lwc_string_unref(bw->frag_id);
+ }
browser_window_history_destroy(bw);
free(bw->name);
- free(bw->status_text);
- bw->status_text = NULL;
- LOG("Status text cache match:miss %d:%d", bw->status_match, bw->status_miss);
+ free(bw->status.text);
+ bw->status.text = NULL;
+ NSLOG(netsurf, INFO, "Status text cache match:miss %d:%d",
+ bw->status.match, bw->status.miss);
}
/**
@@ -1920,7 +2009,8 @@ nserror browser_window_refresh_url_bar(struct browser_window *bw)
/* exported interface documented in netsurf/browser_window.h */
-nserror browser_window_navigate(struct browser_window *bw,
+nserror
+browser_window_navigate(struct browser_window *bw,
nsurl *url,
nsurl *referrer,
enum browser_window_nav_flags flags,
@@ -1940,14 +2030,28 @@ nserror browser_window_navigate(struct browser_window *bw,
assert(bw);
assert(url);
- LOG("bw %p, url %s", bw, nsurl_access(url));
+ NSLOG(netsurf, INFO, "bw %p, url %s", bw, nsurl_access(url));
+
+ /* If we're navigating and we have a history entry and a content
+ * then update the history entry before we navigate to save our
+ * current state. However since history navigation pre-moves
+ * the history state, we ensure that we only do this if we've not
+ * been suppressed. In the suppressed case, the history code
+ * updates the history itself before navigating.
+ */
+ if (bw->current_content != NULL &&
+ bw->history != NULL &&
+ bw->history->current != NULL &&
+ !(flags & BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE)) {
+ browser_window_history_update(bw, bw->current_content);
+ }
/* don't allow massively nested framesets */
for (cur = bw; cur->parent; cur = cur->parent) {
depth++;
}
if (depth > FRAME_DEPTH) {
- LOG("frame depth too high.");
+ NSLOG(netsurf, INFO, "frame depth too high.");
return NSERROR_FRAME_DEPTH;
}
@@ -2039,7 +2143,7 @@ nserror browser_window_navigate(struct browser_window *bw,
browser_window_remove_caret(bw, false);
browser_window_destroy_children(bw);
- LOG("Loading '%s'", nsurl_access(url));
+ NSLOG(netsurf, INFO, "Loading '%s'", nsurl_access(url));
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = (flags & BW_NAVIGATE_HISTORY);
@@ -2121,7 +2225,7 @@ nserror browser_window_navigate_up(struct browser_window *bw, bool new_window)
if (bw == NULL)
return NSERROR_BAD_PARAMETER;
- current = browser_window_get_url(bw);
+ current = browser_window_access_url(bw);
err = nsurl_parent(current, &parent);
if (err != NSERROR_OK) {
@@ -2147,8 +2251,8 @@ nserror browser_window_navigate_up(struct browser_window *bw, bool new_window)
}
-/* Exported interface, documented in browser.h */
-nsurl* browser_window_get_url(struct browser_window *bw)
+/* Exported interface, documented in include/netsurf/browser_window.h */
+nsurl* browser_window_access_url(struct browser_window *bw)
{
assert(bw != NULL);
@@ -2163,6 +2267,36 @@ nsurl* browser_window_get_url(struct browser_window *bw)
return corestring_nsurl_about_blank;
}
+/* Exported interface, documented in include/netsurf/browser_window.h */
+nserror browser_window_get_url(
+ struct browser_window *bw,
+ bool fragment,
+ nsurl** url_out)
+{
+ nserror err;
+ nsurl *url;
+
+ assert(bw != NULL);
+
+ if (!fragment || bw->frag_id == NULL || bw->loading_content != NULL) {
+ /* If there's a loading content, then the bw->frag_id will have
+ * been trampled, possibly with a new frag_id, but we will
+ * still be returning the current URL, so in this edge case
+ * we just drop any fragment. */
+ url = nsurl_ref(browser_window_access_url(bw));
+
+ } else {
+ err = nsurl_refragment(browser_window_access_url(bw),
+ bw->frag_id, &url);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ }
+
+ *url_out = url;
+ return NSERROR_OK;
+}
+
/* Exported interface, documented in browser.h */
const char* browser_window_get_title(struct browser_window *bw)
{
@@ -2255,19 +2389,60 @@ void browser_window_set_dimensions(struct browser_window *bw,
bw->width = width;
bw->height = height;
} else {
- LOG("Asked to set dimensions of front end window.");
+ NSLOG(netsurf, INFO,
+ "Asked to set dimensions of front end window.");
assert(0);
}
}
+/**
+ * scroll to a fragment if present
+ *
+ * \param bw browser window
+ * \return true if the scroll was sucessful
+ */
+static bool frag_scroll(struct browser_window *bw)
+{
+ struct rect rect;
+
+ if (bw->frag_id == NULL) {
+ return false;
+ }
+
+ if (!html_get_id_offset(bw->current_content,
+ bw->frag_id,
+ &rect.x0,
+ &rect.y0)) {
+ return false;
+ }
+
+ rect.x1 = rect.x0;
+ rect.y1 = rect.y0;
+ if (browser_window_set_scroll(bw, &rect) == NSERROR_OK) {
+ if (bw->current_content != NULL &&
+ bw->history != NULL &&
+ bw->history->current != NULL) {
+ browser_window_history_update(bw, bw->current_content);
+ }
+ return true;
+ }
+ return false;
+}
+
/* Exported interface, documented in browser.h */
void browser_window_update(struct browser_window *bw, bool scroll_to_top)
{
- int x, y;
+ static const struct rect zrect = {
+ .x0 = 0,
+ .y0 = 0,
+ .x1 = 0,
+ .y1 = 0
+ };
- if (bw->current_content == NULL)
+ if (bw->current_content == NULL) {
return;
+ }
switch (bw->browser_window_type) {
@@ -2278,17 +2453,15 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
browser_window_update_extent(bw);
- if (scroll_to_top)
- browser_window_set_scroll(bw, 0, 0);
-
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
- if (bw->frag_id && html_get_id_offset(bw->current_content,
- bw->frag_id, &x, &y)) {
- browser_window_set_scroll(bw, x, y);
+ if (!frag_scroll(bw)) {
+ if (scroll_to_top) {
+ browser_window_set_scroll(bw, &zrect);
+ }
}
- guit->window->redraw(bw->window);
+ guit->window->invalidate(bw->window, NULL);
break;
@@ -2299,15 +2472,13 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
browser_window_update_extent(bw);
- if (scroll_to_top)
- browser_window_set_scroll(bw, 0, 0);
+ if (scroll_to_top) {
+ browser_window_set_scroll(bw, &zrect);
+ }
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
- if (bw->frag_id && html_get_id_offset(bw->current_content,
- bw->frag_id, &x, &y)) {
- browser_window_set_scroll(bw, x, y);
- }
+ frag_scroll(bw);
html_redraw_a_box(bw->parent->current_content, bw->box);
break;
@@ -2317,15 +2488,13 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
struct rect rect;
browser_window_update_extent(bw);
- if (scroll_to_top)
- browser_window_set_scroll(bw, 0, 0);
+ if (scroll_to_top) {
+ browser_window_set_scroll(bw, &zrect);
+ }
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
- if (bw->frag_id && html_get_id_offset(bw->current_content,
- bw->frag_id, &x, &y)) {
- browser_window_set_scroll(bw, x, y);
- }
+ frag_scroll(bw);
rect.x0 = scrollbar_get_offset(bw->scroll_x);
rect.y0 = scrollbar_get_offset(bw->scroll_y);
@@ -2354,7 +2523,7 @@ void browser_window_update_box(struct browser_window *bw, struct rect *rect)
if (bw->window != NULL) {
/* Front end window */
- guit->window->update(bw->window, rect);
+ guit->window->invalidate(bw->window, rect);
} else {
/* Core managed browser window */
browser_window_get_position(bw, true, &pos_x, &pos_y);
@@ -2366,7 +2535,7 @@ void browser_window_update_box(struct browser_window *bw, struct rect *rect)
rect->x1 += pos_x / bw->scale;
rect->y1 += pos_y / bw->scale;
- guit->window->update(top->window, rect);
+ guit->window->invalidate(top->window, rect);
}
}
@@ -2465,10 +2634,10 @@ void browser_window_set_status(struct browser_window *bw, const char *text)
while (bw->parent)
bw = bw->parent;
- if ((bw->status_text != NULL) &&
- (strcmp(text, bw->status_text) == 0)) {
+ if ((bw->status.text != NULL) &&
+ (strcmp(text, bw->status.text) == 0)) {
/* status text is unchanged */
- bw->status_match++;
+ bw->status.match++;
return;
}
@@ -2476,18 +2645,18 @@ void browser_window_set_status(struct browser_window *bw, const char *text)
text_len = strlen(text);
- if ((bw->status_text == NULL) || (bw->status_text_len < text_len)) {
+ if ((bw->status.text == NULL) || (bw->status.text_len < text_len)) {
/* no current string allocation or it is not long enough */
- free(bw->status_text);
- bw->status_text = strdup(text);
- bw->status_text_len = text_len;
+ free(bw->status.text);
+ bw->status.text = strdup(text);
+ bw->status.text_len = text_len;
} else {
/* current allocation has enough space */
- memcpy(bw->status_text, text, text_len + 1);
+ memcpy(bw->status.text, text, text_len + 1);
}
- bw->status_miss++;
- guit->window->set_status(bw->window, bw->status_text);
+ bw->status.miss++;
+ guit->window->set_status(bw->window, bw->status.text);
}
@@ -2530,13 +2699,16 @@ void browser_window_set_pointer(struct browser_window *bw,
guit->window->set_pointer(root->window, gui_shape);
}
+
/* exported function documented in netsurf/browser_window.h */
nserror browser_window_schedule_reformat(struct browser_window *bw)
{
- /* The ugly cast here is so the reformat function can be
- * passed a gui window pointer in its API rather than void*
- */
- guit->misc->schedule(0, (void(*)(void*))guit->window->reformat, bw->window);
+ if (bw->window == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ guit->misc->schedule(0, scheduled_reformat, bw);
+
return NSERROR_OK;
}
@@ -2837,7 +3009,7 @@ static void browser_window_mouse_drag_end(struct browser_window *bw,
{
int scr_x, scr_y;
- switch (bw->drag_type) {
+ switch (bw->drag.type) {
case DRAGGING_SELECTION:
case DRAGGING_OTHER:
case DRAGGING_CONTENT_SCROLLBAR:
@@ -2853,7 +3025,7 @@ static void browser_window_mouse_drag_end(struct browser_window *bw,
scrollbar_mouse_drag_end(bw->scroll_x, mouse, scr_x, scr_y);
- bw->drag_type = DRAGGING_NONE;
+ bw->drag.type = DRAGGING_NONE;
break;
case DRAGGING_SCR_Y:
@@ -2865,7 +3037,7 @@ static void browser_window_mouse_drag_end(struct browser_window *bw,
scrollbar_mouse_drag_end(bw->scroll_y, mouse, scr_x, scr_y);
- bw->drag_type = DRAGGING_NONE;
+ bw->drag.type = DRAGGING_NONE;
break;
default:
@@ -2883,11 +3055,11 @@ void browser_window_mouse_track(struct browser_window *bw,
const char *status = NULL;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
- if (bw->window != NULL && bw->drag_window && bw != bw->drag_window) {
+ if (bw->window != NULL && bw->drag.window && bw != bw->drag.window) {
/* This is the root browser window and there's an active drag
* in a sub window.
* Pass the mouse action straight on to that bw. */
- struct browser_window *drag_bw = bw->drag_window;
+ struct browser_window *drag_bw = bw->drag.window;
int off_x = 0;
int off_y = 0;
@@ -2940,25 +3112,27 @@ void browser_window_mouse_track(struct browser_window *bw,
return;
}
- if (c == NULL && bw->drag_type != DRAGGING_FRAME)
+ if (c == NULL && bw->drag.type != DRAGGING_FRAME) {
return;
+ }
- if (bw->drag_type != DRAGGING_NONE && !mouse) {
+ if (bw->drag.type != DRAGGING_NONE && !mouse) {
browser_window_mouse_drag_end(bw, mouse, x, y);
}
/* Browser window's horizontal scrollbar */
- if (bw->scroll_x != NULL && bw->drag_type != DRAGGING_SCR_Y) {
+ if (bw->scroll_x != NULL && bw->drag.type != DRAGGING_SCR_Y) {
int scr_x, scr_y;
browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
- if ((scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw,
- true) &&
- scr_y > 0 && scr_y < SCROLLBAR_WIDTH &&
- bw->drag_type == DRAGGING_NONE) ||
- bw->drag_type == DRAGGING_SCR_X) {
+ if ((bw->drag.type == DRAGGING_SCR_X) ||
+ (scr_x > 0 &&
+ scr_x < browser_window_get_scrollbar_len(bw, true) &&
+ scr_y > 0 &&
+ scr_y < SCROLLBAR_WIDTH &&
+ bw->drag.type == DRAGGING_NONE)) {
/* Start a scrollbar drag, or continue existing drag */
status = scrollbar_mouse_status_to_message(
scrollbar_mouse_action(
@@ -2966,8 +3140,9 @@ void browser_window_mouse_track(struct browser_window *bw,
scr_x, scr_y));
pointer = BROWSER_POINTER_DEFAULT;
- if (status != NULL)
+ if (status != NULL) {
browser_window_set_status(bw, status);
+ }
browser_window_set_pointer(bw, pointer);
return;
@@ -2981,11 +3156,12 @@ void browser_window_mouse_track(struct browser_window *bw,
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
- if ((scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw,
- false) &&
- scr_x > 0 && scr_x < SCROLLBAR_WIDTH &&
- bw->drag_type == DRAGGING_NONE) ||
- bw->drag_type == DRAGGING_SCR_Y) {
+ if ((bw->drag.type == DRAGGING_SCR_Y) ||
+ (scr_y > 0 &&
+ scr_y < browser_window_get_scrollbar_len(bw, false) &&
+ scr_x > 0 &&
+ scr_x < SCROLLBAR_WIDTH &&
+ bw->drag.type == DRAGGING_NONE)) {
/* Start a scrollbar drag, or continue existing drag */
status = scrollbar_mouse_status_to_message(
scrollbar_mouse_action(
@@ -2993,29 +3169,32 @@ void browser_window_mouse_track(struct browser_window *bw,
scr_x, scr_y));
pointer = BROWSER_POINTER_DEFAULT;
- if (status != NULL)
+ if (status != NULL) {
browser_window_set_status(bw, status);
+ }
browser_window_set_pointer(bw, pointer);
return;
}
}
- if (bw->drag_type == DRAGGING_FRAME) {
+ if (bw->drag.type == DRAGGING_FRAME) {
browser_window_resize_frame(bw, bw->x + x, bw->y + y);
- } else if (bw->drag_type == DRAGGING_PAGE_SCROLL) {
+ } else if (bw->drag.type == DRAGGING_PAGE_SCROLL) {
/* mouse movement since drag started */
- int scrollx = bw->drag_start_x - x;
- int scrolly = bw->drag_start_y - y;
+ struct rect rect;
+
+ rect.x0 = bw->drag.start_x - x;
+ rect.y0 = bw->drag.start_y - y;
/* new scroll offsets */
- scrollx += bw->drag_start_scroll_x;
- scrolly += bw->drag_start_scroll_y;
+ rect.x0 += bw->drag.start_scroll_x;
+ rect.y0 += bw->drag.start_scroll_y;
- bw->drag_start_scroll_x = scrollx;
- bw->drag_start_scroll_y = scrolly;
+ bw->drag.start_scroll_x = rect.x1 = rect.x0;
+ bw->drag.start_scroll_y = rect.y1 = rect.y0;
- browser_window_set_scroll(bw, scrollx, scrolly);
+ browser_window_set_scroll(bw, &rect);
} else {
assert(c != NULL);
content_mouse_track(c, bw, mouse, x, y);
@@ -3163,19 +3342,20 @@ void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
browser_window_set_drag_type(bw, DRAGGING_PAGE_SCROLL, NULL);
- bw->drag_start_x = x;
- bw->drag_start_y = y;
+ bw->drag.start_x = x;
+ bw->drag.start_y = y;
if (bw->window != NULL) {
/* Front end window */
- guit->window->get_scroll(bw->window, &bw->drag_start_scroll_x,
- &bw->drag_start_scroll_y);
+ guit->window->get_scroll(bw->window,
+ &bw->drag.start_scroll_x,
+ &bw->drag.start_scroll_y);
guit->window->scroll_start(bw->window);
} else {
/* Core managed browser window */
- bw->drag_start_scroll_x = scrollbar_get_offset(bw->scroll_x);
- bw->drag_start_scroll_y = scrollbar_get_offset(bw->scroll_y);
+ bw->drag.start_scroll_x = scrollbar_get_offset(bw->scroll_x);
+ bw->drag.start_scroll_y = scrollbar_get_offset(bw->scroll_y);
}
}
diff --git a/desktop/browser_history.c b/desktop/browser_history.c
index d21c5bc25..d9db0eb18 100644
--- a/desktop/browser_history.c
+++ b/desktop/browser_history.c
@@ -31,13 +31,12 @@
#include "utils/log.h"
#include "utils/utils.h"
#include "netsurf/layout.h"
-#include "netsurf/plotters.h"
#include "netsurf/content.h"
+#include "netsurf/window.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "netsurf/bitmap.h"
-#include "desktop/system_colour.h"
#include "desktop/gui_internal.h"
#include "desktop/browser_history.h"
#include "desktop/browser_private.h"
@@ -47,45 +46,12 @@
#define RIGHT_MARGIN 50
#define BOTTOM_MARGIN 30
-struct history_page {
- nsurl *url; /**< Page URL, never 0. */
- lwc_string *frag_id; /** Fragment identifier, or 0. */
- char *title; /**< Page title, never 0. */
-};
-
-/** A node in the history tree. */
-struct history_entry {
- struct history_page page;
- struct history_entry *back; /**< Parent. */
- struct history_entry *next; /**< Next sibling. */
- struct history_entry *forward; /**< First child. */
- struct history_entry *forward_pref; /**< Child in direction of
- current entry. */
- struct history_entry *forward_last; /**< Last child. */
- unsigned int children; /**< Number of children. */
- int x; /**< Position of node. */
- int y; /**< Position of node. */
- struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */
-};
-
-/** History tree for a window. */
-struct history {
- /** First page in tree (page that window opened with). */
- struct history_entry *start;
- /** Current position in tree. */
- struct history_entry *current;
- /** Width of layout. */
- int width;
- /** Height of layout. */
- int height;
-};
-
/**
* Clone a history entry
*
* \param history opaque history structure, as returned by history_create()
- * \param entry entry to clone
+ * \param entry entry to clone
* \return A cloned history entry or NULL on error
*/
static struct history_entry *
@@ -97,47 +63,85 @@ browser_window_history__clone_entry(struct history *history,
struct history_entry *prev = NULL;
struct history_entry *new_entry;
+ assert(entry);
assert(entry->page.url);
assert(entry->page.title);
/* clone the entry */
- new_entry = malloc(sizeof *entry);
- if (!new_entry)
+ new_entry = calloc(1, sizeof *entry);
+ if (!new_entry) {
return NULL;
+ }
- memcpy(new_entry, entry, sizeof *entry);
- new_entry->page.url = nsurl_ref(entry->page.url);
- if (entry->page.frag_id)
- new_entry->page.frag_id = lwc_string_ref(entry->page.frag_id);
-
+ /* copy page information */
new_entry->page.title = strdup(entry->page.title);
- if (!new_entry->page.url || !new_entry->page.title ||
- ((entry->page.frag_id) && (!new_entry->page.frag_id))) {
- nsurl_unref(new_entry->page.url);
- if (new_entry->page.frag_id)
- lwc_string_unref(new_entry->page.frag_id);
+ if (new_entry->page.title == NULL) {
+ free(new_entry);
+ return NULL;
+ }
+
+ new_entry->page.url = nsurl_ref(entry->page.url);
+ if (new_entry->page.url == NULL) {
free(new_entry->page.title);
free(new_entry);
return NULL;
}
- /* update references */
- if (history->current == entry)
- history->current = new_entry;
+ if (entry->page.frag_id == NULL) {
+ new_entry->page.frag_id = NULL;
+ } else {
+ new_entry->page.frag_id = lwc_string_ref(entry->page.frag_id);
+ if (new_entry->page.frag_id == NULL) {
+ nsurl_unref(new_entry->page.url);
+ free(new_entry);
+ return NULL;
+ }
+ }
+
+ if (entry->page.bitmap == NULL) {
+ new_entry->page.bitmap = NULL;
+ } else {
+ /* create a new bitmap and copy original into it */
+ unsigned char *bmsrc_data;
+ unsigned char *bmdst_data;
+ size_t bmsize;
+
+ new_entry->page.bitmap = guit->bitmap->create(WIDTH, HEIGHT,
+ BITMAP_NEW | BITMAP_OPAQUE);
+
+ if (new_entry->page.bitmap != NULL) {
+ bmsrc_data = guit->bitmap->get_buffer(entry->page.bitmap);
+ bmdst_data = guit->bitmap->get_buffer(new_entry->page.bitmap);
+ bmsize = guit->bitmap->get_rowstride(new_entry->page.bitmap) *
+ guit->bitmap->get_height(new_entry->page.bitmap);
+ memcpy(bmdst_data, bmsrc_data, bmsize);
+ }
+ }
+
+ /* copy tree values */
+ new_entry->back = entry->back;
+ new_entry->next = entry->next;
+ new_entry->forward = entry->forward;
+ new_entry->forward_pref = entry->forward_pref;
+ new_entry->forward_last = entry->forward_last;
/* recurse for all children */
- for (child = new_entry->forward; child; child = child->next) {
+ for (child = new_entry->forward; child != NULL; child = child->next) {
new_child = browser_window_history__clone_entry(history, child);
- if (new_child) {
- new_child->back = new_entry;
- } else {
+ if (new_child == NULL) {
nsurl_unref(new_entry->page.url);
- if (new_entry->page.frag_id)
+ if (new_entry->page.frag_id) {
lwc_string_unref(new_entry->page.frag_id);
+ }
free(new_entry->page.title);
+ if (entry->page.bitmap != NULL) {
+ guit->bitmap->destroy(entry->page.bitmap);
+ }
free(new_entry);
return NULL;
}
+
+ new_child->back = new_entry;
if (prev)
prev->next = new_child;
if (new_entry->forward == child)
@@ -148,6 +152,12 @@ browser_window_history__clone_entry(struct history *history,
new_entry->forward_last = new_child;
prev = new_child;
}
+
+ /* update references */
+ if (history->current == entry) {
+ history->current = new_entry;
+ }
+
return new_entry;
}
@@ -158,15 +168,20 @@ browser_window_history__clone_entry(struct history *history,
static void browser_window_history__free_entry(struct history_entry *entry)
{
- if (!entry)
- return;
- browser_window_history__free_entry(entry->forward);
- browser_window_history__free_entry(entry->next);
- nsurl_unref(entry->page.url);
- if (entry->page.frag_id)
- lwc_string_unref(entry->page.frag_id);
- free(entry->page.title);
- free(entry);
+ if (entry != NULL) {
+ browser_window_history__free_entry(entry->forward);
+ browser_window_history__free_entry(entry->next);
+
+ nsurl_unref(entry->page.url);
+ if (entry->page.frag_id) {
+ lwc_string_unref(entry->page.frag_id);
+ }
+ free(entry->page.title);
+ if (entry->page.bitmap != NULL) {
+ guit->bitmap->destroy(entry->page.bitmap);
+ }
+ free(entry);
+ }
}
@@ -236,197 +251,9 @@ static void browser_window_history__layout(struct history *history)
history->height += BOTTOM_MARGIN / 2;
}
-/** plot style for drawing lines between nodes */
-static plot_style_t pstyle_line = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 2,
-};
-
-/** plot style for drawing background */
-static plot_style_t pstyle_bg = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-
-/** plot style for drawing rectangle round unselected nodes */
-static plot_style_t pstyle_rect = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 1,
-};
-
-/** plot style for drawing rectangle round selected nodes */
-static plot_style_t pstyle_rect_sel = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 3,
-};
-
-/** plot style for font on unselected nodes */
-static plot_font_style_t pfstyle_node = {
- .family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 8 * FONT_SIZE_SCALE,
- .weight = 400,
- .flags = FONTF_NONE,
-};
-
-/** plot style for font on unselected nodes */
-static plot_font_style_t pfstyle_node_sel = {
- .family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 8 * FONT_SIZE_SCALE,
- .weight = 900,
- .flags = FONTF_NONE,
-};
-
-/**
- * Recursively redraw a history_entry.
- *
- * \param history history containing the entry
- * \param entry entry to render
- * \param x0 area top left x coordinate
- * \param y0 area top left y coordinate
- * \param x1 area bottom right x coordinate
- * \param y1 area bottom right y coordinate
- * \param x window x offset
- * \param y window y offset
- * \param clip clip redraw
- * \param ctx current redraw context
- */
-static bool
-browser_window_history__redraw_entry(struct history *history,
- struct history_entry *entry,
- int x0, int y0, int x1, int y1,
- int x, int y, bool clip,
- const struct redraw_context *ctx)
-{
- const struct plotter_table *plot = ctx->plot;
- size_t char_offset;
- int actual_x;
- struct history_entry *child;
- int tailsize = 5;
- int xoffset = x - x0;
- int yoffset = y - y0;
-
- plot_style_t *pstyle;
- plot_font_style_t *pfstyle;
-
- nserror res;
-
- /* setup plot styles */
- if (entry == history->current) {
- pstyle = &pstyle_rect_sel;
- pfstyle = &pfstyle_node_sel;
- } else {
- pstyle = &pstyle_rect;
- pfstyle = &pfstyle_node;
- }
-
- /* setup clip area */
- if (clip) {
- struct rect rect;
- rect.x0 = x0 + xoffset;
- rect.y0 = y0 + yoffset;
- rect.x1 = x1 + xoffset;
- rect.y1 = y1 + yoffset;
- if (!plot->clip(&rect)) {
- return false;
- }
- }
-
- /* Only attempt to plot bitmap if it is present */
- if (entry->bitmap != NULL) {
- plot->bitmap(entry->x + xoffset,
- entry->y + yoffset,
- WIDTH, HEIGHT,
- entry->bitmap,
- 0xffffff,
- 0);
- }
-
- if (!plot->rectangle(entry->x - 1 + xoffset,
- entry->y - 1 + yoffset,
- entry->x + xoffset + WIDTH,
- entry->y + yoffset + HEIGHT,
- pstyle)) {
- return false;
- }
-
- res = guit->layout->position(plot_style_font, entry->page.title,
- strlen(entry->page.title), WIDTH,
- &char_offset, &actual_x);
- if (res != NSERROR_OK) {
- return false;
- }
-
-
- if (!plot->text(entry->x + xoffset,
- entry->y + HEIGHT + 12 + yoffset,
- entry->page.title,
- char_offset,
- pfstyle)) {
- return false;
- }
-
- /* for each child node draw a line and recurse redraw into it */
- for (child = entry->forward; child; child = child->next) {
- if (!plot->line(entry->x + WIDTH + xoffset,
- entry->y + HEIGHT / 2 + yoffset,
- entry->x + WIDTH + tailsize + xoffset,
- entry->y + HEIGHT / 2 + yoffset,
- &pstyle_line)) {
- return false;
- }
- if (!plot->line(entry->x + WIDTH + tailsize + xoffset,
- entry->y + HEIGHT / 2 + yoffset,
- child->x - tailsize +xoffset,
- child->y + HEIGHT / 2 + yoffset,
- &pstyle_line)) {
- return false;
- }
- if (!plot->line(child->x - tailsize + xoffset,
- child->y + HEIGHT / 2 + yoffset,
- child->x + xoffset, child->y +
- HEIGHT / 2 + yoffset,
- &pstyle_line)) {
- return false;
- }
- if (!browser_window_history__redraw_entry(history, child,
- x0, y0, x1, y1, x, y, clip, ctx)) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * Find the history entry at a position.
- *
- * \param entry entry to search from
- * \param x coordinate
- * \param y coordinate
- * \return an entry if found, 0 if none
- */
-static struct history_entry *browser_window_history__find_position(
- struct history_entry *entry, int x, int y)
-{
- struct history_entry *child;
- struct history_entry *found;
- if (!entry)
- return 0;
-
- if (entry->x <= x && x <= entry->x + WIDTH &&
- entry->y <= y && y <= entry->y + HEIGHT)
- return entry;
-
- for (child = entry->forward; child; child = child->next) {
- found = browser_window_history__find_position(child, x, y);
- if (found)
- return found;
- }
-
- return 0;
-}
/**
* Enumerate subentries in history
@@ -469,17 +296,6 @@ nserror browser_window_history_create(struct browser_window *bw)
{
struct history *history;
- pstyle_bg.fill_colour = ns_system_colour_char("Window");
- pfstyle_node.background = pstyle_bg.fill_colour;
- pfstyle_node_sel.background = pstyle_bg.fill_colour;
-
- pstyle_line.stroke_colour = ns_system_colour_char("GrayText");
- pstyle_rect.stroke_colour = pstyle_line.stroke_colour;
- pfstyle_node.foreground = pstyle_line.stroke_colour;
-
- pstyle_rect_sel.stroke_colour = ns_system_colour_char("Highlight");
- pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour;
-
bw->history = NULL;
history = calloc(1, sizeof *history);
@@ -520,7 +336,7 @@ nserror browser_window_history_clone(const struct browser_window *existing,
new_history->start = browser_window_history__clone_entry(new_history,
new_history->start);
if (!new_history->start) {
- LOG("Insufficient memory to clone history");
+ NSLOG(netsurf, INFO, "Insufficient memory to clone history");
browser_window_history_destroy(clone);
clone->history = NULL;
return NSERROR_NOMEM;
@@ -531,14 +347,14 @@ nserror browser_window_history_clone(const struct browser_window *existing,
/* exported interface documented in desktop/browser_history.h */
-nserror browser_window_history_add(struct browser_window *bw,
- struct hlcache_handle *content, lwc_string *frag_id)
+nserror
+browser_window_history_add(struct browser_window *bw,
+ struct hlcache_handle *content,
+ lwc_string *frag_id)
{
struct history *history;
struct history_entry *entry;
- nsurl *nsurl = hlcache_handle_get_url(content);
char *title;
- struct bitmap *bitmap;
nserror ret;
assert(bw);
@@ -547,32 +363,50 @@ nserror browser_window_history_add(struct browser_window *bw,
history = bw->history;
- /* allocate space */
entry = malloc(sizeof *entry);
if (entry == NULL) {
return NSERROR_NOMEM;
}
+ /* page information */
title = strdup(content_get_title(content));
if (title == NULL) {
free(entry);
return NSERROR_NOMEM;
}
- entry->page.url = nsurl_ref(nsurl);
- entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : 0;
-
+ entry->page.url = nsurl_ref(hlcache_handle_get_url(content));
+ entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : NULL;
entry->page.title = title;
+ entry->page.scroll_x = 0.0f;
+ entry->page.scroll_y = 0.0f;
+
+ /* create thumbnail for localhistory view */
+ NSLOG(netsurf, DEBUG,
+ "Creating thumbnail for %s", nsurl_access(entry->page.url));
+
+ entry->page.bitmap = guit->bitmap->create(WIDTH, HEIGHT,
+ BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE);
+ if (entry->page.bitmap != NULL) {
+ ret = guit->bitmap->render(entry->page.bitmap, content);
+ if (ret != NSERROR_OK) {
+ /* Thumbnail render failed */
+ NSLOG(netsurf, WARNING, "Thumbnail render failed");
+ }
+ }
+
+ /* insert into tree */
entry->back = history->current;
- entry->next = 0;
- entry->forward = entry->forward_pref = entry->forward_last = 0;
+ entry->next = NULL;
+ entry->forward = entry->forward_pref = entry->forward_last = NULL;
entry->children = 0;
- entry->bitmap = 0;
+
if (history->current) {
- if (history->current->forward_last)
+ if (history->current->forward_last) {
history->current->forward_last->next = entry;
- else
+ } else {
history->current->forward = entry;
+ }
history->current->forward_pref = entry;
history->current->forward_last = entry;
history->current->children++;
@@ -581,33 +415,6 @@ nserror browser_window_history_add(struct browser_window *bw,
}
history->current = entry;
- /* if we have a thumbnail, don't update until the page has finished
- * loading */
- bitmap = urldb_get_thumbnail(nsurl);
- if (bitmap == NULL) {
- LOG("Creating thumbnail for %s", nsurl_access(nsurl));
- bitmap = guit->bitmap->create(WIDTH, HEIGHT,
- BITMAP_NEW | BITMAP_CLEAR_MEMORY |
- BITMAP_OPAQUE);
- if (bitmap != NULL) {
- ret = guit->bitmap->render(bitmap, content);
- if (ret == NSERROR_OK) {
- /* Successful thumbnail so register it
- * with the url.
- */
- urldb_set_thumbnail(nsurl, bitmap);
- } else {
- /* Thumbnailing failed. Ignore it
- * silently but clean up bitmap.
- */
- LOG("Thumbnail renderfailed");
- guit->bitmap->destroy(bitmap);
- bitmap = NULL;
- }
- }
- }
- entry->bitmap = bitmap;
-
browser_window_history__layout(history);
return NSERROR_OK;
@@ -620,12 +427,15 @@ nserror browser_window_history_update(struct browser_window *bw,
{
struct history *history;
char *title;
+ int sx, sy;
assert(bw != NULL);
history = bw->history;
- if (!history || !history->current || !history->current->bitmap) {
+ if (!history ||
+ !history->current ||
+ !history->current->page.bitmap) {
return NSERROR_INVALID;
}
@@ -636,16 +446,50 @@ nserror browser_window_history_update(struct browser_window *bw,
if (title == NULL) {
return NSERROR_NOMEM;
}
-
+ NSLOG(netsurf, INFO, "Updating history entry for %s", title);
free(history->current->page.title);
history->current->page.title = title;
- guit->bitmap->render(history->current->bitmap, content);
+ if (history->current->page.bitmap != NULL) {
+ guit->bitmap->render(history->current->page.bitmap, content);
+ }
+ if (bw->window != NULL &&
+ guit->window->get_scroll(bw->window, &sx, &sy)) {
+ /* Successfully got scroll offsets, update the entry */
+ history->current->page.scroll_x = \
+ (float)sx / (float)content_get_width(content);
+ history->current->page.scroll_y = \
+ (float)sy / (float)content_get_height(content);
+ NSLOG(netsurf, INFO, "Updated scroll offsets to %g by %g",
+ history->current->page.scroll_x,
+ history->current->page.scroll_y);
+ }
return NSERROR_OK;
}
+/* exported interface documented in desktop/browser_private.h */
+nserror
+browser_window_history_get_scroll(struct browser_window *bw,
+ float *sx, float *sy)
+{
+ struct history *history;
+
+ assert(bw != NULL);
+
+ history = bw->history;
+
+ if (!history ||
+ !history->current ||
+ !history->current->page.bitmap) {
+ return NSERROR_INVALID;
+ }
+
+ *sx = history->current->page.scroll_x;
+ *sy = history->current->page.scroll_y;
+ return NSERROR_OK;
+}
/* exported interface documented in desktop/browser_history.h */
void browser_window_history_destroy(struct browser_window *bw)
@@ -704,6 +548,27 @@ bool browser_window_history_forward_available(struct browser_window *bw)
bw->history->current->forward_pref);
}
+/* exported interface documented in desktop/browser_history.h */
+nserror
+browser_window_history_get_thumbnail(struct browser_window *bw,
+ struct bitmap **bitmap_out)
+{
+ struct bitmap *bitmap;
+
+ if (!bw || !bw->history || !bw->history->current) {
+ return NSERROR_INVALID;
+ }
+
+ if (bw->history->current->page.bitmap == NULL) {
+ bitmap = content_get_bitmap(bw->current_content);
+ } else {
+ bitmap = bw->history->current->page.bitmap;
+ }
+
+ *bitmap_out = bitmap;
+
+ return NSERROR_OK;
+}
/* exported interface documented in desktop/browser_history.h */
nserror browser_window_history_go(struct browser_window *bw,
@@ -736,9 +601,13 @@ nserror browser_window_history_go(struct browser_window *bw,
url, NULL, bw, NULL);
history->current = current;
} else {
+ if (bw->current_content != NULL) {
+ browser_window_history_update(bw, bw->current_content);
+ }
history->current = entry;
error = browser_window_navigate(bw, url, NULL,
- BW_NAVIGATE_NONE, NULL, NULL, NULL);
+ BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE,
+ NULL, NULL, NULL);
}
nsurl_unref(url);
@@ -748,99 +617,7 @@ nserror browser_window_history_go(struct browser_window *bw,
/* exported interface documented in desktop/browser_history.h */
-void browser_window_history_size(struct browser_window *bw,
- int *width, int *height)
-{
- assert(bw != NULL);
- assert(bw->history != NULL);
-
- *width = bw->history->width;
- *height = bw->history->height;
-}
-
-
-/* exported interface documented in desktop/browser_history.h */
-bool browser_window_history_redraw(struct browser_window *bw,
- const struct redraw_context *ctx)
-{
- struct history *history;
-
- assert(bw != NULL);
- history = bw->history;
-
- if (history == NULL) {
- LOG("Attempt to draw NULL history.");
- return false;
- }
-
- if (!history->start)
- return true;
-
- return browser_window_history__redraw_entry(history, history->start,
- 0, 0, 0, 0, 0, 0, false, ctx);
-}
-
-
-/* exported interface documented in desktop/browser_history.h */
-bool browser_window_history_redraw_rectangle(struct browser_window *bw,
- int x0, int y0, int x1, int y1,
- int x, int y, const struct redraw_context *ctx)
-{
- struct history *history;
-
- assert(bw != NULL);
- history = bw->history;
-
- if (!history->start)
- return true;
-
- return browser_window_history__redraw_entry(history, history->start,
- x0, y0, x1, y1, x, y, true, ctx);
-}
-
-
-/* exported interface documented in desktop/browser_history.h */
-bool browser_window_history_click(struct browser_window *bw,
- int x, int y, bool new_window)
-{
- struct history_entry *entry;
- struct history *history;
-
- assert(bw != NULL);
- history = bw->history;
-
- entry = browser_window_history__find_position(history->start, x, y);
- if (!entry)
- return false;
- if (entry == history->current)
- return false;
-
- browser_window_history_go(bw, entry, new_window);
-
- return true;
-}
-
-
-/* exported interface documented in desktop/browser_history.h */
-const char *browser_window_history_position_url(struct browser_window *bw,
- int x, int y)
-{
- struct history_entry *entry;
- struct history *history;
-
- assert(bw != NULL);
- history = bw->history;
-
- entry = browser_window_history__find_position(history->start, x, y);
- if (!entry)
- return 0;
-
- return nsurl_access(entry->page.url);
-}
-
-
-/* exported interface documented in desktop/browser_history.h */
-void browser_window_history_enumerate_forward(const struct browser_window *bw,
+void browser_window_history_enumerate_forward(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data)
{
struct history_entry *e;
@@ -858,7 +635,7 @@ void browser_window_history_enumerate_forward(const struct browser_window *bw,
/* exported interface documented in desktop/browser_history.h */
-void browser_window_history_enumerate_back(const struct browser_window *bw,
+void browser_window_history_enumerate_back(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data)
{
struct history_entry *e;
@@ -886,10 +663,9 @@ void browser_window_history_enumerate(const struct browser_window *bw,
/* exported interface documented in desktop/browser_history.h */
-const char *browser_window_history_entry_get_url(
- const struct history_entry *entry)
+nsurl *browser_window_history_entry_get_url(const struct history_entry *entry)
{
- return nsurl_access(entry->page.url);
+ return nsurl_ref(entry->page.url);
}
diff --git a/desktop/browser_history.h b/desktop/browser_history.h
index 8ffb6125b..9b6f1fd42 100644
--- a/desktop/browser_history.h
+++ b/desktop/browser_history.h
@@ -16,71 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Browser history tree (interface).
+/**
+ * \file
+ * Interface to browser history operations
+ *
+ * The are operations on a browsing contexts history. These interfaces
+ * allow navigation forward and backwards in the history as well as
+ * enumerating the entries.
+ *
+ * The local history viewing is distinct via corewindow defined in
+ * desktop/local_history.h
*/
-#ifndef _NETSURF_DESKTOP_BROWSER_HISTORY_H_
-#define _NETSURF_DESKTOP_BROWSER_HISTORY_H_
+#ifndef NETSURF_DESKTOP_BROWSER_HISTORY_H
+#define NETSURF_DESKTOP_BROWSER_HISTORY_H
#include <stdbool.h>
-#include <libwapcaplet/libwapcaplet.h>
#include "utils/errors.h"
-struct hlcache_handle;
struct browser_window;
struct history_entry;
-struct redraw_context;
-
-/**
- * Create a new history tree for a browser window window.
- *
- * \param bw browser window to create history for.
- *
- * \return NSERROR_OK or appropriate error otherwise
- */
-nserror browser_window_history_create(struct browser_window *bw);
-
-/**
- * Clone a bw's history tree for new bw
- *
- * \param existing browser window with history to clone.
- * \param clone browser window to make cloned history for.
- *
- * \return NSERROR_OK or appropriate error otherwise
- */
-nserror browser_window_history_clone(const struct browser_window *existing,
- struct browser_window *clone);
-/**
- * Insert a url into the history tree.
- *
- * \param bw browser window with history object
- * \param content content to add to history
- * \param frag_id fragment identifier, or NULL.
- * \return NSERROR_OK or error code on faliure.
- *
- * The page is added after the current entry and becomes current.
- */
-nserror browser_window_history_add(struct browser_window *bw,
- struct hlcache_handle *content, lwc_string *frag_id);
-
-/**
- * Update the thumbnail for the current entry.
- *
- * \param bw The browser window to update the history within.
- * \param content content for current entry
- * \return NSERROR_OK or error code on faliure.
- */
-nserror browser_window_history_update(struct browser_window *bw,
- struct hlcache_handle *content);
-
-/**
- * Free a history structure.
- *
- * \param bw The browser window to destroy the history within.
- */
-void browser_window_history_destroy(struct browser_window *bw);
+struct bitmap;
/**
* Go back in the history.
@@ -91,6 +48,7 @@ void browser_window_history_destroy(struct browser_window *bw);
*/
nserror browser_window_history_back(struct browser_window *bw, bool new_window);
+
/**
* Go forward in the history.
*
@@ -100,6 +58,7 @@ nserror browser_window_history_back(struct browser_window *bw, bool new_window);
*/
nserror browser_window_history_forward(struct browser_window *bw, bool new_window);
+
/**
* Check whether it is pssible to go back in the history.
*
@@ -108,6 +67,7 @@ nserror browser_window_history_forward(struct browser_window *bw, bool new_windo
*/
bool browser_window_history_back_available(struct browser_window *bw);
+
/**
* Check whether it is pssible to go forwards in the history.
*
@@ -117,62 +77,13 @@ bool browser_window_history_back_available(struct browser_window *bw);
bool browser_window_history_forward_available(struct browser_window *bw);
/**
- * Get the dimensions of a history.
- *
- * \param bw browser window with history object.
- * \param width updated to width
- * \param height updated to height
- */
-void browser_window_history_size(struct browser_window *bw,
- int *width, int *height);
-
-/**
- * Redraw all of a history area.
+ * Get the thumbnail bitmap for the current history entry
*
- * \param bw browser window with history object.
- * \param ctx current redraw context
- */
-bool browser_window_history_redraw(struct browser_window *bw,
- const struct redraw_context *ctx);
-
-/**
- * Redraw part of a history area.
- *
- * \param bw browser window with history object.
- * \param x0 left X co-ordinate of redraw area
- * \param y0 top Y co-ordinate of redraw area
- * \param x1 right X co-ordinate of redraw area
- * \param y1 lower Y co-ordinate of redraw area
- * \param x start X co-ordinate on plot canvas
- * \param y start Y co-ordinate on plot canvas
- * \param ctx current redraw context
- */
-bool browser_window_history_redraw_rectangle(struct browser_window *bw,
- int x0, int y0, int x1, int y1, int x, int y,
- const struct redraw_context *ctx);
-
-/**
- * Handle a mouse click in a history.
- *
- * \param bw browser window containing history
- * \param x click coordinate
- * \param y click coordinate
- * \param new_window open a new window instead of using bw
- * \return true if action was taken, false if click was not on an entry
- */
-bool browser_window_history_click(struct browser_window *bw,
- int x, int y, bool new_window);
-
-/**
- * Determine the URL of the entry at a position.
- *
- * \param bw browser window containing history
- * \param x x coordinate.
- * \param y y coordinate.
- * \return URL, or 0 if no entry at (x, y)
+ * \param bw The browser window
+ * \param bitmap The bitmat for the current history entry.
+ * \return NSERROR_OK or error code on faliure.
*/
-const char *browser_window_history_position_url(struct browser_window *bw,
- int x, int y);
+nserror browser_window_history_get_thumbnail(struct browser_window *bw, struct bitmap **bitmap_out);
/**
* Callback function type for history enumeration
@@ -187,6 +98,7 @@ typedef bool (*browser_window_history_enumerate_cb)(
int x0, int y0, int x1, int y1,
const struct history_entry *entry, void *user_data);
+
/**
* Enumerate all entries in the history.
* Do not change the history while it is being enumerated.
@@ -198,6 +110,7 @@ typedef bool (*browser_window_history_enumerate_cb)(
void browser_window_history_enumerate(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data);
+
/**
* Enumerate all entries that will be reached by the 'forward' button
*
@@ -208,6 +121,7 @@ void browser_window_history_enumerate(const struct browser_window *bw,
void browser_window_history_enumerate_forward(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data);
+
/**
* Enumerate all entries that will be reached by the 'back' button
*
@@ -218,32 +132,33 @@ void browser_window_history_enumerate_forward(const struct browser_window *bw,
void browser_window_history_enumerate_back(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data);
+
/**
* Returns the URL to a history entry
*
- * \param entry the history entry to retrieve the URL from
- * \return the URL
+ * \param entry the history entry to retrieve the URL from
+ * \return A referenced nsurl URL
*/
-const char *browser_window_history_entry_get_url(
- const struct history_entry *entry);
+struct nsurl *browser_window_history_entry_get_url(const struct history_entry *entry);
+
/**
* Returns the URL to a history entry
*
- * \param entry the history entry to retrieve the fragment id from
- * \return the fragment id
+ * \param entry the history entry to retrieve the fragment id from
+ * \return the fragment id
*/
-const char *browser_window_history_entry_get_fragment_id(
- const struct history_entry *entry);
+const char *browser_window_history_entry_get_fragment_id(const struct history_entry *entry);
+
/**
* Returns the title of a history entry
*
- * \param entry the history entry to retrieve the title from
- * \return the title
+ * \param entry The history entry to retrieve the title from
+ * \return the title
*/
-const char *browser_window_history_entry_get_title(
- const struct history_entry *entry);
+const char *browser_window_history_entry_get_title(const struct history_entry *entry);
+
/**
* Navigate to specified history entry, optionally in new window
@@ -253,7 +168,6 @@ const char *browser_window_history_entry_get_title(
* \param new_window open entry in new window
* \return NSERROR_OK or error code on faliure.
*/
-nserror browser_window_history_go(struct browser_window *bw,
- struct history_entry *entry, bool new_window);
+nserror browser_window_history_go(struct browser_window *bw, struct history_entry *entry, bool new_window);
#endif
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index 072a894d6..192d22bf0 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -17,7 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Browser window private structure.
*/
@@ -34,27 +35,94 @@
struct box;
struct hlcache_handle;
struct gui_window;
-struct history;
struct selection;
+struct nsurl;
+
+/**
+ * history entry page information
+ */
+struct history_page {
+ struct nsurl *url; /**< Page URL, never NULL. */
+ lwc_string *frag_id; /** Fragment identifier, or NULL. */
+ char *title; /**< Page title, never NULL. */
+ struct bitmap *bitmap; /**< Thumbnail bitmap, or NULL. */
+ float scroll_x; /**< Scroll X offset when visited */
+ float scroll_y; /**< Scroll Y offset when visited */
+};
+
+/**
+ * A node in the history tree.
+ */
+struct history_entry {
+ struct history_page page;
+ struct history_entry *back; /**< Parent. */
+ struct history_entry *next; /**< Next sibling. */
+ struct history_entry *forward; /**< First child. */
+ struct history_entry *forward_pref; /**< Child in direction of
+ current entry. */
+ struct history_entry *forward_last; /**< Last child. */
+ unsigned int children; /**< Number of children. */
+ int x; /**< Position of node. */
+ int y; /**< Position of node. */
+};
+
+/**
+ * History tree for a window.
+ */
+struct history {
+ /** First page in tree (page that window opened with). */
+ struct history_entry *start;
+ /** Current position in tree. */
+ struct history_entry *current;
+ /** Width of layout. */
+ int width;
+ /** Height of layout. */
+ int height;
+};
-/** Browser window data. */
+/**
+ * Browser window data.
+ */
struct browser_window {
- /** Page currently displayed, or 0. Must have status READY or DONE. */
+ /**
+ * Content handle of page currently displayed which must have
+ * READY or DONE status or NULL for no content.
+ */
struct hlcache_handle *current_content;
- /** Page being loaded, or 0. */
+ /**
+ * Content handle of page in process of being loaded or NULL
+ * if no page is being loaded.
+ */
struct hlcache_handle *loading_content;
- /** Page Favicon */
- struct hlcache_handle *current_favicon;
- /** handle for favicon which we started loading early */
- struct hlcache_handle *loading_favicon;
- /** favicon fetch already failed - prevents infinite error looping */
- bool failed_favicon;
-
- /** Window history structure. */
+ /**
+ * Favicon
+ */
+ struct {
+ /**
+ * content handle of current page favicon
+ */
+ struct hlcache_handle *current;
+
+ /**
+ * content handle for favicon which we started loading
+ * early
+ */
+ struct hlcache_handle *loading;
+
+ /**
+ * flag to indicate favicon fetch already failed which
+ * prevents infinite error looping.
+ */
+ bool failed;
+ } favicon;
+
+ /** local history handle. */
struct history *history;
- /** Platform specific window data. */
+ /**
+ * Platform specific window data only valid at top level.
+ */
struct gui_window *window;
/** Busy indicator is active. */
@@ -65,23 +133,32 @@ struct browser_window {
/** Fragment identifier for current_content. */
lwc_string *frag_id;
- /** Current drag status. */
- browser_drag_type drag_type;
+ /**
+ * Current drag status.
+ *
+ * These values are only vald whle type is not DRAGGING_NONE
+ */
+ struct {
+ /** the type of drag in progress */
+ browser_drag_type type;
+
+ /** Current drag's browser window, when not in root bw. */
+ struct browser_window *window;
+
+ /** Mouse position at start of current scroll drag. */
+ int start_x;
+ int start_y;
- /** Current drag's browser window, when not in root bw. */
- struct browser_window *drag_window;
+ /** Scroll offsets at start of current scroll draw. */
+ int start_scroll_x;
+ int start_scroll_y;
- /** Mouse position at start of current scroll drag. */
- int drag_start_x;
- int drag_start_y;
- /** Scroll offsets at start of current scroll draw. */
- int drag_start_scroll_x;
- int drag_start_scroll_y;
- /** Frame resize directions for current frame resize drag. */
- unsigned int drag_resize_left : 1;
- unsigned int drag_resize_right : 1;
- unsigned int drag_resize_up : 1;
- unsigned int drag_resize_down : 1;
+ /** Frame resize directions for current frame resize drag. */
+ unsigned int resize_left : 1;
+ unsigned int resize_right : 1;
+ unsigned int resize_up : 1;
+ unsigned int resize_down : 1;
+ } drag;
/** Current fetch is download */
bool download;
@@ -156,14 +233,15 @@ struct browser_window {
struct jscontext *jsctx;
/** cache of the currently displayed status text. */
- char *status_text; /**< Current status bar text. */
- int status_text_len; /**< Length of the browser_window::status_text buffer. */
- int status_match; /**< Number of times an idempotent status-set operation was performed. */
- int status_miss; /**< Number of times status was really updated. */
+ struct {
+ char *text; /**< Current status bar text. */
+ int text_len; /**< Length of the status::text buffer. */
+ int match; /**< Number of times an idempotent status-set operation was performed. */
+ int miss; /**< Number of times status was really updated. */
+ } status;
};
-
/**
* Initialise common parts of a browser window
*
@@ -174,6 +252,7 @@ struct browser_window {
nserror browser_window_initialise_common(enum browser_window_create_flags flags,
struct browser_window *bw, struct browser_window *existing);
+
/**
* Get the dimensions of the area a browser window occupies
*
@@ -185,6 +264,7 @@ nserror browser_window_initialise_common(enum browser_window_create_flags flags,
void browser_window_get_dimensions(struct browser_window *bw,
int *width, int *height, bool scaled);
+
/**
* Update the extent of the inside of a browser window to that of the current
* content
@@ -193,6 +273,7 @@ void browser_window_get_dimensions(struct browser_window *bw,
*/
void browser_window_update_extent(struct browser_window *bw);
+
/**
* Change the status bar of a browser window.
*
@@ -201,6 +282,7 @@ void browser_window_update_extent(struct browser_window *bw);
*/
void browser_window_set_status(struct browser_window *bw, const char *text);
+
/**
* Get the root level browser window
*
@@ -209,4 +291,68 @@ void browser_window_set_status(struct browser_window *bw, const char *text);
*/
struct browser_window * browser_window_get_root(struct browser_window *bw);
+
+/**
+ * Create a new history tree for a browser window window.
+ *
+ * \param bw browser window to create history for.
+ *
+ * \return NSERROR_OK or appropriate error otherwise
+ */
+nserror browser_window_history_create(struct browser_window *bw);
+
+/**
+ * Clone a bw's history tree for new bw
+ *
+ * \param existing browser window with history to clone.
+ * \param clone browser window to make cloned history for.
+ *
+ * \return NSERROR_OK or appropriate error otherwise
+ */
+nserror browser_window_history_clone(const struct browser_window *existing,
+ struct browser_window *clone);
+
+
+/**
+ * Insert a url into the history tree.
+ *
+ * \param bw browser window with history object
+ * \param content content to add to history
+ * \param frag_id fragment identifier, or NULL.
+ * \return NSERROR_OK or error code on faliure.
+ *
+ * The page is added after the current entry and becomes current.
+ */
+nserror browser_window_history_add(struct browser_window *bw,
+ struct hlcache_handle *content, lwc_string *frag_id);
+
+/**
+ * Update the thumbnail and scroll offsets for the current entry.
+ *
+ * \param bw The browser window to update the history within.
+ * \param content content for current entry
+ * \return NSERROR_OK or error code on faliure.
+ */
+nserror browser_window_history_update(struct browser_window *bw,
+ struct hlcache_handle *content);
+
+/**
+ * Retrieve the stored scroll offsets for the current history entry
+ *
+ * \param bw The browser window to retrieve scroll offsets for.
+ * \param sx Pointer to a float for the X scroll offset
+ * \param sy Pointer to a float for the Y scroll offset
+ * \return NSERROR_OK or error code on failure.
+ */
+nserror browser_window_history_get_scroll(struct browser_window *bw,
+ float *sx, float *sy);
+
+/**
+ * Free a history structure.
+ *
+ * \param bw The browser window to destroy the history within.
+ */
+void browser_window_history_destroy(struct browser_window *bw);
+
+
#endif
diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c
index 5429f6864..a2aab8e9f 100644
--- a/desktop/cookie_manager.c
+++ b/desktop/cookie_manager.c
@@ -576,7 +576,9 @@ static nserror cookie_manager_init_entry_fields(void)
goto error;
}
- cm_ctx.fields[COOKIE_M_DOMAIN].flags = TREE_FLAG_SHOW_NAME;
+ cm_ctx.fields[COOKIE_M_DOMAIN].flags =
+ TREE_FLAG_SHOW_NAME |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelDomain";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -718,7 +720,8 @@ static void cookie_manager_delete_entry(struct cookie_manager_entry *e)
urldb_delete_cookie(domain, path, name);
} else {
- LOG("Delete cookie fail: ""need domain, path, and name.");
+ NSLOG(netsurf, INFO,
+ "Delete cookie fail: ""need domain, path, and name.");
}
}
@@ -788,7 +791,7 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Generating cookie manager data");
+ NSLOG(netsurf, INFO, "Generating cookie manager data");
/* Init. cookie manager treeview entry fields */
err = cookie_manager_init_entry_fields();
@@ -808,7 +811,9 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
err = treeview_create(&cm_ctx.tree, &cm_tree_cb_t,
COOKIE_M_N_FIELDS, cm_ctx.fields,
cw_t, core_window_handle,
- TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS);
+ TREEVIEW_NO_MOVES |
+ TREEVIEW_DEL_EMPTY_DIRS |
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
cm_ctx.tree = NULL;
return err;
@@ -825,7 +830,7 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
/* Inform client of window height */
treeview_get_height(cm_ctx.tree);
- LOG("Generated cookie manager data");
+ NSLOG(netsurf, INFO, "Generated cookie manager data");
return NSERROR_OK;
}
@@ -837,7 +842,7 @@ nserror cookie_manager_fini(void)
int i;
nserror err;
- LOG("Finalising cookie manager");
+ NSLOG(netsurf, INFO, "Finalising cookie manager");
cm_ctx.built = false;
@@ -860,7 +865,7 @@ nserror cookie_manager_fini(void)
return err;
}
- LOG("Finalised cookie manager");
+ NSLOG(netsurf, INFO, "Finalised cookie manager");
return err;
}
diff --git a/desktop/font_haru.c b/desktop/font_haru.c
index caa751bcb..4ee9824f0 100644
--- a/desktop/font_haru.c
+++ b/desktop/font_haru.c
@@ -74,7 +74,10 @@ const struct font_functions haru_nsfont = {
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
- LOG("ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
+ NSLOG(netsurf, INFO,
+ "ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n",
+ (HPDF_UINT)error_no,
+ (HPDF_UINT)detail_no);
#ifdef FONT_HARU_DEBUG
exit(1);
#endif
@@ -143,7 +146,9 @@ bool haru_nsfont_width(const plot_font_style_t *fstyle,
*width = width_real;
#ifdef FONT_HARU_DEBUG
- LOG("Measuring string: %s ; Calculated width: %f %i", string_nt, width_real, *width);
+ NSLOG(netsurf, INFO,
+ "Measuring string: %s ; Calculated width: %f %i", string_nt,
+ width_real, *width);
#endif
free(string_nt);
HPDF_Free(pdf);
@@ -201,7 +206,11 @@ bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
*actual_x = real_width;
#ifdef FONT_HARU_DEBUG
- LOG("Position in string: %s at x: %i; Calculated position: %i", string_nt, x, *char_offset);
+ NSLOG(netsurf, INFO,
+ "Position in string: %s at x: %i; Calculated position: %i",
+ string_nt,
+ x,
+ *char_offset);
#endif
free(string_nt);
HPDF_Free(pdf);
@@ -246,7 +255,12 @@ bool haru_nsfont_split(const plot_font_style_t *fstyle,
HPDF_TRUE, &real_width);
#ifdef FONT_HARU_DEBUG
- LOG("Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f", string_nt, x, *char_offset, real_width);
+ NSLOG(netsurf, INFO,
+ "Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f",
+ string_nt,
+ x,
+ *char_offset,
+ real_width);
#endif
*char_offset = offset - 1;
@@ -327,7 +341,7 @@ bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
strcat(font_name, "-Roman");
#ifdef FONT_HARU_DEBUG
- LOG("Setting font: %s", font_name);
+ NSLOG(netsurf, INFO, "Setting font: %s", font_name);
#endif
size = fstyle->size;
@@ -338,7 +352,7 @@ bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
if (size <= 0)
return true;
- size /= FONT_SIZE_SCALE;
+ size /= PLOT_STYLE_SCALE;
if (size > HPDF_MAX_FONTSIZE)
size = HPDF_MAX_FONTSIZE;
diff --git a/desktop/frames.c b/desktop/frames.c
index 70e51e754..ebc54c6d5 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -33,8 +33,8 @@
#include "utils/utils.h"
#include "netsurf/content.h"
#include "content/hlcache.h"
-#include "render/html.h"
-#include "render/box.h"
+#include "html/html.h"
+#include "html/box.h"
#include "desktop/browser_private.h"
#include "desktop/frames.h"
@@ -354,9 +354,11 @@ nserror browser_window_create_frameset(struct browser_window *bw,
window->parent = bw;
if (window->name)
- LOG("Created frame '%s'", window->name);
+ NSLOG(netsurf, INFO, "Created frame '%s'",
+ window->name);
else
- LOG("Created frame (unnamed)");
+ NSLOG(netsurf, INFO,
+ "Created frame (unnamed)");
}
}
@@ -675,25 +677,31 @@ void browser_window_resize_frame(struct browser_window *bw, int x, int y)
assert((col >= 0) && (row >= 0));
sibling = NULL;
- if (bw->drag_resize_left)
+ if (bw->drag.resize_left) {
sibling = &parent->children[row * parent->cols + (col - 1)];
- else if (bw->drag_resize_right)
+ } else if (bw->drag.resize_right) {
sibling = &parent->children[row * parent->cols + (col + 1)];
- if (sibling)
+ }
+ if (sibling) {
change |= browser_window_resolve_frame_dimension(bw, sibling,
x, y, true, false);
+ }
sibling = NULL;
- if (bw->drag_resize_up)
+ if (bw->drag.resize_up) {
sibling = &parent->children[(row - 1) * parent->cols + col];
- else if (bw->drag_resize_down)
+ } else if (bw->drag.resize_down) {
sibling = &parent->children[(row + 1) * parent->cols + col];
- if (sibling)
+ }
+
+ if (sibling) {
change |= browser_window_resolve_frame_dimension(bw, sibling,
x, y, false, true);
+ }
- if (change)
+ if (change) {
browser_window_recalculate_frameset(parent);
+ }
}
@@ -711,20 +719,22 @@ bool browser_window_resolve_frame_dimension(struct browser_window *bw,
/* extend/shrink the box to the pointer */
if (width) {
- if (bw->drag_resize_left)
+ if (bw->drag.resize_left) {
bw_dimension = bw->x + bw->width - x;
- else
+ } else {
bw_dimension = x - bw->x;
+ }
bw_pixels = bw->width;
sibling_pixels = sibling->width;
bw_d = &bw->frame_width;
sibling_d = &sibling->frame_width;
frame_size = bw->parent->width;
} else {
- if (bw->drag_resize_up)
+ if (bw->drag.resize_up) {
bw_dimension = bw->y + bw->height - y;
- else
+ } else {
bw_dimension = y - bw->y;
+ }
bw_pixels = bw->height;
sibling_pixels = sibling->height;
bw_d = &bw->frame_height;
@@ -919,12 +929,12 @@ static bool browser_window_resize_frames(struct browser_window *bw,
* front end to clamp pointer range */
browser_window_set_drag_type(bw,
DRAGGING_FRAME, NULL);
- bw->drag_start_x = x;
- bw->drag_start_y = y;
- bw->drag_resize_left = left;
- bw->drag_resize_right = right;
- bw->drag_resize_up = up;
- bw->drag_resize_down = down;
+ bw->drag.start_x = x;
+ bw->drag.start_y = y;
+ bw->drag.resize_left = left;
+ bw->drag.resize_right = right;
+ bw->drag.resize_up = up;
+ bw->drag.resize_down = down;
}
return true;
}
diff --git a/desktop/global_history.c b/desktop/global_history.c
index a19349f51..ad39a3e41 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -536,7 +536,9 @@ static nserror global_history_initialise_entry_fields(void)
goto error;
}
- gh_ctx.fields[GH_URL].flags = TREE_FLAG_COPY_TEXT;
+ gh_ctx.fields[GH_URL].flags =
+ TREE_FLAG_COPY_TEXT |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelURL";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -596,7 +598,7 @@ static nserror global_history_initialise_time(void)
/* get the current time */
t = time(NULL);
if (t == -1) {
- LOG("time info unaviable");
+ NSLOG(netsurf, INFO, "time info unaviable");
return NSERROR_UNKNOWN;
}
@@ -607,7 +609,7 @@ static nserror global_history_initialise_time(void)
full_time->tm_hour = 0;
t = mktime(full_time);
if (t == -1) {
- LOG("mktime failed");
+ NSLOG(netsurf, INFO, "mktime failed");
return NSERROR_UNKNOWN;
}
@@ -729,7 +731,7 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Loading global history");
+ NSLOG(netsurf, INFO, "Loading global history");
/* Init. global history treeview time */
err = global_history_initialise_time();
@@ -752,7 +754,8 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
err = treeview_create(&gh_ctx.tree, &gh_tree_cb_t,
N_FIELDS, gh_ctx.fields,
cw_t, core_window_handle,
- TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS);
+ TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS |
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
gh_ctx.tree = NULL;
return err;
@@ -785,7 +788,7 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
/* Inform client of window height */
treeview_get_height(gh_ctx.tree);
- LOG("Loaded global history");
+ NSLOG(netsurf, INFO, "Loaded global history");
return NSERROR_OK;
}
@@ -797,7 +800,7 @@ nserror global_history_fini(void)
int i;
nserror err;
- LOG("Finalising global history");
+ NSLOG(netsurf, INFO, "Finalising global history");
gh_ctx.built = false;
@@ -815,7 +818,7 @@ nserror global_history_fini(void)
return err;
}
- LOG("Finalised global history");
+ NSLOG(netsurf, INFO, "Finalised global history");
return err;
}
@@ -832,7 +835,8 @@ nserror global_history_add(nsurl *url)
data = urldb_get_url_data(url);
if (data == NULL) {
- LOG("Can't add URL to history that's not present in urldb.");
+ NSLOG(netsurf, INFO,
+ "Can't add URL to history that's not present in urldb.");
return NSERROR_BAD_PARAMETER;
}
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index 88bb9baf5..ca9eff1da 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -82,12 +82,6 @@ static void gui_default_window_set_icon(struct gui_window *g,
{
}
-static void gui_default_window_scroll_visible(struct gui_window *g,
- int x0, int y0,
- int x1, int y1)
-{
- guit->window->set_scroll(g, x0, y0);
-}
static void gui_default_window_new_content(struct gui_window *g)
{
@@ -161,10 +155,7 @@ static nserror verify_window_register(struct gui_window_table *gwt)
if (gwt->destroy == NULL) {
return NSERROR_BAD_PARAMETER;
}
- if (gwt->redraw == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
- if (gwt->update == NULL) {
+ if (gwt->invalidate == NULL) {
return NSERROR_BAD_PARAMETER;
}
if (gwt->get_scroll == NULL) {
@@ -179,9 +170,6 @@ static nserror verify_window_register(struct gui_window_table *gwt)
if (gwt->update_extent == NULL) {
return NSERROR_BAD_PARAMETER;
}
- if (gwt->reformat == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
/* fill in the optional entries with defaults */
@@ -218,9 +206,6 @@ static nserror verify_window_register(struct gui_window_table *gwt)
if (gwt->save_link == NULL) {
gwt->save_link = gui_default_window_save_link;
}
- if (gwt->scroll_visible == NULL) {
- gwt->scroll_visible = gui_default_window_scroll_visible;
- }
if (gwt->new_content == NULL) {
gwt->new_content = gui_default_window_new_content;
}
diff --git a/desktop/hotlist.c b/desktop/hotlist.c
index 78473c744..4bdd7c8cb 100644
--- a/desktop/hotlist.c
+++ b/desktop/hotlist.c
@@ -62,6 +62,8 @@ struct hotlist_ctx {
struct treeview_field_desc fields[HL_N_FIELDS];
bool built;
struct hotlist_folder *default_folder;
+ char *save_path;
+ bool save_scheduled;
};
struct hotlist_ctx hl_ctx;
@@ -73,6 +75,113 @@ struct hotlist_entry {
};
+/*
+ * Get path for writing hotlist to
+ *
+ * \param path The final path of the hotlist
+ * \param loaded Updated to the path to write the holist to
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ */
+static nserror hotlist_get_temp_path(const char *path, char **temp_path)
+{
+ const char *extension = "-bk";
+ char *joined;
+ int len;
+
+ len = strlen(path) + strlen(extension);
+
+ joined = malloc(len + 1);
+ if (joined == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ if (snprintf(joined, len + 1, "%s%s", path, extension) != len) {
+ free(joined);
+ return NSERROR_UNKNOWN;
+ }
+
+ *temp_path = joined;
+ return NSERROR_OK;
+}
+
+
+/* Save the hotlist to to a file at the given path
+ *
+ * \param path Path to save hotlist file to. NULL path is a no-op.
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ */
+static nserror hotlist_save(const char *path)
+{
+ nserror res = NSERROR_OK;
+ char *temp_path;
+
+ /* NULL path is a no-op. */
+ if (path == NULL) {
+ return NSERROR_OK;
+ }
+
+ /* Get path to export to */
+ res = hotlist_get_temp_path(path, &temp_path);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Export to temp path */
+ res = hotlist_export(temp_path, NULL);
+ if (res != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ /* Remove old hotlist to handle non-POSIX rename() implementations. */
+ (void)remove(path);
+
+ /* Replace any old hotlist file with the one we just saved */
+ if (rename(temp_path, path) != 0) {
+ res = NSERROR_SAVE_FAILED;
+ NSLOG(netsurf, INFO, "Error renaming hotlist: %s.",
+ strerror(errno));
+ goto cleanup;
+ }
+
+cleanup:
+ free(temp_path);
+
+ return res;
+}
+
+
+/**
+ * Scheduler callback for saving the hotlist.
+ *
+ * \param p Unused user data.
+ */
+static void hotlist_schedule_save_cb(void *p)
+{
+ hl_ctx.save_scheduled = false;
+ hotlist_save(hl_ctx.save_path);
+}
+
+
+/**
+ * Schedule a hotlist save.
+ *
+ * \return NSERROR_OK on success, or appropriate error otherwise
+ */
+static nserror hotlist_schedule_save(void)
+{
+ if (hl_ctx.save_scheduled == false && hl_ctx.save_path != NULL) {
+ nserror err = guit->misc->schedule(10 * 1000,
+ hotlist_schedule_save_cb, NULL);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+ hl_ctx.save_scheduled = true;
+ }
+
+ return NSERROR_OK;
+}
+
+
/**
* Set a hotlist entry's data from the url_data.
*
@@ -436,6 +545,8 @@ hotlist_tree_node_entry_cb(struct treeview_node_msg msg, void *data)
case TREE_MSG_NODE_DELETE:
e->entry = NULL;
hotlist_delete_entry_internal(e);
+
+ err = hotlist_schedule_save();
break;
case TREE_MSG_NODE_EDIT:
@@ -459,6 +570,8 @@ hotlist_tree_node_entry_cb(struct treeview_node_msg msg, void *data)
free((void *)old_text);
}
+ err = hotlist_schedule_save();
+
} else if (lwc_string_isequal(hl_ctx.fields[HL_URL].field,
msg.data.node_edit.field, &match) ==
lwc_error_ok && match == true &&
@@ -476,6 +589,8 @@ hotlist_tree_node_entry_cb(struct treeview_node_msg msg, void *data)
treeview_update_node_entry(hl_ctx.tree,
e->entry, e->data, e);
nsurl_unref(old_url);
+
+ err = hotlist_schedule_save();
}
}
break;
@@ -538,20 +653,20 @@ static nserror hotlist_load_entry(dom_node *li, hotlist_load_ctx *ctx)
/* The li must contain an "a" element */
a = libdom_find_first_element(li, corestring_lwc_a);
if (a == NULL) {
- LOG("Missing <a> in <li>");
+ NSLOG(netsurf, INFO, "Missing <a> in <li>");
return NSERROR_INVALID;
}
derror = dom_node_get_text_content(a, &title1);
if (derror != DOM_NO_ERR) {
- LOG("No title");
+ NSLOG(netsurf, INFO, "No title");
dom_node_unref(a);
return NSERROR_INVALID;
}
derror = dom_element_get_attribute(a, corestring_dom_href, &url1);
if (derror != DOM_NO_ERR || url1 == NULL) {
- LOG("No URL");
+ NSLOG(netsurf, INFO, "No URL");
dom_string_unref(title1);
dom_node_unref(a);
return NSERROR_INVALID;
@@ -569,7 +684,8 @@ static nserror hotlist_load_entry(dom_node *li, hotlist_load_ctx *ctx)
dom_string_unref(url1);
if (err != NSERROR_OK) {
- LOG("Failed normalising '%s'", dom_string_data(url1));
+ NSLOG(netsurf, INFO, "Failed normalising '%s'",
+ dom_string_data(url1));
if (title1 != NULL) {
dom_string_unref(title1);
@@ -596,7 +712,7 @@ static nserror hotlist_load_entry(dom_node *li, hotlist_load_ctx *ctx)
/*
- * Callback for libdom_iterate_child_elements, which dispite the namespace is
+ * Callback for libdom_iterate_child_elements, which despite the namespace is
* a NetSurf function.
*
* \param node Node that is a child of the directory UL node
@@ -649,7 +765,8 @@ nserror hotlist_load_directory_cb(dom_node *node, void *ctx)
error = dom_node_get_text_content(node, &title);
if (error != DOM_NO_ERR || title == NULL) {
- LOG("Empty <h4> or memory exhausted.");
+ NSLOG(netsurf, INFO,
+ "Empty <h4> or memory exhausted.");
dom_string_unref(name);
return NSERROR_DOM;
}
@@ -729,36 +846,6 @@ nserror hotlist_load_directory_cb(dom_node *node, void *ctx)
/*
- * Get path for writing hotlist to
- *
- * \param path The final path of the hotlist
- * \param loaded Updated to the path to write the holist to
- * \return NSERROR_OK on success, or appropriate error otherwise
- */
-static nserror hotlist_get_temp_path(const char *path, char **temp_path)
-{
- const char *extension = "-bk";
- char *joined;
- int len;
-
- len = strlen(path) + strlen(extension);
-
- joined = malloc(len + 1);
- if (joined == NULL) {
- return NSERROR_NOMEM;
- }
-
- if (snprintf(joined, len + 1, "%s%s", path, extension) != len) {
- free(joined);
- return NSERROR_UNKNOWN;
- }
-
- *temp_path = joined;
- return NSERROR_OK;
-}
-
-
-/*
* Load the hotlist data from file
*
* \param path The path to load the hotlist file from, or NULL
@@ -777,7 +864,7 @@ static nserror hotlist_load(const char *path, bool *loaded)
/* Handle no path */
if (path == NULL) {
- LOG("No hotlist file path provided.");
+ NSLOG(netsurf, INFO, "No hotlist file path provided.");
return NSERROR_OK;
}
@@ -918,45 +1005,6 @@ static nserror hotlist_generate(void)
}
-/* Save the hotlist to to a file at the given path
- *
- * \param path Path to save hostlist file to.
- * \return NSERROR_OK on success, or appropriate error otherwise
- */
-static nserror hotlist_save(const char *path)
-{
- nserror res = NSERROR_OK;
- char *temp_path;
-
- /* Get path to export to */
- res = hotlist_get_temp_path(path, &temp_path);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* Export to temp path */
- res = hotlist_export(temp_path, NULL);
- if (res != NSERROR_OK) {
- goto cleanup;
- }
-
- /* Remove old hotlist to handle non-POSIX rename() implementations. */
- (void)remove(path);
-
- /* Replace any old hotlist file with the one we just saved */
- if (rename(temp_path, path) != 0) {
- res = NSERROR_SAVE_FAILED;
- LOG("Error renaming hotlist: %s.", strerror(errno));
- goto cleanup;
- }
-
-cleanup:
- free(temp_path);
-
- return res;
-}
-
-
struct treeview_export_walk_ctx {
FILE *fp;
};
@@ -1150,8 +1198,10 @@ static nserror hotlist_initialise_entry_fields(void)
goto error;
}
- hl_ctx.fields[HL_URL].flags = TREE_FLAG_ALLOW_EDIT |
- TREE_FLAG_COPY_TEXT;
+ hl_ctx.fields[HL_URL].flags =
+ TREE_FLAG_ALLOW_EDIT |
+ TREE_FLAG_COPY_TEXT |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelURL";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -1227,7 +1277,9 @@ static nserror hotlist_populate(const char *path)
/* Exported interface, documented in hotlist.h */
-nserror hotlist_init(const char *path)
+nserror hotlist_init(
+ const char *load_path,
+ const char *save_path)
{
nserror err;
@@ -1236,15 +1288,26 @@ nserror hotlist_init(const char *path)
return err;
}
- LOG("Loading hotlist");
+ NSLOG(netsurf, INFO, "Loading hotlist");
hl_ctx.tree = NULL;
hl_ctx.built = false;
hl_ctx.default_folder = NULL;
+ /* Store the save path */
+ if (save_path != NULL) {
+ hl_ctx.save_path = strdup(save_path);
+ if (hl_ctx.save_path == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ hl_ctx.save_path = NULL;
+ }
+
/* Init. hotlist treeview entry fields */
err = hotlist_initialise_entry_fields();
if (err != NSERROR_OK) {
+ free(hl_ctx.save_path);
hl_ctx.tree = NULL;
return err;
}
@@ -1252,15 +1315,17 @@ nserror hotlist_init(const char *path)
/* Create the hotlist treeview */
err = treeview_create(&hl_ctx.tree, &hl_tree_cb_t,
HL_N_FIELDS, hl_ctx.fields, NULL, NULL,
- TREEVIEW_NO_FLAGS);
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
+ free(hl_ctx.save_path);
hl_ctx.tree = NULL;
return err;
}
/* Populate the hotlist */
- err = hotlist_populate(path);
+ err = hotlist_populate(load_path);
if (err != NSERROR_OK) {
+ free(hl_ctx.save_path);
return err;
}
@@ -1269,7 +1334,7 @@ nserror hotlist_init(const char *path)
* the treeview is built. */
hl_ctx.built = true;
- LOG("Loaded hotlist");
+ NSLOG(netsurf, INFO, "Loaded hotlist");
return NSERROR_OK;
}
@@ -1310,19 +1375,25 @@ nserror hotlist_manager_fini(void)
/* Exported interface, documented in hotlist.h */
-nserror hotlist_fini(const char *path)
+nserror hotlist_fini(void)
{
int i;
nserror err;
- LOG("Finalising hotlist");
+ NSLOG(netsurf, INFO, "Finalising hotlist");
+
+ /* Remove any existing scheduled save callback */
+ guit->misc->schedule(-1, hotlist_schedule_save_cb, NULL);
+ hl_ctx.save_scheduled = false;
/* Save the hotlist */
- err = hotlist_save(path);
+ err = hotlist_save(hl_ctx.save_path);
if (err != NSERROR_OK) {
- LOG("Problem saving the hotlist.");
+ NSLOG(netsurf, INFO, "Problem saving the hotlist.");
}
+ free(hl_ctx.save_path);
+
/* Destroy the hotlist treeview */
err = treeview_destroy(hl_ctx.tree);
hl_ctx.built = false;
@@ -1337,7 +1408,7 @@ nserror hotlist_fini(const char *path)
return err;
}
- LOG("Finalised hotlist");
+ NSLOG(netsurf, INFO, "Finalised hotlist");
return err;
}
@@ -1380,7 +1451,7 @@ nserror hotlist_add_url(nsurl *url)
if (err != NSERROR_OK)
return err;
- return NSERROR_OK;
+ return hotlist_schedule_save();
}
diff --git a/desktop/hotlist.h b/desktop/hotlist.h
index c77ac92d2..571f4de97 100644
--- a/desktop/hotlist.h
+++ b/desktop/hotlist.h
@@ -40,10 +40,16 @@ struct rect;
* be called before URLs can be added to the hotlist, and before the
* hotlist can be queried to ask if URLs are present in the hotlist.
*
- * \param path The path to hotlist file to load
+ * In read-only mode the hotlist can be modified, but changes will not
+ * persist over sessions.
+ *
+ * \param load_path The path to load hotlist from.
+ * \param save_path The path to save hotlist to, or NULL for read-only mode.
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror hotlist_init(const char *path);
+nserror hotlist_init(
+ const char *load_path,
+ const char *save_path);
/**
* Initialise the hotlist manager.
@@ -67,7 +73,6 @@ nserror hotlist_manager_init(struct core_window_callback_table *cw_t,
* allowing destruction of a GUI hotlist window, without finalising the
* hotlist module.
*
- * \param path The path to save hotlist to
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror hotlist_manager_fini(void);
@@ -79,10 +84,9 @@ nserror hotlist_manager_fini(void);
* internal data. After calling this if hotlist is required again,
* hotlist_init must be called.
*
- * \param path The path to save hotlist to
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror hotlist_fini(const char *path);
+nserror hotlist_fini(void);
/**
* Add an entry to the hotlist for given URL.
diff --git a/desktop/knockout.c b/desktop/knockout.c
index bcfc272eb..127a48cdb 100644
--- a/desktop/knockout.c
+++ b/desktop/knockout.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Knockout rendering (implementation).
+/**
+ * \file
+ * Knockout rendering implementation.
*
* Knockout rendering is an optimisation which is particularly for
* unaccelerated screen redraw. It tries to avoid plotting the same area more
@@ -86,47 +87,6 @@
struct knockout_box;
struct knockout_entry;
-
-static void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *box);
-static bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style);
-static bool knockout_plot_bitmap_recursive(struct knockout_box *box,
- struct knockout_entry *entry);
-
-static bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
-static bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle);
-static bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *plot_style);
-static bool knockout_plot_clip(const struct rect *clip);
-static bool knockout_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
-static bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle);
-static bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle);
-static bool knockout_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags);
-static bool knockout_plot_flush(void);
-static bool knockout_plot_group_start(const char *name);
-static bool knockout_plot_group_end(void);
-static bool knockout_plot_path(const float *p, unsigned int n, colour fill,
- float width, colour c, const float transform[6]);
-
-
-const struct plotter_table knockout_plotters = {
- .rectangle = knockout_plot_rectangle,
- .line = knockout_plot_line,
- .polygon = knockout_plot_polygon,
- .clip = knockout_plot_clip,
- .text = knockout_plot_text,
- .disc = knockout_plot_disc,
- .arc = knockout_plot_arc,
- .bitmap = knockout_plot_bitmap,
- .group_start = knockout_plot_group_start,
- .group_end = knockout_plot_group_end,
- .flush = knockout_plot_flush,
- .path = knockout_plot_path,
- .option_knockout = true,
-};
-
-
typedef enum {
KNOCKOUT_PLOT_RECTANGLE,
KNOCKOUT_PLOT_LINE,
@@ -155,17 +115,11 @@ struct knockout_entry {
struct knockout_box *box; /* relating series of knockout clips */
union {
struct {
- int x0;
- int y0;
- int x1;
- int y1;
+ struct rect r;
plot_style_t plot_style;
} rectangle;
struct {
- int x0;
- int y0;
- int x1;
- int y1;
+ struct rect l;
plot_style_t plot_style;
} line;
struct {
@@ -174,10 +128,7 @@ struct knockout_entry {
plot_style_t plot_style;
} polygon;
struct {
- int x0;
- int y0;
- int x1;
- int y1;
+ struct rect r;
plot_style_t plot_style;
} fill;
struct rect clip;
@@ -231,166 +182,193 @@ static struct plotter_table real_plot;
static struct rect clip_cur;
static int nested_depth = 0;
+
/**
- * Start a knockout plotting session
- *
- * \param ctx the redraw context with real plotter table
- * \param knk_ctx updated to copy of ctx, with plotter table replaced
- * \return true on success, false otherwise
+ * fill an area recursively
*/
-bool knockout_plot_start(const struct redraw_context *ctx,
- struct redraw_context *knk_ctx)
+static nserror
+knockout_plot_fill_recursive(const struct redraw_context *ctx,
+ struct knockout_box *box,
+ plot_style_t *plot_style)
{
- /* check if we're recursing */
- if (nested_depth++ > 0) {
- /* we should already have the knockout renderer as default */
- assert(ctx->plot->rectangle == knockout_plotters.rectangle);
- *knk_ctx = *ctx;
- return true;
- }
-
- /* end any previous sessions */
- if (knockout_entry_cur > 0)
- knockout_plot_end();
-
- /* get copy of real plotter table */
- real_plot = *(ctx->plot);
+ struct knockout_box *parent;
+ nserror res;
+ nserror ffres = NSERROR_OK; /* first failing result */
- /* set up knockout rendering context */
- *knk_ctx = *ctx;
- knk_ctx->plot = &knockout_plotters;
- return true;
+ for (parent = box; parent; parent = parent->next) {
+ if (parent->deleted)
+ continue;
+ if (parent->child) {
+ res = knockout_plot_fill_recursive(ctx,
+ parent->child,
+ plot_style);
+ } else {
+ res = real_plot.rectangle(ctx, plot_style, &parent->bbox);
+ }
+ /* remember the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ }
+ return ffres;
}
/**
- * End a knockout plotting session
- *
- * \return true on success, false otherwise
+ * bitmap plot recusivley
*/
-bool knockout_plot_end(void)
+static nserror
+knockout_plot_bitmap_recursive(const struct redraw_context *ctx,
+ struct knockout_box *box,
+ struct knockout_entry *entry)
{
- /* only output when we've finished any nesting */
- if (--nested_depth == 0)
- return knockout_plot_flush();
+ nserror res;
+ nserror ffres = NSERROR_OK; /* first failing result */
+ struct knockout_box *parent;
- assert(nested_depth > 0);
- return true;
-}
+ for (parent = box; parent; parent = parent->next) {
+ if (parent->deleted)
+ continue;
+ if (parent->child) {
+ res = knockout_plot_bitmap_recursive(ctx,
+ parent->child,
+ entry);
+ } else {
+ real_plot.clip(ctx, &parent->bbox);
+ res = real_plot.bitmap(ctx,
+ entry->data.bitmap.bitmap,
+ entry->data.bitmap.x,
+ entry->data.bitmap.y,
+ entry->data.bitmap.width,
+ entry->data.bitmap.height,
+ entry->data.bitmap.bg,
+ entry->data.bitmap.flags);
+ }
+ /* remember the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ }
+ return ffres;
+}
/**
* Flush the current knockout session to empty the buffers
*
* \return true on success, false otherwise
*/
-bool knockout_plot_flush(void)
+static nserror knockout_plot_flush(const struct redraw_context *ctx)
{
int i;
- bool success = true;
struct knockout_box *box;
+ nserror res = NSERROR_OK; /* operation result */
+ nserror ffres = NSERROR_OK; /* first failing result */
/* debugging information */
#ifdef KNOCKOUT_DEBUG
- LOG("Entries are %i/%i, %i/%i, %i/%i", knockout_entry_cur, KNOCKOUT_ENTRIES, knockout_box_cur, KNOCKOUT_BOXES, knockout_polygon_cur, KNOCKOUT_POLYGONS);
+ NSLOG(netsurf, INFO, "Entries are %i/%i, %i/%i, %i/%i",
+ knockout_entry_cur, KNOCKOUT_ENTRIES, knockout_box_cur,
+ KNOCKOUT_BOXES, knockout_polygon_cur, KNOCKOUT_POLYGONS);
#endif
for (i = 0; i < knockout_entry_cur; i++) {
switch (knockout_entries[i].type) {
case KNOCKOUT_PLOT_RECTANGLE:
- success &= real_plot.rectangle(
- knockout_entries[i].data.rectangle.x0,
- knockout_entries[i].data.rectangle.y0,
- knockout_entries[i].data.rectangle.x1,
- knockout_entries[i].data.rectangle.y1,
- &knockout_entries[i].data.rectangle.plot_style);
+ res = real_plot.rectangle(ctx,
+ &knockout_entries[i].data.rectangle.plot_style,
+ &knockout_entries[i].data.rectangle.r);
break;
+
case KNOCKOUT_PLOT_LINE:
- success &= real_plot.line(
- knockout_entries[i].data.line.x0,
- knockout_entries[i].data.line.y0,
- knockout_entries[i].data.line.x1,
- knockout_entries[i].data.line.y1,
- &knockout_entries[i].data.line.plot_style);
+ res = real_plot.line(ctx,
+ &knockout_entries[i].data.line.plot_style,
+ &knockout_entries[i].data.line.l);
break;
+
case KNOCKOUT_PLOT_POLYGON:
- success &= real_plot.polygon(
- knockout_entries[i].data.polygon.p,
- knockout_entries[i].data.polygon.n,
- &knockout_entries[i].data.polygon.plot_style);
+ res = real_plot.polygon(ctx,
+ &knockout_entries[i].data.polygon.plot_style,
+ knockout_entries[i].data.polygon.p,
+ knockout_entries[i].data.polygon.n);
break;
+
case KNOCKOUT_PLOT_FILL:
box = knockout_entries[i].box->child;
- if (box)
- success &= knockout_plot_fill_recursive(box,
- &knockout_entries[i].data.fill.plot_style);
- else if (!knockout_entries[i].box->deleted)
- success &= real_plot.rectangle(
- knockout_entries[i].data.fill.x0,
- knockout_entries[i].data.fill.y0,
- knockout_entries[i].data.fill.x1,
- knockout_entries[i].data.fill.y1,
- &knockout_entries[i].data.fill.plot_style);
+ if (box) {
+ res = knockout_plot_fill_recursive(ctx,
+ box,
+ &knockout_entries[i].data.fill.plot_style);
+ } else if (!knockout_entries[i].box->deleted) {
+ res = real_plot.rectangle(ctx,
+ &knockout_entries[i].data.fill.plot_style,
+ &knockout_entries[i].data.fill.r);
+ }
break;
+
case KNOCKOUT_PLOT_CLIP:
- success &= real_plot.clip(
- &knockout_entries[i].data.clip);
+ res = real_plot.clip(ctx, &knockout_entries[i].data.clip);
break;
+
case KNOCKOUT_PLOT_TEXT:
- success &= real_plot.text(
+ res = real_plot.text(ctx,
+ &knockout_entries[i].data.text.font_style,
knockout_entries[i].data.text.x,
knockout_entries[i].data.text.y,
knockout_entries[i].data.text.text,
- knockout_entries[i].data.text.length,
- &knockout_entries[i].data.text.font_style);
+ knockout_entries[i].data.text.length);
break;
+
case KNOCKOUT_PLOT_DISC:
- success &= real_plot.disc(
+ res = real_plot.disc(ctx,
+ &knockout_entries[i].data.disc.plot_style,
knockout_entries[i].data.disc.x,
knockout_entries[i].data.disc.y,
- knockout_entries[i].data.disc.radius,
- &knockout_entries[i].data.disc.plot_style);
+ knockout_entries[i].data.disc.radius);
break;
+
case KNOCKOUT_PLOT_ARC:
- success &= real_plot.arc(
+ res = real_plot.arc(ctx,
+ &knockout_entries[i].data.arc.plot_style,
knockout_entries[i].data.arc.x,
knockout_entries[i].data.arc.y,
knockout_entries[i].data.arc.radius,
knockout_entries[i].data.arc.angle1,
- knockout_entries[i].data.arc.angle2,
- &knockout_entries[i].data.arc.plot_style);
+ knockout_entries[i].data.arc.angle2);
break;
+
case KNOCKOUT_PLOT_BITMAP:
box = knockout_entries[i].box->child;
if (box) {
- success &= knockout_plot_bitmap_recursive(box,
+ res = knockout_plot_bitmap_recursive(ctx,
+ box,
&knockout_entries[i]);
} else if (!knockout_entries[i].box->deleted) {
- success &= real_plot.bitmap(
- knockout_entries[i].data.
- bitmap.x,
- knockout_entries[i].data.
- bitmap.y,
- knockout_entries[i].data.
- bitmap.width,
- knockout_entries[i].data.
- bitmap.height,
- knockout_entries[i].data.
- bitmap.bitmap,
- knockout_entries[i].data.
- bitmap.bg,
- knockout_entries[i].data.
- bitmap.flags);
+ res = real_plot.bitmap(ctx,
+ knockout_entries[i].data.bitmap.bitmap,
+ knockout_entries[i].data.bitmap.x,
+ knockout_entries[i].data.bitmap.y,
+ knockout_entries[i].data.bitmap.width,
+ knockout_entries[i].data.bitmap.height,
+ knockout_entries[i].data.bitmap.bg,
+ knockout_entries[i].data.bitmap.flags);
}
break;
+
case KNOCKOUT_PLOT_GROUP_START:
- success &= real_plot.group_start(
- knockout_entries[i].data.group_start.name);
+ res = real_plot.group_start(ctx,
+ knockout_entries[i].data.group_start.name);
break;
+
case KNOCKOUT_PLOT_GROUP_END:
- success &= real_plot.group_end();
+ res = real_plot.group_end(ctx);
break;
}
+
+ /* remember the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
}
knockout_entry_cur = 0;
@@ -398,20 +376,24 @@ bool knockout_plot_flush(void)
knockout_polygon_cur = 0;
knockout_list = NULL;
- return success;
+ return ffres;
}
/**
* Knockout a section of previous rendering
*
+ * \param ctx The current redraw context.
* \param x0 The left edge of the removal box
* \param y0 The bottom edge of the removal box
* \param x1 The right edge of the removal box
* \param y1 The top edge of the removal box
* \param owner The parent box set to consider, or NULL for top level
-*/
-void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *owner)
+ */
+static void
+knockout_calculate(const struct redraw_context *ctx,
+ int x0, int y0, int x1, int y1,
+ struct knockout_box *owner)
{
struct knockout_box *box;
struct knockout_box *parent;
@@ -464,11 +446,11 @@ void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *own
/* has the box been replaced by children? */
if (parent->child) {
- knockout_calculate(x0, y0, x1, y1, parent);
+ knockout_calculate(ctx, x0, y0, x1, y1, parent);
} else {
/* we need a maximum of 4 child boxes */
if (knockout_box_cur + 4 >= KNOCKOUT_BOXES) {
- knockout_plot_flush();
+ knockout_plot_flush(ctx);
return;
}
@@ -527,136 +509,138 @@ void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *own
}
-bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style)
-{
- bool success = true;
- struct knockout_box *parent;
-
- for (parent = box; parent; parent = parent->next) {
- if (parent->deleted)
- continue;
- if (parent->child)
- knockout_plot_fill_recursive(parent->child, plot_style);
- else
- success &= real_plot.rectangle(parent->bbox.x0,
- parent->bbox.y0,
- parent->bbox.x1,
- parent->bbox.y1,
- plot_style);
- }
- return success;
-}
-
-
-bool knockout_plot_bitmap_recursive(struct knockout_box *box,
- struct knockout_entry *entry)
-{
- bool success = true;
- struct knockout_box *parent;
-
- for (parent = box; parent; parent = parent->next) {
- if (parent->deleted)
- continue;
- if (parent->child)
- knockout_plot_bitmap_recursive(parent->child, entry);
- else {
- success &= real_plot.clip(&parent->bbox);
- success &= real_plot.bitmap(entry->data.bitmap.x,
- entry->data.bitmap.y,
- entry->data.bitmap.width,
- entry->data.bitmap.height,
- entry->data.bitmap.bitmap,
- entry->data.bitmap.bg,
- entry->data.bitmap.flags);
- }
- }
- return success;
-}
-
-bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
+/**
+ * knockout rectangle plotting.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *rect)
{
int kx0, ky0, kx1, ky1;
+ nserror res = NSERROR_OK;
- if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
+ if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
/* filled draw */
/* get our bounds */
- kx0 = (x0 > clip_cur.x0) ? x0 : clip_cur.x0;
- ky0 = (y0 > clip_cur.y0) ? y0 : clip_cur.y0;
- kx1 = (x1 < clip_cur.x1) ? x1 : clip_cur.x1;
- ky1 = (y1 < clip_cur.y1) ? y1 : clip_cur.y1;
+ kx0 = (rect->x0 > clip_cur.x0) ? rect->x0 : clip_cur.x0;
+ ky0 = (rect->y0 > clip_cur.y0) ? rect->y0 : clip_cur.y0;
+ kx1 = (rect->x1 < clip_cur.x1) ? rect->x1 : clip_cur.x1;
+ ky1 = (rect->y1 < clip_cur.y1) ? rect->y1 : clip_cur.y1;
if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0) ||
- (ky0 > clip_cur.y1) || (ky1 < clip_cur.y0))
- return true;
+ (ky0 > clip_cur.y1) || (ky1 < clip_cur.y0)) {
+ return NSERROR_OK;
+ }
/* fills both knock out and get knocked out */
- knockout_calculate(kx0, ky0, kx1, ky1, NULL);
- knockout_boxes[knockout_box_cur].bbox.x0 = x0;
- knockout_boxes[knockout_box_cur].bbox.y0 = y0;
- knockout_boxes[knockout_box_cur].bbox.x1 = x1;
- knockout_boxes[knockout_box_cur].bbox.y1 = y1;
+ knockout_calculate(ctx, kx0, ky0, kx1, ky1, NULL);
+ knockout_boxes[knockout_box_cur].bbox = *rect;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = knockout_list;
knockout_list = &knockout_boxes[knockout_box_cur];
knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur];
- knockout_entries[knockout_entry_cur].data.fill.x0 = x0;
- knockout_entries[knockout_entry_cur].data.fill.y0 = y0;
- knockout_entries[knockout_entry_cur].data.fill.x1 = x1;
- knockout_entries[knockout_entry_cur].data.fill.y1 = y1;
+ knockout_entries[knockout_entry_cur].data.fill.r = *rect;
knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].data.fill.plot_style.stroke_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the fill */
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_FILL;
if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) ||
- (++knockout_box_cur >= KNOCKOUT_BOXES))
- knockout_plot_flush();
- }
+ (++knockout_box_cur >= KNOCKOUT_BOXES)) {
+ res = knockout_plot_flush(ctx);
+ }
+ }
if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
/* draw outline */
- knockout_entries[knockout_entry_cur].data.rectangle.x0 = x0;
- knockout_entries[knockout_entry_cur].data.rectangle.y0 = y0;
- knockout_entries[knockout_entry_cur].data.rectangle.x1 = x1;
- knockout_entries[knockout_entry_cur].data.rectangle.y1 = y1;
+ knockout_entries[knockout_entry_cur].data.rectangle.r = *rect;
knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].data.fill.plot_style.fill_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the outline */
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_RECTANGLE;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- }
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ }
+ return res;
}
-bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
+
+/**
+ * Knockout line plotting.
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *line)
{
- knockout_entries[knockout_entry_cur].data.line.x0 = x0;
- knockout_entries[knockout_entry_cur].data.line.y0 = y0;
- knockout_entries[knockout_entry_cur].data.line.x1 = x1;
- knockout_entries[knockout_entry_cur].data.line.y1 = y1;
+ knockout_entries[knockout_entry_cur].data.line.l = *line;
knockout_entries[knockout_entry_cur].data.line.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_LINE;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ return knockout_plot_flush(ctx);
+ }
+ return NSERROR_OK;
}
-bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle)
+/**
+ * Knockout polygon plotting.
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const int *p,
+ unsigned int n)
{
- bool success = true;
int *dest;
+ nserror res = NSERROR_OK;
+ nserror ffres = NSERROR_OK;
/* ensure we have sufficient room even when flushed */
if (n * 2 >= KNOCKOUT_POLYGONS) {
- knockout_plot_flush();
- success = real_plot.polygon(p, n, pstyle);
- return success;
+ ffres = knockout_plot_flush(ctx);
+ res = real_plot.polygon(ctx, pstyle, p, n);
+ /* return the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ return ffres;
}
/* ensure we have enough room right now */
- if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS)
- knockout_plot_flush();
+ if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS) {
+ ffres = knockout_plot_flush(ctx);
+ }
/* copy our data */
dest = &(knockout_polygons[knockout_polygon_cur]);
@@ -666,27 +650,62 @@ bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pst
knockout_entries[knockout_entry_cur].data.polygon.n = n;
knockout_entries[knockout_entry_cur].data.polygon.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_POLYGON;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ /* return the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ return ffres;
}
-bool knockout_plot_path(const float *p, unsigned int n, colour fill,
- float width, colour c, const float transform[6])
+/**
+ * knockout path plotting.
+ *
+ * The knockout implementation simply flushes the queue and plots the path
+ * directly using real plotter.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
- knockout_plot_flush();
- return real_plot.path(p, n, fill, width, c, transform);
+ nserror res;
+ nserror ffres;
+
+ ffres = knockout_plot_flush(ctx);
+ res = real_plot.path(ctx, pstyle, p, n, transform);
+
+ /* return the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ return ffres;
}
-bool knockout_plot_clip(const struct rect *clip)
+static nserror
+knockout_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
{
+ nserror res = NSERROR_OK;
+
if (clip->x1 < clip->x0 || clip->y0 > clip->y1) {
#ifdef KNOCKOUT_DEBUG
- LOG("bad clip rectangle %i %i %i %i", clip->x0, clip->y0, clip->x1, clip->y1);
+ NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
+ clip->x0, clip->y0, clip->x1, clip->y1);
#endif
- return false;
+ return NSERROR_BAD_SIZE;
}
/* memorise clip for bitmap tiling */
@@ -694,41 +713,107 @@ bool knockout_plot_clip(const struct rect *clip)
knockout_entries[knockout_entry_cur].data.clip = *clip;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_CLIP;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ return res;
}
-bool knockout_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_text(const struct redraw_context *ctx,
+ const plot_font_style_t *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
+ nserror res = NSERROR_OK;
+
knockout_entries[knockout_entry_cur].data.text.x = x;
knockout_entries[knockout_entry_cur].data.text.y = y;
knockout_entries[knockout_entry_cur].data.text.text = text;
knockout_entries[knockout_entry_cur].data.text.length = length;
knockout_entries[knockout_entry_cur].data.text.font_style = *fstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_TEXT;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ return res;
}
-bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle)
+/**
+ * knockout circle plotting
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x,
+ int y,
+ int radius)
{
+ nserror res = NSERROR_OK;
+
knockout_entries[knockout_entry_cur].data.disc.x = x;
knockout_entries[knockout_entry_cur].data.disc.y = y;
knockout_entries[knockout_entry_cur].data.disc.radius = radius;
knockout_entries[knockout_entry_cur].data.disc.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_DISC;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ return res;
}
-bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle)
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x,
+ int y,
+ int radius,
+ int angle1,
+ int angle2)
{
+ nserror res = NSERROR_OK;
+
knockout_entries[knockout_entry_cur].data.arc.x = x;
knockout_entries[knockout_entry_cur].data.arc.y = y;
knockout_entries[knockout_entry_cur].data.arc.radius = radius;
@@ -736,18 +821,48 @@ bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const p
knockout_entries[knockout_entry_cur].data.arc.angle2 = angle2;
knockout_entries[knockout_entry_cur].data.arc.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_ARC;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ res = knockout_plot_flush(ctx);
+ }
+ return res;
}
-
-bool knockout_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+/**
+ * knockout bitmap plotting.
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width, int height,
+ colour bg,
+ bitmap_flags_t flags)
{
int kx0, ky0, kx1, ky1;
+ nserror res;
+ nserror ffres = NSERROR_OK;
/* get our bounds */
kx0 = clip_cur.x0;
@@ -760,7 +875,7 @@ bool knockout_plot_bitmap(int x, int y, int width, int height,
if (x + width < kx1)
kx1 = x + width;
if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0))
- return true;
+ return NSERROR_OK;
}
if (!(flags & BITMAPF_REPEAT_Y)) {
if (y > ky0)
@@ -768,12 +883,12 @@ bool knockout_plot_bitmap(int x, int y, int width, int height,
if (y + height < ky1)
ky1 = y + height;
if ((ky0 > clip_cur.y1) || (ky1 < clip_cur.y0))
- return true;
+ return NSERROR_OK;
}
/* tiled bitmaps both knock out and get knocked out */
if (guit->bitmap->get_opaque(bitmap)) {
- knockout_calculate(kx0, ky0, kx1, ky1, NULL);
+ knockout_calculate(ctx, kx0, ky0, kx1, ky1, NULL);
}
knockout_boxes[knockout_box_cur].bbox.x0 = kx0;
knockout_boxes[knockout_box_cur].bbox.y0 = ky0;
@@ -792,33 +907,120 @@ bool knockout_plot_bitmap(int x, int y, int width, int height,
knockout_entries[knockout_entry_cur].data.bitmap.bg = bg;
knockout_entries[knockout_entry_cur].data.bitmap.flags = flags;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_BITMAP;
+
if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) ||
- (++knockout_box_cur >= KNOCKOUT_BOXES))
- knockout_plot_flush();
- return knockout_plot_clip(&clip_cur);
+ (++knockout_box_cur >= KNOCKOUT_BOXES)) {
+ ffres = knockout_plot_flush(ctx);
+ }
+ res = knockout_plot_clip(ctx, &clip_cur);
+ /* return the first error */
+ if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) {
+ ffres = res;
+ }
+ return ffres;
}
-bool knockout_plot_group_start(const char *name)
+
+/**
+ * Start of a group of objects.
+ *
+ * Used when plotter implements export to a vector graphics file format.
+ *
+ * \param ctx The current redraw context.
+ * \param name The name of the group being started.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+knockout_plot_group_start(const struct redraw_context *ctx, const char *name)
{
if (real_plot.group_start == NULL) {
- return true;
+ return NSERROR_OK;
}
knockout_entries[knockout_entry_cur].data.group_start.name = name;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_START;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
- return true;
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ return knockout_plot_flush(ctx);
+ }
+ return NSERROR_OK;
}
-bool knockout_plot_group_end(void)
+
+/**
+ * End a group of objects.
+ *
+ * Used when plotter implements export to a vector graphics file format.
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror knockout_plot_group_end(const struct redraw_context *ctx)
{
if (real_plot.group_end == NULL) {
- return true;
+ return NSERROR_OK;
}
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_END;
- if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
- knockout_plot_flush();
+ if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) {
+ return knockout_plot_flush(ctx);
+ }
+ return NSERROR_OK;
+}
+
+/* exported functions documented in desktop/knockout.h */
+bool knockout_plot_start(const struct redraw_context *ctx,
+ struct redraw_context *knk_ctx)
+{
+ /* check if we're recursing */
+ if (nested_depth++ > 0) {
+ /* we should already have the knockout renderer as default */
+ assert(ctx->plot->rectangle == knockout_plotters.rectangle);
+ *knk_ctx = *ctx;
+ return true;
+ }
+
+ /* end any previous sessions */
+ if (knockout_entry_cur > 0)
+ knockout_plot_end(ctx);
+
+ /* get copy of real plotter table */
+ real_plot = *(ctx->plot);
+
+ /* set up knockout rendering context */
+ *knk_ctx = *ctx;
+ knk_ctx->plot = &knockout_plotters;
return true;
}
+
+
+/* exported functions documented in desktop/knockout.h */
+bool knockout_plot_end(const struct redraw_context *ctx)
+{
+ /* only output when we've finished any nesting */
+ if (--nested_depth == 0) {
+ return knockout_plot_flush(ctx);
+ }
+
+ assert(nested_depth > 0);
+ return true;
+}
+
+
+/**
+ * knockout plotter operation table
+ */
+const struct plotter_table knockout_plotters = {
+ .rectangle = knockout_plot_rectangle,
+ .line = knockout_plot_line,
+ .polygon = knockout_plot_polygon,
+ .clip = knockout_plot_clip,
+ .text = knockout_plot_text,
+ .disc = knockout_plot_disc,
+ .arc = knockout_plot_arc,
+ .bitmap = knockout_plot_bitmap,
+ .group_start = knockout_plot_group_start,
+ .group_end = knockout_plot_group_end,
+ .flush = knockout_plot_flush,
+ .path = knockout_plot_path,
+ .option_knockout = true,
+};
diff --git a/desktop/knockout.h b/desktop/knockout.h
index c4f1245fc..f7ff04553 100644
--- a/desktop/knockout.h
+++ b/desktop/knockout.h
@@ -26,9 +26,21 @@
#include "netsurf/plotters.h"
+/**
+ * Start a knockout plotting session
+ *
+ * \param ctx the redraw context with real plotter table
+ * \param knk_ctx updated to copy of ctx, with plotter table replaced
+ * \return true on success, false otherwise
+ */
bool knockout_plot_start(const struct redraw_context *ctx,
struct redraw_context *knk_ctx);
-bool knockout_plot_end(void);
+/**
+ * End a knockout plotting session
+ *
+ * \return true on success, false otherwise
+ */
+bool knockout_plot_end(const struct redraw_context *ctx);
extern const struct plotter_table knockout_plotters;
diff --git a/desktop/local_history.c b/desktop/local_history.c
new file mode 100644
index 000000000..75da4aff1
--- /dev/null
+++ b/desktop/local_history.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Local history viewer implementation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/errors.h"
+#include "utils/nsurl.h"
+#include "netsurf/types.h"
+#include "netsurf/layout.h"
+#include "netsurf/core_window.h"
+#include "netsurf/plotters.h"
+
+#include "desktop/gui_internal.h"
+#include "desktop/system_colour.h"
+#include "desktop/browser_private.h"
+#include "desktop/browser_history.h"
+#include "desktop/local_history.h"
+
+#define WIDTH 100
+#define HEIGHT 86
+
+/**
+ * local history viewer context
+ */
+struct local_history_session {
+ struct browser_window *bw;
+ struct core_window_callback_table *cw_t;
+ void *core_window_handle;
+};
+
+
+/**
+ * plot style for drawing lines between nodes
+ */
+static plot_style_t pstyle_line = {
+ .stroke_type = PLOT_OP_TYPE_SOLID,
+ .stroke_width = plot_style_int_to_fixed(2),
+};
+
+
+/**
+ * plot style for drawing background
+ */
+static plot_style_t pstyle_bg = {
+ .fill_type = PLOT_OP_TYPE_SOLID,
+};
+
+
+/**
+ * plot style for drawing rectangle round unselected nodes
+ */
+static plot_style_t pstyle_rect = {
+ .stroke_type = PLOT_OP_TYPE_SOLID,
+ .stroke_width = plot_style_int_to_fixed(1),
+};
+
+
+/**
+ * plot style for drawing rectangle round selected nodes
+ */
+static plot_style_t pstyle_rect_sel = {
+ .stroke_type = PLOT_OP_TYPE_SOLID,
+ .stroke_width = plot_style_int_to_fixed(3),
+};
+
+
+/**
+ * plot style for font on unselected nodes
+ */
+static plot_font_style_t pfstyle_node = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 8 * PLOT_STYLE_SCALE,
+ .weight = 400,
+ .flags = FONTF_NONE,
+};
+
+
+/**
+ * plot style for font on unselected nodes
+ */
+static plot_font_style_t pfstyle_node_sel = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 8 * PLOT_STYLE_SCALE,
+ .weight = 900,
+ .flags = FONTF_NONE,
+};
+
+
+/**
+ * Recursively redraw a history entry.
+ *
+ * \param history history containing the entry
+ * \param entry entry to render
+ * \param clip redraw area
+ * \param x window x offset
+ * \param y window y offset
+ * \param ctx current redraw context
+ */
+static nserror
+redraw_entry(struct history *history,
+ struct history_entry *entry,
+ struct rect *clip,
+ int x, int y,
+ const struct redraw_context *ctx)
+{
+ size_t char_offset;
+ int actual_x;
+ struct history_entry *child;
+ int tailsize = 5;
+
+ plot_style_t *pstyle;
+ plot_font_style_t *pfstyle;
+ struct rect rect;
+ nserror res;
+
+ /* setup plot styles */
+ if (entry == history->current) {
+ pstyle = &pstyle_rect_sel;
+ pfstyle = &pfstyle_node_sel;
+ } else {
+ pstyle = &pstyle_rect;
+ pfstyle = &pfstyle_node;
+ }
+
+ /* Only attempt to plot bitmap if it is present */
+ if (entry->page.bitmap != NULL) {
+ res = ctx->plot->bitmap(ctx,
+ entry->page.bitmap,
+ entry->x + x,
+ entry->y + y,
+ WIDTH, HEIGHT,
+ 0xffffff,
+ 0);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ rect.x0 = entry->x - 1 + x;
+ rect.y0 = entry->y - 1 + y;
+ rect.x1 = entry->x + x + WIDTH;
+ rect.y1 = entry->y + y + HEIGHT;
+ res = ctx->plot->rectangle(ctx, pstyle, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = guit->layout->position(plot_style_font, entry->page.title,
+ strlen(entry->page.title), WIDTH,
+ &char_offset, &actual_x);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ctx->plot->text(ctx,
+ pfstyle,
+ entry->x + x,
+ entry->y + HEIGHT + 12 + y,
+ entry->page.title,
+ char_offset);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* for each child node draw a line and recurse redraw into it */
+ for (child = entry->forward; child; child = child->next) {
+ rect.x0 = entry->x + WIDTH + x;
+ rect.y0 = entry->y + HEIGHT / 2 + y;
+ rect.x1 = entry->x + WIDTH + tailsize + x;
+ rect.y1 = entry->y + HEIGHT / 2 + y;
+ res = ctx->plot->line(ctx, &pstyle_line, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ rect.x0 = entry->x + WIDTH + tailsize + x;
+ rect.y0 = entry->y + HEIGHT / 2 + y;
+ rect.x1 = child->x - tailsize + x;
+ rect.y1 = child->y + HEIGHT / 2 + y;
+ res = ctx->plot->line(ctx, &pstyle_line, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ rect.x0 = child->x - tailsize + x;
+ rect.y0 = child->y + HEIGHT / 2 + y;
+ rect.x1 = child->x + x;
+ rect.y1 = child->y + HEIGHT / 2 + y;
+ res = ctx->plot->line(ctx, &pstyle_line, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = redraw_entry(history, child, clip, x, y, ctx);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find the history entry at a position.
+ *
+ * \param entry entry to search from
+ * \param x coordinate
+ * \param y coordinate
+ * \return an entry if found, 0 if none
+ */
+static struct history_entry *
+find_entry_position(struct history_entry *entry, int x, int y)
+{
+ struct history_entry *child;
+ struct history_entry *found;
+
+ if (!entry) {
+ return NULL;
+ }
+
+ if ((entry->x <= x) &&
+ (x <= entry->x + WIDTH) &&
+ (entry->y <= y) &&
+ (y <= entry->y + HEIGHT)) {
+ return entry;
+ }
+
+ for (child = entry->forward; child; child = child->next) {
+ found = find_entry_position(child, x, y);
+ if (found) {
+ return found;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle,
+ struct browser_window *bw,
+ struct local_history_session **session)
+{
+ nserror res;
+ struct local_history_session *nses;
+
+ res = ns_system_colour_char("Window", &pstyle_bg.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ pfstyle_node.background = pstyle_bg.fill_colour;
+ pfstyle_node_sel.background = pstyle_bg.fill_colour;
+
+ res = ns_system_colour_char("GrayText", &pstyle_line.stroke_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ pstyle_rect.stroke_colour = pstyle_line.stroke_colour;
+ pfstyle_node.foreground = pstyle_line.stroke_colour;
+
+ res = ns_system_colour_char("Highlight", &pstyle_rect_sel.stroke_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour;
+
+ nses = calloc(1, sizeof(struct local_history_session));
+ if (nses == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ nses->cw_t = cw_t;
+ nses->core_window_handle = core_window_handle;
+
+ local_history_set(nses, bw);
+
+ *session = nses;
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in desktop/local_history.h */
+nserror local_history_fini(struct local_history_session *session)
+{
+ free(session);
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_redraw(struct local_history_session *session,
+ int x,
+ int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct rect r = {
+ .x0 = clip->x0 + x,
+ .y0 = clip->y0 + y,
+ .x1 = clip->x1 + x,
+ .y1 = clip->y1 + y,
+ };
+
+ if (session->bw == NULL) {
+ return NSERROR_OK;
+ }
+
+ if (session->bw->history->start == NULL) {
+ return NSERROR_OK;
+ }
+
+ ctx->plot->clip(ctx, &r);
+ ctx->plot->rectangle(ctx, &pstyle_bg, &r);
+
+ return redraw_entry(session->bw->history,
+ session->bw->history->start,
+ clip,
+ x, y,
+ ctx);
+}
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_mouse_action(struct local_history_session *session,
+ enum browser_mouse_state mouse,
+ int x,
+ int y)
+{
+ struct history_entry *entry;
+ bool new_window;
+
+ if (session->bw == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ if ((mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) == 0) {
+ return NSERROR_NOT_IMPLEMENTED;
+ }
+
+ entry = find_entry_position(session->bw->history->start, x, y);
+ if (entry == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ if (entry == session->bw->history->current) {
+ return NSERROR_PERMISSION;
+ }
+
+ if (mouse & BROWSER_MOUSE_PRESS_1) {
+ new_window = false;
+ } else if (mouse & BROWSER_MOUSE_PRESS_2) {
+ new_window = true;
+ } else {
+ new_window = false;
+ }
+
+ browser_window_history_go(session->bw, entry, new_window);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in desktop/local_history.h */
+bool
+local_history_keypress(struct local_history_session *session, uint32_t key)
+{
+ return false;
+}
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_set(struct local_history_session *session,
+ struct browser_window *bw)
+{
+ session->bw = bw;
+ if (bw != NULL) {
+ assert(session->bw->history != NULL);
+
+ session->cw_t->update_size(session->core_window_handle,
+ session->bw->history->width,
+ session->bw->history->height);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_get_size(struct local_history_session *session,
+ int *width,
+ int *height)
+{
+ *width = session->bw->history->width + 20;
+ *height = session->bw->history->height + 20;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in desktop/local_history.h */
+nserror
+local_history_get_url(struct local_history_session *session,
+ int x, int y,
+ nsurl **url_out)
+{
+ struct history_entry *entry;
+
+ if (session->bw == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ entry = find_entry_position(session->bw->history->start, x, y);
+ if (entry == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ *url_out = nsurl_ref(entry->page.url);
+
+ return NSERROR_OK;
+}
diff --git a/desktop/local_history.h b/desktop/local_history.h
new file mode 100644
index 000000000..7f85a633e
--- /dev/null
+++ b/desktop/local_history.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_DESKTOP_LOCAL_HISTORY_H
+#define NETSURF_DESKTOP_LOCAL_HISTORY_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "utils/errors.h"
+#include "netsurf/mouse.h"
+
+struct core_window_callback_table;
+struct redraw_context;
+struct nsurl;
+struct rect;
+struct local_history_session;
+struct browser_window;
+
+/**
+ * Initialise the local history.
+ *
+ * This iterates through the history object of a browser window and
+ * creates tree of visited pages with thumbnails which may be selected
+ * to cause navigation.
+ *
+ * This must be called before any other local_history_* function.
+ *
+ * \param[in] cw_t Callback table for core_window containing the treeview.
+ * \param[in] core_window_handle The core_window in which the treeview is shown.
+ * \param[in] bw browser window to show history of.
+ * \param[out] session The created local history session context.
+ * \return NSERROR_OK on success and session set, appropriate error code otherwise
+ */
+nserror local_history_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle,
+ struct browser_window *bw,
+ struct local_history_session **session);
+
+/**
+ * Finalise the local history.
+ *
+ * This destroys the local history view and the local history module's
+ * internal data. After calling this if local history is required again,
+ * local_history_init must be called to create a new session.
+ *
+ * \param session The local history session to finalise.
+ * \return NSERROR_OK on success and session freed appropriate error otherwise
+ */
+nserror local_history_fini(struct local_history_session *session);
+
+
+/**
+ * Redraw the local history.
+ *
+ * Causes the local history viewer to issue plot operations to redraw
+ * the specified area of the viewport.
+ *
+ * \param[in] session The local history session context.
+ * \param[in] x X coordinate to render history at
+ * \param[in] y Y coordinate to render history at
+ * \param[in] clip Current clip rectangle (wrt tree origin)
+ * \param[in] ctx Current redraw context
+ */
+nserror local_history_redraw(struct local_history_session *session, int x, int y, struct rect *clip, const struct redraw_context *ctx);
+
+
+/**
+ * Handles all kinds of mouse action
+ *
+ * \param[in] session The local history session context.
+ * \param[in] mouse The current mouse state
+ * \param[in] x The current mouse X coordinate
+ * \param[in] y The current mouse Y coordinate
+ * \return NSERROR_OK if mouse action was processed.
+ * NSERROR_NOT_FOUND if nothing under the pointer where it was clicked
+ * NSERROR_NOT_IMPLEMENTED if the action was not processed.
+ * NSERROR_PERMISSION if the clicked item was the current page
+ */
+nserror local_history_mouse_action(struct local_history_session *session, enum browser_mouse_state mouse, int x, int y);
+
+
+/**
+ * Key press handling.
+ *
+ * \param[in] session The local history session context.
+ * \param[in] key The ucs4 character codepoint
+ * \return true if the keypress is dealt with, false otherwise.
+ */
+bool local_history_keypress(struct local_history_session *session, uint32_t key);
+
+
+/**
+ * Change the browser window to draw local history for.
+ *
+ * \param[in] session The local history session context.
+ * \param bw browser window to show history of.
+ * \return NSERROR_OK or appropriate error code.
+ */
+nserror local_history_set(struct local_history_session *session, struct browser_window *bw);
+
+
+/**
+ * get size of local history content area.
+ *
+ * \param[in] session The local history session context.
+ * \param[out] width on sucessful return the width of the localhistory content
+ * \param[out] height on sucessful return the height of the localhistory content
+ * \return NSERROR_OK or appropriate error code.
+ */
+nserror local_history_get_size(struct local_history_session *session, int *width, int *height);
+
+
+/**
+ * get url of entry at position in local history content area.
+ *
+ * \todo the returned url should be a referenced nsurl.
+ *
+ * \param[in] session The local history session context.
+ * \param[in] x The x coordinate to get url of.
+ * \param[in] y The y coordinate to get url of.
+ * \param[out] url_out referenced url.
+ * \return NSERROR_OK and url_out updated or NSERROR_NOT_FOUND if no url at
+ * location.
+ */
+nserror local_history_get_url(struct local_history_session *session, int x, int y, struct nsurl **url_out);
+
+
+#endif
diff --git a/desktop/mouse.c b/desktop/mouse.c
index 6d22fd461..d22910582 100644
--- a/desktop/mouse.c
+++ b/desktop/mouse.c
@@ -30,5 +30,5 @@
*/
void browser_mouse_state_dump(browser_mouse_state mouse)
{
- LOG("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ", mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ", mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ", mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ", mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ", mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ", mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ", mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ", mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ", mouse & BROWSER_MOUSE_HOLDING_1 ? "H1" : " ", mouse & BROWSER_MOUSE_HOLDING_2 ? "H2" : " ", mouse & BROWSER_MOUSE_MOD_1 ? "M1" : " ", mouse & BROWSER_MOUSE_MOD_2 ? "M2" : " ", mouse & BROWSER_MOUSE_MOD_3 ? "M3" : " ");
+ NSLOG(netsurf, INFO, "mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ", mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ", mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ", mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ", mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ", mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ", mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ", mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ", mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ", mouse & BROWSER_MOUSE_HOLDING_1 ? "H1" : " ", mouse & BROWSER_MOUSE_HOLDING_2 ? "H2" : " ", mouse & BROWSER_MOUSE_MOD_1 ? "M1" : " ", mouse & BROWSER_MOUSE_MOD_2 ? "M2" : " ", mouse & BROWSER_MOUSE_MOD_3 ? "M3" : " ");
}
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 0f597aa9d..76ff4b19a 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -41,8 +41,8 @@
#include "image/image.h"
#include "image/image_cache.h"
#include "javascript/js.h"
-#include "render/html.h"
-#include "render/textplain.h"
+#include "html/html.h"
+#include "text/textplain.h"
#include "netsurf/browser_window.h"
#include "desktop/system_colour.h"
@@ -89,7 +89,8 @@
static void netsurf_lwc_iterator(lwc_string *str, void *pw)
{
- LOG("[%3u] %.*s", str->refcnt, (int)lwc_string_length(str), lwc_string_data(str));
+ NSLOG(netsurf, INFO, "[%3u] %.*s", str->refcnt,
+ (int)lwc_string_length(str), lwc_string_data(str));
}
/**
@@ -165,8 +166,9 @@ nserror netsurf_init(const char *store_path)
if (hlcache_parameters.llcache.limit < MINIMUM_MEMORY_CACHE_SIZE) {
hlcache_parameters.llcache.limit = MINIMUM_MEMORY_CACHE_SIZE;
- LOG("Setting minimum memory cache size %" PRIsizet,
- hlcache_parameters.llcache.limit);
+ NSLOG(netsurf, INFO,
+ "Setting minimum memory cache size %"PRIsizet,
+ hlcache_parameters.llcache.limit);
}
/* Set up the max attempts made to fetch a timing out resource */
@@ -212,10 +214,6 @@ nserror netsurf_init(const char *store_path)
if (ret != NSERROR_OK)
return ret;
- ret = mimesniff_init();
- if (ret != NSERROR_OK)
- return ret;
-
setlocale(LC_ALL, "");
/* initialise the fetchers */
@@ -247,44 +245,42 @@ void netsurf_exit(void)
{
hlcache_stop();
- LOG("Closing GUI");
+ NSLOG(netsurf, INFO, "Closing GUI");
guit->misc->quit();
- LOG("Finalising JavaScript");
+ NSLOG(netsurf, INFO, "Finalising JavaScript");
js_finalise();
- LOG("Finalising Web Search");
+ NSLOG(netsurf, INFO, "Finalising Web Search");
search_web_finalise();
- LOG("Finalising high-level cache");
+ NSLOG(netsurf, INFO, "Finalising high-level cache");
hlcache_finalise();
- LOG("Closing fetches");
+ NSLOG(netsurf, INFO, "Closing fetches");
fetcher_quit();
- mimesniff_fini();
-
/* dump any remaining cache entries */
image_cache_fini();
/* Clean up after content handlers */
content_factory_fini();
- LOG("Closing utf8");
+ NSLOG(netsurf, INFO, "Closing utf8");
utf8_finalise();
- LOG("Destroying URLdb");
+ NSLOG(netsurf, INFO, "Destroying URLdb");
urldb_destroy();
- LOG("Destroying System colours");
+ NSLOG(netsurf, INFO, "Destroying System colours");
ns_system_colour_finalize();
- LOG("Destroying Messages");
+ NSLOG(netsurf, INFO, "Destroying Messages");
messages_destroy();
corestrings_fini();
- LOG("Remaining lwc strings:");
+ NSLOG(netsurf, INFO, "Remaining lwc strings:");
lwc_iterate_strings(netsurf_lwc_iterator, NULL);
- LOG("Exited successfully");
+ NSLOG(netsurf, INFO, "Exited successfully");
}
diff --git a/desktop/options.h b/desktop/options.h
index d91898c6e..9b7064efa 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -289,3 +289,8 @@ NSOPTION_COLOUR(sys_colour_ThreeDShadow, 0x00d5d5d5)
NSOPTION_COLOUR(sys_colour_Window, 0x00f1f1f1)
NSOPTION_COLOUR(sys_colour_WindowFrame, 0x004e4e4e)
NSOPTION_COLOUR(sys_colour_WindowText, 0x00000000)
+
+/** Filter for non-verbose logging */
+NSOPTION_STRING(log_filter, "level:WARNING")
+/** Filter for verbose logging */
+NSOPTION_STRING(verbose_filter, "level:VERBOSE")
diff --git a/desktop/plot_style.c b/desktop/plot_style.c
index 1f0ac39cf..05954144a 100644
--- a/desktop/plot_style.c
+++ b/desktop/plot_style.c
@@ -47,7 +47,7 @@ plot_style_t *plot_style_fill_red = &plot_style_fill_red_static;
static const plot_style_t plot_style_content_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x00ff0000,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
plot_style_t const * const plot_style_content_edge =
&plot_style_content_edge_static;
@@ -55,7 +55,7 @@ plot_style_t const * const plot_style_content_edge =
static const plot_style_t plot_style_padding_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x000000ff,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
plot_style_t const * const plot_style_padding_edge =
&plot_style_padding_edge_static;
@@ -63,7 +63,7 @@ plot_style_t const * const plot_style_padding_edge =
static const plot_style_t plot_style_margin_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x0000ffff,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
plot_style_t const * const plot_style_margin_edge =
&plot_style_margin_edge_static;
@@ -74,14 +74,14 @@ static const plot_style_t plot_style_broken_object_static = {
.fill_colour = 0x008888ff,
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x000000ff,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
plot_style_t const * const plot_style_broken_object =
&plot_style_broken_object_static;
static const plot_font_style_t plot_fstyle_broken_object_static = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 16 * FONT_SIZE_SCALE,
+ .size = 16 * PLOT_STYLE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0x8888ff,
@@ -134,7 +134,7 @@ plot_style_t *plot_style_fill_wblobc = &plot_style_fill_wblobc_static;
static plot_style_t plot_style_stroke_wblobc_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = WIDGET_BLOBC,
- .stroke_width = 2,
+ .stroke_width = plot_style_int_to_fixed(2),
};
plot_style_t *plot_style_stroke_wblobc = &plot_style_stroke_wblobc_static;
@@ -156,7 +156,7 @@ plot_style_t *plot_style_stroke_lightwbasec = &plot_style_stroke_lightwbasec_sta
/* Generic font style */
static const plot_font_style_t plot_style_font_static = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 8 * FONT_SIZE_SCALE,
+ .size = 8 * PLOT_STYLE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
diff --git a/desktop/print.c b/desktop/print.c
index e7c8cf2fa..de579dcf2 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -34,7 +34,7 @@
#include "netsurf/plotters.h"
#include "content/hlcache.h"
#include "css/utils.h"
-#include "render/box.h"
+#include "html/box.h"
#include "desktop/print.h"
#include "desktop/printer.h"
@@ -126,8 +126,10 @@ print_apply_settings(hlcache_handle *content, struct print_settings *settings)
content_reformat(content, false, page_content_width, 0);
- LOG("New layout applied.New height = %d ; New width = %d ",
- content_get_height(content), content_get_width(content));
+ NSLOG(netsurf, INFO,
+ "New layout applied.New height = %d ; New width = %d ",
+ content_get_height(content),
+ content_get_width(content));
return true;
}
@@ -179,7 +181,8 @@ bool print_draw_next_page(const struct printer *printer,
struct redraw_context ctx = {
.interactive = false,
.background_images = !nsoption_bool(remove_backgrounds),
- .plot = printer->plotter
+ .plot = printer->plotter,
+ .priv = settings->priv
};
html_redraw_printing_top_cropped = INT_MAX;
@@ -254,6 +257,11 @@ struct print_settings *print_make_settings(print_configuration configuration,
struct print_settings *settings;
css_fixed length = 0;
css_unit unit = CSS_UNIT_MM;
+ nscss_len_ctx len_ctx = {
+ .vw = DEFAULT_PAGE_WIDTH,
+ .vh = DEFAULT_PAGE_HEIGHT,
+ .root_style = NULL,
+ };
switch (configuration){
case PRINT_DEFAULT:
@@ -269,17 +277,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = DEFAULT_EXPORT_SCALE;
length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM);
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM);
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_TOP_MM);
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM);
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
/* use settings from the Export options tab */
case PRINT_OPTIONS:
@@ -295,17 +303,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = (float)nsoption_int(export_scale) / 100;
length = INTTOFIX(nsoption_int(margin_left));
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_right));
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_top));
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_bottom));
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
default:
return NULL;
diff --git a/desktop/print.h b/desktop/print.h
index fb1fd63ac..4d178aa8a 100644
--- a/desktop/print.h
+++ b/desktop/print.h
@@ -61,6 +61,9 @@ struct print_settings{
/*the functions used to measure fonts*/
const struct gui_layout_table *font_func;
+
+ /* Private data for the plotter context */
+ void *priv;
};
diff --git a/desktop/save_complete.c b/desktop/save_complete.c
index f8f005743..ef794d4d7 100644
--- a/desktop/save_complete.c
+++ b/desktop/save_complete.c
@@ -43,8 +43,9 @@
#include "netsurf/content.h"
#include "content/hlcache.h"
#include "css/css.h"
-#include "render/box.h"
-#include "render/html.h"
+#include "html/box.h"
+#include "html/html_save.h"
+#include "html/html.h"
#include "netsurf/misc.h"
#include "desktop/gui_internal.h"
@@ -168,7 +169,7 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
fp = fopen(fname, "wb");
if (fp == NULL) {
free(fname);
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -195,10 +196,12 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
* \param osize updated with the size of the result.
* \return converted source, or NULL on out of memory.
*/
-
-static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
- const char *source, unsigned long size, const nsurl *base,
- unsigned long *osize)
+static char *
+save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
+ const char *source,
+ unsigned long size,
+ const nsurl *base,
+ unsigned long *osize)
{
char *rewritten;
unsigned long offset = 0;
@@ -207,8 +210,9 @@ static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
/* count number occurrences of @import to (over)estimate result size */
/* can't use strstr because source is not 0-terminated string */
- for (offset = 0; SLEN("@import") < size &&
- offset <= size - SLEN("@import"); offset++) {
+ for (offset = 0;
+ (SLEN("@import") < size) && (offset <= (size - SLEN("@import")));
+ offset++) {
if (source[offset] == '@' &&
ascii_to_lower(source[offset + 1]) == 'i' &&
ascii_to_lower(source[offset + 2]) == 'm' &&
@@ -637,9 +641,9 @@ static bool save_complete_handle_attr_value(save_complete_ctx *ctx,
*
* Attribute: Elements:
*
- * 1) data <object>
- * 2) href <a> <area> <link>
- * 3) src <script> <input> <frame> <iframe> <img>
+ * 1) data object
+ * 2) href a, area, link
+ * 3) src script, input, frame, iframe, img
* 4) background any (except those above)
*/
/* 1 */
@@ -1044,7 +1048,7 @@ static bool save_complete_node_handler(dom_node *node,
} else if (type == DOM_DOCUMENT_NODE) {
/* Do nothing */
} else {
- LOG("Unhandled node type: %d", type);
+ NSLOG(netsurf, INFO, "Unhandled node type: %d", type);
}
return true;
@@ -1075,7 +1079,7 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx,
fp = fopen(fname, "wb");
if (fp == NULL) {
free(fname);
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -1154,7 +1158,7 @@ static bool save_complete_inventory(save_complete_ctx *ctx)
fp = fopen(fname, "w");
free(fname);
if (fp == NULL) {
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -1182,7 +1186,8 @@ static nserror regcomp_wrapper(regex_t *preg, const char *regex, int cflags)
if (r) {
char errbuf[200];
regerror(r, preg, errbuf, sizeof errbuf);
- LOG("Failed to compile regexp '%s': %s\n", regex, errbuf);
+ NSLOG(netsurf, INFO, "Failed to compile regexp '%s': %s\n",
+ regex, errbuf);
return NSERROR_INIT_FAILED;
}
return NSERROR_OK;
diff --git a/desktop/save_pdf.c b/desktop/save_pdf.c
index d303eca7c..889190089 100644
--- a/desktop/save_pdf.c
+++ b/desktop/save_pdf.c
@@ -171,7 +171,8 @@ bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *psty
{
DashPattern_e dash;
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour);
+ NSLOG(netsurf, INFO, "%d %d %d %d %f %X", x0, y0, x1, y1,
+ page_height - y0, pstyle->fill_colour);
#endif
if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
@@ -212,10 +213,10 @@ bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *psty
}
apply_clip_and_mode(false,
- NS_TRANSPARENT,
- pstyle->stroke_colour,
- pstyle->stroke_width,
- dash);
+ NS_TRANSPARENT,
+ pstyle->stroke_colour,
+ plot_style_int_to_fixed(pstyle->stroke_width),
+ dash);
HPDF_Page_Rectangle(pdf_page, x0, page_height - y0, x1 - x0, -(y1 - y0));
HPDF_Page_Stroke(pdf_page);
@@ -244,10 +245,10 @@ bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
}
apply_clip_and_mode(false,
- NS_TRANSPARENT,
- pstyle->stroke_colour,
- pstyle->stroke_width,
- dash);
+ NS_TRANSPARENT,
+ pstyle->stroke_colour,
+ plot_style_int_to_fixed(pstyle->stroke_width),
+ dash);
HPDF_Page_MoveTo(pdf_page, x0, page_height - y0);
HPDF_Page_LineTo(pdf_page, x1, page_height - y1);
@@ -262,7 +263,7 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
#ifdef PDF_DEBUG
int pmaxx = p[0], pmaxy = p[1];
int pminx = p[0], pminy = p[1];
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (n == 0)
return true;
@@ -281,7 +282,8 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
}
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy, page_height - pminy);
+ NSLOG(netsurf, INFO, "%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy,
+ page_height - pminy);
#endif
HPDF_Page_Fill(pdf_page);
@@ -294,7 +296,8 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
bool pdf_plot_clip(const struct rect *clip)
{
#ifdef PDF_DEBUG
- LOG("%d %d %d %d", clip->x0, clip->y0, clip->x1, clip->y1);
+ NSLOG(netsurf, INFO, "%d %d %d %d", clip->x0, clip->y0, clip->x1,
+ clip->y1);
#endif
/*Normalize cllipping area - to prevent overflows.
@@ -314,7 +317,7 @@ bool pdf_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
#ifdef PDF_DEBUG
- LOG(". %d %d %.*s", x, y, (int)length, text);
+ NSLOG(netsurf, INFO, ". %d %d %.*s", x, y, (int)length, text);
#endif
char *word;
HPDF_Font pdf_font;
@@ -347,7 +350,7 @@ bool pdf_plot_text(int x, int y, const char *text, size_t length,
bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
{
#ifdef PDF_DEBUG
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (style->fill_type != PLOT_OP_TYPE_NONE) {
apply_clip_and_mode(false,
@@ -378,7 +381,8 @@ bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
{
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour);
+ NSLOG(netsurf, INFO, "%d %d %d %d %d %X", x, y, radius, angle1,
+ angle2, style->stroke_colour);
#endif
/* FIXME: line width 1 is ok ? */
@@ -406,7 +410,8 @@ bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
HPDF_REAL max_width, max_height;
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %p 0x%x", x, y, width, height, bitmap, bg);
+ NSLOG(netsurf, INFO, "%d %d %d %d %p 0x%x", x, y, width, height,
+ bitmap, bg);
#endif
if (width == 0 || height == 0)
return true;
@@ -483,7 +488,8 @@ HPDF_Image pdf_extract_image(struct bitmap *bitmap)
rgb_buffer = (unsigned char *)malloc(3 * img_width * img_height);
alpha_buffer = (unsigned char *)malloc(img_width * img_height);
if (rgb_buffer == NULL || alpha_buffer == NULL) {
- LOG("Not enough memory to create RGB buffer");
+ NSLOG(netsurf, INFO,
+ "Not enough memory to create RGB buffer");
free(rgb_buffer);
free(alpha_buffer);
return NULL;
@@ -607,7 +613,7 @@ bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
bool empty_path;
#ifdef PDF_DEBUG
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (n == 0)
@@ -649,7 +655,7 @@ bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
i += 7;
empty_path = false;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
return false;
}
}
@@ -685,7 +691,7 @@ bool pdf_begin(struct print_settings *print_settings)
HPDF_Free(pdf_doc);
pdf_doc = HPDF_New(error_handler, NULL);
if (!pdf_doc) {
- LOG("Error creating pdf_doc");
+ NSLOG(netsurf, INFO, "Error creating pdf_doc");
return false;
}
@@ -708,7 +714,7 @@ bool pdf_begin(struct print_settings *print_settings)
pdf_page = NULL;
#ifdef PDF_DEBUG
- LOG("pdf_begin finishes");
+ NSLOG(netsurf, INFO, "pdf_begin finishes");
#endif
return true;
}
@@ -717,7 +723,7 @@ bool pdf_begin(struct print_settings *print_settings)
bool pdf_next_page(void)
{
#ifdef PDF_DEBUG
- LOG("pdf_next_page begins");
+ NSLOG(netsurf, INFO, "pdf_next_page begins");
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
@@ -745,7 +751,7 @@ bool pdf_next_page(void)
pdfw_gs_save(pdf_page);
#ifdef PDF_DEBUG
- LOG("%f %f", page_width, page_height);
+ NSLOG(netsurf, INFO, "%f %f", page_width, page_height);
#endif
return true;
@@ -755,7 +761,7 @@ bool pdf_next_page(void)
void pdf_end(void)
{
#ifdef PDF_DEBUG
- LOG("pdf_end begins");
+ NSLOG(netsurf, INFO, "pdf_end begins");
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
@@ -780,7 +786,7 @@ void pdf_end(void)
else
save_pdf(settings->output);
#ifdef PDF_DEBUG
- LOG("pdf_end finishes");
+ NSLOG(netsurf, INFO, "pdf_end finishes");
#endif
}
@@ -819,7 +825,8 @@ nserror save_pdf(const char *path)
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
- LOG("ERROR:\n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
+ NSLOG(netsurf, INFO, "ERROR:\n\terror_no=%x\n\tdetail_no=%d\n",
+ (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
#ifdef PDF_DEBUG
exit(1);
#endif
diff --git a/desktop/save_text.c b/desktop/save_text.c
index e63c96eb9..a86f173b0 100644
--- a/desktop/save_text.c
+++ b/desktop/save_text.c
@@ -32,8 +32,8 @@
#include "utils/utf8.h"
#include "utils/utils.h"
#include "netsurf/content.h"
-#include "render/box.h"
-#include "render/html.h"
+#include "html/box.h"
+#include "html/html_save.h"
#include "netsurf/utf8.h"
#include "desktop/gui_internal.h"
@@ -75,7 +75,8 @@ void save_as_text(struct hlcache_handle *c, char *path)
free(save.block);
if (ret != NSERROR_OK) {
- LOG("failed to convert to local encoding, return %d", ret);
+ NSLOG(netsurf, INFO,
+ "failed to convert to local encoding, return %d", ret);
return;
}
@@ -84,12 +85,13 @@ void save_as_text(struct hlcache_handle *c, char *path)
int res = fputs(result, out);
if (res < 0) {
- LOG("Warning: write failed");
+ NSLOG(netsurf, INFO, "Warning: write failed");
}
res = fputs("\n", out);
if (res < 0) {
- LOG("Warning: failed writing trailing newline");
+ NSLOG(netsurf, INFO,
+ "Warning: failed writing trailing newline");
}
fclose(out);
diff --git a/desktop/scrollbar.c b/desktop/scrollbar.c
index 9a4d70fe4..af5536ba4 100644
--- a/desktop/scrollbar.c
+++ b/desktop/scrollbar.c
@@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Scrollbar widget (implementation).
+/**
+ * \file
+ * implementation of scrollbar widget.
*/
#include <stdbool.h>
@@ -36,44 +37,65 @@
#include "desktop/system_colour.h"
#include "desktop/scrollbar.h"
+/**
+ * Scrollbar context
+ */
struct scrollbar {
- bool horizontal; /* Horizontal scrollbar if true, else vertical
- */
- int length; /* Length of the scrollbar widget */
-
- int full_size; /* Length of the full scrollable area */
- int visible_size; /* Length visible part of the scrollable area */
-
- int offset; /* Current scroll offset to visible area */
-
- int bar_pos; /* Position of the scrollbar */
- int bar_len; /* Length of the scrollbar */
-
- scrollbar_client_callback client_callback; /* Callback receiving
- * scrollbar events */
- void *client_data; /* User data passed to the callback */
-
- bool dragging; /* Flag indicating drag at progess */
- int drag_start_coord; /* Coordinate value at drag start */
- int drag_start_pos; /* Scrollbar offset or bar_pos at drag start */
- bool drag_content; /* Flag indicating that the drag corresponds to
- * a dragged content area, rather than a dragged
- * scrollbar. */
+ /** Horizontal scrollbar if true, else vertical */
+ bool horizontal;
+ /** Length of the scrollbar widget */
+ int length;
+
+ /** Length of the full scrollable area */
+ int full_size;
+ /** Length visible part of the scrollable area */
+ int visible_size;
+
+ /** Current scroll offset to visible area */
+ int offset;
+
+ /** Position of the scrollbar */
+ int bar_pos;
+ /** Length of the scrollbar */
+ int bar_len;
+
+ /** Callback receiving scrollbar events */
+ scrollbar_client_callback client_callback;
+ /** User data passed to the callback */
+ void *client_data;
+
+ /** Flag indicating drag at progess */
+ bool dragging;
+ /** Coordinate value at drag start */
+ int drag_start_coord;
+ /** Scrollbar offset or bar_pos at drag start */
+ int drag_start_pos;
+ /** Flag indicating that the drag corresponds to a dragged
+ * content area, rather than a dragged scrollbar.
+ */
+ bool drag_content;
- struct scrollbar *pair; /* Parpendicular scrollbar, or NULL */
- bool pair_drag; /* Flag indicating that the current drag affects
- the perpendicular scrollbar too */
+ /** Parpendicular scrollbar, or NULL */
+ struct scrollbar *pair;
+ /** Flag indicating that the current drag affects the
+ * perpendicular scrollbar too
+ */
+ bool pair_drag;
};
/*
- * Exported function. Documented in desktop/scrollbar.h
+ * Exported interface. Documented in desktop/scrollbar.h
*/
-nserror scrollbar_create(bool horizontal, int length, int full_size,
- int visible_size, void *client_data,
- scrollbar_client_callback client_callback,
- struct scrollbar **s)
+nserror
+scrollbar_create(bool horizontal,
+ int length,
+ int full_size,
+ int visible_size,
+ void *client_data,
+ scrollbar_client_callback client_callback,
+ struct scrollbar **s)
{
struct scrollbar *scrollbar;
int well_length;
@@ -95,7 +117,7 @@ nserror scrollbar_create(bool horizontal, int length, int full_size,
well_length = length - 2 * SCROLLBAR_WIDTH;
scrollbar->bar_len = (full_size == 0) ? 0 :
- ((well_length * visible_size) / full_size);
+ ((well_length * visible_size) / full_size);
scrollbar->client_callback = client_callback;
scrollbar->client_data = client_data;
@@ -110,49 +132,49 @@ nserror scrollbar_create(bool horizontal, int length, int full_size,
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_destroy(struct scrollbar *s)
{
- if (s->pair != NULL)
+ if (s->pair != NULL) {
s->pair->pair = NULL;
+ }
free(s);
}
/**
- * Draw an outline rectangle common to a several scrollbar elements.
+ * Draw an outline rectangle common to several scrollbar elements.
*
- * \param x0 left border of the outline
- * \param y0 top border of the outline
- * \param x1 right border of the outline
- * \param y1 bottom border of the outline
- * \param c base colour of the outline, the other colours are created by
- * lightening or darkening this one
- * \param ctx current redraw context
+ * \param ctx current redraw context
+ * \param area the area of the scrollbar
+ * \param c base colour of the outline, the other colours are created by
+ * lightening or darkening this one
* \param inset true for inset outline, false for an outset one
- * \return
+ * \return NSERROR_OK on success else error code
*/
-
-static inline bool scrollbar_redraw_scrollbar_rectangle(int x0, int y0,
- int x1, int y1, colour c, bool inset,
- const struct redraw_context *ctx)
+static inline nserror
+scrollbar_rectangle(const struct redraw_context *ctx,
+ struct rect *area,
+ colour c,
+ bool inset)
{
- const struct plotter_table *plot = ctx->plot;
+ struct rect line;
+ nserror res;
static plot_style_t c0 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
static plot_style_t c1 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
static plot_style_t c2 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
if (inset) {
@@ -165,225 +187,338 @@ static inline bool scrollbar_redraw_scrollbar_rectangle(int x0, int y0,
c2.stroke_colour = blend_colour(c0.stroke_colour, c1.stroke_colour);
/* Plot the outline */
- if (!plot->line(x0, y0, x1, y0, &c0)) return false;
- if (!plot->line(x1, y0, x1, y1 + 1, &c1)) return false;
- if (!plot->line(x1, y0, x1, y0 + 1, &c2)) return false;
- if (!plot->line(x1, y1, x0, y1, &c1)) return false;
- if (!plot->line(x0, y1, x0, y0, &c0)) return false;
- if (!plot->line(x0, y1, x0, y1 + 1, &c2)) return false;
- return true;
+ line.x0 = area->x0; line.y0 = area->y0;
+ line.x1 = area->x1; line.y1 = area->y0;
+ res = ctx->plot->line(ctx, &c0, &line);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ line.x0 = area->x1; line.y0 = area->y0;
+ line.x1 = area->x1; line.y1 = area->y1 + 1;
+ res = ctx->plot->line(ctx, &c1, &line);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ line.x0 = area->x1; line.y0 = area->y0;
+ line.x1 = area->x1; line.y1 = area->y0 + 1;
+ res = ctx->plot->line(ctx, &c2, &line);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ line.x0 = area->x1; line.y0 = area->y1;
+ line.x1 = area->x0; line.y1 = area->y1;
+ res = ctx->plot->line(ctx, &c1, &line);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ line.x0 = area->x0; line.y0 = area->y1;
+ line.x1 = area->x0; line.y1 = area->y0;
+ res = ctx->plot->line(ctx, &c0, &line);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ line.x0 = area->x0; line.y0 = area->y1;
+ line.x1 = area->x0; line.y1 = area->y1 + 1;
+ res = ctx->plot->line(ctx, &c2, &line);
+
+ return res;
}
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
-bool scrollbar_redraw(struct scrollbar *s, int x, int y,
- const struct rect *clip, float scale,
- const struct redraw_context *ctx)
+nserror
+scrollbar_redraw(struct scrollbar *s,
+ int x, int y,
+ const struct rect *clip,
+ float scale,
+ const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
int w = SCROLLBAR_WIDTH;
int bar_pos, bar_c0, bar_c1;
int v[6]; /* array of triangle vertices */
- int x0, y0, x1, y1;
-
- colour bg_fill_colour = ns_system_colour_char("Scrollbar");
- colour fg_fill_colour = ns_system_colour_char("ButtonFace");
- colour arrow_fill_colour = ns_system_colour_char("ButtonText");
+ struct rect area;
+ struct rect rect;
+ nserror res;
plot_style_t bg_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = bg_fill_colour
};
plot_style_t fg_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = fg_fill_colour
};
plot_style_t arrow_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = arrow_fill_colour
};
- x0 = x;
- y0 = y;
- x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1;
- y1 = y + (s->horizontal ? SCROLLBAR_WIDTH : s->length) - 1;
+ res = ns_system_colour_char("Scrollbar", &bg_fill_style.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ns_system_colour_char("ButtonFace", &fg_fill_style.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = ns_system_colour_char("ButtonText", &arrow_fill_style.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ area.x0 = x;
+ area.y0 = y;
+ area.x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1;
+ area.y1 = y + (s->horizontal ? SCROLLBAR_WIDTH : s->length) - 1;
bar_pos = s->bar_pos;
- bar_c1 = (s->horizontal ? x0 : y0) + SCROLLBAR_WIDTH +
- s->bar_pos + s->bar_len - 1;
+ bar_c1 = (s->horizontal ? area.x0 : area.y0) + SCROLLBAR_WIDTH +
+ s->bar_pos + s->bar_len - 1;
if (scale != 1.0) {
w *= scale;
- x0 *= scale;
- y0 *= scale;
- x1 *= scale;
- y1 *= scale;
+ area.x0 *= scale;
+ area.y0 *= scale;
+ area.x1 *= scale;
+ area.y1 *= scale;
bar_pos *= scale;
bar_c1 *= scale;
}
- bar_c0 = (s->horizontal ? x0 : y0) + w + bar_pos;
+ bar_c0 = (s->horizontal ? area.x0 : area.y0) + w + bar_pos;
- if (x1 < clip->x0 || y1 < clip->y0 || clip->x1 < x0 || clip->y1 < y0)
- /* scrollbar is outside the clipping rectangle, nothing to
- * render */
- return true;
+ /* if scrollbar is outside the clipping rectangle, nothing to render */
+ if ((area.x1 < clip->x0) ||
+ (area.y1 < clip->y0) ||
+ (clip->x1 < area.x0) ||
+ (clip->y1 < area.y0)) {
+ return NSERROR_OK;
+ }
-
if (s->horizontal) {
/* scrollbar is horizontal */
-
+
/* scrollbar outline */
- if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1,
- bg_fill_colour, true, ctx))
- return false;
+ res = scrollbar_rectangle(ctx, &area,
+ bg_fill_style.fill_colour, true);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* left arrow icon border */
- if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
- y0 + 1,
- x0 + w - 2,
- y1 - 1,
- fg_fill_colour, false, ctx))
- return false;
+ rect.x0 = area.x0 + 1;
+ rect.y0 = area.y0 + 1;
+ rect.x1 = area.x0 + w - 2;
+ rect.y1 = area.y1 - 1;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* left arrow icon background */
- if (!plot->rectangle(x0 + 2,
- y0 + 2,
- x0 + w - 2,
- y1 - 1,
- &fg_fill_style))
- return false;
+ rect.x0 = area.x0 + 2;
+ rect.y0 = area.y0 + 2;
+ rect.x1 = area.x0 + w - 2;
+ rect.y1 = area.y1 - 1;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* left arrow */
- v[0] = x0 + w / 4;
- v[1] = y0 + w / 2;
- v[2] = x0 + w * 3 / 4;
- v[3] = y0 + w / 4;
- v[4] = x0 + w * 3 / 4;
- v[5] = y0 + w * 3 / 4;
- if (!plot->polygon(v, 3, &arrow_fill_style))
- return false;
+ v[0] = area.x0 + w / 4;
+ v[1] = area.y0 + w / 2;
+ v[2] = area.x0 + w * 3 / 4;
+ v[3] = area.y0 + w / 4;
+ v[4] = area.x0 + w * 3 / 4;
+ v[5] = area.y0 + w * 3 / 4;
+ res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* scrollbar well background */
- if (!plot->rectangle(x0 + w - 1,
- y0 + 1,
- x1 - w + 2,
- y1,
- &bg_fill_style))
- return false;
+ rect.x0 = area.x0 + w - 1;
+ rect.y0 = area.y0 + 1;
+ rect.x1 = area.x1 - w + 2;
+ rect.y1 = area.y1;
+ res = ctx->plot->rectangle(ctx, &bg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* scrollbar position indicator bar */
- if (!scrollbar_redraw_scrollbar_rectangle(bar_c0,
- y0 + 1,
- bar_c1,
- y1 - 1,
- fg_fill_colour, false, ctx))
- return false;
- if (!plot->rectangle(bar_c0 + 1,
- y0 + 2,
- bar_c1,
- y1 - 1,
- &fg_fill_style))
- return false;
+ rect.x0 = bar_c0;
+ rect.y0 = area.y0 + 1;
+ rect.x1 = bar_c1;
+ rect.y1 = area.y1 - 1;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ rect.x0 = bar_c0 + 1;
+ rect.y0 = area.y0 + 2;
+ rect.x1 = bar_c1;
+ rect.y1 = area.y1 - 1;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* right arrow icon border */
- if (!scrollbar_redraw_scrollbar_rectangle(x1 - w + 2,
- y0 + 1,
- x1 - 1,
- y1 - 1,
- fg_fill_colour, false, ctx))
- return false;
+ rect.x0 = area.x1 - w + 2;
+ rect.y0 = area.y0 + 1;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y1 - 1;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* right arrow icon background */
- if (!plot->rectangle(x1 - w + 3,
- y0 + 2,
- x1 - 1,
- y1 - 1,
- &fg_fill_style))
- return false;
+ rect.x0 = area.x1 - w + 3;
+ rect.y0 = area.y0 + 2;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y1 - 1;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* right arrow */
- v[0] = x1 - w / 4 + 1;
- v[1] = y0 + w / 2;
- v[2] = x1 - w * 3 / 4 + 1;
- v[3] = y0 + w / 4;
- v[4] = x1 - w * 3 / 4 + 1;
- v[5] = y0 + w * 3 / 4;
- if (!plot->polygon(v, 3, &arrow_fill_style))
- return false;
+ v[0] = rect.x1 - w / 4 + 1;
+ v[1] = rect.y0 + w / 2;
+ v[2] = rect.x1 - w * 3 / 4 + 1;
+ v[3] = rect.y0 + w / 4;
+ v[4] = rect.x1 - w * 3 / 4 + 1;
+ v[5] = rect.y0 + w * 3 / 4;
+ res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3);
+ if (res != NSERROR_OK) {
+ return res;
+ }
} else {
/* scrollbar is vertical */
-
+
/* outline */
- if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1,
- bg_fill_colour, true, ctx))
- return false;
- /* top arrow background */
- if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
- y0 + 1,
- x1 - 1,
- y0 + w - 2,
- fg_fill_colour, false, ctx))
- return false;
- if (!plot->rectangle(x0 + 2,
- y0 + 2,
- x1 - 1,
- y0 + w - 2,
- &fg_fill_style))
- return false;
+ res = scrollbar_rectangle(ctx, &area,
+ bg_fill_style.fill_colour, true);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* top arrow border */
+ rect.x0 = area.x0 + 1;
+ rect.y0 = area.y0 + 1;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y0 + w - 2;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* top arrow background */
+ rect.x0 = area.x0 + 2;
+ rect.y0 = area.y0 + 2;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y0 + w - 2;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* up arrow */
- v[0] = x0 + w / 2;
- v[1] = y0 + w / 4;
- v[2] = x0 + w / 4;
- v[3] = y0 + w * 3 / 4;
- v[4] = x0 + w * 3 / 4;
- v[5] = y0 + w * 3 / 4;
- if (!plot->polygon(v, 3, &arrow_fill_style))
- return false;
+ v[0] = area.x0 + w / 2;
+ v[1] = area.y0 + w / 4;
+ v[2] = area.x0 + w / 4;
+ v[3] = area.y0 + w * 3 / 4;
+ v[4] = area.x0 + w * 3 / 4;
+ v[5] = area.y0 + w * 3 / 4;
+ res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* scrollbar well background */
- if (!plot->rectangle(x0 + 1,
- y0 + w - 1,
- x1,
- y1 - w + 2,
- &bg_fill_style))
- return false;
+ rect.x0 = area.x0 + 1;
+ rect.y0 = area.y0 + w - 1;
+ rect.x1 = area.x1;
+ rect.y1 = area.y1 - w + 2;
+ res = ctx->plot->rectangle(ctx, &bg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* scrollbar position indicator bar */
- if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
- bar_c0,
- x1 - 1,
- bar_c1,
- fg_fill_colour, false, ctx))
- return false;
- if (!plot->rectangle(x0 + 2,
- bar_c0 + 1,
- x1 - 1,
- bar_c1,
- &fg_fill_style))
- return false;
- /* bottom arrow background */
- if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
- y1 - w + 2,
- x1 - 1,
- y1 - 1,
- fg_fill_colour, false, ctx))
- return false;
- if (!plot->rectangle(x0 + 2,
- y1 - w + 3,
- x1 - 1,
- y1 - 1,
- &fg_fill_style))
- return false;
+ rect.x0 = area.x0 + 1;
+ rect.y0 = bar_c0;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = bar_c1;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ rect.x0 = area.x0 + 2;
+ rect.y0 = bar_c0 + 1;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = bar_c1;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* down arrow icon border */
+ rect.x0 = area.x0 + 1;
+ rect.y0 = area.y1 - w + 2;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y1 - 1;
+ res = scrollbar_rectangle(ctx, &rect,
+ fg_fill_style.fill_colour, false);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* down arrow icon background */
+ rect.x0 = area.x0 + 2;
+ rect.y0 = area.y1 - w + 3;
+ rect.x1 = area.x1 - 1;
+ rect.y1 = area.y1 - 1;
+ res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
/* down arrow */
- v[0] = x0 + w / 2;
- v[1] = y1 - w / 4 + 1;
- v[2] = x0 + w / 4;
- v[3] = y1 - w * 3 / 4 + 1;
- v[4] = x0 + w * 3 / 4;
- v[5] = y1 - w * 3 / 4 + 1;
- if (!plot->polygon(v, 3, &arrow_fill_style))
- return false;
+ v[0] = area.x0 + w / 2;
+ v[1] = area.y1 - w / 4 + 1;
+ v[2] = area.x0 + w / 4;
+ v[3] = area.y1 - w * 3 / 4 + 1;
+ v[4] = area.x0 + w * 3 / 4;
+ v[5] = area.y1 - w * 3 / 4 + 1;
+ res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3);
+ if (res != NSERROR_OK) {
+ return res;
+ }
}
- return true;
+ return NSERROR_OK;
}
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_set(struct scrollbar *s, int value, bool bar_pos)
{
@@ -391,46 +526,49 @@ void scrollbar_set(struct scrollbar *s, int value, bool bar_pos)
int old_offset = s->offset;
struct scrollbar_msg_data msg;
- if (value < 0)
+ if (value < 0) {
value = 0;
+ }
- if (s->full_size == s->visible_size)
+ if (s->full_size == s->visible_size) {
return;
+ }
well_length = s->length - 2 * SCROLLBAR_WIDTH;
if (bar_pos) {
- if (value > well_length - s->bar_len)
+ if (value > well_length - s->bar_len) {
s->bar_pos = well_length - s->bar_len;
- else
+ } else {
s->bar_pos = value;
+ }
s->offset = ((well_length - s->bar_len) < 1) ? 0 :
- (((s->full_size - s->visible_size) *
- s->bar_pos) / (well_length - s->bar_len));
+ (((s->full_size - s->visible_size) *
+ s->bar_pos) / (well_length - s->bar_len));
} else {
- if (value > s->full_size - s->visible_size)
+ if (value > s->full_size - s->visible_size) {
s->offset = s->full_size - s->visible_size;
- else
+ } else {
s->offset = value;
+ }
s->bar_pos = (s->full_size < 1) ? 0 :
- ((well_length * s->offset) / s->full_size);
+ ((well_length * s->offset) / s->full_size);
}
- if (s->offset == old_offset)
- /* Nothing happened */
- return;
-
- msg.scrollbar = s;
- msg.msg = SCROLLBAR_MSG_MOVED;
- msg.scroll_offset = s->offset;
- s->client_callback(s->client_data, &msg);
+ if (s->offset != old_offset) {
+ /* client callback if there was a chnage */
+ msg.scrollbar = s;
+ msg.msg = SCROLLBAR_MSG_MOVED;
+ msg.scroll_offset = s->offset;
+ s->client_callback(s->client_data, &msg);
+ }
}
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
bool scrollbar_scroll(struct scrollbar *s, int change)
{
@@ -438,9 +576,10 @@ bool scrollbar_scroll(struct scrollbar *s, int change)
int old_offset = s->offset;
struct scrollbar_msg_data msg;
- if (change == 0 || s->full_size <= s->visible_size)
+ if (change == 0 || s->full_size <= s->visible_size) {
/* zero scroll step, or unscrollable */
return false;
+ }
/* Convert named change values to appropriate pixel offset value */
switch (change) {
@@ -466,21 +605,23 @@ bool scrollbar_scroll(struct scrollbar *s, int change)
}
/* Get new offset */
- if (s->offset + change > s->full_size - s->visible_size)
+ if (s->offset + change > s->full_size - s->visible_size) {
s->offset = s->full_size - s->visible_size;
- else if (s->offset + change < 0)
+ } else if (s->offset + change < 0) {
s->offset = 0;
- else
+ } else {
s->offset += change;
+ }
- if (s->offset == old_offset)
+ if (s->offset == old_offset) {
/* Nothing happened */
return false;
+ }
/* Update scrollbar */
well_length = s->length - 2 * SCROLLBAR_WIDTH;
s->bar_pos = (s->full_size < 1) ? 0 :
- ((well_length * s->offset) / s->full_size);
+ ((well_length * s->offset) / s->full_size);
msg.scrollbar = s;
msg.msg = SCROLLBAR_MSG_MOVED;
@@ -492,41 +633,47 @@ bool scrollbar_scroll(struct scrollbar *s, int change)
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
int scrollbar_get_offset(struct scrollbar *s)
{
- if (s == NULL)
+ if (s == NULL) {
return 0;
+ }
return s->offset;
}
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_set_extents(struct scrollbar *s, int length,
- int visible_size, int full_size)
+ int visible_size, int full_size)
{
int cur_excess = s->full_size - s->visible_size;
int well_length;
struct scrollbar_msg_data msg;
- if (length == s->length && visible_size == s->visible_size &&
- full_size == s->full_size) {
+ if (length == s->length &&
+ visible_size == s->visible_size &&
+ full_size == s->full_size) {
/* Nothing's changed. */
return;
}
- if (length != -1)
+ if (length != -1) {
s->length = length;
- if (visible_size != -1)
+ }
+ if (visible_size != -1) {
s->visible_size = visible_size;
- if (full_size != -1)
+ }
+ if (full_size != -1) {
s->full_size = full_size;
+ }
- if (s->full_size < s->visible_size)
+ if (s->full_size < s->visible_size) {
s->full_size = s->visible_size;
+ }
/* Update scroll offset (scaled in proportion with change in excess) */
if (cur_excess <= 0) {
@@ -553,7 +700,7 @@ void scrollbar_set_extents(struct scrollbar *s, int length,
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
bool scrollbar_is_horizontal(struct scrollbar *s)
{
@@ -568,12 +715,14 @@ bool scrollbar_is_horizontal(struct scrollbar *s)
* \param x the X coordinate of the drag start
* \param y the Y coordinate of the drag start
* \param content_drag whether this should be a reverse drag (used when the
- * user drags the content area, rather than the scrollbar)
+ * user drags the content area, rather than the scrollbar)
* \param pair whether the drag is a '2D' scroll
*/
-
-static void scrollbar_drag_start_internal(struct scrollbar *s, int x, int y,
- bool content_drag, bool pair)
+static void
+scrollbar_drag_start_internal(struct scrollbar *s,
+ int x, int y,
+ bool content_drag,
+ bool pair)
{
struct scrollbar_msg_data msg;
@@ -585,7 +734,7 @@ static void scrollbar_drag_start_internal(struct scrollbar *s, int x, int y,
msg.scrollbar = s;
- /* \todo - some proper numbers please! */
+ /** \todo some proper numbers please! */
if (s->horizontal) {
msg.x0 = -2048;
msg.x1 = 2048;
@@ -602,10 +751,10 @@ static void scrollbar_drag_start_internal(struct scrollbar *s, int x, int y,
s->pair_drag = true;
s->pair->drag_start_coord =
- s->pair->horizontal ? x : y;
+ s->pair->horizontal ? x : y;
s->pair->drag_start_pos = (content_drag) ? s->pair->offset :
- s->pair->bar_pos;
+ s->pair->bar_pos;
s->pair->dragging = true;
s->pair->drag_content = content_drag;
@@ -624,10 +773,12 @@ static void scrollbar_drag_start_internal(struct scrollbar *s, int x, int y,
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
-scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s,
- browser_mouse_state mouse, int x, int y)
+scrollbar_mouse_status
+scrollbar_mouse_action(struct scrollbar *s,
+ browser_mouse_state mouse,
+ int x, int y)
{
int x0, y0, x1, y1;
int val;
@@ -638,13 +789,13 @@ scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s,
* scrollbar indication bar to be launching actions on the scroll area
*/
bool but1 = ((mouse & BROWSER_MOUSE_PRESS_1) ||
- ((mouse & BROWSER_MOUSE_HOLDING_1) &&
- (mouse & BROWSER_MOUSE_DRAG_ON) &&
- !s->dragging));
+ ((mouse & BROWSER_MOUSE_HOLDING_1) &&
+ (mouse & BROWSER_MOUSE_DRAG_ON) &&
+ !s->dragging));
bool but2 = ((mouse & BROWSER_MOUSE_PRESS_2) ||
- ((mouse & BROWSER_MOUSE_HOLDING_2) &&
- (mouse & BROWSER_MOUSE_DRAG_ON) &&
- !s->dragging));
+ ((mouse & BROWSER_MOUSE_HOLDING_2) &&
+ (mouse & BROWSER_MOUSE_DRAG_ON) &&
+ !s->dragging));
h = s->horizontal;
@@ -659,88 +810,91 @@ scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s,
}
- if (h)
+ if (h) {
val = x;
- else
+ } else {
val = y;
+ }
if (s->dragging) {
val -= s->drag_start_coord;
- if (s->drag_content)
+ if (s->drag_content) {
val = -val;
- if (val != 0)
+ }
+ if (val != 0) {
scrollbar_set(s, s->drag_start_pos + val,
- !(s->drag_content));
+ !(s->drag_content));
+ }
if (s->pair_drag) {
scrollbar_mouse_action(s->pair, mouse, x, y);
status = SCROLLBAR_MOUSE_BOTH;
- } else
+ } else {
status = h ? SCROLLBAR_MOUSE_HRZ : SCROLLBAR_MOUSE_VRT;
-
+ }
return status;
}
if (val < SCROLLBAR_WIDTH) {
/* left/up arrow */
-
+
status = h ? SCROLLBAR_MOUSE_LFT : SCROLLBAR_MOUSE_UP;
- if (but1)
+ if (but1) {
scrollbar_set(s, s->offset - SCROLLBAR_WIDTH, false);
- else if (but2)
+ } else if (but2) {
scrollbar_set(s, s->offset + SCROLLBAR_WIDTH, false);
-
+ }
} else if (val < SCROLLBAR_WIDTH + s->bar_pos) {
/* well between left/up arrow and bar */
status = h ? SCROLLBAR_MOUSE_PLFT : SCROLLBAR_MOUSE_PUP;
- if (but1)
+ if (but1) {
scrollbar_set(s, s->offset - s->length, false);
- else if (but2)
+ } else if (but2) {
scrollbar_set(s, s->offset + s->length, false);
-
+ }
} else if (val > s->length - SCROLLBAR_WIDTH) {
/* right/down arrow */
status = h ? SCROLLBAR_MOUSE_RGT : SCROLLBAR_MOUSE_DWN;
- if (but1)
+ if (but1) {
scrollbar_set(s, s->offset + SCROLLBAR_WIDTH, false);
- else if (but2)
+ } else if (but2) {
scrollbar_set(s, s->offset - SCROLLBAR_WIDTH, false);
-
- } else if (val > SCROLLBAR_WIDTH + s->bar_pos +
- s->bar_len) {
+ }
+ } else if (val > SCROLLBAR_WIDTH + s->bar_pos + s->bar_len) {
/* well between right/down arrow and bar */
status = h ? SCROLLBAR_MOUSE_PRGT : SCROLLBAR_MOUSE_PDWN;
- if (but1)
+ if (but1) {
scrollbar_set(s, s->offset + s->length, false);
- else if (but2)
+ } else if (but2) {
scrollbar_set(s, s->offset - s->length, false);
- }
- else {
+ }
+ } else {
/* scrollbar position indication bar */
-
+
status = h ? SCROLLBAR_MOUSE_HRZ : SCROLLBAR_MOUSE_VRT;
}
-
+
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2) &&
- (val >= SCROLLBAR_WIDTH + s->bar_pos
- && val < SCROLLBAR_WIDTH + s->bar_pos +
- s->bar_len))
+ (val >= SCROLLBAR_WIDTH + s->bar_pos
+ && val < SCROLLBAR_WIDTH + s->bar_pos +
+ s->bar_len)) {
/* The mouse event is a drag start on the scrollbar position
* indication bar. */
scrollbar_drag_start_internal(s, x, y, false,
- (mouse & BROWSER_MOUSE_DRAG_2) ? true : false);
+ (mouse & BROWSER_MOUSE_DRAG_2) ? true : false);
+ }
return status;
}
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
const char *scrollbar_mouse_status_to_message(scrollbar_mouse_status status)
{
@@ -784,10 +938,10 @@ const char *scrollbar_mouse_status_to_message(scrollbar_mouse_status status)
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_mouse_drag_end(struct scrollbar *s,
- browser_mouse_state mouse, int x, int y)
+ browser_mouse_state mouse, int x, int y)
{
struct scrollbar_msg_data msg;
int val, drag_start_pos;
@@ -797,10 +951,12 @@ void scrollbar_mouse_drag_end(struct scrollbar *s,
drag_start_pos = s->drag_start_pos;
val = (s->horizontal ? x : y) - s->drag_start_coord;
- if (s->drag_content)
+ if (s->drag_content) {
val = -val;
- if (val != 0)
+ }
+ if (val != 0) {
scrollbar_set(s, drag_start_pos + val, !(s->drag_content));
+ }
s->dragging = false;
s->drag_content = false;
@@ -811,11 +967,13 @@ void scrollbar_mouse_drag_end(struct scrollbar *s,
drag_start_pos = s->pair->drag_start_pos;
val = (s->pair->horizontal ? x : y) - s->pair->drag_start_coord;
- if (s->pair->drag_content)
+ if (s->pair->drag_content) {
val = -val;
- if (val != 0)
+ }
+ if (val != 0) {
scrollbar_set(s->pair, drag_start_pos + val,
- !(s->pair->drag_content));
+ !(s->pair->drag_content));
+ }
s->pair->dragging = false;
s->pair->drag_content = false;
@@ -828,7 +986,7 @@ void scrollbar_mouse_drag_end(struct scrollbar *s,
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_start_content_drag(struct scrollbar *s, int x, int y)
{
@@ -837,13 +995,13 @@ void scrollbar_start_content_drag(struct scrollbar *s, int x, int y)
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void scrollbar_make_pair(struct scrollbar *horizontal,
- struct scrollbar *vertical)
+ struct scrollbar *vertical)
{
assert(horizontal->horizontal &&
- !vertical->horizontal);
+ !vertical->horizontal);
horizontal->pair = vertical;
vertical->pair = horizontal;
@@ -851,10 +1009,9 @@ void scrollbar_make_pair(struct scrollbar *horizontal,
/*
- * Exported function. Documented in scrollbar.h
+ * Exported interface. Documented in scrollbar.h
*/
void *scrollbar_get_data(struct scrollbar *s)
{
return s->client_data;
}
-
diff --git a/desktop/scrollbar.h b/desktop/scrollbar.h
index d277be26c..fa5e167f2 100644
--- a/desktop/scrollbar.h
+++ b/desktop/scrollbar.h
@@ -16,12 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Scrollbar widget (interface).
+/**
+ * \file
+ * Scrollbar widget interface.
+ *
+ * Scrollbar widgets used in frames code, not for frontend use
*/
-#ifndef _NETSURF_DESKTOP_SCROLLBAR_H_
-#define _NETSURF_DESKTOP_SCROLLBAR_H_
+#ifndef NETSURF_DESKTOP_SCROLLBAR_H
+#define NETSURF_DESKTOP_SCROLLBAR_H
#include <stdbool.h>
#include <limits.h>
@@ -29,23 +32,29 @@
#define SCROLLBAR_WIDTH 16
/* Region dependent values for scrollbar_scroll function */
-#define SCROLL_TOP INT_MIN
-#define SCROLL_PAGE_UP INT_MIN + 1
-#define SCROLL_PAGE_DOWN INT_MAX - 1
-#define SCROLL_BOTTOM INT_MAX
+#define SCROLL_TOP INT_MIN
+#define SCROLL_PAGE_UP (INT_MIN + 1)
+#define SCROLL_PAGE_DOWN (INT_MAX - 1)
+#define SCROLL_BOTTOM INT_MAX
struct scrollbar;
+/**
+ * scrollbar message types
+ */
typedef enum {
- SCROLLBAR_MSG_MOVED, /* the scroll value has changed */
- SCROLLBAR_MSG_SCROLL_START, /* a scrollbar drag has started, all
- * mouse events should be passed to
+ SCROLLBAR_MSG_MOVED, /**< the scroll value has changed */
+ SCROLLBAR_MSG_SCROLL_START, /**< a scrollbar drag has started, all
+ * mouse events should be passed to
* the scrollbar regardless of the
* coordinates
*/
- SCROLLBAR_MSG_SCROLL_FINISHED, /* cancel the above */
+ SCROLLBAR_MSG_SCROLL_FINISHED, /**< cancel a scrollbar drag */
} scrollbar_msg;
+/**
+ * scrollbar message context data
+ */
struct scrollbar_msg_data {
struct scrollbar *scrollbar;
scrollbar_msg msg;
@@ -53,9 +62,30 @@ struct scrollbar_msg_data {
int x0, y0, x1, y1;
};
+
+/**
+ * Scrollbar mouse input status flags
+ */
+typedef enum {
+ SCROLLBAR_MOUSE_NONE = 0, /**< Not relevant */
+ SCROLLBAR_MOUSE_USED = (1 << 0), /**< Took action with input */
+ SCROLLBAR_MOUSE_BOTH = (1 << 1), /**< Scrolling both bars */
+ SCROLLBAR_MOUSE_UP = (1 << 2), /**< Hover: scroll up */
+ SCROLLBAR_MOUSE_PUP = (1 << 3), /**< Hover: scroll page up */
+ SCROLLBAR_MOUSE_VRT = (1 << 4), /**< Hover: vert. drag bar */
+ SCROLLBAR_MOUSE_PDWN = (1 << 5), /**< Hover: scroll page down */
+ SCROLLBAR_MOUSE_DWN = (1 << 6), /**< Hover: scroll down */
+ SCROLLBAR_MOUSE_LFT = (1 << 7), /**< Hover: scroll left */
+ SCROLLBAR_MOUSE_PLFT = (1 << 8), /**< Hover: scroll page left */
+ SCROLLBAR_MOUSE_HRZ = (1 << 9), /**< Hover: horiz. drag bar */
+ SCROLLBAR_MOUSE_PRGT = (1 << 10), /**< Hover: scroll page right */
+ SCROLLBAR_MOUSE_RGT = (1 << 11) /**< Hover: scroll right */
+} scrollbar_mouse_status;
+
+
/**
* Client callback for the scrollbar.
- *
+ *
* \param client_data user data passed at scroll creation
* \param scrollbar_data scrollbar message data
*/
@@ -84,7 +114,7 @@ nserror scrollbar_create(bool horizontal, int length, int full_size,
/**
* Destroy a scrollbar.
*
- * \param s the scrollbar to be destroyed
+ * \param s the scrollbar to be destroyed
*/
void scrollbar_destroy(struct scrollbar *s);
@@ -97,9 +127,9 @@ void scrollbar_destroy(struct scrollbar *s);
* \param clip the clipping rectangle
* \param scale scale for the redraw
* \param ctx current redraw context
- * \return true on succes false otherwise
+ * \return NSERROR_OK on success otherwise error code
*/
-bool scrollbar_redraw(struct scrollbar *s, int x, int y,
+nserror scrollbar_redraw(struct scrollbar *s, int x, int y,
const struct rect *clip, float scale,
const struct redraw_context *ctx);
@@ -125,8 +155,8 @@ bool scrollbar_scroll(struct scrollbar *s, int change);
/**
* Get the current scroll offset to the visible part of the full area.
*
- * \param s the scrollbar to get the scroll offset value from
- * \return current scroll offset
+ * \param s the scrollbar to get the scroll offset value from
+ * \return current scroll offset
*/
int scrollbar_get_offset(struct scrollbar *s);
@@ -150,22 +180,6 @@ void scrollbar_set_extents(struct scrollbar *s, int length,
*/
bool scrollbar_is_horizontal(struct scrollbar *s);
-/* Scrollbar mouse input status flags */
-typedef enum {
- SCROLLBAR_MOUSE_NONE = 0, /**< Not relevant */
- SCROLLBAR_MOUSE_USED = (1 << 0), /**< Took action with input */
- SCROLLBAR_MOUSE_BOTH = (1 << 1), /**< Scrolling both bars */
- SCROLLBAR_MOUSE_UP = (1 << 2), /**< Hover: scroll up */
- SCROLLBAR_MOUSE_PUP = (1 << 3), /**< Hover: scroll page up */
- SCROLLBAR_MOUSE_VRT = (1 << 4), /**< Hover: vert. drag bar */
- SCROLLBAR_MOUSE_PDWN = (1 << 5), /**< Hover: scroll page down */
- SCROLLBAR_MOUSE_DWN = (1 << 6), /**< Hover: scroll down */
- SCROLLBAR_MOUSE_LFT = (1 << 7), /**< Hover: scroll left */
- SCROLLBAR_MOUSE_PLFT = (1 << 8), /**< Hover: scroll page left */
- SCROLLBAR_MOUSE_HRZ = (1 << 9), /**< Hover: horiz. drag bar */
- SCROLLBAR_MOUSE_PRGT = (1 << 10), /**< Hover: scroll page right */
- SCROLLBAR_MOUSE_RGT = (1 << 11) /**< Hover: scroll right */
-} scrollbar_mouse_status;
/**
* Handle mouse actions other then drag ends.
@@ -179,6 +193,7 @@ typedef enum {
scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s,
browser_mouse_state mouse, int x, int y);
+
/**
* Get a status bar message from a scrollbar mouse input status.
*
@@ -187,6 +202,7 @@ scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s,
*/
const char *scrollbar_mouse_status_to_message(scrollbar_mouse_status status);
+
/**
* Handle end of mouse drags.
*
@@ -198,18 +214,21 @@ const char *scrollbar_mouse_status_to_message(scrollbar_mouse_status status);
void scrollbar_mouse_drag_end(struct scrollbar *s,
browser_mouse_state mouse, int x, int y);
+
/**
* Called when the content is being dragged to the scrollbars have to adjust.
+ *
* If the content has both scrollbars, and scrollbar_make_pair has beed called
* before, only the one scroll which will receive further mouse events has to be
* passed.
*
- * \param s one of the the scrollbars owned by the dragged content
- * \param x X coordinate of mouse during drag start
- * \param y Y coordinate of mouse during drag start
+ * \param s one of the the scrollbars owned by the dragged content
+ * \param x X coordinate of mouse during drag start
+ * \param y Y coordinate of mouse during drag start
*/
void scrollbar_start_content_drag(struct scrollbar *s, int x, int y);
+
/**
* Connect a horizontal and a vertical scrollbar into a pair so that they
* co-operate during 2D drags.
@@ -220,11 +239,12 @@ void scrollbar_start_content_drag(struct scrollbar *s, int x, int y);
void scrollbar_make_pair(struct scrollbar *horizontal,
struct scrollbar *vertical);
+
/**
* Get the scrollbar's client data
*
- * \param s the scrollbar to get the client data from
- * \return client data
+ * \param s the scrollbar to get the client data from
+ * \return client data
*/
void *scrollbar_get_data(struct scrollbar *s);
diff --git a/desktop/searchweb.c b/desktop/searchweb.c
index 29a998eb2..c07cac9d5 100644
--- a/desktop/searchweb.c
+++ b/desktop/searchweb.c
@@ -289,13 +289,19 @@ search_web_ico_callback(hlcache_handle *ico,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("icon '%s' retrieved", nsurl_access(hlcache_handle_get_url(ico)));
+ NSLOG(netsurf, INFO, "icon '%s' retrieved",
+ nsurl_access(hlcache_handle_get_url(ico)));
guit->search_web->provider_update(provider->name,
content_get_bitmap(ico));
break;
case CONTENT_MSG_ERROR:
- LOG("icon %s error: %s", nsurl_access(hlcache_handle_get_url(ico)), event->data.error);
+ NSLOG(netsurf, INFO, "icon %s error: %s",
+ nsurl_access(hlcache_handle_get_url(ico)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(ico);
/* clear reference to released handle */
provider->ico_handle = NULL;
@@ -438,7 +444,8 @@ default_ico_callback(hlcache_handle *ico,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("default icon '%s' retrieved", nsurl_access(hlcache_handle_get_url(ico)));
+ NSLOG(netsurf, INFO, "default icon '%s' retrieved",
+ nsurl_access(hlcache_handle_get_url(ico)));
/* only set to default icon if providers icon has no handle */
if (ctx->providers[search_web_ctx.current].ico_handle == NULL) {
@@ -449,7 +456,12 @@ default_ico_callback(hlcache_handle *ico,
break;
case CONTENT_MSG_ERROR:
- LOG("icon %s error: %s", nsurl_access(hlcache_handle_get_url(ico)), event->data.error);
+ NSLOG(netsurf, INFO, "icon %s error: %s",
+ nsurl_access(hlcache_handle_get_url(ico)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(ico);
/* clear reference to released handle */
ctx->default_ico_handle = NULL;
diff --git a/desktop/selection.c b/desktop/selection.c
index 7506af0ef..35eabb2a9 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -32,10 +32,10 @@
#include "utils/utf8.h"
#include "utils/utils.h"
#include "netsurf/form.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/font.h"
-#include "render/textplain.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/font.h"
+#include "text/textplain.h"
#include "netsurf/mouse.h"
#include "desktop/browser_private.h"
@@ -70,18 +70,20 @@ struct selection_string {
typedef bool (*seln_traverse_handler)(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
- size_t whitespace_length);
+ struct box *box, const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length);
-static bool redraw_handler(const char *text, size_t length, struct box *box,
+static bool redraw_handler(const char *text, size_t length,
+ struct box *box, const nscss_len_ctx *len_ctx,
void *handle, const char *whitespace_text,
size_t whitespace_length);
static void selection_redraw(struct selection *s, unsigned start_idx,
unsigned end_idx);
static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset);
-static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+static bool traverse_tree(struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker);
@@ -198,7 +200,10 @@ void selection_reinit(struct selection *s, struct box *root)
* \param root the root box for html document or NULL for text/plain
*/
-void selection_init(struct selection *s, struct box *root)
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx)
{
if (s->defined)
selection_clear(s, true);
@@ -207,6 +212,13 @@ void selection_init(struct selection *s, struct box *root)
s->start_idx = 0;
s->end_idx = 0;
s->drag_state = DRAG_NONE;
+ if (len_ctx != NULL) {
+ s->len_ctx = *len_ctx;
+ } else {
+ s->len_ctx.vw = 0;
+ s->len_ctx.vh = 0;
+ s->len_ctx.root_style = NULL;
+ }
selection_reinit(s, root);
}
@@ -442,6 +454,7 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* for all boxes that lie (partially) within the given range
*
* \param box box subtree
+ * \param len_ctx Length conversion context.
* \param start_idx start of range within textual representation (bytes)
* \param end_idx end of range
* \param handler handler function to call
@@ -452,7 +465,9 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* \return false iff traversal abandoned part-way through
*/
-bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+bool traverse_tree(
+ struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker)
@@ -473,9 +488,9 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
- if (!traverse_tree(box->list_marker, start_idx, end_idx,
- handler, handle, before, first,
- true))
+ if (!traverse_tree(box->list_marker, len_ctx,
+ start_idx, end_idx, handler, handle,
+ before, first, true))
return false;
}
@@ -506,7 +521,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
&end_offset)) {
if (!handler(box->text + start_offset, min(box->length,
end_offset) - start_offset,
- box, handle, whitespace_text,
+ box, len_ctx, handle, whitespace_text,
whitespace_length))
return false;
if (before) {
@@ -533,7 +548,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
* the tree */
struct box *next = child->next;
- if (!traverse_tree(child, start_idx, end_idx,
+ if (!traverse_tree(child, len_ctx, start_idx, end_idx,
handler, handle, before, first, false))
return false;
@@ -568,14 +583,16 @@ static bool selection_traverse(struct selection *s,
if (s->root) {
/* HTML */
- return traverse_tree(s->root, s->start_idx, s->end_idx,
- handler, handle, &before, &first, false);
+ return traverse_tree(s->root, &s->len_ctx,
+ s->start_idx, s->end_idx,
+ handler, handle,
+ &before, &first, false);
}
/* Text */
text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length);
- if (text && !handler(text, length, NULL, handle, NULL, 0))
+ if (text && !handler(text, length, NULL, NULL, handle, NULL, 0))
return false;
return true;
@@ -597,8 +614,8 @@ static bool selection_traverse(struct selection *s,
*/
bool redraw_handler(const char *text, size_t length, struct box *box,
- void *handle, const char *whitespace_text,
- size_t whitespace_length)
+ const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length)
{
if (box) {
struct rdw_info *r = (struct rdw_info*)handle;
@@ -606,7 +623,7 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
int x, y;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
/* \todo - it should be possible to reduce the redrawn area by
* considering the 'text', 'length' and 'space' parameters */
@@ -652,7 +669,7 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
rdw.inited = false;
if (s->root) {
- if (!traverse_tree(s->root, start_idx, end_idx,
+ if (!traverse_tree(s->root, &s->len_ctx, start_idx, end_idx,
redraw_handler, &rdw,
NULL, NULL, false))
return;
@@ -739,10 +756,11 @@ static bool selection_string_append(const char *text, size_t length, bool space,
/**
* Selection traversal routine for appending text to a string
*
- * \param text pointer to text being added, or NULL for newline
- * \param length length of text to be appended (bytes)
- * \param box pointer to text box, or NULL if from textplain
- * \param handle selection string to append to
+ * \param text pointer to text being added, or NULL for newline
+ * \param length length of text to be appended (bytes)
+ * \param box pointer to text box, or NULL if from textplain
+ * \param len_ctx Length conversion context
+ * \param handle selection string to append to
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
@@ -750,7 +768,8 @@ static bool selection_string_append(const char *text, size_t length, bool space,
*/
static bool selection_copy_handler(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
+ struct box *box, const nscss_len_ctx *len_ctx,
+ void *handle, const char *whitespace_text,
size_t whitespace_length)
{
bool add_space = false;
@@ -771,7 +790,7 @@ static bool selection_copy_handler(const char *text, size_t length,
if (box->style != NULL) {
/* Override default font style */
- font_plot_style_from_css(box->style, &style);
+ font_plot_style_from_css(len_ctx, box->style, &style);
pstyle = &style;
} else {
/* If there's no style, there must be no text */
diff --git a/desktop/selection.h b/desktop/selection.h
index e2bc3b31d..2f3f6dcfe 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "netsurf/mouse.h"
+#include "content/handlers/css/utils.h"
struct box;
@@ -43,6 +44,7 @@ struct selection
{
struct content *c;
struct box *root;
+ nscss_len_ctx len_ctx;
unsigned max_idx; /* total bytes in text representation */
@@ -60,7 +62,10 @@ struct selection *selection_create(struct content *c, bool is_html);
void selection_prepare(struct selection *s, struct content *c, bool is_html);
void selection_destroy(struct selection *s);
-void selection_init(struct selection *s, struct box *root);
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx);
void selection_reinit(struct selection *s, struct box *root);
/* struct box *selection_root(struct selection *s); */
diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c
index 09a281c1c..f40af5968 100644
--- a/desktop/sslcert_viewer.c
+++ b/desktop/sslcert_viewer.c
@@ -17,8 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * SSL Certificate verification UI (implementation)
+/**
+ * \file
+ * SSL Certificate verification UI implementation
*/
#include <assert.h>
@@ -33,6 +34,9 @@
#include "utils/log.h"
#include "utils/utils.h"
+/**
+ * ssl certificate viewer data fields
+ */
enum sslcert_viewer_field {
SSLCERT_V_SUBJECT,
SSLCERT_V_SERIAL,
@@ -45,7 +49,10 @@ enum sslcert_viewer_field {
SSLCERT_V_N_FIELDS
};
-/** ssl certificate verification context. */
+
+/**
+ * ssl certificate verification context.
+ */
struct sslcert_session_data {
struct ssl_cert_info *certs; /**< Certificates */
unsigned long num; /**< Number of certificates in chain */
@@ -57,6 +64,10 @@ struct sslcert_session_data {
struct treeview_field_desc fields[SSLCERT_V_N_FIELDS];
};
+
+/**
+ * ssl certificate tree entry
+ */
struct sslcert_entry {
treeview_node *entry;
char version[24];
@@ -67,12 +78,11 @@ struct sslcert_entry {
/**
- * Free a sll certificate viewer entry's treeview field data.
+ * Free a ssl certificate viewer entry's treeview field data.
*
- * \param e Entry to free data from
+ * \param e Entry to free data from
*/
-static void sslcert_viewer_free_treeview_field_data(
- struct sslcert_entry *e)
+static void sslcert_viewer_free_treeview_field_data(struct sslcert_entry *e)
{
}
@@ -80,17 +90,17 @@ static void sslcert_viewer_free_treeview_field_data(
/**
* Build a sslcert viewer treeview field from given text
*
- * \param field SSL certificate treeview field to build
- * \param data SSL certificate entry field data to set
- * \param value Text to set in field, ownership yielded
- * \param ssl_d SSL certificate session data
+ * \param field SSL certificate treeview field to build
+ * \param data SSL certificate entry field data to set
+ * \param value Text to set in field, ownership yielded
+ * \param ssl_d SSL certificate session data
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static inline nserror sslcert_viewer_field_builder(
- enum sslcert_viewer_field field,
- struct treeview_field_data *data,
- const char *value,
- struct sslcert_session_data *ssl_d)
+static inline nserror
+sslcert_viewer_field_builder(enum sslcert_viewer_field field,
+ struct treeview_field_data *data,
+ const char *value,
+ struct sslcert_session_data *ssl_d)
{
data->field = ssl_d->fields[field].field;
data->value = value;
@@ -103,15 +113,15 @@ static inline nserror sslcert_viewer_field_builder(
/**
* Set a sslcert viewer entry's data from the certificate.
*
- * \param e Entry to set up
- * \param cert Data associated with entry's certificate
- * \param ssl_d SSL certificate session data
+ * \param e Entry to set up
+ * \param cert Data associated with entry's certificate
+ * \param ssl_d SSL certificate session data
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror sslcert_viewer_set_treeview_field_data(
- struct sslcert_entry *e,
- const struct ssl_cert_info *cert,
- struct sslcert_session_data *ssl_d)
+static nserror
+sslcert_viewer_set_treeview_field_data(struct sslcert_entry *e,
+ const struct ssl_cert_info *cert,
+ struct sslcert_session_data *ssl_d)
{
unsigned int written;
@@ -121,39 +131,39 @@ static nserror sslcert_viewer_set_treeview_field_data(
/* Set the fields up */
sslcert_viewer_field_builder(SSLCERT_V_SUBJECT,
- &e->data[SSLCERT_V_SUBJECT],
- cert->subject, ssl_d);
+ &e->data[SSLCERT_V_SUBJECT],
+ cert->subject, ssl_d);
written = snprintf(e->serial, sizeof(e->serial), "%li", cert->serial);
assert(written < sizeof(e->serial));
sslcert_viewer_field_builder(SSLCERT_V_SERIAL,
- &e->data[SSLCERT_V_SERIAL],
- e->serial, ssl_d);
+ &e->data[SSLCERT_V_SERIAL],
+ e->serial, ssl_d);
written = snprintf(e->type, sizeof(e->type), "%i", cert->cert_type);
assert(written < sizeof(e->type));
sslcert_viewer_field_builder(SSLCERT_V_TYPE,
- &e->data[SSLCERT_V_TYPE],
- e->type, ssl_d);
+ &e->data[SSLCERT_V_TYPE],
+ e->type, ssl_d);
sslcert_viewer_field_builder(SSLCERT_V_VALID_UNTIL,
- &e->data[SSLCERT_V_VALID_UNTIL],
- cert->not_after, ssl_d);
+ &e->data[SSLCERT_V_VALID_UNTIL],
+ cert->not_after, ssl_d);
sslcert_viewer_field_builder(SSLCERT_V_VALID_FROM,
- &e->data[SSLCERT_V_VALID_FROM],
- cert->not_before, ssl_d);
+ &e->data[SSLCERT_V_VALID_FROM],
+ cert->not_before, ssl_d);
written = snprintf(e->version, sizeof(e->version),
- "%li", cert->version);
+ "%li", cert->version);
assert(written < sizeof(e->version));
sslcert_viewer_field_builder(SSLCERT_V_VERSION,
- &e->data[SSLCERT_V_VERSION],
- e->version, ssl_d);
+ &e->data[SSLCERT_V_VERSION],
+ e->version, ssl_d);
sslcert_viewer_field_builder(SSLCERT_V_ISSUER,
- &e->data[SSLCERT_V_ISSUER],
- cert->issuer, ssl_d);
+ &e->data[SSLCERT_V_ISSUER],
+ cert->issuer, ssl_d);
return NSERROR_OK;
}
@@ -162,12 +172,12 @@ static nserror sslcert_viewer_set_treeview_field_data(
/**
* Create a treeview node for a certificate
*
- * \param ssl_d SSL certificate session data
- * \param n Number of SSL certificate in chain, to make node for
- * \return true on success, false on memory exhaustion
+ * \param ssl_d SSL certificate session data
+ * \param n Number of SSL certificate in chain, to make node for
+ * \return NSERROR_OK on success otherwise error code.
*/
-static nserror sslcert_viewer_create_node(
- struct sslcert_session_data *ssl_d, int n)
+static nserror
+sslcert_viewer_create_node(struct sslcert_session_data *ssl_d, int n)
{
struct sslcert_entry *e;
const struct ssl_cert_info *cert = &(ssl_d->certs[n]);
@@ -187,8 +197,8 @@ static nserror sslcert_viewer_create_node(
/* Create the new treeview node */
err = treeview_create_node_entry(ssl_d->tree, &(e->entry),
- NULL, TREE_REL_FIRST_CHILD,
- e->data, e, TREE_OPTION_NONE);
+ NULL, TREE_REL_FIRST_CHILD,
+ e->data, e, TREE_OPTION_NONE);
if (err != NSERROR_OK) {
sslcert_viewer_free_treeview_field_data(e);
free(e);
@@ -200,10 +210,10 @@ static nserror sslcert_viewer_create_node(
/**
- * Initialise the treeview entry feilds
+ * Initialise the treeview entry fields
*
- * \param ssl_d SSL certificate session data
- * \return true on success, false on memory exhaustion
+ * \param ssl_d SSL certificate session data
+ * \return NSERROR_OK on success otherwise error code.
*/
static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
{
@@ -217,8 +227,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelSubject";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_SUBJECT].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_SUBJECT].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -226,8 +236,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelSerial";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_SERIAL].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_SERIAL].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -235,8 +245,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelType";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_TYPE].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_TYPE].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -244,8 +254,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelValidUntil";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_VALID_UNTIL].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_VALID_UNTIL].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -253,8 +263,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelValidFrom";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_VALID_FROM].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_VALID_FROM].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -262,8 +272,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelVersion";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_VERSION].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_VERSION].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -271,8 +281,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelIssuer";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_ISSUER].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_ISSUER].field) !=
+ lwc_error_ok) {
goto error;
}
@@ -280,8 +290,8 @@ static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d)
label = "TreeviewLabelCertificates";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
- &ssl_d->fields[SSLCERT_V_CERTIFICATES].field) !=
- lwc_error_ok) {
+ &ssl_d->fields[SSLCERT_V_CERTIFICATES].field) !=
+ lwc_error_ok) {
return false;
}
@@ -299,7 +309,7 @@ error:
/**
* Delete ssl certificate viewer entries
*
- * \param e Entry to delete.
+ * \param e Entry to delete.
*/
static void sslcert_viewer_delete_entry(struct sslcert_entry *e)
{
@@ -308,8 +318,15 @@ static void sslcert_viewer_delete_entry(struct sslcert_entry *e)
}
-static nserror sslcert_viewer_tree_node_folder_cb(
- struct treeview_node_msg msg, void *data)
+/**
+ * folder operation callback
+ *
+ * \param msg treeview message
+ * \param data message context
+ * \return NSERROR_OK on success
+ */
+static nserror
+sslcert_viewer_tree_node_folder_cb(struct treeview_node_msg msg, void *data)
{
switch (msg.msg) {
case TREE_MSG_NODE_DELETE:
@@ -320,8 +337,17 @@ static nserror sslcert_viewer_tree_node_folder_cb(
return NSERROR_OK;
}
-static nserror sslcert_viewer_tree_node_entry_cb(
- struct treeview_node_msg msg, void *data)
+
+
+/**
+ * node entry callback
+ *
+ * \param msg treeview message
+ * \param data message context
+ * \return NSERROR_OK on success
+ */
+static nserror
+sslcert_viewer_tree_node_entry_cb(struct treeview_node_msg msg, void *data)
{
struct sslcert_entry *e = data;
@@ -338,6 +364,11 @@ static nserror sslcert_viewer_tree_node_entry_cb(
return NSERROR_OK;
}
+
+
+/**
+ * ssl certificate treeview callbacks
+ */
struct treeview_callback_table sslv_tree_cb_t = {
.folder = sslcert_viewer_tree_node_folder_cb,
.entry = sslcert_viewer_tree_node_entry_cb
@@ -345,8 +376,10 @@ struct treeview_callback_table sslv_tree_cb_t = {
/* Exported interface, documented in sslcert_viewer.h */
-nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
- void *core_window_handle, struct sslcert_session_data *ssl_d)
+nserror
+sslcert_viewer_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle,
+ struct sslcert_session_data *ssl_d)
{
nserror err;
int cert_loop;
@@ -358,7 +391,7 @@ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Building certificate viewer");
+ NSLOG(netsurf, INFO, "Building certificate viewer");
/* Init. certificate chain treeview entry fields */
err = sslcert_init_entry_fields(ssl_d);
@@ -369,8 +402,8 @@ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
/* Create the certificate treeview */
err = treeview_create(&ssl_d->tree, &sslv_tree_cb_t,
- SSLCERT_V_N_FIELDS, ssl_d->fields,
- cw_t, core_window_handle, TREEVIEW_READ_ONLY);
+ SSLCERT_V_N_FIELDS, ssl_d->fields,
+ cw_t, core_window_handle, TREEVIEW_READ_ONLY);
if (err != NSERROR_OK) {
ssl_d->tree = NULL;
return err;
@@ -384,7 +417,7 @@ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
}
}
- LOG("Built certificate viewer");
+ NSLOG(netsurf, INFO, "Built certificate viewer");
return NSERROR_OK;
}
@@ -393,7 +426,7 @@ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
/**
* Free SSL certificate session data
*
- * \param ssl_d SSL certificate session data
+ * \param ssl_d SSL certificate session data
*/
static void sslcert_cleanup_session(struct sslcert_session_data *ssl_d)
{
@@ -419,7 +452,7 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d)
int i;
nserror err;
- LOG("Finalising ssl certificate viewer");
+ NSLOG(netsurf, INFO, "Finalising ssl certificate viewer");
/* Destroy the treeview */
err = treeview_destroy(ssl_d->tree);
@@ -437,17 +470,20 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d)
return err;
}
- LOG("Finalised ssl certificate viewer");
+ NSLOG(netsurf, INFO, "Finalised ssl certificate viewer");
return err;
}
/* Exported interface, documented in sslcert_viewer.h */
-nserror sslcert_viewer_create_session_data(unsigned long num, nsurl *url,
- llcache_query_response cb, void *cbpw,
- const struct ssl_cert_info *certs,
- struct sslcert_session_data **ssl_d)
+nserror
+sslcert_viewer_create_session_data(unsigned long num,
+ nsurl *url,
+ llcache_query_response cb,
+ void *cbpw,
+ const struct ssl_cert_info *certs,
+ struct sslcert_session_data **ssl_d)
{
struct sslcert_session_data *data;
@@ -506,9 +542,11 @@ nserror sslcert_viewer_accept(struct sslcert_session_data *ssl_d)
/* Exported interface, documented in sslcert_viewer.h */
-void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
- int x, int y, struct rect *clip,
- const struct redraw_context *ctx)
+void
+sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
+ int x, int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
{
assert(ssl_d != NULL &&
"sslcert_viewer_redraw() given bad session data");
@@ -518,8 +556,10 @@ void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
/* Exported interface, documented in sslcert_viewer.h */
-void sslcert_viewer_mouse_action(struct sslcert_session_data *ssl_d,
- browser_mouse_state mouse, int x, int y)
+void
+sslcert_viewer_mouse_action(struct sslcert_session_data *ssl_d,
+ browser_mouse_state mouse,
+ int x, int y)
{
treeview_mouse_action(ssl_d->tree, mouse, x, y);
}
diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h
index 9b21cd1b6..9a57b965c 100644
--- a/desktop/sslcert_viewer.h
+++ b/desktop/sslcert_viewer.h
@@ -17,9 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * SSL Certificate verification UI interface
+ */
-#ifndef _NETSURF_DESKTOP_SSLCERT_VIEWER_H_
-#define _NETSURF_DESKTOP_SSLCERT_VIEWER_H_
+#ifndef NETSURF_DESKTOP_SSLCERT_VIEWER_H
+#define NETSURF_DESKTOP_SSLCERT_VIEWER_H
#include "content/llcache.h"
#include "netsurf/mouse.h"
@@ -48,6 +52,7 @@ nserror sslcert_viewer_create_session_data(
void *cbpw, const struct ssl_cert_info *certs,
struct sslcert_session_data **ssl_d);
+
/**
* Initialise a ssl certificate viewer from session data.
*
@@ -61,6 +66,7 @@ nserror sslcert_viewer_create_session_data(
nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
void *core_window_handle, struct sslcert_session_data *ssl_d);
+
/**
* Finalise a ssl certificate viewer.
*
@@ -72,6 +78,7 @@ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
*/
nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d);
+
/**
* Reject a certificate chain.
*
@@ -80,6 +87,7 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d);
*/
nserror sslcert_viewer_reject(struct sslcert_session_data *ssl_d);
+
/**
* Accept a certificate chain.
*
@@ -88,6 +96,7 @@ nserror sslcert_viewer_reject(struct sslcert_session_data *ssl_d);
*/
nserror sslcert_viewer_accept(struct sslcert_session_data *ssl_d);
+
/**
* Redraw the ssl certificate viewer.
*
@@ -101,6 +110,7 @@ void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
int x, int y, struct rect *clip,
const struct redraw_context *ctx);
+
/**
* Handles all kinds of mouse action
*
@@ -112,6 +122,7 @@ void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
void sslcert_viewer_mouse_action(struct sslcert_session_data *ssl_d,
browser_mouse_state mouse, int x, int y);
+
/**
* Key press handling.
*
diff --git a/desktop/system_colour.c b/desktop/system_colour.c
index f33b57a37..42a51eaea 100644
--- a/desktop/system_colour.c
+++ b/desktop/system_colour.c
@@ -16,9 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * System colour handling
- *
+/**
+ * \file
+ * System colour handling implementation.
*/
#include <string.h>
@@ -38,6 +38,7 @@ static lwc_string *colour_list[colour_list_len];
static lwc_string **ns_system_colour_pw = NULL;
+/* exported interface documented in desktop/system_colour.h */
nserror ns_system_colour_init(void)
{
unsigned int ccount;
@@ -61,6 +62,8 @@ nserror ns_system_colour_init(void)
return NSERROR_OK;
}
+
+/* exported interface documented in desktop/system_colour.h */
void ns_system_colour_finalize(void)
{
unsigned int ccount;
@@ -70,21 +73,25 @@ void ns_system_colour_finalize(void)
}
}
-colour ns_system_colour_char(const char *name)
+
+/* exported interface documented in desktop/system_colour.h */
+nserror ns_system_colour_char(const char *name, colour *colour_out)
{
- colour ret = 0;
unsigned int ccount;
for (ccount = 0; ccount < colour_list_len; ccount++) {
if (strcmp(name,
nsoptions[ccount + NSOPTION_SYS_COLOUR_START].key + SLEN("sys_colour_")) == 0) {
- ret = nsoptions[ccount + NSOPTION_SYS_COLOUR_START].value.c;
- break;
+ *colour_out = nsoptions[ccount + NSOPTION_SYS_COLOUR_START].value.c;
+ return NSERROR_OK;
}
}
- return ret;
+
+ return NSERROR_INVALID;
}
+
+/* exported interface documented in desktop/system_colour.h */
css_error ns_system_colour(void *pw, lwc_string *name, css_color *colour)
{
unsigned int ccount;
diff --git a/desktop/system_colour.h b/desktop/system_colour.h
index 8e82818aa..0b7553003 100644
--- a/desktop/system_colour.h
+++ b/desktop/system_colour.h
@@ -16,25 +16,59 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Interface to system colour values.
+ *
+ * Netsurf has a list of user configurable colours with frontend
+ * specific defaults. These colours are used for the css system
+ * colours and to colour and style internally rendered widgets
+ * (e.g. cookies treeview or local file directory views.
*/
-#ifndef _NETSURF_DESKTOP_SYSTEM_COLOUR_H_
-#define _NETSURF_DESKTOP_SYSTEM_COLOUR_H_
+#ifndef NETSURF_DESKTOP_SYSTEM_COLOUR_H
+#define NETSURF_DESKTOP_SYSTEM_COLOUR_H
#include <libcss/libcss.h>
#include "utils/errors.h"
#include "netsurf/types.h"
-/** css callback to obtain named system colours. */
+/**
+ * css callback to obtain named system colour.
+ *
+ * \param[in] pw context unused in implementation
+ * \param[in] name The name of the colour being looked up
+ * \param[out] color The system colour associated with the name.
+ * \return CSS_OK and \a color updated on success else CSS_INVALID if
+ * the \a name is unrecognised
+ */
css_error ns_system_colour(void *pw, lwc_string *name, css_color *color);
-/** Obtain a named system colour from a frontend. */
-colour ns_system_colour_char(const char *name);
+/**
+ * Obtain a system colour from a name.
+ *
+ * \param[in] name The name of the colour being looked up
+ * \param[out] color The system colour associated with the name in the
+ * netsurf colour representation.
+ * \return NSERROR_OK and \a color updated on success else appropriate
+ * error code.
+ */
+nserror ns_system_colour_char(const char *name, colour *color);
+
+
+/**
+ * Initialise the system colours
+ *
+ * \return NSERROR_OK on success else appropriate error code.
+ */
nserror ns_system_colour_init(void);
+
+
+/**
+ * release any resources associated with the system colours.
+ */
void ns_system_colour_finalize(void);
#endif
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 203c28e93..5bae27a5c 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -45,9 +45,9 @@
#define TA_ALLOC_STEP 512
static plot_style_t pstyle_stroke_caret = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_colour = CARET_COLOR,
- .stroke_width = 1,
+ .stroke_type = PLOT_OP_TYPE_SOLID,
+ .stroke_colour = CARET_COLOR,
+ .stroke_width = plot_style_int_to_fixed(1),
};
struct line_info {
@@ -828,7 +828,7 @@ static bool textarea_reflow_singleline(struct textarea *ta, size_t b_off,
ta->lines =
malloc(LINE_CHUNK_SIZE * sizeof(struct line_info));
if (ta->lines == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return false;
}
ta->lines_alloc_size = LINE_CHUNK_SIZE;
@@ -852,7 +852,7 @@ static bool textarea_reflow_singleline(struct textarea *ta, size_t b_off,
char *temp = realloc(ta->password.data,
b_len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -936,7 +936,8 @@ static bool textarea_reflow_multiline(struct textarea *ta,
if (ta->lines == NULL) {
ta->lines = calloc(sizeof(struct line_info), LINE_CHUNK_SIZE);
if (ta->lines == NULL) {
- LOG("Failed to allocate memory for textarea lines");
+ NSLOG(netsurf, INFO,
+ "Failed to allocate memory for textarea lines");
return false;
}
ta->lines_alloc_size = LINE_CHUNK_SIZE;
@@ -1053,7 +1054,7 @@ static bool textarea_reflow_multiline(struct textarea *ta,
(line + 2 + LINE_CHUNK_SIZE) *
sizeof(struct line_info));
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1334,7 +1335,7 @@ static bool textarea_insert_text(struct textarea *ta, const char *text,
char *temp = realloc(ta->text.data, b_len + ta->text.len +
TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1484,7 +1485,7 @@ static bool textarea_replace_text_internal(struct textarea *ta, size_t b_start,
rep_len + ta->text.len - (b_end - b_start) +
TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1561,7 +1562,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
char *temp = realloc(undo->text.data,
b_offset + len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1575,7 +1576,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
(undo->next_detail + 128) *
sizeof(struct textarea_undo_detail));
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1802,6 +1803,10 @@ static void textarea_setup_text_offsets(struct textarea *ta)
{
int text_y_offset, text_y_offset_baseline;
+ ta->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL(
+ nscss_screen_dpi, FDIV(INTTOFIX(ta->fstyle.size),
+ INTTOFIX(PLOT_STYLE_SCALE))), F_72)));
+
text_y_offset = text_y_offset_baseline = ta->border_width;
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
@@ -1821,6 +1826,27 @@ static void textarea_setup_text_offsets(struct textarea *ta)
}
+/**
+ * Set font styles up for a textarea.
+ *
+ * \param[in] ta Textarea to update.
+ * \param[in] fstyle Font style to set in textarea.
+ * \param[in] selected_text Textarea selected text colour.
+ * \param[in] selected_bg Textarea selection background colour.
+ */
+static void textarea_set_text_style(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ colour selected_text,
+ colour selected_bg)
+{
+ ta->fstyle = *fstyle;
+
+ ta->sel_fstyle = *fstyle;
+ ta->sel_fstyle.foreground = selected_text;
+ ta->sel_fstyle.background = selected_bg;
+}
+
/* exported interface, documented in textarea.h */
struct textarea *textarea_create(const textarea_flags flags,
@@ -1835,13 +1861,13 @@ struct textarea *textarea_create(const textarea_flags flags,
flags & TEXTAREA_PASSWORD));
if (callback == NULL) {
- LOG("no callback provided");
+ NSLOG(netsurf, INFO, "no callback provided");
return NULL;
}
ret = malloc(sizeof(struct textarea));
if (ret == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return NULL;
}
@@ -1860,11 +1886,10 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->border_width = setup->border_width;
ret->border_col = setup->border_col;
- ret->fstyle = setup->text;
-
- ret->sel_fstyle = setup->text;
- ret->sel_fstyle.foreground = setup->selected_text;
- ret->sel_fstyle.background = setup->selected_bg;
+ textarea_set_text_style(ret,
+ &setup->text,
+ setup->selected_text,
+ setup->selected_bg);
ret->scroll_x = 0;
ret->scroll_y = 0;
@@ -1888,7 +1913,7 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->text.data = malloc(TA_ALLOC_STEP);
if (ret->text.data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
free(ret);
return NULL;
}
@@ -1900,7 +1925,7 @@ struct textarea *textarea_create(const textarea_flags flags,
if (flags & TEXTAREA_PASSWORD) {
ret->password.data = malloc(TA_ALLOC_STEP);
if (ret->password.data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
free(ret->text.data);
free(ret);
return NULL;
@@ -1923,7 +1948,7 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL(
nscss_screen_dpi, FDIV(INTTOFIX(setup->text.size),
- INTTOFIX(FONT_SIZE_SCALE))), F_72)));
+ INTTOFIX(PLOT_STYLE_SCALE))), F_72)));
ret->caret_pos.line = ret->caret_pos.byte_off = -1;
ret->caret_x = 0;
@@ -1975,7 +2000,7 @@ bool textarea_set_text(struct textarea *ta, const char *text)
if (len >= ta->text.alloc) {
char *temp = realloc(ta->text.data, len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
ta->text.data = temp;
@@ -2062,7 +2087,7 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
}
if (len < ta->text.len) {
- LOG("buffer too small");
+ NSLOG(netsurf, INFO, "buffer too small");
return -1;
}
@@ -2073,6 +2098,17 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
/* exported interface, documented in textarea.h */
+const char * textarea_data(struct textarea *ta, unsigned int *len)
+{
+ if (len != NULL) {
+ *len = ta->text.len;
+ }
+
+ return ta->text.data;
+}
+
+
+/* exported interface, documented in textarea.h */
bool textarea_set_caret(struct textarea *ta, int caret)
{
int b_off;
@@ -2095,13 +2131,13 @@ bool textarea_set_caret(struct textarea *ta, int caret)
void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
const struct rect *clip, const struct redraw_context *ctx)
{
- const struct plotter_table *plot = ctx->plot;
int line0, line1, line, left, right, line_y;
int text_y_offset, text_y_offset_baseline;
unsigned int b_pos, b_len, b_len_part, b_end;
unsigned int sel_start, sel_end;
char *line_text;
struct rect r, s;
+ struct rect rect;
bool selected = false;
plot_font_style_t fstyle;
int fsize = ta->fstyle.size;
@@ -2162,20 +2198,24 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
r.y1 = y + ta->vis_height * scale;
}
- plot->clip(&r);
+ ctx->plot->clip(ctx, &r);
if (ta->border_col != NS_TRANSPARENT &&
ta->border_width > 0) {
/* Plot border */
- plot->rectangle(x, y, x + ta->vis_width, y + ta->vis_height,
- &plot_style_fill_bg);
+ rect.x0 = x;
+ rect.y0 = y;
+ rect.x1 = x + ta->vis_width;
+ rect.y1 = y + ta->vis_height;
+ ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect);
}
if (ta->fstyle.background != NS_TRANSPARENT) {
/* Plot background */
plot_style_fill_bg.fill_colour = ta->fstyle.background;
- plot->rectangle(x + ta->border_width, y + ta->border_width,
- x + ta->vis_width - ta->border_width,
- y + ta->vis_height - ta->border_width,
- &plot_style_fill_bg);
+ rect.x0 = x + ta->border_width;
+ rect.y0 = y + ta->border_width;
+ rect.x1 = x + ta->vis_width - ta->border_width;
+ rect.y1 = y + ta->vis_height - ta->border_width;
+ ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect);
}
if (scale == 1.0) {
@@ -2223,16 +2263,16 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
plot_style_fill_bg.fill_colour = ta->sel_fstyle.background;
- for (line = line0; (line <= line1) &&
- (y + line * ta->line_height <= r.y1 + ta->scroll_y);
- line++) {
+ for (line = line0;
+ (line <= line1) && (y + line * ta->line_height <= r.y1 + ta->scroll_y);
+ line++) {
if (ta->lines[line].b_length == 0) {
b_pos++;
continue;
}
/* reset clip rectangle */
- plot->clip(&r);
+ ctx->plot->clip(ctx, &r);
b_len = ta->lines[line].b_length;
@@ -2256,12 +2296,12 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
fstyle = ta->fstyle;
fstyle.size = fsize;
- plot->text(x + ta->border_width + ta->pad_left -
- ta->scroll_x,
+ ctx->plot->text(ctx,
+ &fstyle,
+ x + ta->border_width + ta->pad_left - ta->scroll_x,
y + line_y + text_y_offset_baseline,
- ta->show->data +
- ta->lines[line].b_start,
- ta->lines[line].b_length, &fstyle);
+ ta->show->data + ta->lines[line].b_start,
+ ta->lines[line].b_length);
b_pos += b_len;
@@ -2338,24 +2378,24 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
continue;
}
- plot->clip(&s);
+ ctx->plot->clip(ctx, &s);
if (selected) {
/* draw selection fill */
- plot->rectangle(s.x0, y + line_y +
- text_y_offset,
- s.x1, y + line_y + line_height +
- text_y_offset,
- &plot_style_fill_bg);
+ rect.x0 = s.x0;
+ rect.y0 = y + line_y + text_y_offset;
+ rect.x1 = s.x1;
+ rect.y1 = y + line_y + line_height + text_y_offset;
+ ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect);
}
/* draw text */
- plot->text(x + ta->border_width + ta->pad_left -
- ta->scroll_x,
+ ctx->plot->text(ctx,
+ &fstyle,
+ x + ta->border_width + ta->pad_left - ta->scroll_x,
y + line_y + text_y_offset_baseline,
- ta->show->data +
- ta->lines[line].b_start,
- ta->lines[line].b_length, &fstyle);
+ ta->show->data + ta->lines[line].b_start,
+ ta->lines[line].b_length);
b_pos += b_len_part;
b_len -= b_len_part;
@@ -2376,30 +2416,33 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
/* No native caret, there is no selection, and caret visible */
int caret_y = y - ta->scroll_y + ta->caret_y;
- plot->clip(&r);
+ ctx->plot->clip(ctx, &r);
/* Render our own caret */
- plot->line(x - ta->scroll_x + ta->caret_x, caret_y,
- x - ta->scroll_x + ta->caret_x,
- caret_y + ta->line_height,
- &pstyle_stroke_caret);
+ rect.x0 = x - ta->scroll_x + ta->caret_x;
+ rect.y0 = caret_y;
+ rect.x1 = x - ta->scroll_x + ta->caret_x;
+ rect.y1 = caret_y + ta->line_height;
+ ctx->plot->line(ctx, &pstyle_stroke_caret, &rect);
}
- plot->clip(clip);
+ ctx->plot->clip(ctx, clip);
- if (ta->bar_x != NULL)
+ if (ta->bar_x != NULL) {
scrollbar_redraw(ta->bar_x,
x / scale + ta->border_width,
y / scale + ta->vis_height - ta->border_width -
SCROLLBAR_WIDTH,
clip, scale, ctx);
+ }
- if (ta->bar_y != NULL)
+ if (ta->bar_y != NULL) {
scrollbar_redraw(ta->bar_y,
x / scale + ta->vis_width - ta->border_width -
SCROLLBAR_WIDTH,
y / scale + ta->border_width,
clip, scale, ctx);
+ }
}
@@ -2842,7 +2885,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
}
- redraw &= ~textarea_set_caret_internal(ta, caret);
+ redraw &= !textarea_set_caret_internal(ta, caret);
/* TODO: redraw only the bit that changed */
msg.ta = ta;
@@ -3201,8 +3244,12 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height)
/* exported interface, documented in textarea.h */
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left)
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left)
{
struct rect r = {0, 0, 0, 0};
@@ -3213,6 +3260,10 @@ void textarea_set_layout(struct textarea *ta, int width, int height,
ta->pad_bottom = bottom + ((ta->bar_x == NULL) ? 0 : SCROLLBAR_WIDTH);
ta->pad_left = left;
+ textarea_set_text_style(ta, fstyle,
+ ta->sel_fstyle.foreground,
+ ta->sel_fstyle.background);
+
textarea_setup_text_offsets(ta);
if (ta->flags & TEXTAREA_MULTILINE) {
diff --git a/desktop/textarea.h b/desktop/textarea.h
index 65e2594c7..82e0de95b 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -1,6 +1,6 @@
/*
* Copyright 2006 John-Mark Bell <jmb@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -17,12 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Single/Multi-line UTF-8 text area (interface)
+/**
+ * \file
+ * Single/Multi-line UTF-8 text area interface
*/
-#ifndef _NETSURF_DESKTOP_TEXTAREA_H_
-#define _NETSURF_DESKTOP_TEXTAREA_H_
+#ifndef NETSURF_DESKTOP_TEXTAREA_H
+#define NETSURF_DESKTOP_TEXTAREA_H
#include <stdint.h>
#include <stdbool.h>
@@ -33,21 +34,31 @@
struct textarea;
struct redraw_context;
-/* Text area flags */
+/**
+ * Text area flags
+ */
typedef enum {
- TEXTAREA_DEFAULT = (1 << 0), /**< Standard input */
- TEXTAREA_MULTILINE = (1 << 1), /**< Multiline area */
- TEXTAREA_READONLY = (1 << 2), /**< Non-editable */
- TEXTAREA_INTERNAL_CARET = (1 << 3), /**< Render own caret */
- TEXTAREA_PASSWORD = (1 << 4) /**< Obscured display */
+ TEXTAREA_DEFAULT = (1 << 0), /**< Standard input */
+ TEXTAREA_MULTILINE = (1 << 1), /**< Multiline area */
+ TEXTAREA_READONLY = (1 << 2), /**< Non-editable */
+ TEXTAREA_INTERNAL_CARET = (1 << 3), /**< Render own caret */
+ TEXTAREA_PASSWORD = (1 << 4) /**< Obscured display */
} textarea_flags;
+
+/**
+ * Textarea drag status
+ */
typedef enum {
TEXTAREA_DRAG_NONE,
TEXTAREA_DRAG_SCROLLBAR,
TEXTAREA_DRAG_SELECTION
-} textarea_drag_type; /**< Textarea drag status */
+} textarea_drag_type;
+
+/**
+ * textarea message types
+ */
typedef enum {
TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */
TEXTAREA_MSG_SELECTION_REPORT, /**< Textarea text selection presence */
@@ -56,6 +67,10 @@ typedef enum {
TEXTAREA_MSG_TEXT_MODIFIED /**< Textarea text modified */
} textarea_msg_type;
+
+/**
+ * textarea message
+ */
struct textarea_msg {
struct textarea *ta; /**< The textarea widget */
@@ -73,10 +88,10 @@ struct textarea_msg {
TEXTAREA_CARET_HIDE /**< Hide */
} type;
struct {
- int x; /**< Carret x-coord */
- int y; /**< Carret y-coord */
- int height; /**< Carret height */
- struct rect *clip; /**< Carret clip rect */
+ int x; /**< Caret x-coord */
+ int y; /**< Caret y-coord */
+ int height; /**< Caret height */
+ struct rect *clip; /**< Caret clip rect */
} pos; /**< With _CARET_SET_POS */
} caret; /**< With _CARET_UPDATE */
struct {
@@ -86,6 +101,10 @@ struct textarea_msg {
} data; /**< Depends on msg type */
};
+
+/**
+ * textarea setup parameters
+ */
typedef struct textarea_setup {
int width; /**< Textarea width */
int height; /**< Textarea height */
@@ -104,14 +123,39 @@ typedef struct textarea_setup {
} textarea_setup;
+
+/**
+ * Text area mouse input status flags
+ */
+typedef enum {
+ TEXTAREA_MOUSE_NONE = 0, /**< Not relevant */
+ TEXTAREA_MOUSE_USED = (1 << 0), /**< Took action with input */
+ TEXTAREA_MOUSE_EDITOR = (1 << 1), /**< Hover: caret pointer */
+ TEXTAREA_MOUSE_SELECTION= (1 << 2), /**< Hover: selection */
+ TEXTAREA_MOUSE_SCR_USED = (1 << 3), /**< Scrollbar action */
+ TEXTAREA_MOUSE_SCR_BOTH = (1 << 4), /**< Scrolling both bars */
+ TEXTAREA_MOUSE_SCR_UP = (1 << 5), /**< Hover: scroll up */
+ TEXTAREA_MOUSE_SCR_PUP = (1 << 6), /**< Hover: scroll page up */
+ TEXTAREA_MOUSE_SCR_VRT = (1 << 7), /**< Hover: vert. drag bar */
+ TEXTAREA_MOUSE_SCR_PDWN = (1 << 8), /**< Hover: scroll page down */
+ TEXTAREA_MOUSE_SCR_DWN = (1 << 9), /**< Hover: scroll down */
+ TEXTAREA_MOUSE_SCR_LFT = (1 << 10), /**< Hover: scroll left */
+ TEXTAREA_MOUSE_SCR_PLFT = (1 << 11), /**< Hover: scroll page left */
+ TEXTAREA_MOUSE_SCR_HRZ = (1 << 12), /**< Hover: horiz. drag bar */
+ TEXTAREA_MOUSE_SCR_PRGT = (1 << 13), /**< Hover: scroll page right */
+ TEXTAREA_MOUSE_SCR_RGT = (1 << 14) /**< Hover: scroll right */
+} textarea_mouse_status;
+
+
/**
* Client callback for the textarea
*
- * \param data user data passed at textarea creation
- * \param textarea_msg textarea message data
+ * \param data user data passed at textarea creation
+ * \param msg textarea message data
*/
typedef void(*textarea_client_callback)(void *data, struct textarea_msg *msg);
+
/**
* Create a text area.
*
@@ -125,6 +169,7 @@ struct textarea *textarea_create(const textarea_flags flags,
const textarea_setup *setup,
textarea_client_callback callback, void *data);
+
/**
* Destroy a text area
*
@@ -132,6 +177,7 @@ struct textarea *textarea_create(const textarea_flags flags,
*/
void textarea_destroy(struct textarea *ta);
+
/**
* Set the text in a text area, discarding any current text
*
@@ -141,6 +187,7 @@ void textarea_destroy(struct textarea *ta);
*/
bool textarea_set_text(struct textarea *ta, const char *text);
+
/**
* Insert the text in a text area at the caret, replacing any selection.
*
@@ -152,6 +199,7 @@ bool textarea_set_text(struct textarea *ta, const char *text);
bool textarea_drop_text(struct textarea *ta, const char *text,
size_t text_length);
+
/**
* Extract the text from a text area
*
@@ -163,16 +211,28 @@ bool textarea_drop_text(struct textarea *ta, const char *text,
*/
int textarea_get_text(struct textarea *ta, char *buf, unsigned int len);
+
+/**
+ * Access text data in a text area
+ *
+ * \param[in] ta Text area
+ * \param[out] len Returns byte length of returned text, if passed non-NULL.
+ * \return textarea string data.
+ */
+const char * textarea_data(struct textarea *ta, unsigned int *len);
+
+
/**
* Set the caret's position
*
- * \param ta Text area
- * \param caret 0-based character index to place caret at, -1 removes
- * the caret
+ * \param ta Text area
+ * \param caret 0-based character index to place caret at, -1 removes
+ * the caret
* \return true on success false otherwise
*/
bool textarea_set_caret(struct textarea *ta, int caret);
+
/**
* Handle redraw requests for text areas
*
@@ -187,34 +247,16 @@ bool textarea_set_caret(struct textarea *ta, int caret);
void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale,
const struct rect *clip, const struct redraw_context *ctx);
+
/**
* Key press handling for text areas.
*
* \param ta The text area which got the keypress
* \param key The ucs4 character codepoint
- * \return true if the keypress is dealt with, false otherwise.
+ * \return true if the keypress is dealt with, false otherwise.
*/
bool textarea_keypress(struct textarea *ta, uint32_t key);
-/* Text area mouse input status flags */
-typedef enum {
- TEXTAREA_MOUSE_NONE = 0, /**< Not relevant */
- TEXTAREA_MOUSE_USED = (1 << 0), /**< Took action with input */
- TEXTAREA_MOUSE_EDITOR = (1 << 1), /**< Hover: caret pointer */
- TEXTAREA_MOUSE_SELECTION= (1 << 2), /**< Hover: selection */
- TEXTAREA_MOUSE_SCR_USED = (1 << 3), /**< Scrollbar action */
- TEXTAREA_MOUSE_SCR_BOTH = (1 << 4), /**< Scrolling both bars */
- TEXTAREA_MOUSE_SCR_UP = (1 << 5), /**< Hover: scroll up */
- TEXTAREA_MOUSE_SCR_PUP = (1 << 6), /**< Hover: scroll page up */
- TEXTAREA_MOUSE_SCR_VRT = (1 << 7), /**< Hover: vert. drag bar */
- TEXTAREA_MOUSE_SCR_PDWN = (1 << 8), /**< Hover: scroll page down */
- TEXTAREA_MOUSE_SCR_DWN = (1 << 9), /**< Hover: scroll down */
- TEXTAREA_MOUSE_SCR_LFT = (1 << 10), /**< Hover: scroll left */
- TEXTAREA_MOUSE_SCR_PLFT = (1 << 11), /**< Hover: scroll page left */
- TEXTAREA_MOUSE_SCR_HRZ = (1 << 12), /**< Hover: horiz. drag bar */
- TEXTAREA_MOUSE_SCR_PRGT = (1 << 13), /**< Hover: scroll page right */
- TEXTAREA_MOUSE_SCR_RGT = (1 << 14) /**< Hover: scroll right */
-} textarea_mouse_status;
/**
* Handles all kinds of mouse action
@@ -228,22 +270,28 @@ typedef enum {
textarea_mouse_status textarea_mouse_action(struct textarea *ta,
browser_mouse_state mouse, int x, int y);
+
/**
* Clear any selection in the textarea.
*
- * \param ta textarea widget
+ * \param ta textarea widget
* \return true if there was a selection to clear, false otherwise
*/
bool textarea_clear_selection(struct textarea *ta);
+
/**
- * Get selected text, ownership passed to caller, which needs to free() it.
+ * Get selected text.
*
- * \param ta Textarea widget
+ * ownership of the returned string is passed to caller which needs to
+ * free it.
+ *
+ * \param ta Textarea widget
* \return Selected text, or NULL if none.
*/
char *textarea_get_selection(struct textarea *ta);
+
/**
* Gets the dimensions of a textarea
*
@@ -253,34 +301,47 @@ char *textarea_get_selection(struct textarea *ta);
*/
void textarea_get_dimensions(struct textarea *ta, int *width, int *height);
+
/**
- * Set the dimensions of a textarea, causing a reflow and
- * Does not emit a redraw request. Up to client to call textarea_redraw.
+ * Set the dimensions of a textarea.
+ *
+ * This causes a reflow of the text and does not emit a redraw
+ * request. Up to client to call textarea_redraw.
*
* \param ta textarea widget
- * \param width the new width of the textarea
+ * \param width the new width of the textarea
* \param height the new height of the textarea
*/
void textarea_set_dimensions(struct textarea *ta, int width, int height);
+
/**
- * Set the dimensions and padding of a textarea, causing a reflow.
- * Does not emit a redraw request. Up to client to call textarea_redraw.
+ * Set the dimensions and padding of a textarea.
+ *
+ * This causes a reflow of the text. Does not emit a redraw request.
+ * Up to client to call textarea_redraw.
*
* \param ta textarea widget
- * \param width the new width of the textarea
+ * \param width the new width of the textarea
* \param height the new height of the textarea
* \param top the new top padding of the textarea
* \param right the new right padding of the textarea
* \param bottom the new bottom padding of the textarea
* \param left the new left padding of the textarea
*/
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left);
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left);
+
/**
- * Scroll a textarea by an amount. Only does anything if multi-line textarea
- * has scrollbars. If it scrolls, it will emit a redraw request.
+ * Scroll a textarea by an amount.
+ *
+ * Only does anything if multi-line textarea has scrollbars. If it
+ * scrolls, it will emit a redraw request.
*
* \param ta textarea widget
* \param scrx number of px try to scroll in x direction
@@ -288,5 +349,5 @@ void textarea_set_layout(struct textarea *ta, int width, int height,
* \return true iff the textarea was scrolled
*/
bool textarea_scroll(struct textarea *ta, int scrx, int scry);
-#endif
+#endif
diff --git a/desktop/textinput.c b/desktop/textinput.c
index c0e0ba8f7..7fc95f792 100644
--- a/desktop/textinput.c
+++ b/desktop/textinput.c
@@ -37,9 +37,9 @@
#include "netsurf/form.h"
#include "netsurf/window.h"
#include "netsurf/keypress.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/layout.h"
#include "desktop/browser_private.h"
#include "desktop/textinput.h"
diff --git a/desktop/textinput.h b/desktop/textinput.h
index 5859ea8d6..7c6be9547 100644
--- a/desktop/textinput.h
+++ b/desktop/textinput.h
@@ -24,19 +24,19 @@
* Textual input handling interface
*/
-#ifndef _NETSURF_DESKTOP_TEXTINPUT_H_
-#define _NETSURF_DESKTOP_TEXTINPUT_H_
+#ifndef NETSURF_DESKTOP_TEXTINPUT_H
+#define NETSURF_DESKTOP_TEXTINPUT_H
struct browser_window;
/**
* Position the caret and assign a callback for key presses.
*
- * \param bw The browser window in which to place the caret
- * \param x X coordinate of the caret
- * \param y Y coordinate
- * \param height Height of caret
- * \param clip Clip rectangle for caret, or NULL if none
+ * \param bw The browser window in which to place the caret
+ * \param x X coordinate of the caret
+ * \param y Y coordinate
+ * \param height Height of caret
+ * \param clip Clip rectangle for caret, or NULL if none
*/
void browser_window_place_caret(struct browser_window *bw, int x, int y,
int height, const struct rect *clip);
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 4d8fbaaeb..48422e8e3 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -22,10 +22,13 @@
* Treeview handling implementation.
*/
+#include <string.h>
+
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/nsoption.h"
+#include "utils/config.h"
#include "netsurf/bitmap.h"
#include "netsurf/content.h"
#include "netsurf/plotters.h"
@@ -42,9 +45,17 @@
#include "desktop/treeview.h"
#include "desktop/gui_internal.h"
-/** @todo get rid of REDRAW_MAX -- need to be able to know window size */
+/**
+ * The maximum horizontal size a treeview can possibly be.
+ *
+ * \todo get rid of REDRAW_MAX -- need to be able to know window size
+ */
#define REDRAW_MAX 8000
+
+/**
+ * Treeview handling global context
+ */
struct treeview_globals {
unsigned initialised;
int line_height;
@@ -56,32 +67,54 @@ struct treeview_globals {
int move_offset;
} tree_g;
+
+/**
+ * Section type of a treeview at a point
+ */
enum treeview_node_part {
- TV_NODE_PART_TOGGLE, /**< Expansion toggle */
- TV_NODE_PART_ON_NODE, /**< Node content (text, icon) */
- TV_NODE_PART_NONE /**< Empty area */
-}; /**< Section type of a treeview at a point */
+ TV_NODE_PART_TOGGLE, /**< Expansion toggle */
+ TV_NODE_PART_ON_NODE, /**< Node content (text, icon) */
+ TV_NODE_PART_NONE /**< Empty area */
+};
+
+/**
+ * Text within a treeview field or node
+ */
struct treeview_text {
const char *data; /**< Text string */
uint32_t len; /**< Length of string in bytes */
int width; /**< Width of text in px */
};
+
+/**
+ * a treeview field
+ */
struct treeview_field {
+ /** flags controlling how field is interpreted */
enum treeview_field_flags flags;
- lwc_string *field;
- struct treeview_text value;
+ lwc_string *field; /**< field contents */
+ struct treeview_text value; /**< field text */
};
+
+/**
+ * flags indicating render state of node.
+ */
enum treeview_node_flags {
- TV_NFLAGS_NONE = 0, /**< No node flags set */
- TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */
- TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */
- TV_NFLAGS_SPECIAL = (1 << 2) /**< Render as special node */
+ TV_NFLAGS_NONE = 0, /**< No node flags set */
+ TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */
+ TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */
+ TV_NFLAGS_SPECIAL = (1 << 2), /**< Render as special node */
+ TV_NFLAGS_MATCHED = (1 << 3), /**< Whether node matches search */
};
+
+/**
+ * Treeview target position
+ */
enum treeview_target_pos {
TV_TARGET_ABOVE,
TV_TARGET_INSIDE,
@@ -89,6 +122,10 @@ enum treeview_target_pos {
TV_TARGET_NONE
};
+
+/**
+ * Treeview node
+ */
struct treeview_node {
enum treeview_node_flags flags; /**< Node flags */
enum treeview_node_type type; /**< Node type */
@@ -96,49 +133,73 @@ struct treeview_node {
int height; /**< Includes height of any descendants (pixels) */
int inset; /**< Node's inset depending on tree depth (pixels) */
- treeview_node *parent;
- treeview_node *prev_sib;
- treeview_node *next_sib;
- treeview_node *children;
+ treeview_node *parent; /**< parent node */
+ treeview_node *prev_sib; /**< previous sibling node */
+ treeview_node *next_sib; /**< next sibling node */
+ treeview_node *children; /**< first child node */
void *client_data; /**< Passed to client on node event msg callback */
struct treeview_text text; /** Text to show for node (default field) */
-}; /**< Treeview node */
+};
+
+/**
+ * Node entry
+ *
+ * node entry contains a base node at the beginning allowing for
+ * trivial containerof by cast and some number of fields.
+ */
struct treeview_node_entry {
- treeview_node base;
+ treeview_node base; /**< Entry class inherits node base class */
struct treeview_field fields[FLEX_ARRAY_LEN_DECL];
-}; /**< Entry class inherits node base class */
+};
+
+/**
+ * A mouse position wrt treeview
+ */
struct treeview_pos {
int x; /**< Mouse X coordinate */
int y; /**< Mouse Y coordinate */
int node_y; /**< Top of node at y */
int node_h; /**< Height of node at y */
-}; /**< A mouse position wrt treeview */
+};
+
+/**
+ * Treeview drag state
+ */
struct treeview_drag {
enum {
TV_DRAG_NONE,
TV_DRAG_SELECTION,
TV_DRAG_MOVE,
- TV_DRAG_TEXTAREA
+ TV_DRAG_TEXTAREA,
+ TV_DRAG_SEARCH,
} type; /**< Drag type */
treeview_node *start_node; /**< Start node */
bool selected; /**< Start node is selected */
enum treeview_node_part part; /**< Node part at start */
struct treeview_pos start; /**< Start pos */
struct treeview_pos prev; /**< Previous pos */
-}; /**< Drag state */
+};
+
+/**
+ * Treeview node move details
+ */
struct treeview_move {
treeview_node *root; /**< Head of yanked node list */
treeview_node *target; /**< Move target */
struct rect target_area; /**< Pos/size of target indicator */
enum treeview_target_pos target_pos; /**< Pos wrt render node */
-}; /**< Move details */
+};
+
+/**
+ * Treeview node edit details
+ */
struct treeview_edit {
treeview_node *node; /**< Node being edited, or NULL */
struct textarea *textarea; /**< Textarea for edit, or NULL */
@@ -147,22 +208,39 @@ struct treeview_edit {
int y; /**< Textarea y position */
int w; /**< Textarea width */
int h; /**< Textarea height */
-}; /**< Edit details */
+};
+
+/**
+ * Treeview search box details
+ */
+struct treeview_search {
+ struct textarea *textarea; /**< Search box. */
+ bool active; /**< Whether the search box has focus. */
+ bool search; /**< Whether we have a search term. */
+ int height; /**< Current search display height. */
+};
+
+
+/**
+ * The treeview context
+ */
struct treeview {
- uint32_t view_width; /**< Viewport size */
+ uint32_t view_width; /**< Viewport horizontal size */
- treeview_flags flags; /**< Treeview behaviour settings */
+ treeview_flags flags; /**< Treeview behaviour settings */
- treeview_node *root; /**< Root node */
+ treeview_node *root; /**< Root node */
struct treeview_field *fields; /**< Array of fields */
int n_fields; /**< fields[n_fields] is folder, lower are entry fields */
int field_width; /**< Max width of shown field names */
- struct treeview_drag drag; /**< Drag state */
- struct treeview_move move; /**< Move drag details */
- struct treeview_edit edit; /**< Edit details */
+ struct treeview_drag drag; /**< Drag state */
+ struct treeview_move move; /**< Move drag details */
+ struct treeview_edit edit; /**< Edit details */
+
+ struct treeview_search search; /**< Treeview search box */
const struct treeview_callback_table *callbacks; /**< For node events */
@@ -171,38 +249,62 @@ struct treeview {
};
+/**
+ * Treeview furniture states.
+ */
enum treeview_furniture_id {
TREE_FURN_EXPAND = 0,
TREE_FURN_CONTRACT,
TREE_FURN_LAST
};
-struct treeview_furniture {
- int size;
- struct bitmap *bmp;
- struct bitmap *sel;
-};
+
+/**
+ * style for a node
+ */
struct treeview_node_style {
- plot_style_t bg; /**< Background */
- plot_font_style_t text; /**< Text */
- plot_font_style_t itext; /**< Entry field text */
+ plot_style_t bg; /**< Background */
+ plot_font_style_t text; /**< Text */
+ plot_font_style_t itext; /**< Entry field text */
+
+ plot_style_t sbg; /**< Selected background */
+ plot_font_style_t stext; /**< Selected text */
+ plot_font_style_t sitext; /**< Selected entry field text */
+
+ struct {
+ int size;
+ struct bitmap *bmp;
+ struct bitmap *sel;
+ } furn[TREE_FURN_LAST];
+};
- plot_style_t sbg; /**< Selected background */
- plot_font_style_t stext; /**< Selected text */
- plot_font_style_t sitext; /**< Selected entry field text */
- struct treeview_furniture furn[TREE_FURN_LAST];
-};
+/**
+ * Plot style for odd rows
+ */
+struct treeview_node_style plot_style_odd;
+
+
+/**
+ * Plot style for even rows
+ */
+struct treeview_node_style plot_style_even;
-struct treeview_node_style plot_style_odd; /**< Plot style for odd rows */
-struct treeview_node_style plot_style_even; /**< Plot style for even rows */
+/**
+ * Treeview content resource data
+ */
struct treeview_resource {
const char *url;
struct hlcache_handle *c;
int height;
bool ready;
-}; /**< Treeview content resource data */
+};
+
+
+/**
+ * treeview resource indexes
+ */
enum treeview_resource_id {
TREE_RES_ARROW = 0,
TREE_RES_CONTENT,
@@ -211,27 +313,46 @@ enum treeview_resource_id {
TREE_RES_SEARCH,
TREE_RES_LAST
};
+
+
+/**
+ * Treeview content resources
+ */
static struct treeview_resource treeview_res[TREE_RES_LAST] = {
{ "resource:icons/arrow-l.png", NULL, 0, false },
{ "resource:icons/content.png", NULL, 0, false },
{ "resource:icons/directory.png", NULL, 0, false },
{ "resource:icons/directory2.png", NULL, 0, false },
{ "resource:icons/search.png", NULL, 0, false }
-}; /**< Treeview content resources */
+};
+
+
+/**
+ * Get the display height of the treeview data component of the display.
+ *
+ * \param[in] tree Treeview to get the height of.
+ * \return the display height in pixels.
+ */
+static inline int treeview__get_display_height(const treeview *tree)
+{
+ return (tree->search.search == false) ?
+ tree->root->height :
+ tree->search.height;
+}
/**
* Corewindow callback wrapper: Request a redraw of the window
*
- * \param[in] cw the core window object
+ * \param[in] tree The treeview to request redraw on.
* \param[in] r rectangle to redraw
*/
-static inline void treeview__cw_redraw_request(
+static inline void treeview__cw_invalidate_area(
const struct treeview *tree,
const struct rect *r)
{
if (tree->cw_t != NULL) {
- tree->cw_t->redraw_request(tree->cw_h, r);
+ tree->cw_t->invalidate(tree->cw_h, r);
}
}
@@ -239,16 +360,41 @@ static inline void treeview__cw_redraw_request(
/**
* Corewindow callback wrapper: Update the limits of the window
*
- * \param[in] cw the core window object
+ * \param[in] tree The treeview to update size for.
* \param[in] width the width in px, or negative if don't care
* \param[in] height the height in px, or negative if don't care
*/
static inline void treeview__cw_update_size(
- const struct treeview *tree,
- int width, int height)
+ const struct treeview *tree,
+ int width, int height)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
if (tree->cw_t != NULL) {
- tree->cw_t->update_size(tree->cw_h, width, height);
+ tree->cw_t->update_size(tree->cw_h, width,
+ height + search_height);
+ }
+}
+
+
+/**
+ * Corewindow callback_wrapper: Scroll to top of window.
+ *
+ * \param[in] tree The treeview to scroll.
+ */
+static inline void treeview__cw_scroll_top(
+ const struct treeview *tree)
+{
+ struct rect r = {
+ .x0 = 0,
+ .y0 = 0,
+ .x1 = tree_g.window_padding,
+ .y1 = tree_g.line_height,
+ };
+
+ if (tree->cw_t != NULL) {
+ tree->cw_t->scroll_visible(tree->cw_h, &r);
}
}
@@ -256,13 +402,13 @@ static inline void treeview__cw_update_size(
/**
* Corewindow callback wrapper: Get window viewport dimensions
*
- * \param[in] cw the core window object
+ * \param[in] tree The treeview to get dimensions for.
* \param[out] width to be set to viewport width in px
* \param[out] height to be set to viewport height in px
*/
static inline void treeview__cw_get_window_dimensions(
- const struct treeview *tree,
- int *width, int *height)
+ const struct treeview *tree,
+ int *width, int *height)
{
if (tree->cw_t != NULL) {
tree->cw_t->get_window_dimensions(tree->cw_h, width, height);
@@ -273,12 +419,12 @@ static inline void treeview__cw_get_window_dimensions(
/**
* Corewindow callback wrapper: Inform corewindow owner of drag status
*
- * \param[in] cw the core window object
+ * \param[in] tree The treeview to report status on.
* \param[in] ds the current drag status
*/
static inline void treeview__cw_drag_status(
- const struct treeview *tree,
- core_window_drag_status ds)
+ const struct treeview *tree,
+ core_window_drag_status ds)
{
if (tree->cw_t != NULL) {
tree->cw_t->drag_status(tree->cw_h, ds);
@@ -286,15 +432,16 @@ static inline void treeview__cw_drag_status(
}
-/* Helper function to access the given field of a node
+/**
+ * Helper function to access the given field of a node
*
- * \param tree Treeview that node belongs to
- * \param n Node to get field from
- * \param i Index of field of interest
+ * \param tree Treeview that node belongs to
+ * \param n Node to get field from
+ * \param i Index of field of interest
* \return text entry for field or NULL.
*/
-static inline struct treeview_text * treeview_get_text_for_field(
- treeview *tree, treeview_node *n, int i)
+static inline struct treeview_text *
+treeview_get_text_for_field(treeview *tree, treeview_node *n, int i)
{
if (i == 0) {
return &n->text;
@@ -309,19 +456,19 @@ static inline struct treeview_text * treeview_get_text_for_field(
}
-/* Find the next node in depth first tree order
+/**
+ * Find the next node in depth first tree order
*
- * \param node Start node
- * \param full Iff true, visit children of collapsed nodes
- * \param next Updated to next node, or NULL if 'node' is last node
- * \return NSERROR_OK on success, or appropriate error otherwise
+ * \param node Start node
+ * \param full Iff true, visit children of collapsed nodes
+ * \return next node, or NULL if \a node is last node
*/
static inline treeview_node * treeview_node_next(treeview_node *node, bool full)
{
assert(node != NULL);
if ((full || (node->flags & TV_NFLAGS_EXPANDED)) &&
- node->children != NULL) {
+ node->children != NULL) {
/* Next node is child */
node = node->children;
} else {
@@ -345,17 +492,17 @@ static inline treeview_node * treeview_node_next(treeview_node *node, bool full)
}
-/* Find node at given y-position
+/**
+ * Find node at given y-position
*
- * \param tree Treeview object to delete node from
- * \param target_y Target y-position
+ * \param tree Treeview object to delete node from
+ * \param target_y Target y-position
* \return node at y_target
*/
static treeview_node * treeview_y_node(treeview *tree, int target_y)
{
+ int y = (tree->flags & TREEVIEW_SEARCHABLE) ? tree_g.line_height : 0;
treeview_node *n;
- int y = 0;
- int h;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -363,8 +510,8 @@ static treeview_node * treeview_y_node(treeview *tree, int target_y)
n = treeview_node_next(tree->root, false);
while (n != NULL) {
- h = (n->type == TREE_NODE_ENTRY) ?
- n->height : tree_g.line_height;
+ int h = (n->type == TREE_NODE_ENTRY) ?
+ n->height : tree_g.line_height;
if (target_y >= y && target_y < y + h)
return n;
y += h;
@@ -376,16 +523,19 @@ static treeview_node * treeview_y_node(treeview *tree, int target_y)
}
-/* Find y position of the top of a node
+/**
+ * Find y position of the top of a node
*
- * \param tree Treeview object to delete node from
- * \param node Node to get position of
+ * \param tree Treeview object to delete node from
+ * \param node Node to get position of
* \return node's y position
*/
-static int treeview_node_y(treeview *tree, treeview_node *node)
+static int treeview_node_y(
+ const treeview *tree,
+ const treeview_node *node)
{
treeview_node *n;
- int y = 0;
+ int y = (tree->flags & TREEVIEW_SEARCHABLE) ? tree_g.line_height : 0;
assert(tree != NULL);
assert(tree->root != NULL);
@@ -394,7 +544,7 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
while (n != NULL && n != node) {
y += (n->type == TREE_NODE_ENTRY) ?
- n->height : tree_g.line_height;
+ n->height : tree_g.line_height;
n = treeview_node_next(n, false);
}
@@ -403,40 +553,108 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
}
-/* Walk a treeview subtree, calling a callback at each node (depth first)
+/**
+ * Redraw tree from given node to the bottom.
+ *
+ * \param[in] tree Tree to redraw from node in.
+ * \param[in] node Node to redraw from.
+ */
+static void treeview__redraw_from_node(
+ const treeview *tree,
+ const treeview_node *node)
+{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ struct rect r = {
+ .x0 = 0,
+ .y0 = treeview_node_y(tree, node),
+ .x1 = REDRAW_MAX,
+ .y1 = treeview__get_display_height(tree) + search_height,
+ };
+
+ assert(tree != NULL);
+
+ treeview__cw_invalidate_area(tree, &r);
+}
+
+
+/**
+ * The treeview walk mode. Controls which nodes are visited in a walk.
+ */
+enum treeview_walk_mode {
+ /**
+ * Walk to all nodes in the (sub)tree.
+ */
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+
+ /**
+ * Walk to expanded nodes in the (sub)tree only. Children of
+ * collapsed nodes are not visited.
+ */
+ TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
+
+ /**
+ * Walk displayed nodes. This differs from the
+ * `TREEVIEW_WALK_MODE_LOGICAL_EXPANDED` mode when there is
+ * an active search filter display.
+ */
+ TREEVIEW_WALK_MODE_DISPLAY,
+};
+
+
+/**
+ * Walk a treeview subtree, calling a callback at each node (depth first)
*
+ * \param tree Treeview being walked.
* \param root Root to walk tree from (doesn't get a callback call)
- * \param full Iff true, visit children of collapsed nodes
+ * \param mode The treeview walk mode to use.
* \param callback_bwd Function to call on each node in backwards order
* \param callback_fwd Function to call on each node in forwards order
* \param ctx Context to pass to callback
* \return NSERROR_OK on success, or appropriate error otherwise
*
- * Note: Any node deletion must happen in callback_bwd.
+ * \note Any node deletion must happen in callback_bwd.
*/
-static nserror treeview_walk_internal(treeview_node *root, bool full,
- nserror (*callback_bwd)(treeview_node *n, void *ctx, bool *end),
- nserror (*callback_fwd)(treeview_node *n, void *ctx,
- bool *skip_children, bool *end),
+static nserror treeview_walk_internal(
+ treeview *tree,
+ treeview_node *root,
+ enum treeview_walk_mode mode,
+ nserror (*callback_bwd)(
+ treeview_node *n,
+ void *ctx,
+ bool *end),
+ nserror (*callback_fwd)(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end),
void *ctx)
{
treeview_node *node, *child, *parent, *next_sibling;
- bool abort = false;
+ bool walking_search = (mode == TREEVIEW_WALK_MODE_DISPLAY &&
+ tree->search.search == true);
bool skip_children = false;
+ bool abort = false;
+ bool full = false;
nserror err;
+ bool entry;
assert(root != NULL);
+ if (mode == TREEVIEW_WALK_MODE_LOGICAL_COMPLETE || walking_search) {
+ /* We need to visit children of collapsed folders. */
+ full = true;
+ }
+
node = root;
parent = node->parent;
next_sibling = node->next_sib;
- child = (!skip_children &&
- (full || (node->flags & TV_NFLAGS_EXPANDED))) ?
- node->children : NULL;
+ child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ?
+ node->children : NULL;
while (node != NULL) {
- if (child != NULL) {
+ if (child != NULL && !skip_children) {
/* Down to children */
node = child;
} else {
@@ -444,9 +662,10 @@ static nserror treeview_walk_internal(treeview_node *root, bool full,
* go to next sibling if present, or nearest ancestor
* with a next sibling. */
- while (node != root &&
- next_sibling == NULL) {
- if (callback_bwd != NULL) {
+ while (node != root && next_sibling == NULL) {
+ entry = (node->type == TREE_NODE_ENTRY);
+ if (callback_bwd != NULL &&
+ (entry || !walking_search)) {
/* Backwards callback */
err = callback_bwd(node, ctx, &abort);
@@ -486,10 +705,17 @@ static nserror treeview_walk_internal(treeview_node *root, bool full,
assert(node != NULL);
assert(node != root);
+ entry = (node->type == TREE_NODE_ENTRY);
+
parent = node->parent;
next_sibling = node->next_sib;
child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ?
- node->children : NULL;
+ node->children : NULL;
+
+ if (walking_search && (!entry ||
+ !(node->flags & TV_NFLAGS_MATCHED))) {
+ continue;
+ }
if (callback_fwd != NULL) {
/* Forwards callback */
@@ -503,16 +729,251 @@ static nserror treeview_walk_internal(treeview_node *root, bool full,
return NSERROR_OK;
}
}
- child = skip_children ? NULL : child;
}
return NSERROR_OK;
}
/**
+ * Data used when doing a treeview walk for search.
+ */
+struct treeview_search_walk_data {
+ treeview *tree; /**< The treeview to search. */
+ const char *text; /**< The string being searched for. */
+ const unsigned int len; /**< Length of string being searched for. */
+ int window_height; /**< Accumulate height for matching entries. */
+};
+
+
+/**
+ * Treewalk node callback for handling search.
+ *
+ * \param[in] n Current node.
+ * \param[in] ctx Treeview search context.
+ * \param[in,out] skip_children Flag to allow children to be skipped.
+ * \param[in,out] end Flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror treeview__search_walk_cb(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
+{
+ struct treeview_search_walk_data *sw = ctx;
+
+ if (n->type != TREE_NODE_ENTRY) {
+ return NSERROR_OK;
+ }
+
+ if (sw->len == 0) {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ } else {
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)n;
+ bool matched = false;
+
+ for (int i = 0; i < sw->tree->n_fields; i++) {
+ struct treeview_field *ef = &(sw->tree->fields[i + 1]);
+ if (ef->flags & TREE_FLAG_SEARCHABLE) {
+ if (strcasestr(entry->fields[i].value.data,
+ sw->text) != NULL) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched && strcasestr(n->text.data, sw->text) != NULL) {
+ matched = true;
+ }
+
+ if (matched) {
+ n->flags |= TV_NFLAGS_MATCHED;
+ sw->window_height += n->height;
+ } else {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Search treeview for text.
+ *
+ * \param[in] tree Treeview to search.
+ * \param[in] text UTF-8 string to search for. (NULL-terminated.)
+ * \param[in] len Byte length of UTF-8 string.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror treeview__search(
+ treeview *tree,
+ const char *text,
+ unsigned int len)
+{
+ nserror err;
+ uint32_t height;
+ uint32_t prev_height = treeview__get_display_height(tree);
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ struct treeview_search_walk_data sw = {
+ .len = len,
+ .text = text,
+ .tree = tree,
+ .window_height = 0,
+ };
+ struct rect r = {
+ .x0 = 0,
+ .y0 = search_height,
+ .x1 = REDRAW_MAX,
+ };
+
+ assert(text[len] == '\0');
+
+ if (tree->root == NULL) {
+ return NSERROR_OK;
+ }
+
+ err = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
+ treeview__search_walk_cb, &sw);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (len > 0) {
+ tree->search.height = sw.window_height;
+ tree->search.search = true;
+ height = sw.window_height;
+ } else {
+ tree->search.search = false;
+ height = tree->root->height;
+ }
+
+ r.y1 = ((height > prev_height) ? height : prev_height) + search_height;
+ treeview__cw_invalidate_area(tree, &r);
+ treeview__cw_update_size(tree, -1, height);
+ treeview__cw_scroll_top(tree);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Cancel a treeview search, optionally droping focus from search widget.
+ *
+ * \param[in] tree Treeview to cancel search in.
+ * \param[in] drop_focus Iff true, drop input focus from search widget.
+ */
+static void treeview__search_cancel(treeview *tree, bool drop_focus)
+{
+ struct rect r = {
+ .x0 = tree_g.window_padding + tree_g.icon_size,
+ .x1 = 600,
+ .y0 = 0,
+ .y1 = tree_g.line_height,
+ };
+
+ tree->search.search = false;
+ if (tree->search.active == false) {
+ return;
+ }
+
+ if (drop_focus) {
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ } else {
+ textarea_set_caret(tree->search.textarea, 0);
+ }
+
+ textarea_set_text(tree->search.textarea, "");
+ treeview__cw_invalidate_area(tree, &r);
+}
+
+
+/**
+ * Callback for textarea_create, in desktop/treeview.h
+ *
+ * \param data treeview context
+ * \param msg textarea message
+ */
+static void treeview_textarea_search_callback(void *data,
+ struct textarea_msg *msg)
+{
+ treeview *tree = data;
+ struct rect *r;
+
+ if (tree->search.active == false || tree->root == NULL) {
+ return;
+ }
+
+ switch (msg->type) {
+ case TEXTAREA_MSG_DRAG_REPORT:
+ if (msg->data.drag == TEXTAREA_DRAG_NONE) {
+ /* Textarea drag finished */
+ tree->drag.type = TV_DRAG_NONE;
+ } else {
+ /* Textarea drag started */
+ tree->drag.type = TV_DRAG_SEARCH;
+ }
+ treeview__cw_drag_status(tree, tree->drag.type);
+ break;
+
+ case TEXTAREA_MSG_REDRAW_REQUEST:
+ r = &msg->data.redraw;
+ r->x0 += tree_g.window_padding + tree_g.icon_size;
+ r->y0 += 0;
+ r->x1 += 600;
+ r->y1 += tree_g.line_height;
+
+ /* Redraw the textarea */
+ treeview__cw_invalidate_area(tree, r);
+ break;
+
+ case TEXTAREA_MSG_TEXT_MODIFIED:
+ /* Textarea length includes trailing NULL, so subtract it. */
+ treeview__search(tree,
+ msg->data.modified.text,
+ msg->data.modified.len - 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Update the layout for any active search.
+ *
+ * \param[in] tree The tree to update.
+ */
+static void treeview__search_update_display(
+ treeview *tree)
+{
+ const char *string;
+ unsigned int len;
+
+ if (tree->search.search == false) {
+ /* No active search to update view for. */
+ return;
+ }
+
+ string = textarea_data(tree->search.textarea, &len);
+ if (string == NULL || len == 0) {
+ return;
+ }
+
+ treeview__search(tree, string, len - 1);
+}
+
+
+/**
* Create treeview's root node
*
- * \param root Returns root node
+ * \param[out] root Returns root node
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror treeview_create_node_root(treeview_node **root)
@@ -548,10 +1009,20 @@ static nserror treeview_create_node_root(treeview_node **root)
/**
- * Set a node's inset from its parent (can be used as treeview walk callback)
+ * Set a node's inset from its parent
+ *
+ * This may be used as treeview walk callback
+ *
+ * \param[in] n node to set inset on
+ * \param[in] ctx context unused
+ * \param[out] skip_children set to false so child nodes are not skipped.
+ * \param[out] end unused flag so treewalk in not terminated early.
*/
-static nserror treeview_set_inset_from_parent(treeview_node *n, void *ctx,
- bool *skip_children, bool *end)
+static nserror
+treeview_set_inset_from_parent(treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
if (n->parent != NULL)
n->inset = n->parent->inset + tree_g.step_width;
@@ -559,14 +1030,20 @@ static nserror treeview_set_inset_from_parent(treeview_node *n, void *ctx,
*skip_children = false;
return NSERROR_OK;
}
+
+
/**
* Insert a treeview node into a treeview
*
- * \param a parentless node to insert
- * \param b tree node to insert a as a relation of
- * \param rel a's relationship to b
+ * \param tree the treeview to insert node into.
+ * \param a parentless node to insert
+ * \param b tree node to insert a as a relation of
+ * \param rel The relationship between \a a and \a b
*/
-static inline void treeview_insert_node(treeview_node *a,
+static inline void
+treeview_insert_node(
+ treeview *tree,
+ treeview_node *a,
treeview_node *b,
enum treeview_relationship rel)
{
@@ -603,7 +1080,8 @@ static inline void treeview_insert_node(treeview_node *a,
a->inset = a->parent->inset + tree_g.step_width;
if (a->children != NULL) {
- treeview_walk_internal(a, true, NULL,
+ treeview_walk_internal(tree, a,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
treeview_set_inset_from_parent, NULL);
}
@@ -627,12 +1105,14 @@ static inline void treeview_insert_node(treeview_node *a,
/* Exported interface, documented in treeview.h */
-nserror treeview_create_node_folder(treeview *tree,
- treeview_node **folder,
- treeview_node *relation,
- enum treeview_relationship rel,
- const struct treeview_field_data *field,
- void *data, treeview_node_options_flags flags)
+nserror
+treeview_create_node_folder(treeview *tree,
+ treeview_node **folder,
+ treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data,
+ treeview_node_options_flags flags)
{
treeview_node *n;
@@ -651,7 +1131,7 @@ nserror treeview_create_node_folder(treeview *tree,
}
n->flags = (flags & TREE_OPTION_SPECIAL_DIR) ?
- TV_NFLAGS_SPECIAL : TV_NFLAGS_NONE;
+ TV_NFLAGS_SPECIAL : TV_NFLAGS_NONE;
n->type = TREE_NODE_FOLDER;
n->height = tree_g.line_height;
@@ -667,13 +1147,13 @@ nserror treeview_create_node_folder(treeview *tree,
n->client_data = data;
- treeview_insert_node(n, relation, rel);
+ treeview_insert_node(tree, n, relation, rel);
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
/* Inform front end of change in dimensions */
if (!(flags & TREE_OPTION_SUPPRESS_RESIZE))
treeview__cw_update_size(tree, -1,
- tree->root->height);
+ tree->root->height);
/* Redraw */
if (!(flags & TREE_OPTION_SUPPRESS_REDRAW)) {
@@ -682,7 +1162,7 @@ nserror treeview_create_node_folder(treeview *tree,
r.y0 = treeview_node_y(tree, n);
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
@@ -693,10 +1173,11 @@ nserror treeview_create_node_folder(treeview *tree,
/* Exported interface, documented in treeview.h */
-nserror treeview_update_node_folder(treeview *tree,
- treeview_node *folder,
- const struct treeview_field_data *field,
- void *data)
+nserror
+treeview_update_node_folder(treeview *tree,
+ treeview_node *folder,
+ const struct treeview_field_data *field,
+ void *data)
{
bool match;
@@ -708,8 +1189,8 @@ nserror treeview_update_node_folder(treeview *tree,
assert(field != NULL);
assert(lwc_string_isequal(tree->fields[tree->n_fields].field,
- field->field, &match) == lwc_error_ok &&
- match == true);
+ field->field, &match) == lwc_error_ok &&
+ match == true);
folder->text.data = field->value;
folder->text.len = field->value_len;
folder->text.width = 0;
@@ -717,9 +1198,9 @@ nserror treeview_update_node_folder(treeview *tree,
if (folder->parent->flags & TV_NFLAGS_EXPANDED) {
/* Text will be seen, get its width */
guit->layout->width(&plot_style_odd.text,
- folder->text.data,
- folder->text.len,
- &(folder->text.width));
+ folder->text.data,
+ folder->text.len,
+ &(folder->text.width));
} else {
/* Just invalidate the width, since it's not needed now */
folder->text.width = 0;
@@ -732,7 +1213,7 @@ nserror treeview_update_node_folder(treeview *tree,
r.y0 = treeview_node_y(tree, folder);
r.x1 = REDRAW_MAX;
r.y1 = r.y0 + tree_g.line_height;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
@@ -740,10 +1221,11 @@ nserror treeview_update_node_folder(treeview *tree,
/* Exported interface, documented in treeview.h */
-nserror treeview_update_node_entry(treeview *tree,
- treeview_node *entry,
- const struct treeview_field_data fields[],
- void *data)
+nserror
+treeview_update_node_entry(treeview *tree,
+ treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data)
{
bool match;
struct treeview_node_entry *e = (struct treeview_node_entry *)entry;
@@ -758,8 +1240,8 @@ nserror treeview_update_node_entry(treeview *tree,
assert(fields != NULL);
assert(fields[0].field != NULL);
assert(lwc_string_isequal(tree->fields[0].field,
- fields[0].field, &match) == lwc_error_ok &&
- match == true);
+ fields[0].field, &match) == lwc_error_ok &&
+ match == true);
entry->text.data = fields[0].value;
entry->text.len = fields[0].value_len;
entry->text.width = 0;
@@ -767,9 +1249,9 @@ nserror treeview_update_node_entry(treeview *tree,
if (entry->parent->flags & TV_NFLAGS_EXPANDED) {
/* Text will be seen, get its width */
guit->layout->width(&plot_style_odd.text,
- entry->text.data,
- entry->text.len,
- &(entry->text.width));
+ entry->text.data,
+ entry->text.len,
+ &(entry->text.width));
} else {
/* Just invalidate the width, since it's not needed now */
entry->text.width = 0;
@@ -778,8 +1260,8 @@ nserror treeview_update_node_entry(treeview *tree,
for (i = 1; i < tree->n_fields; i++) {
assert(fields[i].field != NULL);
assert(lwc_string_isequal(tree->fields[i].field,
- fields[i].field, &match) == lwc_error_ok &&
- match == true);
+ fields[i].field, &match) == lwc_error_ok &&
+ match == true);
e->fields[i - 1].value.data = fields[i].value;
e->fields[i - 1].value.len = fields[i].value_len;
@@ -787,15 +1269,17 @@ nserror treeview_update_node_entry(treeview *tree,
if (entry->flags & TV_NFLAGS_EXPANDED) {
/* Text will be seen, get its width */
guit->layout->width(&plot_style_odd.text,
- e->fields[i - 1].value.data,
- e->fields[i - 1].value.len,
- &(e->fields[i - 1].value.width));
+ e->fields[i - 1].value.data,
+ e->fields[i - 1].value.len,
+ &(e->fields[i - 1].value.width));
} else {
/* Invalidate the width, since it's not needed yet */
e->fields[i - 1].value.width = 0;
}
}
+ treeview__search_update_display(tree);
+
/* Redraw */
if (entry->parent->flags & TV_NFLAGS_EXPANDED) {
struct rect r;
@@ -803,7 +1287,7 @@ nserror treeview_update_node_entry(treeview *tree,
r.y0 = treeview_node_y(tree, entry);
r.x1 = REDRAW_MAX;
r.y1 = r.y0 + entry->height;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
@@ -811,12 +1295,14 @@ nserror treeview_update_node_entry(treeview *tree,
/* Exported interface, documented in treeview.h */
-nserror treeview_create_node_entry(treeview *tree,
- treeview_node **entry,
- treeview_node *relation,
- enum treeview_relationship rel,
- const struct treeview_field_data fields[],
- void *data, treeview_node_options_flags flags)
+nserror
+treeview_create_node_entry(treeview *tree,
+ treeview_node **entry,
+ treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data,
+ treeview_node_options_flags flags)
{
bool match;
struct treeview_node_entry *e;
@@ -873,13 +1359,13 @@ nserror treeview_create_node_entry(treeview *tree,
e->fields[i - 1].value.width = 0;
}
- treeview_insert_node(n, relation, rel);
+ treeview_insert_node(tree, n, relation, rel);
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
/* Inform front end of change in dimensions */
if (!(flags & TREE_OPTION_SUPPRESS_RESIZE))
treeview__cw_update_size(tree, -1,
- tree->root->height);
+ tree->root->height);
/* Redraw */
if (!(flags & TREE_OPTION_SUPPRESS_REDRAW)) {
@@ -888,25 +1374,42 @@ nserror treeview_create_node_entry(treeview *tree,
r.y0 = treeview_node_y(tree, n);
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
+ treeview__search_update_display(tree);
+
*entry = n;
return NSERROR_OK;
}
+/**
+ * Treewalk iterator context
+ */
struct treeview_walk_ctx {
treeview_walk_cb enter_cb;
treeview_walk_cb leave_cb;
void *ctx;
enum treeview_node_type type;
};
-/** Treewalk node enter callback. */
-static nserror treeview_walk_fwd_cb(treeview_node *n, void *ctx,
- bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node enter callback.
+ *
+ * \param n current node
+ * \param ctx treewalk context
+ * \param skip_children set if child nodes should be skipped
+ * \param end set if iteration should end early
+ */
+static nserror
+treeview_walk_fwd_cb(treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_walk_ctx *tw = ctx;
@@ -916,7 +1419,15 @@ static nserror treeview_walk_fwd_cb(treeview_node *n, void *ctx,
return NSERROR_OK;
}
-/** Treewalk node leave callback. */
+
+
+/**
+ * Treewalk node leave callback.
+ *
+ * \param n current node
+ * \param ctx treewalk context
+ * \param end set if iteration should end early
+ */
static nserror treeview_walk_bwd_cb(treeview_node *n, void *ctx, bool *end)
{
struct treeview_walk_ctx *tw = ctx;
@@ -927,10 +1438,16 @@ static nserror treeview_walk_bwd_cb(treeview_node *n, void *ctx, bool *end)
return NSERROR_OK;
}
+
+
/* Exported interface, documented in treeview.h */
-nserror treeview_walk(treeview *tree, treeview_node *root,
- treeview_walk_cb enter_cb, treeview_walk_cb leave_cb,
- void *ctx, enum treeview_node_type type)
+nserror
+treeview_walk(treeview *tree,
+ treeview_node *root,
+ treeview_walk_cb enter_cb,
+ treeview_walk_cb leave_cb,
+ void *ctx,
+ enum treeview_node_type type)
{
struct treeview_walk_ctx tw = {
.enter_cb = enter_cb,
@@ -945,16 +1462,18 @@ nserror treeview_walk(treeview *tree, treeview_node *root,
if (root == NULL)
root = tree->root;
- return treeview_walk_internal(root, true,
+ return treeview_walk_internal(tree, root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
(leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
- (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL, &tw);
+ (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
+ &tw);
}
/**
* Unlink a treeview node
*
- * \param n Node to unlink
+ * \param n Node to unlink
* \return true iff ancestor heights need to be reduced
*/
static inline bool treeview_unlink_node(treeview_node *n)
@@ -975,7 +1494,8 @@ static inline bool treeview_unlink_node(treeview_node *n)
}
/* Reduce ancestor heights */
- if (n->parent != NULL && n->parent->flags & TV_NFLAGS_EXPANDED) {
+ if ((n->parent != NULL) &&
+ (n->parent->flags & TV_NFLAGS_EXPANDED)) {
return true;
}
@@ -986,8 +1506,8 @@ static inline bool treeview_unlink_node(treeview_node *n)
/**
* Cancel the editing of a treeview node
*
- * \param tree Treeview object to cancel node editing in
- * \param redraw Set true iff redraw of removed textarea area required
+ * \param tree Treeview object to cancel node editing in
+ * \param redraw Set true iff redraw of removed textarea area required
*/
static void treeview_edit_cancel(treeview *tree, bool redraw)
{
@@ -1009,15 +1529,17 @@ static void treeview_edit_cancel(treeview *tree, bool redraw)
r.y0 = tree->edit.y;
r.x1 = tree->edit.x + tree->edit.w;
r.y1 = tree->edit.y + tree->edit.h;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
/**
- * Complete a treeview edit, by informing the client with a change request msg
+ * Complete a treeview edit
+ *
+ * Complete edit by informing the client with a change request msg
*
- * \param tree Treeview object to complete edit in
+ * \param tree Treeview object to complete edit in
*/
static void treeview_edit_done(treeview *tree)
{
@@ -1027,8 +1549,9 @@ static void treeview_edit_done(treeview *tree)
struct treeview_node_msg msg;
msg.msg = TREE_MSG_NODE_EDIT;
- if (tree->edit.textarea == NULL)
+ if (tree->edit.textarea == NULL) {
return;
+ }
assert(n != NULL);
@@ -1066,7 +1589,6 @@ static void treeview_edit_done(treeview *tree)
break;
}
-
/* Finished with the new text */
free(new_text);
@@ -1075,17 +1597,25 @@ static void treeview_edit_done(treeview *tree)
}
+/**
+ * context for treeview node deletion iterator
+ */
struct treeview_node_delete {
treeview *tree;
int h_reduction;
bool user_interaction;
};
-/** Treewalk node callback deleting nodes. */
-static nserror treeview_delete_node_walk_cb(treeview_node *n,
- void *ctx, bool *end)
+
+
+/**
+ * Treewalk node callback deleting nodes.
+ */
+static nserror
+treeview_delete_node_walk_cb(treeview_node *n, void *ctx, bool *end)
{
struct treeview_node_delete *nd = (struct treeview_node_delete *)ctx;
struct treeview_node_msg msg;
+
msg.msg = TREE_MSG_NODE_DELETE;
msg.data.delete.user = nd->user_interaction;
@@ -1093,51 +1623,60 @@ static nserror treeview_delete_node_walk_cb(treeview_node *n,
if (treeview_unlink_node(n))
nd->h_reduction += (n->type == TREE_NODE_ENTRY) ?
- n->height : tree_g.line_height;
+ n->height : tree_g.line_height;
/* Handle any special treatment */
switch (n->type) {
case TREE_NODE_ENTRY:
nd->tree->callbacks->entry(msg, n->client_data);
break;
+
case TREE_NODE_FOLDER:
nd->tree->callbacks->folder(msg, n->client_data);
break;
+
case TREE_NODE_ROOT:
break;
+
default:
return NSERROR_BAD_PARAMETER;
}
/* Cancel any edit of this node */
if (nd->tree->edit.textarea != NULL &&
- nd->tree->edit.node == n)
+ nd->tree->edit.node == n) {
treeview_edit_cancel(nd->tree, false);
+ }
/* Free the node */
free(n);
return NSERROR_OK;
}
+
+
/**
* Delete a treeview node
*
- * \param tree Treeview object to delete node from
- * \param n Node to delete
- * \param interaction Delete is result of user interaction with treeview
- * \param flags Treeview node options flags
- * \return NSERROR_OK on success, appropriate error otherwise
- *
* Will emit folder or entry deletion msg callback.
*
- * Note this can be called from inside a treeview_walk fwd callback.
+ * \note this can be called from inside a treeview_walk fwd callback.
* For example walking the tree and calling this for any node that's selected.
*
* This function does not delete empty nodes, so if TREEVIEW_DEL_EMPTY_DIRS is
* set, caller must also call treeview_delete_empty.
+ *
+ * \param tree Treeview object to delete node from
+ * \param n Node to delete
+ * \param interaction Delete is result of user interaction with treeview
+ * \param flags Treeview node options flags
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror treeview_delete_node_internal(treeview *tree, treeview_node *n,
- bool interaction, treeview_node_options_flags flags)
+static nserror
+treeview_delete_node_internal(treeview *tree,
+ treeview_node *n,
+ bool interaction,
+ treeview_node_options_flags flags)
{
nserror err;
treeview_node *p = n->parent;
@@ -1152,8 +1691,9 @@ static nserror treeview_delete_node_internal(treeview *tree, treeview_node *n,
}
/* Delete any children first */
- err = treeview_walk_internal(n, true, treeview_delete_node_walk_cb,
- NULL, &nd);
+ err = treeview_walk_internal(tree, n,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ treeview_delete_node_walk_cb, NULL, &nd);
if (err != NSERROR_OK) {
return err;
}
@@ -1175,12 +1715,14 @@ static nserror treeview_delete_node_internal(treeview *tree, treeview_node *n,
/* Inform front end of change in dimensions */
if (tree->root != NULL && p != NULL && p->flags & TV_NFLAGS_EXPANDED &&
- nd.h_reduction > 0 &&
- !(flags & TREE_OPTION_SUPPRESS_RESIZE)) {
+ nd.h_reduction > 0 &&
+ !(flags & TREE_OPTION_SUPPRESS_RESIZE)) {
treeview__cw_update_size(tree, -1,
- tree->root->height);
+ tree->root->height);
}
+ treeview__search_update_display(tree);
+
return NSERROR_OK;
}
@@ -1188,8 +1730,8 @@ static nserror treeview_delete_node_internal(treeview *tree, treeview_node *n,
/**
* Delete any empty treeview folder nodes
*
- * \param tree Treeview object to delete empty nodes from
- * \param interaction Delete is result of user interaction with treeview
+ * \param tree Treeview object to delete empty nodes from
+ * \param interaction Delete is result of user interaction with treeview
* \return NSERROR_OK on success, appropriate error otherwise
*
* Note this must not be called within a treeview_walk. It may delete the
@@ -1226,21 +1768,21 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction)
* with a next sibling. */
while (node->parent != NULL &&
- next_sibling == NULL) {
+ next_sibling == NULL) {
if (node->type == TREE_NODE_FOLDER &&
- node->children == NULL) {
+ node->children == NULL) {
/* Delete node */
p = node->parent;
err = treeview_delete_node_walk_cb(
- node, &nd, &abort);
+ node, &nd, &abort);
if (err != NSERROR_OK) {
return err;
}
/* Reduce ancestor heights */
while (p != NULL &&
- p->flags &
- TV_NFLAGS_EXPANDED) {
+ p->flags &
+ TV_NFLAGS_EXPANDED) {
p->height -= nd.h_reduction;
p = p->parent;
}
@@ -1255,18 +1797,18 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction)
break;
if (node->type == TREE_NODE_FOLDER &&
- node->children == NULL) {
+ node->children == NULL) {
/* Delete node */
p = node->parent;
err = treeview_delete_node_walk_cb(
- node, &nd, &abort);
+ node, &nd, &abort);
if (err != NSERROR_OK) {
return err;
}
/* Reduce ancestor heights */
while (p != NULL &&
- p->flags & TV_NFLAGS_EXPANDED) {
+ p->flags & TV_NFLAGS_EXPANDED) {
p->height -= nd.h_reduction;
p = p->parent;
}
@@ -1281,7 +1823,7 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction)
parent = node->parent;
next_sibling = node->next_sib;
child = (node->flags & TV_NFLAGS_EXPANDED) ?
- node->children : NULL;
+ node->children : NULL;
}
return NSERROR_OK;
@@ -1289,8 +1831,10 @@ static nserror treeview_delete_empty_nodes(treeview *tree, bool interaction)
/* Exported interface, documented in treeview.h */
-nserror treeview_delete_node(treeview *tree, treeview_node *n,
- treeview_node_options_flags flags)
+nserror
+treeview_delete_node(treeview *tree,
+ treeview_node *n,
+ treeview_node_options_flags flags)
{
nserror err;
struct rect r;
@@ -1321,7 +1865,7 @@ nserror treeview_delete_node(treeview *tree, treeview_node *n,
r.y0 = 0;
if (!(flags & TREE_OPTION_SUPPRESS_RESIZE)) {
treeview__cw_update_size(tree, -1,
- tree->root->height);
+ tree->root->height);
}
}
}
@@ -1330,19 +1874,69 @@ nserror treeview_delete_node(treeview *tree, treeview_node *n,
if (visible && !(flags & TREE_OPTION_SUPPRESS_REDRAW)) {
r.x0 = 0;
r.x1 = REDRAW_MAX;
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
}
+/**
+ * Helper to create a textarea.
+ *
+ * \param[in] tree The treeview we're creating the textarea for.
+ * \param[in] width The width of the textarea.
+ * \param[in] height The height of the textarea.
+ * \param[in] border The border colour to use.
+ * \param[in] background The background colour to use.
+ * \param[in] foreground The foreground colour to use.
+ * \param[in] text The text style to use for the text area.
+ * \param[in] ta_callback The textarea callback function to give the textarea.
+ * \return the textarea pointer on success, or NULL on failure.
+ */
+static struct textarea *treeview__create_textarea(
+ treeview *tree,
+ int width,
+ int height,
+ colour border,
+ colour background,
+ colour foreground,
+ plot_font_style_t text,
+ textarea_client_callback ta_callback)
+{
+ /* Configure the textarea */
+ textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
+ textarea_setup ta_setup = {
+ .text = text,
+ .width = width,
+ .height = height,
+ .pad_top = 0,
+ .pad_left = 2,
+ .pad_right = 2,
+ .pad_bottom = 0,
+ .border_width = 1,
+ .border_col = border,
+ .selected_bg = foreground,
+ .selected_text = background,
+ };
+
+ ta_setup.text.foreground = foreground;
+ ta_setup.text.background = background;
+
+ /* Create text area */
+ return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
+}
+
+
/* Exported interface, documented in treeview.h */
-nserror treeview_create(treeview **tree,
+nserror
+treeview_create(treeview **tree,
const struct treeview_callback_table *callbacks,
- int n_fields, struct treeview_field_desc fields[],
+ int n_fields,
+ struct treeview_field_desc fields[],
const struct core_window_callback_table *cw_t,
- struct core_window *cw, treeview_flags flags)
+ struct core_window *cw,
+ treeview_flags flags)
{
nserror error;
int i;
@@ -1383,7 +1977,7 @@ nserror treeview_create(treeview **tree,
f->value.len = lwc_string_length(fields[i].field);
guit->layout->width(&plot_style_odd.text, f->value.data,
- f->value.len, &(f->value.width));
+ f->value.len, &(f->value.width));
if (f->flags & TREE_FLAG_SHOW_NAME)
if ((*tree)->field_width < f->value.width)
@@ -1413,6 +2007,24 @@ nserror treeview_create(treeview **tree,
(*tree)->edit.textarea = NULL;
(*tree)->edit.node = NULL;
+ if (flags & TREEVIEW_SEARCHABLE) {
+ (*tree)->search.textarea = treeview__create_textarea(
+ *tree, 600, tree_g.line_height,
+ plot_style_even.text.background,
+ plot_style_even.text.background,
+ plot_style_even.text.foreground,
+ plot_style_odd.text,
+ treeview_textarea_search_callback);
+ if ((*tree)->search.textarea == NULL) {
+ treeview_destroy(*tree);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ (*tree)->search.textarea = NULL;
+ }
+ (*tree)->search.active = false;
+ (*tree)->search.search = false;
+
(*tree)->flags = flags;
(*tree)->cw_t = cw_t;
@@ -1423,15 +2035,16 @@ nserror treeview_create(treeview **tree,
/* Exported interface, documented in treeview.h */
-nserror treeview_cw_attach(treeview *tree,
- const struct core_window_callback_table *cw_t,
- struct core_window *cw)
+nserror
+treeview_cw_attach(treeview *tree,
+ const struct core_window_callback_table *cw_t,
+ struct core_window *cw)
{
assert(cw_t != NULL);
assert(cw != NULL);
if (tree->cw_t != NULL || tree->cw_h != NULL) {
- LOG("Treeview already attached.");
+ NSLOG(netsurf, INFO, "Treeview already attached.");
return NSERROR_UNKNOWN;
}
tree->cw_t = cw_t;
@@ -1447,6 +2060,8 @@ nserror treeview_cw_detach(treeview *tree)
tree->cw_t = NULL;
tree->cw_h = NULL;
+ treeview__search_cancel(tree, true);
+
return NSERROR_OK;
}
@@ -1458,10 +2073,16 @@ nserror treeview_destroy(treeview *tree)
assert(tree != NULL);
+ if (tree->search.textarea != NULL) {
+ tree->search.active = false;
+ tree->search.search = false;
+ textarea_destroy(tree->search.textarea);
+ }
+
/* Destroy nodes */
treeview_delete_node_internal(tree, tree->root, false,
- TREE_OPTION_SUPPRESS_RESIZE |
- TREE_OPTION_SUPPRESS_REDRAW);
+ TREE_OPTION_SUPPRESS_RESIZE |
+ TREE_OPTION_SUPPRESS_REDRAW);
/* Destroy feilds */
for (f = 0; f <= tree->n_fields; f++) {
@@ -1483,8 +2104,8 @@ nserror treeview_destroy(treeview *tree)
* \param node The node to expand.
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-static nserror treeview_node_expand_internal(treeview *tree,
- treeview_node *node)
+static nserror
+treeview_node_expand_internal(treeview *tree, treeview_node *node)
{
treeview_node *child;
struct treeview_node_entry *e;
@@ -1496,7 +2117,7 @@ static nserror treeview_node_expand_internal(treeview *tree,
if (node->flags & TV_NFLAGS_EXPANDED) {
/* What madness is this? */
- LOG("Tried to expand an expanded node.");
+ NSLOG(netsurf, INFO, "Tried to expand an expanded node.");
return NSERROR_OK;
}
@@ -1509,12 +2130,11 @@ static nserror treeview_node_expand_internal(treeview *tree,
}
do {
- assert((child->flags & TV_NFLAGS_EXPANDED) == false);
if (child->text.width == 0) {
guit->layout->width(&plot_style_odd.text,
- child->text.data,
- child->text.len,
- &(child->text.width));
+ child->text.data,
+ child->text.len,
+ &(child->text.width));
}
additional_height += child->height;
@@ -1533,9 +2153,9 @@ static nserror treeview_node_expand_internal(treeview *tree,
if (e->fields[i].value.width == 0) {
guit->layout->width(&plot_style_odd.text,
- e->fields[i].value.data,
- e->fields[i].value.len,
- &(e->fields[i].value.width));
+ e->fields[i].value.data,
+ e->fields[i].value.len,
+ &(e->fields[i].value.width));
}
/* Add height for field */
@@ -1554,17 +2174,24 @@ static nserror treeview_node_expand_internal(treeview *tree,
/* Update the node */
node->flags |= TV_NFLAGS_EXPANDED;
- /* And parent's heights */
- do {
- node->height += additional_height;
- node = node->parent;
- } while (node->parent != NULL);
+ /* And node heights */
+ for (struct treeview_node *n = node;
+ (n != NULL) && (n->flags & TV_NFLAGS_EXPANDED);
+ n = n->parent) {
+ n->height += additional_height;
+ }
- node->height += additional_height;
+ if (tree->search.search &&
+ node->type == TREE_NODE_ENTRY &&
+ node->flags & TV_NFLAGS_MATCHED) {
+ tree->search.height += additional_height;
+ }
/* Inform front end of change in dimensions */
- if (additional_height != 0)
- treeview__cw_update_size(tree, -1, tree->root->height);
+ if (additional_height != 0) {
+ treeview__cw_update_size(tree, -1,
+ treeview__get_display_height(tree));
+ }
return NSERROR_OK;
}
@@ -1573,29 +2200,37 @@ static nserror treeview_node_expand_internal(treeview *tree,
/* Exported interface, documented in treeview.h */
nserror treeview_node_expand(treeview *tree, treeview_node *node)
{
- nserror err;
- struct rect r;
-
- err = treeview_node_expand_internal(tree, node);
- if (err != NSERROR_OK)
- return err;
-
- r.x0 = 0;
- r.y0 = treeview_node_y(tree, node);
- r.x1 = REDRAW_MAX;
- r.y1 = tree->root->height;
-
- /* Redraw */
- treeview__cw_redraw_request(tree, &r);
+ nserror res;
+
+ res = treeview_node_expand_internal(tree, node);
+ NSLOG(netsurf, INFO, "Expanding!");
+ if (res == NSERROR_OK) {
+ /* expansion was successful, attempt redraw */
+ treeview__redraw_from_node(tree, node);
+ NSLOG(netsurf, INFO, "Expanded!");
+ }
- return NSERROR_OK;
+ return res;
}
+/**
+ * context for treeview contraction callback
+ */
struct treeview_contract_data {
+ treeview *tree;
bool only_entries;
};
-/** Treewalk node callback for handling node contraction. */
+
+
+/**
+ * Treewalk node callback for handling node contraction.
+ *
+ * \param n node
+ * \param ctx contract iterator context
+ * \param end flag to end iteration now
+ * \return NSERROR_OK on success else appropriate error code
+ */
static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end)
{
struct treeview_contract_data *data = ctx;
@@ -1607,32 +2242,39 @@ static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end)
n->flags &= ~TV_NFLAGS_SELECTED;
if ((n->flags & TV_NFLAGS_EXPANDED) == false ||
- (n->type == TREE_NODE_FOLDER && data->only_entries)) {
+ (n->type == TREE_NODE_FOLDER && data->only_entries)) {
/* Nothing to do. */
return NSERROR_OK;
}
- n->flags ^= TV_NFLAGS_EXPANDED;
h_reduction = n->height - tree_g.line_height;
assert(h_reduction >= 0);
+ for (struct treeview_node *node = n;
+ (node != NULL) && (node->flags & TV_NFLAGS_EXPANDED);
+ node = node->parent) {
+ node->height -= h_reduction;
+ }
- do {
- n->height -= h_reduction;
- n = n->parent;
- } while (n != NULL);
+ if (data->tree->search.search) {
+ data->tree->search.height -= h_reduction;
+ }
+
+ n->flags ^= TV_NFLAGS_EXPANDED;
return NSERROR_OK;
}
+
+
/**
* Contract a treeview node
*
- * \param tree Treeview object to contract node in
- * \param node Node to contract
+ * \param tree Treeview object to contract node in
+ * \param node Node to contract
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror treeview_node_contract_internal(treeview *tree,
- treeview_node *node)
+static nserror
+treeview_node_contract_internal(treeview *tree, treeview_node *node)
{
struct treeview_contract_data data;
bool selected;
@@ -1640,16 +2282,17 @@ static nserror treeview_node_contract_internal(treeview *tree,
if ((node->flags & TV_NFLAGS_EXPANDED) == false) {
/* What madness is this? */
- LOG("Tried to contract a contracted node.");
+ NSLOG(netsurf, INFO, "Tried to contract a contracted node.");
return NSERROR_OK;
}
+ data.tree = tree;
data.only_entries = false;
selected = node->flags & TV_NFLAGS_SELECTED;
/* Contract children. */
- treeview_walk_internal(node, false, treeview_node_contract_cb,
- NULL, &data);
+ treeview_walk_internal(tree, node, TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
+ treeview_node_contract_cb, NULL, &data);
/* Contract node */
treeview_node_contract_cb(node, &data, false);
@@ -1658,7 +2301,7 @@ static nserror treeview_node_contract_internal(treeview *tree,
node->flags |= TV_NFLAGS_SELECTED;
/* Inform front end of change in dimensions */
- treeview__cw_update_size(tree, -1, tree->root->height);
+ treeview__cw_update_size(tree, -1, treeview__get_display_height(tree));
return NSERROR_OK;
}
@@ -1667,30 +2310,27 @@ static nserror treeview_node_contract_internal(treeview *tree,
/* Exported interface, documented in treeview.h */
nserror treeview_node_contract(treeview *tree, treeview_node *node)
{
- nserror err;
- struct rect r;
+ nserror res;
assert(tree != NULL);
- r.x0 = 0;
- r.y0 = treeview_node_y(tree, node);
- r.x1 = REDRAW_MAX;
- r.y1 = tree->root->height;
-
- err = treeview_node_contract_internal(tree, node);
- if (err != NSERROR_OK)
- return err;
-
- /* Redraw */
- treeview__cw_redraw_request(tree, &r);
+ res = treeview_node_contract_internal(tree, node);
+ NSLOG(netsurf, INFO, "Contracting!");
+ if (res == NSERROR_OK) {
+ /* successful contraction, request redraw */
+ treeview__redraw_from_node(tree, node);
+ NSLOG(netsurf, INFO, "Contracted!");
+ }
- return NSERROR_OK;
+ return res;
}
/* Exported interface, documented in treeview.h */
nserror treeview_contract(treeview *tree, bool all)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
struct treeview_contract_data data;
bool selected;
treeview_node *n;
@@ -1702,8 +2342,9 @@ nserror treeview_contract(treeview *tree, bool all)
r.x0 = 0;
r.y0 = 0;
r.x1 = REDRAW_MAX;
- r.y1 = tree->root->height;
+ r.y1 = tree->root->height + search_height;
+ data.tree = tree;
data.only_entries = !all;
for (n = tree->root->children; n != NULL; n = n->next_sib) {
@@ -1714,7 +2355,8 @@ nserror treeview_contract(treeview *tree, bool all)
selected = n->flags & TV_NFLAGS_SELECTED;
/* Contract children. */
- treeview_walk_internal(n, false,
+ treeview_walk_internal(tree, n,
+ TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
treeview_node_contract_cb, NULL, &data);
/* Contract node */
@@ -1728,19 +2370,35 @@ nserror treeview_contract(treeview *tree, bool all)
treeview__cw_update_size(tree, -1, tree->root->height);
/* Redraw */
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
return NSERROR_OK;
}
+/**
+ * context data for treeview expansion
+ */
struct treeview_expand_data {
treeview *tree;
bool only_folders;
};
-/** Treewalk node callback for handling recursive node expansion. */
-static nserror treeview_expand_cb(treeview_node *n, void *ctx,
- bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node callback for handling recursive node expansion.
+ *
+ * \param n current node
+ * \param ctx node expansion context
+ * \param skip_children flag to allow children to be skipped
+ * \param end flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+treeview_expand_cb(treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_expand_data *data = ctx;
nserror err;
@@ -1749,7 +2407,7 @@ static nserror treeview_expand_cb(treeview_node *n, void *ctx,
assert(n->type != TREE_NODE_ROOT);
if (n->flags & TV_NFLAGS_EXPANDED ||
- (data->only_folders && n->type != TREE_NODE_FOLDER)) {
+ (data->only_folders && n->type != TREE_NODE_FOLDER)) {
/* Nothing to do. */
return NSERROR_OK;
}
@@ -1758,11 +2416,13 @@ static nserror treeview_expand_cb(treeview_node *n, void *ctx,
return err;
}
+
+
/* Exported interface, documented in treeview.h */
nserror treeview_expand(treeview *tree, bool only_folders)
{
struct treeview_expand_data data;
- nserror err;
+ nserror res;
struct rect r;
assert(tree != NULL);
@@ -1771,50 +2431,57 @@ nserror treeview_expand(treeview *tree, bool only_folders)
data.tree = tree;
data.only_folders = only_folders;
- err = treeview_walk_internal(tree->root, true, NULL,
- treeview_expand_cb, &data);
- if (err != NSERROR_OK)
- return err;
-
- r.x0 = 0;
- r.y0 = 0;
- r.x1 = REDRAW_MAX;
- r.y1 = tree->root->height;
+ res = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ NULL, treeview_expand_cb, &data);
+ if (res == NSERROR_OK) {
+ /* expansion succeeded, schedule redraw */
- /* Redraw */
- treeview__cw_redraw_request(tree, &r);
+ r.x0 = 0;
+ r.y0 = 0;
+ r.x1 = REDRAW_MAX;
+ r.y1 = tree->root->height;
- return NSERROR_OK;
+ treeview__cw_invalidate_area(tree, &r);
+ }
+ return res;
}
-/* Exported interface, documented in treeview.h */
-void treeview_redraw(treeview *tree, const int x, const int y,
- struct rect *clip, const struct redraw_context *ctx)
+/**
+ * Draw a treeview normally, in tree mode.
+ *
+ * \param[in] tree The treeview we're rendering.
+ * \param[in] x X coordinate we're rendering the treeview at.
+ * \param[in] y Y coordinate we're rendering the treeview at.
+ * \param[in,out] render_y Current vertical position in tree, updated on exit.
+ * \param[in] r Clip rectangle.
+ * \param[in] data Redraw data for rendering contents.
+ * \param[in] ctx Current render context.
+ */
+static void treeview_redraw_tree(
+ treeview *tree,
+ const int x,
+ const int y,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
+ const struct redraw_context *ctx)
{
- struct redraw_context new_ctx = *ctx;
- treeview_node *node, *root, *next;
- struct treeview_node_entry *entry;
struct treeview_node_style *style = &plot_style_odd;
- struct content_redraw_data data;
- struct rect r;
- uint32_t count = 0;
- int render_y = y;
- int inset;
- int x0, y0, y1;
- int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
- plot_style_t *bg_style;
- plot_font_style_t *text_style;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
plot_font_style_t *infotext_style;
- struct bitmap *furniture;
- int height;
+ treeview_node *root = tree->root;
+ treeview_node *node = tree->root;
+ int render_y = *render_y_in_out;
+ plot_font_style_t *text_style;
+ plot_style_t *bg_style;
int sel_min, sel_max;
- bool invert_selection;
-
- assert(tree != NULL);
- assert(tree->root != NULL);
- assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+ uint32_t count = 0;
+ struct rect rect;
+ int inset;
+ int x0;
if (tree->drag.start.y > tree->drag.prev.y) {
sel_min = tree->drag.prev.y;
@@ -1824,31 +2491,16 @@ void treeview_redraw(treeview *tree, const int x, const int y,
sel_max = tree->drag.prev.y;
}
- /* Start knockout rendering if it's available for this plotter */
- if (ctx->plot->option_knockout)
- knockout_plot_start(ctx, &new_ctx);
-
- /* Set up clip rectangle */
- r.x0 = clip->x0 + x;
- r.y0 = clip->y0 + y;
- r.x1 = clip->x1 + x;
- r.y1 = clip->y1 + y;
- new_ctx.plot->clip(&r);
-
- /* Draw the tree */
- node = root = tree->root;
-
- /* Setup common content redraw data */
- data.width = tree_g.icon_size;
- data.height = tree_g.icon_size;
- data.scale = 1;
- data.repeat_x = false;
- data.repeat_y = false;
-
while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
int i;
+
next = (node->flags & TV_NFLAGS_EXPANDED) ?
- node->children : NULL;
+ node->children : NULL;
if (next != NULL) {
/* down to children */
@@ -1859,7 +2511,7 @@ void treeview_redraw(treeview *tree, const int x, const int y,
* with a next sibling. */
while (node != root &&
- node->next_sib == NULL) {
+ node->next_sib == NULL) {
node = node->parent;
}
@@ -1872,14 +2524,14 @@ void treeview_redraw(treeview *tree, const int x, const int y,
assert(node != NULL);
assert(node != root);
assert(node->type == TREE_NODE_FOLDER ||
- node->type == TREE_NODE_ENTRY);
+ node->type == TREE_NODE_ENTRY);
count++;
inset = x + node->inset;
height = (node->type == TREE_NODE_ENTRY) ? node->height :
- tree_g.line_height;
+ tree_g.line_height;
- if ((render_y + height) < r.y0) {
+ if ((render_y + height) < r->y0) {
/* This node's line is above clip region */
render_y += height;
continue;
@@ -1887,70 +2539,77 @@ void treeview_redraw(treeview *tree, const int x, const int y,
style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
if (tree->drag.type == TV_DRAG_SELECTION &&
- (render_y + height >= sel_min &&
- render_y < sel_max)) {
+ (render_y + height >= sel_min &&
+ render_y < sel_max)) {
invert_selection = true;
} else {
invert_selection = false;
}
if ((node->flags & TV_NFLAGS_SELECTED && !invert_selection) ||
- (!(node->flags & TV_NFLAGS_SELECTED) &&
- invert_selection)) {
+ (!(node->flags & TV_NFLAGS_SELECTED) &&
+ invert_selection)) {
bg_style = &style->sbg;
text_style = &style->stext;
infotext_style = &style->sitext;
furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
- style->furn[TREE_FURN_CONTRACT].sel :
- style->furn[TREE_FURN_EXPAND].sel;
+ style->furn[TREE_FURN_CONTRACT].sel :
+ style->furn[TREE_FURN_EXPAND].sel;
} else {
bg_style = &style->bg;
text_style = &style->text;
infotext_style = &style->itext;
furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
- style->furn[TREE_FURN_CONTRACT].bmp :
- style->furn[TREE_FURN_EXPAND].bmp;
+ style->furn[TREE_FURN_CONTRACT].bmp :
+ style->furn[TREE_FURN_EXPAND].bmp;
}
/* Render background */
- y0 = render_y;
- y1 = render_y + height;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg_style);
+ rect.x0 = r->x0;
+ rect.y0 = render_y;
+ rect.x1 = r->x1;
+ rect.y1 = render_y + height;
+ ctx->plot->rectangle(ctx, bg_style, &rect);
/* Render toggle */
- new_ctx.plot->bitmap(inset, render_y + tree_g.line_height / 4,
+ ctx->plot->bitmap(ctx,
+ furniture,
+ inset,
+ render_y + tree_g.line_height / 4,
style->furn[TREE_FURN_EXPAND].size,
style->furn[TREE_FURN_EXPAND].size,
- furniture,
- bg_style->fill_colour, BITMAPF_NONE);
+ bg_style->fill_colour,
+ BITMAPF_NONE);
/* Render icon */
- if (node->type == TREE_NODE_ENTRY)
+ if (node->type == TREE_NODE_ENTRY) {
res = TREE_RES_CONTENT;
- else if (node->flags & TV_NFLAGS_SPECIAL)
+ } else if (node->flags & TV_NFLAGS_SPECIAL) {
res = TREE_RES_FOLDER_SPECIAL;
- else
+ } else {
res = TREE_RES_FOLDER;
+ }
if (treeview_res[res].ready) {
/* Icon resource is available */
- data.x = inset + tree_g.step_width;
- data.y = render_y + ((tree_g.line_height -
- treeview_res[res].height + 1) / 2);
- data.background_colour = bg_style->fill_colour;
+ data->x = inset + tree_g.step_width;
+ data->y = render_y + ((tree_g.line_height -
+ treeview_res[res].height + 1) / 2);
+ data->background_colour = bg_style->fill_colour;
- content_redraw(treeview_res[res].c,
- &data, &r, &new_ctx);
+ content_redraw(treeview_res[res].c, data, r, ctx);
}
/* Render text */
x0 = inset + tree_g.step_width + tree_g.icon_step;
- new_ctx.plot->text(x0, render_y + baseline,
- node->text.data, node->text.len,
- text_style);
+ ctx->plot->text(ctx,
+ text_style,
+ x0, render_y + baseline,
+ node->text.data,
+ node->text.len);
/* Rendered the node */
render_y += tree_g.line_height;
- if (render_y > r.y1) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
@@ -1958,7 +2617,7 @@ void treeview_redraw(treeview *tree, const int x, const int y,
if (node->type != TREE_NODE_ENTRY ||
- !(node->flags & TV_NFLAGS_EXPANDED))
+ !(node->flags & TV_NFLAGS_EXPANDED))
/* Done everything for this node */
continue;
@@ -1970,57 +2629,364 @@ void treeview_redraw(treeview *tree, const int x, const int y,
if (ef->flags & TREE_FLAG_SHOW_NAME) {
int max_width = tree->field_width;
- new_ctx.plot->text(x0 + max_width -
- ef->value.width -
- tree_g.step_width,
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width - ef->value.width - tree_g.step_width,
render_y + baseline,
ef->value.data,
- ef->value.len,
- infotext_style);
+ ef->value.len);
- new_ctx.plot->text(x0 + max_width,
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width,
render_y + baseline,
entry->fields[i].value.data,
- entry->fields[i].value.len,
- infotext_style);
+ entry->fields[i].value.len);
} else {
- new_ctx.plot->text(x0, render_y + baseline,
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0, render_y + baseline,
entry->fields[i].value.data,
- entry->fields[i].value.len,
- infotext_style);
+ entry->fields[i].value.len);
+ }
+
+ /* Rendered the expanded entry field */
+ render_y += tree_g.line_height;
+ }
+
+ /* Finished rendering expanded entry */
+
+ if (render_y > r->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+ }
+
+ *render_y_in_out = render_y;
+}
+
+
+/**
+ * Draw a treeview normally, in tree mode.
+ *
+ * \param[in] tree The treeview we're rendering.
+ * \param[in] x X coordinate we're rendering the treeview at.
+ * \param[in] y Y coordinate we're rendering the treeview at.
+ * \param[in,out] render_y Current vertical position in tree, updated on exit.
+ * \param[in] r Clip rectangle.
+ * \param[in] data Redraw data for rendering contents.
+ * \param[in] ctx Current render context.
+ */
+static void treeview_redraw_search(
+ treeview *tree,
+ const int x,
+ const int y,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
+ const struct redraw_context *ctx)
+{
+ struct treeview_node_style *style = &plot_style_odd;
+ enum treeview_resource_id res = TREE_RES_CONTENT;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
+ plot_font_style_t *infotext_style;
+ treeview_node *root = tree->root;
+ treeview_node *node = tree->root;
+ int render_y = *render_y_in_out;
+ plot_font_style_t *text_style;
+ plot_style_t *bg_style;
+ int sel_min, sel_max;
+ uint32_t count = 0;
+ struct rect rect;
+ int inset;
+ int x0;
+
+ if (tree->drag.start.y > tree->drag.prev.y) {
+ sel_min = tree->drag.prev.y;
+ sel_max = tree->drag.start.y;
+ } else {
+ sel_min = tree->drag.start.y;
+ sel_max = tree->drag.prev.y;
+ }
+
+ while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
+ int i;
+
+ next = node->children;
+
+ if (next != NULL) {
+ /* down to children */
+ node = next;
+ } else {
+ /* No children. As long as we're not at the root,
+ * go to next sibling if present, or nearest ancestor
+ * with a next sibling. */
+
+ while (node != root &&
+ node->next_sib == NULL) {
+ node = node->parent;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->next_sib;
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+ assert(node->type == TREE_NODE_FOLDER ||
+ node->type == TREE_NODE_ENTRY);
+
+ if (node->type == TREE_NODE_FOLDER ||
+ !(node->flags & TV_NFLAGS_MATCHED)) {
+ continue;
+ }
+
+ count++;
+ inset = x + tree_g.window_padding;
+ height = node->height;
+
+ if ((render_y + height) < r->y0) {
+ /* This node's line is above clip region */
+ render_y += height;
+ continue;
+ }
+
+ style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
+ if (tree->drag.type == TV_DRAG_SELECTION &&
+ (render_y + height >= sel_min &&
+ render_y < sel_max)) {
+ invert_selection = true;
+ } else {
+ invert_selection = false;
+ }
+ if ((node->flags & TV_NFLAGS_SELECTED && !invert_selection) ||
+ (!(node->flags & TV_NFLAGS_SELECTED) &&
+ invert_selection)) {
+ bg_style = &style->sbg;
+ text_style = &style->stext;
+ infotext_style = &style->sitext;
+ furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
+ style->furn[TREE_FURN_CONTRACT].sel :
+ style->furn[TREE_FURN_EXPAND].sel;
+ } else {
+ bg_style = &style->bg;
+ text_style = &style->text;
+ infotext_style = &style->itext;
+ furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
+ style->furn[TREE_FURN_CONTRACT].bmp :
+ style->furn[TREE_FURN_EXPAND].bmp;
+ }
+
+ /* Render background */
+ rect.x0 = r->x0;
+ rect.y0 = render_y;
+ rect.x1 = r->x1;
+ rect.y1 = render_y + height;
+ ctx->plot->rectangle(ctx, bg_style, &rect);
+
+ /* Render toggle */
+ ctx->plot->bitmap(ctx,
+ furniture,
+ inset,
+ render_y + tree_g.line_height / 4,
+ style->furn[TREE_FURN_EXPAND].size,
+ style->furn[TREE_FURN_EXPAND].size,
+ bg_style->fill_colour,
+ BITMAPF_NONE);
+
+ /* Render icon */
+ if (node->type == TREE_NODE_ENTRY) {
+ res = TREE_RES_CONTENT;
+ } else if (node->flags & TV_NFLAGS_SPECIAL) {
+ res = TREE_RES_FOLDER_SPECIAL;
+ } else {
+ res = TREE_RES_FOLDER;
+ }
+
+ if (treeview_res[res].ready) {
+ /* Icon resource is available */
+ data->x = inset + tree_g.step_width;
+ data->y = render_y + ((tree_g.line_height -
+ treeview_res[res].height + 1) / 2);
+ data->background_colour = bg_style->fill_colour;
+
+ content_redraw(treeview_res[res].c, data, r, ctx);
+ }
+
+ /* Render text */
+ x0 = inset + tree_g.step_width + tree_g.icon_step;
+ ctx->plot->text(ctx,
+ text_style,
+ x0, render_y + baseline,
+ node->text.data,
+ node->text.len);
+
+ /* Rendered the node */
+ render_y += tree_g.line_height;
+ if (render_y > r->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+
+
+ if (node->type != TREE_NODE_ENTRY ||
+ !(node->flags & TV_NFLAGS_EXPANDED))
+ /* Done everything for this node */
+ continue;
+
+ /* Render expanded entry fields */
+ entry = (struct treeview_node_entry *)node;
+ for (i = 0; i < tree->n_fields - 1; i++) {
+ struct treeview_field *ef = &(tree->fields[i + 1]);
+
+ if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ int max_width = tree->field_width;
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width - ef->value.width - tree_g.step_width,
+ render_y + baseline,
+ ef->value.data,
+ ef->value.len);
+
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width,
+ render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
+ } else {
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0, render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
}
/* Rendered the expanded entry field */
render_y += tree_g.line_height;
}
- /* Finshed rendering expanded entry */
+ /* Finished rendering expanded entry */
- if (render_y > r.y1) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
}
}
+ *render_y_in_out = render_y;
+}
+
+
+/* Exported interface, documented in treeview.h */
+void
+treeview_redraw(treeview *tree,
+ const int x,
+ const int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct content_redraw_data data;
+ struct rect r;
+ struct rect rect;
+ int render_y = y;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+
+ /* Start knockout rendering if it's available for this plotter */
+ if (ctx->plot->option_knockout) {
+ knockout_plot_start(ctx, &new_ctx);
+ }
+
+ /* Set up clip rectangle */
+ r.x0 = clip->x0 + x;
+ r.y0 = clip->y0 + y;
+ r.x1 = clip->x1 + x;
+ r.y1 = clip->y1 + y;
+ new_ctx.plot->clip(&new_ctx, &r);
+
+ /* Setup common content redraw data */
+ data.width = tree_g.icon_size;
+ data.height = tree_g.icon_size;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (tree->flags & TREEVIEW_SEARCHABLE) {
+ if (render_y < r.y1) {
+ enum treeview_resource_id icon = TREE_RES_SEARCH;
+
+ /* Fill the blank area at the bottom */
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
+ &rect);
+
+ if (treeview_res[icon].ready) {
+ /* Icon resource is available */
+ data.x = tree_g.window_padding;
+ data.y = render_y + ((tree_g.line_height -
+ treeview_res[icon].height + 1) /
+ 2);
+ data.background_colour = plot_style_even.bg.
+ fill_colour;
+
+ content_redraw(treeview_res[icon].c,
+ &data, &r, &new_ctx);
+ }
+
+ textarea_redraw(tree->search.textarea,
+ x + tree_g.window_padding +
+ tree_g.icon_step, y,
+ plot_style_even.bg.fill_colour, 1.0,
+ &r, &new_ctx);
+ }
+ render_y += tree_g.line_height;
+ }
+
+ /* Render the treeview data */
+ if (tree->search.search == true) {
+ treeview_redraw_search(tree, x, y,
+ &render_y, &r, &data, &new_ctx);
+ } else {
+ treeview_redraw_tree(tree, x, y,
+ &render_y, &r, &data, &new_ctx);
+ }
+
if (render_y < r.y1) {
/* Fill the blank area at the bottom */
- y0 = render_y;
- new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1,
- &plot_style_even.bg);
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = r.y1;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg, &rect);
}
/* All normal treeview rendering is done; render any overlays */
- if (tree->move.target_pos != TV_TARGET_NONE &&
- treeview_res[TREE_RES_ARROW].ready) {
+ if ((tree->move.target_pos != TV_TARGET_NONE) &&
+ (treeview_res[TREE_RES_ARROW].ready)) {
/* Got a MOVE drag; render move indicator arrow */
data.x = tree->move.target_area.x0 + x;
data.y = tree->move.target_area.y0 + y;
data.background_colour = plot_style_even.bg.fill_colour;
- content_redraw(treeview_res[TREE_RES_ARROW].c,
- &data, &r, &new_ctx);
+ content_redraw(treeview_res[TREE_RES_ARROW].c, &data, &r, &new_ctx);
} else if (tree->edit.textarea != NULL) {
/* Edit in progress; render textarea */
@@ -2031,10 +2997,15 @@ void treeview_redraw(treeview *tree, const int x, const int y,
}
/* Rendering complete */
- if (ctx->plot->option_knockout)
- knockout_plot_end();
+ if (ctx->plot->option_knockout) {
+ knockout_plot_end(ctx);
+ }
}
+
+/**
+ * context for treeview selection
+ */
struct treeview_selection_walk_data {
enum {
TREEVIEW_WALK_HAS_SELECTION,
@@ -2059,6 +3030,7 @@ struct treeview_selection_walk_data {
} drag;
struct {
treeview_node *prev;
+ treeview_node *fixed;
} yank;
struct {
treeview_node *n;
@@ -2071,9 +3043,22 @@ struct treeview_selection_walk_data {
int current_y;
treeview *tree;
};
-/** Treewalk node callback for handling selection related actions. */
-static nserror treeview_node_selection_walk_cb(treeview_node *n,
- void *ctx, bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node callback for handling selection related actions.
+ *
+ * \param n current node
+ * \param ctx node selection context
+ * \param skip_children flag to allow children to be skipped
+ * \param end flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+treeview_node_selection_walk_cb(treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_selection_walk_data *sw = ctx;
int height;
@@ -2103,7 +3088,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
case TREEVIEW_WALK_DELETE_SELECTION:
if (n->flags & TV_NFLAGS_SELECTED) {
err = treeview_delete_node_internal(sw->tree, n, true,
- TREE_OPTION_NONE);
+ TREE_OPTION_NONE);
if (err != NSERROR_OK) {
return err;
}
@@ -2114,8 +3099,8 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
case TREEVIEW_WALK_PROPAGATE_SELECTION:
if (n->parent != NULL &&
- n->parent->flags & TV_NFLAGS_SELECTED &&
- !(n->flags & TV_NFLAGS_SELECTED)) {
+ n->parent->flags & TV_NFLAGS_SELECTED &&
+ !(n->flags & TV_NFLAGS_SELECTED)) {
n->flags ^= TV_NFLAGS_SELECTED;
changed = true;
}
@@ -2137,8 +3122,8 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
case TREEVIEW_WALK_COMMIT_SELECT_DRAG:
if (sw->current_y >= sw->data.drag.sel_min &&
- sw->current_y - height <
- sw->data.drag.sel_max) {
+ sw->current_y - height <
+ sw->data.drag.sel_max) {
n->flags ^= TV_NFLAGS_SELECTED;
}
return NSERROR_OK;
@@ -2148,6 +3133,10 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
treeview_node *p = n->parent;
int h = 0;
+ if (n == sw->data.yank.fixed) {
+ break;
+ }
+
if (treeview_unlink_node(n))
h = n->height;
@@ -2175,7 +3164,7 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
case TREEVIEW_WALK_COPY_SELECTION:
if (n->flags & TV_NFLAGS_SELECTED &&
- n->type == TREE_NODE_ENTRY) {
+ n->type == TREE_NODE_ENTRY) {
int i;
char *temp;
uint32_t len;
@@ -2190,12 +3179,12 @@ static nserror treeview_node_selection_walk_cb(treeview_node *n,
continue;
}
val = treeview_get_text_for_field(sw->tree,
- n, i);
+ n, i);
text = val->data;
len = val->len;
temp = realloc(sw->data.copy.text,
- sw->data.copy.len + len + 1);
+ sw->data.copy.len + len + 1);
if (temp == NULL) {
free(sw->data.copy.text);
sw->data.copy.text = NULL;
@@ -2238,7 +3227,8 @@ bool treeview_has_selection(treeview *tree)
sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
sw.data.has_selection = false;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.has_selection;
@@ -2248,7 +3238,7 @@ bool treeview_has_selection(treeview *tree)
/**
* Get first selected node (in any)
*
- * \param tree Treeview object in which to create folder
+ * \param tree Treeview object in which to create folder
* \return the first selected treeview node, or NULL
*/
static treeview_node * treeview_get_first_selected(treeview *tree)
@@ -2258,7 +3248,8 @@ static treeview_node * treeview_get_first_selected(treeview *tree)
sw.purpose = TREEVIEW_WALK_GET_FIRST_SELECTED;
sw.data.first.n = NULL;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.first.n;
@@ -2267,7 +3258,7 @@ static treeview_node * treeview_get_first_selected(treeview *tree)
/* Exported interface, documented in treeview.h */
enum treeview_node_type treeview_get_selection(treeview *tree,
- void **node_data)
+ void **node_data)
{
treeview_node *n;
@@ -2288,8 +3279,8 @@ enum treeview_node_type treeview_get_selection(treeview *tree,
/**
* Clear any selection in a treeview
*
- * \param tree Treeview object to clear selection in
- * \param rect Redraw rectangle (if redraw required)
+ * \param tree Treeview object to clear selection in
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
static bool treeview_clear_selection(treeview *tree, struct rect *rect)
@@ -2304,9 +3295,11 @@ static bool treeview_clear_selection(treeview *tree, struct rect *rect)
sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
@@ -2316,8 +3309,8 @@ static bool treeview_clear_selection(treeview *tree, struct rect *rect)
/**
* Select all in a treeview
*
- * \param tree Treeview object to select all in
- * \param rect Redraw rectangle (if redraw required)
+ * \param tree Treeview object to select all in
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
static bool treeview_select_all(treeview *tree, struct rect *rect)
@@ -2332,9 +3325,11 @@ static bool treeview_select_all(treeview *tree, struct rect *rect)
sw.purpose = TREEVIEW_WALK_SELECT_ALL;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
@@ -2344,14 +3339,15 @@ static bool treeview_select_all(treeview *tree, struct rect *rect)
/**
* Commit a current selection drag, modifying the node's selection state.
*
- * \param tree Treeview object to commit drag selection in
+ * \param tree Treeview object to commit drag selection in
*/
static void treeview_commit_selection_drag(treeview *tree)
{
struct treeview_selection_walk_data sw;
sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
if (tree->drag.start.y > tree->drag.prev.y) {
sw.data.drag.sel_min = tree->drag.prev.y;
@@ -2361,7 +3357,8 @@ static void treeview_commit_selection_drag(treeview *tree)
sw.data.drag.sel_max = tree->drag.prev.y;
}
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
}
@@ -2369,17 +3366,20 @@ static void treeview_commit_selection_drag(treeview *tree)
/**
* Yank a selection to the node move list.
*
- * \param tree Treeview object to yank selection from
+ * \param tree Treeview object to yank selection from
+ * \param fixed Treeview node that should not be yanked
*/
-static void treeview_move_yank_selection(treeview *tree)
+static void treeview_move_yank_selection(treeview *tree, treeview_node *fixed)
{
struct treeview_selection_walk_data sw;
sw.purpose = TREEVIEW_WALK_YANK_SELECTION;
+ sw.data.yank.fixed = fixed;
sw.data.yank.prev = NULL;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
}
@@ -2387,7 +3387,7 @@ static void treeview_move_yank_selection(treeview *tree)
/**
* Copy a selection to the clipboard.
*
- * \param tree Treeview object to yank selection from
+ * \param tree Treeview object to yank selection from
*/
static void treeview_copy_selection(treeview *tree)
{
@@ -2399,7 +3399,8 @@ static void treeview_copy_selection(treeview *tree)
sw.data.copy.len = 0;
sw.tree = tree;
- err = treeview_walk_internal(tree->root, false, NULL,
+ err = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
if (err != NSERROR_OK) {
return;
@@ -2407,7 +3408,7 @@ static void treeview_copy_selection(treeview *tree)
if (sw.data.copy.text != NULL) {
guit->clipboard->set(sw.data.copy.text,
- sw.data.copy.len - 1, NULL, 0);
+ sw.data.copy.len - 1, NULL, 0);
free(sw.data.copy.text);
}
}
@@ -2416,8 +3417,8 @@ static void treeview_copy_selection(treeview *tree)
/**
* Delete a selection.
*
- * \param tree Treeview object to delete selected nodes from
- * \param rect Updated to redraw rectangle
+ * \param tree Treeview object to delete selected nodes from
+ * \param rect Updated to redraw rectangle
* \return true iff redraw required.
*/
static bool treeview_delete_selection(treeview *tree, struct rect *rect)
@@ -2438,7 +3439,8 @@ static bool treeview_delete_selection(treeview *tree, struct rect *rect)
sw.current_y = 0;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
@@ -2448,8 +3450,8 @@ static bool treeview_delete_selection(treeview *tree, struct rect *rect)
/**
* Propagate selection to visible descendants of selected nodes.
*
- * \param tree Treeview object to propagate selection in
- * \param rect Redraw rectangle (if redraw required)
+ * \param tree Treeview object to propagate selection in
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
static bool treeview_propagate_selection(treeview *tree, struct rect *rect)
@@ -2470,7 +3472,8 @@ static bool treeview_propagate_selection(treeview *tree, struct rect *rect)
sw.current_y = 0;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
@@ -2480,8 +3483,9 @@ static bool treeview_propagate_selection(treeview *tree, struct rect *rect)
/**
* Move a selection according to the current move drag.
*
- * \param tree Treeview object to move selected nodes in
- * \param rect Redraw rectangle
+ * \param tree Treeview object to move selected nodes in
+ * \param rect Redraw rectangle
+ * \return NSERROR_OK on success else appropriate error code
*/
static nserror treeview_move_selection(treeview *tree, struct rect *rect)
{
@@ -2534,7 +3538,7 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
break;
default:
- LOG("Bad drop target for move.");
+ NSLOG(netsurf, INFO, "Bad drop target for move.");
return NSERROR_BAD_PARAMETER;
}
@@ -2544,23 +3548,24 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
parent = relation->parent;
}
- /* The node that we're moving selection to can't itself be selected */
- assert(!(relation->flags & TV_NFLAGS_SELECTED));
-
/* Move all selected nodes from treeview to tree->move.root */
- treeview_move_yank_selection(tree);
+ treeview_move_yank_selection(tree, relation);
/* Move all nodes on tree->move.root to target location */
for (node = tree->move.root; node != NULL; node = next) {
next = node->next_sib;
+ if (node == relation) {
+ continue;
+ }
+
if (!(parent->flags & TV_NFLAGS_EXPANDED)) {
if (node->flags & TV_NFLAGS_EXPANDED)
treeview_node_contract_internal(tree, node);
node->flags &= ~TV_NFLAGS_SELECTED;
}
- treeview_insert_node(node, relation, relationship);
+ treeview_insert_node(tree, node, relation, relationship);
relation = node;
relationship = TREE_REL_NEXT_SIBLING;
@@ -2581,13 +3586,20 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
}
+/**
+ * context for treeview launch action
+ */
struct treeview_launch_walk_data {
int selected_depth;
treeview *tree;
};
-/** Treewalk node walk backward callback for tracking folder selection. */
-static nserror treeview_node_launch_walk_bwd_cb(treeview_node *n, void *ctx,
- bool *end)
+
+
+/**
+ * Treewalk node walk backward callback for tracking folder selection.
+ */
+static nserror
+treeview_node_launch_walk_bwd_cb(treeview_node *n, void *ctx, bool *end)
{
struct treeview_launch_walk_data *lw = ctx;
@@ -2597,9 +3609,22 @@ static nserror treeview_node_launch_walk_bwd_cb(treeview_node *n, void *ctx,
return NSERROR_OK;
}
-/** Treewalk node walk forward callback for launching nodes. */
-static nserror treeview_node_launch_walk_fwd_cb(treeview_node *n, void *ctx,
- bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node walk forward callback for launching nodes.
+ *
+ * \param n current node
+ * \param ctx node launch context
+ * \param skip_children flag to allow children to be skipped
+ * \param end flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+treeview_node_launch_walk_fwd_cb(treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_launch_walk_data *lw = ctx;
nserror ret = NSERROR_OK;
@@ -2608,8 +3633,8 @@ static nserror treeview_node_launch_walk_fwd_cb(treeview_node *n, void *ctx,
lw->selected_depth++;
} else if (n->type == TREE_NODE_ENTRY &&
- (n->flags & TV_NFLAGS_SELECTED ||
- lw->selected_depth > 0)) {
+ (n->flags & TV_NFLAGS_SELECTED ||
+ lw->selected_depth > 0)) {
struct treeview_node_msg msg;
msg.msg = TREE_MSG_NODE_LAUNCH;
msg.data.node_launch.mouse = BROWSER_MOUSE_HOVER;
@@ -2618,14 +3643,16 @@ static nserror treeview_node_launch_walk_fwd_cb(treeview_node *n, void *ctx,
return ret;
}
+
+
/**
* Launch a selection.
*
- * \param tree Treeview object to launch selected nodes in
- * \return NSERROR_OK on success, appropriate error otherwise
+ * \note Selected entries are launched. Entries that are descendants
+ * of selected folders are also launched.
*
- * Note: Selected entries are launched.
- * Entries that are descendants of selected folders are also launched.
+ * \param tree Treeview object to launch selected nodes in
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror treeview_launch_selection(treeview *tree)
{
@@ -2637,15 +3664,20 @@ static nserror treeview_launch_selection(treeview *tree)
lw.selected_depth = 0;
lw.tree = tree;
- return treeview_walk_internal(tree->root, true,
+ return treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
treeview_node_launch_walk_bwd_cb,
treeview_node_launch_walk_fwd_cb, &lw);
}
/* Exported interface, documented in treeview.h */
-nserror treeview_get_relation(treeview *tree, treeview_node **relation,
- enum treeview_relationship *rel, bool at_y, int y)
+nserror
+treeview_get_relation(treeview *tree,
+ treeview_node **relation,
+ enum treeview_relationship *rel,
+ bool at_y,
+ int y)
{
treeview_node *n;
@@ -2687,6 +3719,9 @@ nserror treeview_get_relation(treeview *tree, treeview_node **relation,
}
+/**
+ * context for treeview keyboard action
+ */
struct treeview_nav_state {
treeview *tree;
treeview_node *prev;
@@ -2696,9 +3731,22 @@ struct treeview_nav_state {
int n_selected;
int prev_n_selected;
};
-/** Treewalk node callback for handling mouse action. */
-static nserror treeview_node_nav_cb(treeview_node *node, void *ctx,
- bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node callback for handling mouse action.
+ *
+ * \param node current node
+ * \param ctx node context
+ * \param skip_children flag to allow children to be skipped
+ * \param end flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+treeview_node_nav_cb(treeview_node *node,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_nav_state *ns = ctx;
@@ -2724,19 +3772,21 @@ static nserror treeview_node_nav_cb(treeview_node *node, void *ctx,
return NSERROR_OK;
}
+
+
/**
* Handle keyboard navigation.
*
- * \param tree Treeview object to launch selected nodes in
- * \param key The ucs4 character codepoint
- * \param rect Updated to redraw rectangle
- * \return true if treeview needs redraw, false otherwise
- *
- * Note: Selected entries are launched.
+ * \note Selected entries are launched.
* Entries that are descendants of selected folders are also launched.
+ *
+ * \param tree Treeview object to launch selected nodes in
+ * \param key The ucs4 character codepoint
+ * \param rect Updated to redraw rectangle
+ * \return true if treeview needs redraw, false otherwise
*/
-static bool treeview_keyboard_navigation(treeview *tree, uint32_t key,
- struct rect *rect)
+static bool
+treeview_keyboard_navigation(treeview *tree, uint32_t key, struct rect *rect)
{
struct treeview_nav_state ns = {
.tree = tree,
@@ -2747,26 +3797,35 @@ static bool treeview_keyboard_navigation(treeview *tree, uint32_t key,
.n_selected = 0,
.prev_n_selected = 0
};
- int h = tree->root->height;
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ int h = treeview__get_display_height(tree) + search_height;
bool redraw = false;
/* Fill out the nav. state struct, by examining the current selection
* state */
- treeview_walk_internal(tree->root, false, NULL,
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_nav_cb, &ns);
- if (ns.next == NULL)
- ns.next = tree->root->children;
- if (ns.prev == NULL)
- ns.prev = ns.last;
+
+ if (tree->search.search == false) {
+ if (ns.next == NULL)
+ ns.next = tree->root->children;
+ if (ns.prev == NULL)
+ ns.prev = ns.last;
+ }
/* Clear any existing selection */
redraw = treeview_clear_selection(tree, rect);
switch (key) {
case NS_KEY_LEFT:
+ if (tree->search.search == true) {
+ break;
+ }
if (ns.curr != NULL &&
- ns.curr->parent != NULL &&
- ns.curr->parent->type != TREE_NODE_ROOT) {
+ ns.curr->parent != NULL &&
+ ns.curr->parent->type != TREE_NODE_ROOT) {
/* Step to parent */
ns.curr->parent->flags |= TV_NFLAGS_SELECTED;
@@ -2784,7 +3843,7 @@ static bool treeview_keyboard_navigation(treeview *tree, uint32_t key,
if (ns.curr->children != NULL) {
/* Step to first child */
ns.curr->children->flags |=
- TV_NFLAGS_SELECTED;
+ TV_NFLAGS_SELECTED;
} else {
/* Retain current node selection */
ns.curr->flags |= TV_NFLAGS_SELECTED;
@@ -2824,8 +3883,8 @@ static bool treeview_keyboard_navigation(treeview *tree, uint32_t key,
rect->x0 = 0;
rect->y0 = 0;
rect->x1 = REDRAW_MAX;
- if (tree->root->height > h)
- rect->y1 = tree->root->height;
+ if (treeview__get_display_height(tree) + search_height > h)
+ rect->y1 = treeview__get_display_height(tree) + search_height;
else
rect->y1 = h;
redraw = true;
@@ -2842,7 +3901,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
assert(tree != NULL);
- /* Pass to textarea, if editing in progress */
+ /* Pass to any textarea, if editing in progress */
if (tree->edit.textarea != NULL) {
switch (key) {
case NS_KEY_ESCAPE:
@@ -2855,6 +3914,17 @@ bool treeview_keypress(treeview *tree, uint32_t key)
default:
return textarea_keypress(tree->edit.textarea, key);
}
+ } else if (tree->search.active == true) {
+ switch (key) {
+ case NS_KEY_ESCAPE:
+ treeview__search_cancel(tree, false);
+ return true;
+ case NS_KEY_NL:
+ case NS_KEY_CR:
+ return true;
+ default:
+ return textarea_keypress(tree->search.textarea, key);
+ }
}
/* Keypress to be handled by treeview */
@@ -2878,7 +3948,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
if (tree->root->height != h) {
r.y0 = 0;
treeview__cw_update_size(tree, -1,
- tree->root->height);
+ tree->root->height);
}
}
break;
@@ -2901,7 +3971,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
}
if (redraw) {
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return true;
@@ -2920,9 +3990,14 @@ bool treeview_keypress(treeview *tree, uint32_t key)
* \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
-static bool treeview_set_move_indicator(treeview *tree, bool need_redraw,
- treeview_node *target, int node_height,
- int node_y, int mouse_y, struct rect *rect)
+static bool
+treeview_set_move_indicator(treeview *tree,
+ bool need_redraw,
+ treeview_node *target,
+ int node_height,
+ int node_y,
+ int mouse_y,
+ struct rect *rect)
{
treeview_node *orig = target;
enum treeview_target_pos target_pos;
@@ -2937,44 +4012,44 @@ static bool treeview_set_move_indicator(treeview *tree, bool need_redraw,
if (target->flags & TV_NFLAGS_SELECTED) {
/* Find top selected ancestor */
while (target->parent &&
- target->parent->flags & TV_NFLAGS_SELECTED) {
+ target->parent->flags & TV_NFLAGS_SELECTED) {
target = target->parent;
}
- /* Find top ajdacent selected sibling */
+ /* Find top adjacent selected sibling */
while (target->prev_sib &&
- target->prev_sib->flags & TV_NFLAGS_SELECTED) {
+ target->prev_sib->flags & TV_NFLAGS_SELECTED) {
target = target->prev_sib;
}
target_pos = TV_TARGET_ABOVE;
} else switch (target->type) {
- case TREE_NODE_FOLDER:
- if (mouse_pos <= node_height / 4) {
- target_pos = TV_TARGET_ABOVE;
- } else if (mouse_pos <= (3 * node_height) / 4 ||
- target->flags & TV_NFLAGS_EXPANDED) {
- target_pos = TV_TARGET_INSIDE;
- } else {
- target_pos = TV_TARGET_BELOW;
- }
- break;
+ case TREE_NODE_FOLDER:
+ if (mouse_pos <= node_height / 4) {
+ target_pos = TV_TARGET_ABOVE;
+ } else if (mouse_pos <= (3 * node_height) / 4 ||
+ target->flags & TV_NFLAGS_EXPANDED) {
+ target_pos = TV_TARGET_INSIDE;
+ } else {
+ target_pos = TV_TARGET_BELOW;
+ }
+ break;
- case TREE_NODE_ENTRY:
- if (mouse_pos <= node_height / 2) {
- target_pos = TV_TARGET_ABOVE;
- } else {
- target_pos = TV_TARGET_BELOW;
- }
- break;
+ case TREE_NODE_ENTRY:
+ if (mouse_pos <= node_height / 2) {
+ target_pos = TV_TARGET_ABOVE;
+ } else {
+ target_pos = TV_TARGET_BELOW;
+ }
+ break;
- default:
- assert(target->type != TREE_NODE_ROOT);
- return false;
- }
+ default:
+ assert(target->type != TREE_NODE_ROOT);
+ return false;
+ }
if (target_pos == tree->move.target_pos &&
- target == tree->move.target) {
+ target == tree->move.target) {
/* No change */
return need_redraw;
}
@@ -3008,7 +4083,7 @@ static bool treeview_set_move_indicator(treeview *tree, bool need_redraw,
/* Oftsets are all relative to centred (INSIDE) */
node_y += (tree_g.line_height -
- treeview_res[TREE_RES_ARROW].height + 1) / 2;
+ treeview_res[TREE_RES_ARROW].height + 1) / 2;
x = target->inset + tree_g.move_offset;
@@ -3043,6 +4118,9 @@ static bool treeview_set_move_indicator(treeview *tree, bool need_redraw,
/**
* Callback for textarea_create, in desktop/treeview.h
+ *
+ * \param data treeview context
+ * \param msg textarea message
*/
static void treeview_textarea_callback(void *data, struct textarea_msg *msg)
{
@@ -3069,7 +4147,7 @@ static void treeview_textarea_callback(void *data, struct textarea_msg *msg)
r->y1 += tree->edit.y;
/* Redraw the textarea */
- treeview__cw_redraw_request(tree, r);
+ treeview__cw_invalidate_area(tree, r);
break;
default:
@@ -3081,16 +4159,21 @@ static void treeview_textarea_callback(void *data, struct textarea_msg *msg)
/**
* Start edit of node field, at given y-coord, if editable
*
- * \param tree Treeview object to consider editing in
- * \param n The treeview node to try editing
- * \param node_y The Y coord of the top of n
- * \param mouse_x X coord of mouse position
- * \param mouse_y Y coord of mouse position
- * \param rect Redraw rectangle (if redraw required)
+ * \param tree Treeview object to consider editing in
+ * \param n The treeview node to try editing
+ * \param node_y The Y coord of the top of n
+ * \param mouse_x X coord of mouse position
+ * \param mouse_y Y coord of mouse position
+ * \param rect Redraw rectangle (if redraw required)
* \return true iff redraw required
*/
-static bool treeview_edit_node_at_point(treeview *tree, treeview_node *n,
- int node_y, int mouse_x, int mouse_y, struct rect *rect)
+static bool
+treeview_edit_node_at_point(treeview *tree,
+ treeview_node *n,
+ int node_y,
+ int mouse_x,
+ int mouse_y,
+ struct rect *rect)
{
struct treeview_text *field_data = NULL;
struct treeview_field *ef, *field_desc = NULL;
@@ -3098,8 +4181,6 @@ static bool treeview_edit_node_at_point(treeview *tree, treeview_node *n,
int field_y = node_y;
int field_x;
int width, height;
- textarea_setup ta_setup;
- textarea_flags ta_flags;
bool success;
/* If the main field is editable, make field_data point to it */
@@ -3125,7 +4206,7 @@ static bool treeview_edit_node_at_point(treeview *tree, treeview_node *n,
ef = &(tree->fields[i + 1]);
pos += tree_g.line_height;
if (mouse_y <= pos && (ef->flags &
- TREE_FLAG_ALLOW_EDIT)) {
+ TREE_FLAG_ALLOW_EDIT)) {
field_data = &e->fields[i].value;
field_desc = ef;
field_y = pos - tree_g.line_height;
@@ -3141,31 +4222,15 @@ static bool treeview_edit_node_at_point(treeview *tree, treeview_node *n,
/* Get window width/height */
treeview__cw_get_window_dimensions(tree, &width, &height);
- /* Anow textarea width/height */
+ /* Calculate textarea width/height */
field_x = n->inset + tree_g.step_width + tree_g.icon_step - 3;
width -= field_x;
height = tree_g.line_height;
- /* Configure the textarea */
- ta_flags = TEXTAREA_INTERNAL_CARET;
-
- ta_setup.width = width;
- ta_setup.height = height;
- ta_setup.pad_top = 0;
- ta_setup.pad_right = 2;
- ta_setup.pad_bottom = 0;
- ta_setup.pad_left = 2;
- ta_setup.border_width = 1;
- ta_setup.border_col = 0x000000;
- ta_setup.selected_text = 0xffffff;
- ta_setup.selected_bg = 0x000000;
- ta_setup.text = plot_style_odd.text;
- ta_setup.text.foreground = 0x000000;
- ta_setup.text.background = 0xffffff;
-
/* Create text area */
- tree->edit.textarea = textarea_create(ta_flags, &ta_setup,
- treeview_textarea_callback, tree);
+ tree->edit.textarea = treeview__create_textarea(tree, width, height,
+ 0x000000, 0xffffff, 0x000000, plot_style_odd.text,
+ treeview_textarea_callback);
if (tree->edit.textarea == NULL) {
return false;
}
@@ -3187,8 +4252,8 @@ static bool treeview_edit_node_at_point(treeview *tree, treeview_node *n,
mouse_x = width - 1;
textarea_mouse_action(tree->edit.textarea,
- BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1,
- mouse_x, tree_g.line_height / 2);
+ BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1,
+ mouse_x, tree_g.line_height / 2);
/* Position the textarea */
tree->edit.x = field_x;
@@ -3232,7 +4297,7 @@ void treeview_edit_selection(treeview *tree)
/* Edit node at y */
redraw = treeview_edit_node_at_point(tree, n, y,
- 0, y + tree_g.line_height / 2, &rect);
+ 0, y + tree_g.line_height / 2, &rect);
if (redraw == false)
return;
@@ -3242,20 +4307,37 @@ void treeview_edit_selection(treeview *tree)
rect.y0 = y;
rect.x1 = REDRAW_MAX;
rect.y1 = y + tree_g.line_height;
- treeview__cw_redraw_request(tree, &rect);
+ treeview__cw_invalidate_area(tree, &rect);
}
+/**
+ * context for treeview mouse handling
+ */
struct treeview_mouse_action {
treeview *tree;
browser_mouse_state mouse;
int x;
int y;
int current_y; /* Y coordinate value of top of current node */
+ int search_height;
};
-/** Treewalk node callback for handling mouse action. */
-static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
- bool *skip_children, bool *end)
+
+
+/**
+ * Treewalk node callback for handling mouse action.
+ *
+ * \param node current node
+ * \param ctx node context
+ * \param skip_children flag to allow children to be skipped
+ * \param end flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+treeview_node_mouse_action_cb(treeview_node *node,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
{
struct treeview_mouse_action *ma = ctx;
struct rect r;
@@ -3273,7 +4355,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
r.x1 = REDRAW_MAX;
height = (node->type == TREE_NODE_ENTRY) ? node->height :
- tree_g.line_height;
+ tree_g.line_height;
/* Skip line if we've not reached mouse y */
if (ma->y > ma->current_y + height) {
@@ -3283,25 +4365,29 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
/* Find where the mouse is */
if (ma->y <= ma->current_y + tree_g.line_height) {
- if (ma->x >= node->inset - 1 &&
- ma->x < node->inset + tree_g.step_width) {
+ int inset = node->inset;
+ if (ma->tree->search.search == true) {
+ inset = tree_g.window_padding;
+ }
+ if (ma->x >= inset - 1 &&
+ ma->x < inset + tree_g.step_width) {
/* Over expansion toggle */
part = TV_NODE_PART_TOGGLE;
- } else if (ma->x >= node->inset + tree_g.step_width &&
- ma->x < node->inset + tree_g.step_width +
+ } else if (ma->x >= inset + tree_g.step_width &&
+ ma->x < inset + tree_g.step_width +
tree_g.icon_step + node->text.width) {
/* On node */
part = TV_NODE_PART_ON_NODE;
}
} else if (node->type == TREE_NODE_ENTRY &&
- height > tree_g.line_height) {
+ height > tree_g.line_height) {
/* Expanded entries */
int x = node->inset + tree_g.step_width + tree_g.icon_step;
int y = ma->current_y + tree_g.line_height;
int i;
struct treeview_node_entry *entry =
- (struct treeview_node_entry *)node;
+ (struct treeview_node_entry *)node;
for (i = 0; i < ma->tree->n_fields - 1; i++) {
struct treeview_field *ef = &(ma->tree->fields[i + 1]);
@@ -3314,21 +4400,21 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
int max_width = ma->tree->field_width;
if (ma->x >= x + max_width - ef->value.width -
- tree_g.step_width &&
- ma->x < x + max_width -
- tree_g.step_width) {
+ tree_g.step_width &&
+ ma->x < x + max_width -
+ tree_g.step_width) {
/* On a field name */
part = TV_NODE_PART_ON_NODE;
} else if (ma->x >= x + max_width &&
- ma->x < x + max_width +
- entry->fields[i].value.width) {
+ ma->x < x + max_width +
+ entry->fields[i].value.width) {
/* On a field value */
part = TV_NODE_PART_ON_NODE;
}
} else {
if (ma->x >= x && ma->x < x +
- entry->fields[i].value.width) {
+ entry->fields[i].value.width) {
/* On a field value */
part = TV_NODE_PART_ON_NODE;
}
@@ -3340,7 +4426,7 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
/* Record what position / part a drag started on */
if (ma->mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
- ma->tree->drag.type == TV_DRAG_NONE) {
+ ma->tree->drag.type == TV_DRAG_NONE) {
ma->tree->drag.selected = node->flags & TV_NFLAGS_SELECTED;
ma->tree->drag.start_node = node;
ma->tree->drag.part = part;
@@ -3358,29 +4444,30 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
/* Handle drag start */
if (ma->tree->drag.type == TV_DRAG_NONE) {
if (ma->mouse & BROWSER_MOUSE_DRAG_1 &&
- ma->tree->drag.selected == false &&
- ma->tree->drag.part == TV_NODE_PART_NONE) {
+ ma->tree->drag.selected == false &&
+ ma->tree->drag.part == TV_NODE_PART_NONE) {
ma->tree->drag.type = TV_DRAG_SELECTION;
treeview__cw_drag_status(ma->tree,
- CORE_WINDOW_DRAG_SELECTION);
+ CORE_WINDOW_DRAG_SELECTION);
- } else if (!(ma->tree->flags & TREEVIEW_NO_MOVES) &&
- ma->mouse & BROWSER_MOUSE_DRAG_1 &&
- (ma->tree->drag.selected == true ||
- ma->tree->drag.part == TV_NODE_PART_ON_NODE)) {
+ } else if (ma->tree->search.search == false &&
+ !(ma->tree->flags & TREEVIEW_NO_MOVES) &&
+ ma->mouse & BROWSER_MOUSE_DRAG_1 &&
+ (ma->tree->drag.selected == true ||
+ ma->tree->drag.part == TV_NODE_PART_ON_NODE)) {
ma->tree->drag.type = TV_DRAG_MOVE;
treeview__cw_drag_status(ma->tree,
- CORE_WINDOW_DRAG_MOVE);
+ CORE_WINDOW_DRAG_MOVE);
redraw |= treeview_propagate_selection(ma->tree, &r);
} else if (ma->mouse & BROWSER_MOUSE_DRAG_2) {
ma->tree->drag.type = TV_DRAG_SELECTION;
treeview__cw_drag_status(ma->tree,
- CORE_WINDOW_DRAG_SELECTION);
+ CORE_WINDOW_DRAG_SELECTION);
}
if (ma->tree->drag.start_node != NULL &&
- ma->tree->drag.type == TV_DRAG_SELECTION) {
+ ma->tree->drag.type == TV_DRAG_SELECTION) {
ma->tree->drag.start_node->flags ^= TV_NFLAGS_SELECTED;
}
}
@@ -3391,10 +4478,10 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
{
int curr_y1 = ma->current_y + height;
int prev_y1 = ma->tree->drag.prev.node_y +
- ma->tree->drag.prev.node_h;
+ ma->tree->drag.prev.node_h;
r.y0 = (ma->current_y < ma->tree->drag.prev.node_y) ?
- ma->current_y : ma->tree->drag.prev.node_y;
+ ma->current_y : ma->tree->drag.prev.node_y;
r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
redraw = true;
@@ -3408,7 +4495,8 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
case TV_DRAG_MOVE:
redraw |= treeview_set_move_indicator(ma->tree, redraw,
- node, height, ma->current_y, ma->y, &r);
+ node, height,
+ ma->current_y, ma->y, &r);
break;
default:
@@ -3418,9 +4506,10 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
click = ma->mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2);
if (((node->type == TREE_NODE_FOLDER) &&
- (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) ||
- (part == TV_NODE_PART_TOGGLE && click)) {
- int h = ma->tree->root->height;
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) ||
+ (part == TV_NODE_PART_TOGGLE && click)) {
+ int h = treeview__get_display_height(ma->tree) +
+ ma->search_height;
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
@@ -3438,11 +4527,17 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
/* Set up redraw */
if (!redraw || r.y0 > ma->current_y)
r.y0 = ma->current_y;
- r.y1 = h > ma->tree->root->height ? h : ma->tree->root->height;
+ if (h > treeview__get_display_height(ma->tree) +
+ ma->search_height) {
+ r.y1 = h;
+ } else {
+ r.y1 = treeview__get_display_height(ma->tree) +
+ ma->search_height;
+ }
redraw = true;
} else if ((node->type == TREE_NODE_ENTRY) &&
- (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
+ (ma->mouse & BROWSER_MOUSE_DOUBLE_CLICK) && click) {
struct treeview_node_msg msg;
msg.msg = TREE_MSG_NODE_LAUNCH;
msg.data.node_launch.mouse = ma->mouse;
@@ -3454,28 +4549,29 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
ma->tree->callbacks->entry(msg, node->client_data);
} else if (ma->mouse & BROWSER_MOUSE_PRESS_2 ||
- (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
- ma->mouse & BROWSER_MOUSE_MOD_2)) {
+ (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
+ ma->mouse & BROWSER_MOUSE_MOD_2)) {
/* Toggle selection of node */
action |= TV_NODE_ACTION_SELECTION;
} else if (ma->mouse & BROWSER_MOUSE_CLICK_1 &&
- ma->mouse &
- (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_3) &&
- part != TV_NODE_PART_TOGGLE) {
+ ma->mouse &
+ (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_3) &&
+ part != TV_NODE_PART_TOGGLE) {
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
/* Edit node */
redraw |= treeview_edit_node_at_point(ma->tree, node,
- ma->current_y, ma->x, ma->y, &r);
+ ma->current_y, ma->x,
+ ma->y, &r);
} else if (ma->mouse & BROWSER_MOUSE_PRESS_1 &&
- !(ma->mouse &
- (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_3)) &&
- !(node->flags & TV_NFLAGS_SELECTED) &&
- part != TV_NODE_PART_TOGGLE) {
+ !(ma->mouse &
+ (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_3)) &&
+ !(node->flags & TV_NFLAGS_SELECTED) &&
+ part != TV_NODE_PART_TOGGLE) {
/* Clear any existing selection */
redraw |= treeview_clear_selection(ma->tree, &r);
@@ -3494,35 +4590,69 @@ static nserror treeview_node_mouse_action_cb(treeview_node *node, void *ctx,
r.y1 = ma->current_y + height;
redraw = true;
} else {
- if (r.y0 > ma->current_y)
+ if (r.y0 > ma->current_y) {
r.y0 = ma->current_y;
- if (r.y1 < ma->current_y + height)
+ }
+ if (r.y1 < ma->current_y + height) {
r.y1 = ma->current_y + height;
+ }
}
}
if (redraw) {
- treeview__cw_redraw_request(ma->tree, &r);
+ treeview__cw_invalidate_area(ma->tree, &r);
}
*end = true; /* Reached line with click; stop walking tree */
return NSERROR_OK;
}
+
+
/* Exported interface, documented in treeview.h */
-void treeview_mouse_action(treeview *tree,
- browser_mouse_state mouse, int x, int y)
+void
+treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
{
struct rect r;
bool redraw = false;
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
assert(tree != NULL);
assert(tree->root != NULL);
+ /* Not interested in whether mouse leaves window. */
+ if (mouse == BROWSER_MOUSE_LEAVE) {
+ return;
+ }
+
/* Handle mouse drag captured by textarea */
if (tree->drag.type == TV_DRAG_TEXTAREA) {
textarea_mouse_action(tree->edit.textarea, mouse,
- x - tree->edit.x, y - tree->edit.y);
+ x - tree->edit.x, y - tree->edit.y);
+ return;
+ } else if (tree->drag.type == TV_DRAG_SEARCH ||
+ (y < search_height &&
+ tree->drag.type == TV_DRAG_NONE)) {
+ if (tree->search.active == false) {
+ tree->search.active = true;
+ if (treeview_clear_selection(tree, &r)) {
+ treeview__cw_invalidate_area(tree, &r);
+ }
+ }
+ textarea_mouse_action(tree->search.textarea, mouse,
+ x - tree_g.window_padding - tree_g.icon_size,
+ y);
return;
+ } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->search.active == true) {
+
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ r.x0 = 0;
+ r.y0 = 0;
+ r.x1 = REDRAW_MAX;
+ r.y1 = tree_g.line_height;
+ treeview__cw_invalidate_area(tree, &r);
}
/* Handle textarea related mouse action */
@@ -3531,10 +4661,10 @@ void treeview_mouse_action(treeview *tree,
int ta_y = y - tree->edit.y;
if (ta_x > 0 && ta_x < tree->edit.w &&
- ta_y > 0 && ta_y < tree->edit.h) {
+ ta_y > 0 && ta_y < tree->edit.h) {
/* Inside textarea */
textarea_mouse_action(tree->edit.textarea, mouse,
- ta_x, ta_y);
+ ta_x, ta_y);
return;
} else if (mouse != BROWSER_MOUSE_HOVER) {
@@ -3562,7 +4692,7 @@ void treeview_mouse_action(treeview *tree,
tree->move.target_pos = TV_TARGET_NONE;
treeview__cw_drag_status(tree, CORE_WINDOW_DRAG_NONE);
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
return;
default:
/* No drag to end */
@@ -3570,7 +4700,7 @@ void treeview_mouse_action(treeview *tree,
}
}
- if (y > tree->root->height) {
+ if (y > treeview__get_display_height(tree) + search_height) {
/* Below tree */
r.x0 = 0;
@@ -3578,7 +4708,7 @@ void treeview_mouse_action(treeview *tree,
/* Record what position / part a drag started on */
if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
- tree->drag.type == TV_DRAG_NONE) {
+ tree->drag.type == TV_DRAG_NONE) {
tree->drag.selected = false;
tree->drag.start_node = NULL;
tree->drag.part = TV_NODE_PART_NONE;
@@ -3596,8 +4726,8 @@ void treeview_mouse_action(treeview *tree,
/* Handle drag start */
if (tree->drag.type == TV_DRAG_NONE) {
if (mouse & BROWSER_MOUSE_DRAG_1 &&
- tree->drag.selected == false &&
- tree->drag.part == TV_NODE_PART_NONE) {
+ tree->drag.selected == false &&
+ tree->drag.part == TV_NODE_PART_NONE) {
tree->drag.type = TV_DRAG_SELECTION;
treeview__cw_drag_status(tree,
CORE_WINDOW_DRAG_SELECTION);
@@ -3608,9 +4738,9 @@ void treeview_mouse_action(treeview *tree,
}
if (tree->drag.start_node != NULL &&
- tree->drag.type == TV_DRAG_SELECTION) {
+ tree->drag.type == TV_DRAG_SELECTION) {
tree->drag.start_node->flags ^=
- TV_NFLAGS_SELECTED;
+ TV_NFLAGS_SELECTED;
}
}
@@ -3618,7 +4748,7 @@ void treeview_mouse_action(treeview *tree,
if (tree->drag.type == TV_DRAG_SELECTION) {
int curr_y1 = tree->root->height;
int prev_y1 = tree->drag.prev.node_y +
- tree->drag.prev.node_h;
+ tree->drag.prev.node_h;
r.y0 = tree->drag.prev.node_y;
r.y1 = (curr_y1 > prev_y1) ? curr_y1 : prev_y1;
@@ -3637,20 +4767,22 @@ void treeview_mouse_action(treeview *tree,
}
if (redraw) {
- treeview__cw_redraw_request(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
} else {
/* On tree */
- struct treeview_mouse_action ma;
-
- ma.tree = tree;
- ma.mouse = mouse;
- ma.x = x;
- ma.y = y;
- ma.current_y = 0;
-
- treeview_walk_internal(tree->root, false, NULL,
+ struct treeview_mouse_action ma = {
+ ma.tree = tree,
+ ma.mouse = mouse,
+ ma.x = x,
+ ma.y = y,
+ ma.current_y = search_height,
+ ma.search_height = search_height,
+ };
+
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
treeview_node_mouse_action_cb, &ma);
}
}
@@ -3659,78 +4791,111 @@ void treeview_mouse_action(treeview *tree,
/* Exported interface, documented in treeview.h */
int treeview_get_height(treeview *tree)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ int height = treeview__get_display_height(tree);
+
assert(tree != NULL);
assert(tree->root != NULL);
- treeview__cw_update_size(tree, -1, tree->root->height);
+ treeview__cw_update_size(tree, -1, height);
- return tree->root->height;
+ return height + search_height;
}
/**
* Initialise the plot styles from CSS system colour values.
+ *
+ * \param font_pt_size font size to use
+ * \return NSERROR_OK on success else appropriate error code
*/
-static void treeview_init_plot_styles(int font_pt_size)
+static nserror treeview_init_plot_styles(int font_pt_size)
{
+ nserror res;
+
/* Background colour */
plot_style_even.bg.stroke_type = PLOT_OP_TYPE_NONE;
plot_style_even.bg.stroke_width = 0;
plot_style_even.bg.stroke_colour = 0;
plot_style_even.bg.fill_type = PLOT_OP_TYPE_SOLID;
- plot_style_even.bg.fill_colour = ns_system_colour_char("Window");
+ res = ns_system_colour_char("Window", &plot_style_even.bg.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
/* Text colour */
plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF;
plot_style_even.text.size = font_pt_size;
plot_style_even.text.weight = 400;
plot_style_even.text.flags = FONTF_NONE;
- plot_style_even.text.foreground = ns_system_colour_char("WindowText");
- plot_style_even.text.background = ns_system_colour_char("Window");
+ res = ns_system_colour_char("WindowText", &plot_style_even.text.foreground);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ res = ns_system_colour_char("Window", &plot_style_even.text.background);
+ if (res != NSERROR_OK) {
+ return res;
+ }
/* Entry field text colour */
plot_style_even.itext = plot_style_even.text;
plot_style_even.itext.foreground = mix_colour(
- plot_style_even.text.foreground,
- plot_style_even.text.background, 255 * 10 / 16);
+ plot_style_even.text.foreground,
+ plot_style_even.text.background,
+ 255 * 10 / 16);
/* Selected background colour */
plot_style_even.sbg = plot_style_even.bg;
- plot_style_even.sbg.fill_colour = ns_system_colour_char("Highlight");
+ res = ns_system_colour_char("Highlight", &plot_style_even.sbg.fill_colour);
+ if (res != NSERROR_OK) {
+ return res;
+ }
/* Selected text colour */
plot_style_even.stext = plot_style_even.text;
- plot_style_even.stext.foreground =
- ns_system_colour_char("HighlightText");
- plot_style_even.stext.background = ns_system_colour_char("Highlight");
+ res = ns_system_colour_char("HighlightText", &plot_style_even.stext.foreground);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ res = ns_system_colour_char("Highlight", &plot_style_even.stext.background);
+ if (res != NSERROR_OK) {
+ return res;
+ }
/* Selected entry field text colour */
plot_style_even.sitext = plot_style_even.stext;
plot_style_even.sitext.foreground = mix_colour(
- plot_style_even.stext.foreground,
- plot_style_even.stext.background, 255 * 25 / 32);
-
+ plot_style_even.stext.foreground,
+ plot_style_even.stext.background,
+ 255 * 25 / 32);
/* Odd numbered node styles */
plot_style_odd.bg = plot_style_even.bg;
plot_style_odd.bg.fill_colour = mix_colour(
- plot_style_even.bg.fill_colour,
- plot_style_even.text.foreground, 255 * 15 / 16);
+ plot_style_even.bg.fill_colour,
+ plot_style_even.text.foreground, 255 * 15 / 16);
plot_style_odd.text = plot_style_even.text;
plot_style_odd.text.background = plot_style_odd.bg.fill_colour;
plot_style_odd.itext = plot_style_odd.text;
plot_style_odd.itext.foreground = mix_colour(
- plot_style_odd.text.foreground,
- plot_style_odd.text.background, 255 * 10 / 16);
+ plot_style_odd.text.foreground,
+ plot_style_odd.text.background, 255 * 10 / 16);
plot_style_odd.sbg = plot_style_even.sbg;
plot_style_odd.stext = plot_style_even.stext;
plot_style_odd.sitext = plot_style_even.sitext;
+
+ return NSERROR_OK;
}
/**
- * Callback for hlcache.
+ * Callback for hlcache retrieving resources.
+ *
+ * \param handle content hlcache handle
+ * \param event The event that occurred on the content
+ * \param pw treeview resource context
*/
static nserror
treeview_res_cb(struct hlcache_handle *handle,
@@ -3767,9 +4932,10 @@ static void treeview_init_resources(void)
treeview_res[i].height = 0;
if (nsurl_create(treeview_res[i].url, &url) == NSERROR_OK) {
hlcache_handle_retrieve(url, 0, NULL, NULL,
- treeview_res_cb,
- &(treeview_res[i]), NULL,
- CONTENT_IMAGE, &(treeview_res[i].c));
+ treeview_res_cb,
+ &(treeview_res[i]), NULL,
+ CONTENT_IMAGE,
+ &(treeview_res[i].c));
nsurl_unref(url);
}
}
@@ -3779,12 +4945,12 @@ static void treeview_init_resources(void)
/**
* Create a right-pointing anti-aliased triangle bitmap
*
- * bg background colour
- * fg foreground colour
- * size required bitmap size
+ * \param bg background colour
+ * \param fg foreground colour
+ * \param size required bitmap size
*/
-static struct bitmap * treeview_generate_triangle_bitmap(
- colour bg, colour fg, int size)
+static struct bitmap *
+treeview_generate_triangle_bitmap(colour bg, colour fg, int size)
{
struct bitmap *b = NULL;
int x, y;
@@ -3881,11 +5047,11 @@ static struct bitmap * treeview_generate_triangle_bitmap(
/**
* Create bitmap copy of another bitmap
*
- * orig bitmap to copy
- * size required bitmap size
+ * \param orig bitmap to copy
+ * \param size required bitmap size
*/
-static struct bitmap * treeview_generate_copy_bitmap(
- struct bitmap *orig, int size)
+static struct bitmap *
+treeview_generate_copy_bitmap(struct bitmap *orig, int size)
{
struct bitmap *b = NULL;
unsigned char *data;
@@ -3926,11 +5092,11 @@ static struct bitmap * treeview_generate_copy_bitmap(
/**
* Create bitmap from rotation of another bitmap
*
- * orig bitmap to create rotation of
- * size required bitmap size
+ * \param orig bitmap to create rotation of
+ * \param size required bitmap size
*/
-static struct bitmap * treeview_generate_rotate_bitmap(
- struct bitmap *orig, int size)
+static struct bitmap *
+treeview_generate_rotate_bitmap(struct bitmap *orig, int size)
{
struct bitmap *b = NULL;
int x, y;
@@ -3967,7 +5133,7 @@ static struct bitmap * treeview_generate_rotate_bitmap(
*(pos++) = *(orig_pos++);
*(pos++) = *(orig_pos);
*(pos++) = 0xff;
-
+
}
rpos += stride;
@@ -3987,6 +5153,8 @@ static struct bitmap * treeview_generate_rotate_bitmap(
/**
* Measures width of characters used to represent treeview furniture.
+ *
+ * \return NSERROR_OK on success else error code
*/
static nserror treeview_init_furniture(void)
{
@@ -3994,47 +5162,47 @@ static nserror treeview_init_furniture(void)
plot_style_odd.furn[TREE_FURN_EXPAND].size = size;
plot_style_odd.furn[TREE_FURN_EXPAND].bmp =
- treeview_generate_triangle_bitmap(
+ treeview_generate_triangle_bitmap(
plot_style_odd.bg.fill_colour,
plot_style_odd.itext.foreground, size);
plot_style_odd.furn[TREE_FURN_EXPAND].sel =
- treeview_generate_triangle_bitmap(
+ treeview_generate_triangle_bitmap(
plot_style_odd.sbg.fill_colour,
plot_style_odd.sitext.foreground, size);
plot_style_even.furn[TREE_FURN_EXPAND].size = size;
plot_style_even.furn[TREE_FURN_EXPAND].bmp =
- treeview_generate_triangle_bitmap(
+ treeview_generate_triangle_bitmap(
plot_style_even.bg.fill_colour,
plot_style_even.itext.foreground, size);
plot_style_even.furn[TREE_FURN_EXPAND].sel =
- treeview_generate_copy_bitmap(
+ treeview_generate_copy_bitmap(
plot_style_odd.furn[TREE_FURN_EXPAND].sel, size);
plot_style_odd.furn[TREE_FURN_CONTRACT].size = size;
plot_style_odd.furn[TREE_FURN_CONTRACT].bmp =
- treeview_generate_rotate_bitmap(
+ treeview_generate_rotate_bitmap(
plot_style_odd.furn[TREE_FURN_EXPAND].bmp, size);
plot_style_odd.furn[TREE_FURN_CONTRACT].sel =
- treeview_generate_rotate_bitmap(
+ treeview_generate_rotate_bitmap(
plot_style_odd.furn[TREE_FURN_EXPAND].sel, size);
plot_style_even.furn[TREE_FURN_CONTRACT].size = size;
plot_style_even.furn[TREE_FURN_CONTRACT].bmp =
- treeview_generate_rotate_bitmap(
+ treeview_generate_rotate_bitmap(
plot_style_even.furn[TREE_FURN_EXPAND].bmp, size);
plot_style_even.furn[TREE_FURN_CONTRACT].sel =
- treeview_generate_rotate_bitmap(
+ treeview_generate_rotate_bitmap(
plot_style_even.furn[TREE_FURN_EXPAND].sel, size);
if (plot_style_odd.furn[TREE_FURN_EXPAND].bmp == NULL ||
- plot_style_odd.furn[TREE_FURN_EXPAND].sel == NULL ||
- plot_style_even.furn[TREE_FURN_EXPAND].bmp == NULL ||
- plot_style_even.furn[TREE_FURN_EXPAND].sel == NULL ||
- plot_style_odd.furn[TREE_FURN_CONTRACT].bmp == NULL ||
- plot_style_odd.furn[TREE_FURN_CONTRACT].sel == NULL ||
- plot_style_even.furn[TREE_FURN_CONTRACT].bmp == NULL ||
- plot_style_even.furn[TREE_FURN_CONTRACT].sel == NULL)
+ plot_style_odd.furn[TREE_FURN_EXPAND].sel == NULL ||
+ plot_style_even.furn[TREE_FURN_EXPAND].bmp == NULL ||
+ plot_style_even.furn[TREE_FURN_EXPAND].sel == NULL ||
+ plot_style_odd.furn[TREE_FURN_CONTRACT].bmp == NULL ||
+ plot_style_odd.furn[TREE_FURN_CONTRACT].sel == NULL ||
+ plot_style_even.furn[TREE_FURN_CONTRACT].bmp == NULL ||
+ plot_style_even.furn[TREE_FURN_CONTRACT].sel == NULL)
return NSERROR_NOMEM;
tree_g.furniture_width = size + tree_g.line_height / 4;
@@ -4048,14 +5216,14 @@ nserror treeview_init(void)
{
long long font_px_size;
long long font_pt_size;
- nserror err;
+ nserror res;
if (tree_g.initialised > 0) {
tree_g.initialised++;
return NSERROR_OK;
}
- LOG("Initialising treeview module");
+ NSLOG(netsurf, INFO, "Initialising treeview module");
font_pt_size = nsoption_int(treeview_font_size);
if (font_pt_size <= 0) {
@@ -4066,11 +5234,17 @@ nserror treeview_init(void)
10 + 36) / 72;
tree_g.line_height = (font_px_size * 8 + 3) / 6;
- treeview_init_plot_styles(font_pt_size * FONT_SIZE_SCALE / 10);
+ res = treeview_init_plot_styles(font_pt_size * PLOT_STYLE_SCALE / 10);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
treeview_init_resources();
- err = treeview_init_furniture();
- if (err != NSERROR_OK)
- return err;
+
+ res = treeview_init_furniture();
+ if (res != NSERROR_OK) {
+ return res;
+ }
tree_g.step_width = tree_g.furniture_width;
tree_g.window_padding = 6;
@@ -4080,7 +5254,7 @@ nserror treeview_init(void)
tree_g.initialised++;
- LOG("Initialised treeview module");
+ NSLOG(netsurf, INFO, "Initialised treeview module");
return NSERROR_OK;
}
@@ -4096,11 +5270,12 @@ nserror treeview_fini(void)
return NSERROR_OK;
} else if (tree_g.initialised == 0) {
- LOG("Warning: tried to finalise uninitialised treeview module");
+ NSLOG(netsurf, INFO,
+ "Warning: tried to finalise uninitialised treeview module");
return NSERROR_OK;
}
- LOG("Finalising treeview module");
+ NSLOG(netsurf, INFO, "Finalising treeview module");
for (i = 0; i < TREE_RES_LAST; i++) {
hlcache_handle_release(treeview_res[i].c);
@@ -4117,7 +5292,7 @@ nserror treeview_fini(void)
tree_g.initialised--;
- LOG("Finalised treeview module");
+ NSLOG(netsurf, INFO, "Finalised treeview module");
return NSERROR_OK;
}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 518f045aa..a8cf29ac5 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -37,6 +37,10 @@ struct core_window_callback_table;
typedef struct treeview treeview;
typedef struct treeview_node treeview_node;
+
+/**
+ * treeview node type
+ */
enum treeview_node_type {
TREE_NODE_NONE = 0, /**< No node */
TREE_NODE_ROOT = (1 << 0), /**< Node is treeview's root */
@@ -44,40 +48,60 @@ enum treeview_node_type {
TREE_NODE_ENTRY = (1 << 2) /**< Node is an entry */
};
+
+/**
+ * Relationship between nodes
+ */
enum treeview_relationship {
TREE_REL_FIRST_CHILD,
TREE_REL_NEXT_SIBLING
-}; /**< Relationship between nodes */
+};
+
+/**
+ * Node change handling options
+ */
typedef enum {
TREE_OPTION_NONE = (0), /* No flags set */
TREE_OPTION_SPECIAL_DIR = (1 << 0), /* Special folder */
TREE_OPTION_SUPPRESS_RESIZE = (1 << 1), /* Suppress callback */
TREE_OPTION_SUPPRESS_REDRAW = (1 << 2) /* Suppress callback */
-} treeview_node_options_flags; /**< Node change handling options */
+} treeview_node_options_flags;
+/**
+ * treeview control flags
+ */
typedef enum {
TREEVIEW_NO_FLAGS = (0), /**< No flags set */
TREEVIEW_NO_MOVES = (1 << 0), /**< No node drags */
TREEVIEW_NO_DELETES = (1 << 1), /**< No node deletes */
TREEVIEW_READ_ONLY = TREEVIEW_NO_MOVES | TREEVIEW_NO_DELETES,
- TREEVIEW_DEL_EMPTY_DIRS = (1 << 2) /**< Delete dirs on empty */
+ TREEVIEW_DEL_EMPTY_DIRS = (1 << 2), /**< Delete dirs on empty */
+ TREEVIEW_SEARCHABLE = (1 << 3), /**< Treeview has search bar */
} treeview_flags;
+/**
+ * treeview message types
+ */
enum treeview_msg {
TREE_MSG_NODE_DELETE, /**< Node to be deleted */
TREE_MSG_NODE_EDIT, /**< Node to be edited */
TREE_MSG_NODE_LAUNCH /**< Node to be launched */
};
+
+
+/**
+ * treeview message
+ */
struct treeview_node_msg {
enum treeview_msg msg; /**< The message type */
union {
struct {
- bool user; /* True iff delete by user interaction */
+ bool user; /**< True iff delete by user interaction */
} delete;
struct {
- lwc_string *field; /* The field being edited */
- const char *text; /* The proposed new value */
+ lwc_string *field; /**< The field being edited */
+ const char *text; /**< The proposed new value */
} node_edit; /* Client may call treeview_update_node_* */
struct {
browser_mouse_state mouse; /* Button / modifier used */
@@ -85,18 +109,32 @@ struct treeview_node_msg {
} data; /**< The message data. */
};
+
+/**
+ * treeview field flags
+ */
enum treeview_field_flags {
- TREE_FLAG_NONE = 0, /**< No flags set */
- TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
- TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
- TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
- TREE_FLAG_COPY_TEXT = (1 << 3) /**< Whether to copy to clipb */
+ TREE_FLAG_NONE = 0, /**< No flags set */
+ TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
+ TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
+ TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
+ TREE_FLAG_COPY_TEXT = (1 << 3), /**< Whether to copy to clipb */
+ TREE_FLAG_SEARCHABLE = (1 << 4), /**< Whether field is searchable */
};
+
+
+/**
+ * Treeview field description
+ */
struct treeview_field_desc {
lwc_string *field; /**< A treeview field name */
enum treeview_field_flags flags; /**< Flags for field */
-}; /**< Treeview field description */
+};
+
+/**
+ * Treeview field data
+ */
struct treeview_field_data {
lwc_string *field; /**< Field name */
const char *value; /**< Field value */
@@ -104,10 +142,14 @@ struct treeview_field_data {
};
+/**
+ * Client callbacks for events concerning nodes
+ */
struct treeview_callback_table {
nserror (*folder)(struct treeview_node_msg msg, void *data);
nserror (*entry)(struct treeview_node_msg msg, void *data);
-}; /**< Client callbacks for events concerning nodes */
+};
+
/**
* Prepare treeview module for treeview usage
@@ -116,6 +158,7 @@ struct treeview_callback_table {
*/
nserror treeview_init(void);
+
/**
* Finalise the treeview module (all treeviews must have been destroyed first)
*
@@ -123,9 +166,18 @@ nserror treeview_init(void);
*/
nserror treeview_fini(void);
+
/**
* Create a treeview
*
+ * The fields array order is as follows (N = n_fields):
+ *
+ * fields[0] Main field for entries (shown when not expanded)
+ * fields[1]...fields[N-2] Additional fields for entries
+ * fields[N-1] Field for folder nodes
+ *
+ * So fields[0] and fields[N-1] have TREE_FLAG_DEFAULT set.
+ *
* \param tree Returns created treeview object
* \param callbacks Treeview client node event callbacks
* \param n_fields Number of treeview fields (see description)
@@ -134,20 +186,13 @@ nserror treeview_fini(void);
* \param cw The core_window in which the treeview is shown
* \param flags Treeview behaviour flags
* \return NSERROR_OK on success, appropriate error otherwise
- *
- * The fields array order is as follows (N = n_fields):
- *
- * fields[0] Main field for entries (shown when not expanded)
- * fields[1]...fields[N-2] Additional fields for entries
- * fields[N-1] Field for folder nodes
- *
- * So fields[0] and fields[N-1] have TREE_FLAG_DEFAULT set.
*/
nserror treeview_create(treeview **tree,
- const struct treeview_callback_table *callbacks,
- int n_fields, struct treeview_field_desc fields[],
- const struct core_window_callback_table *cw_t,
- struct core_window *cw, treeview_flags flags);
+ const struct treeview_callback_table *callbacks,
+ int n_fields, struct treeview_field_desc fields[],
+ const struct core_window_callback_table *cw_t,
+ struct core_window *cw, treeview_flags flags);
+
/**
* Attach a treeview to a corewindow.
@@ -160,45 +205,50 @@ nserror treeview_create(treeview **tree,
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror treeview_cw_attach(treeview *tree,
- const struct core_window_callback_table *cw_t,
- struct core_window *cw);
+ const struct core_window_callback_table *cw_t,
+ struct core_window *cw);
+
/**
* Detach a treeview from a corewindow
*
- * \param tree Treeview object
+ * \param tree Treeview object
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror treeview_cw_detach(treeview *tree);
+
/**
* Destroy a treeview object
*
- * \param tree Treeview object to destroy
- * \return NSERROR_OK on success, appropriate error otherwise
- *
* Will emit folder and entry deletion msg callbacks for all nodes in treeview.
+ *
+ * \param tree Treeview object to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
nserror treeview_destroy(treeview *tree);
+
/**
- * Find a releation for node creation.
- *
- * \param tree Treeview object in which to create folder
- * \param relation Existing node to insert as relation of, or NULL
- * \param rel Folder's relationship to relation
- * \param at_y Iff true, insert at y-offest
- * \param y Y-offset in px from top of hotlist. Ignored if (!at_y).
- * \return NSERROR_OK on success, appropriate error otherwise
+ * Find a relation for node creation.
*
* If at_y is set, we find a relation that will put the created node at that
* position.
*
* If at_y is unset, we find a relation that would put the node below the first
* selected node, or at the end of the treeview if no nodes selected.
+ *
+ * \param tree Treeview object in which to create folder
+ * \param relation Existing node to insert as relation of, or NULL
+ * \param rel Folder's relationship to relation
+ * \param at_y Iff true, insert at y-offset
+ * \param y Y-offset in px from top of hotlist. Ignored if (!at_y).
+ * \return NSERROR_OK on success, appropriate error otherwise
*/
nserror treeview_get_relation(treeview *tree, treeview_node **relation,
- enum treeview_relationship *rel, bool at_y, int y);
+ enum treeview_relationship *rel,
+ bool at_y, int y);
+
/**
* Create a folder node in given treeview
@@ -217,11 +267,13 @@ nserror treeview_get_relation(treeview *tree, treeview_node **relation,
* If relation is NULL, will insert as child of root node.
*/
nserror treeview_create_node_folder(treeview *tree,
- treeview_node **folder,
- treeview_node *relation,
- enum treeview_relationship rel,
- const struct treeview_field_data *field,
- void *data, treeview_node_options_flags flags);
+ treeview_node **folder,
+ treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data *field,
+ void *data,
+ treeview_node_options_flags flags);
+
/**
* Create an entry node in given treeview
@@ -240,11 +292,13 @@ nserror treeview_create_node_folder(treeview *tree,
* If relation is NULL, will insert as child of root node.
*/
nserror treeview_create_node_entry(treeview *tree,
- treeview_node **entry,
- treeview_node *relation,
- enum treeview_relationship rel,
- const struct treeview_field_data fields[],
- void *data, treeview_node_options_flags flags);
+ treeview_node **entry,
+ treeview_node *relation,
+ enum treeview_relationship rel,
+ const struct treeview_field_data fields[],
+ void *data,
+ treeview_node_options_flags flags);
+
/**
* Update an folder node in given treeview
@@ -258,9 +312,10 @@ nserror treeview_create_node_entry(treeview *tree,
* Field name must match name past in treeview_create fields[N-1].
*/
nserror treeview_update_node_folder(treeview *tree,
- treeview_node *folder,
- const struct treeview_field_data *field,
- void *data);
+ treeview_node *folder,
+ const struct treeview_field_data *field,
+ void *data);
+
/**
* Update an entry node in given treeview
@@ -274,9 +329,9 @@ nserror treeview_update_node_folder(treeview *tree,
* Fields array names must match names past in treeview_create fields[0...N-2].
*/
nserror treeview_update_node_entry(treeview *tree,
- treeview_node *entry,
- const struct treeview_field_data fields[],
- void *data);
+ treeview_node *entry,
+ const struct treeview_field_data fields[],
+ void *data);
/**
@@ -289,12 +344,19 @@ nserror treeview_update_node_entry(treeview *tree,
* \return NSERROR_OK on success, or appropriate error otherwise
*/
typedef nserror (*treeview_walk_cb)(void *ctx, void *node_data,
- enum treeview_node_type type, bool *abort);
+ enum treeview_node_type type, bool *abort);
+
/**
* Walk (depth first) a treeview subtree, calling a callback at each node of
* required type.
*
+ * Example usage: To export a treeview as XML, XML elements can be opened in
+ * enter_cb, and closed in leave_cb.
+ *
+ * Note, if deleting returned node in enter_cb, the walk must be terminated by
+ * setting abort to true.
+ *
* \param tree Treeview object to walk
* \param root Root node to walk tree from (or NULL for tree root)
* \param enter_cb Function to call on entering nodes, or NULL
@@ -302,16 +364,11 @@ typedef nserror (*treeview_walk_cb)(void *ctx, void *node_data,
* \param ctx Client context, passed back to callback function
* \param type The node type(s) of interest
* \return NSERROR_OK on success, or appropriate error otherwise
- *
- * Example usage: To export a treeview as XML, XML elements can be opened in
- * enter_cb, and closed in leave_cb.
- *
- * Note, if deleting returned node in enter_cb, the walk must be terminated by
- * setting abort to true.
*/
nserror treeview_walk(treeview *tree, treeview_node *root,
- treeview_walk_cb enter_cb, treeview_walk_cb leave_cb,
- void *ctx, enum treeview_node_type type);
+ treeview_walk_cb enter_cb, treeview_walk_cb leave_cb,
+ void *ctx, enum treeview_node_type type);
+
/**
* Delete a treeview node
@@ -324,7 +381,8 @@ nserror treeview_walk(treeview *tree, treeview_node *root,
* Will emit folder or entry deletion msg callback.
*/
nserror treeview_delete_node(treeview *tree, treeview_node *n,
- treeview_node_options_flags flags);
+ treeview_node_options_flags flags);
+
/**
* Expand a treeview node
@@ -335,6 +393,7 @@ nserror treeview_delete_node(treeview *tree, treeview_node *n,
*/
nserror treeview_node_expand(treeview *tree, treeview_node *node);
+
/**
* Contract a treeview node
*
@@ -344,6 +403,7 @@ nserror treeview_node_expand(treeview *tree, treeview_node *node);
*/
nserror treeview_node_contract(treeview *tree, treeview_node *node);
+
/**
* Expand a treeview's nodes
*
@@ -353,6 +413,7 @@ nserror treeview_node_contract(treeview *tree, treeview_node *node);
*/
nserror treeview_expand(treeview *tree, bool only_folders);
+
/**
* Contract a treeview's nodes
*
@@ -362,6 +423,7 @@ nserror treeview_expand(treeview *tree, bool only_folders);
*/
nserror treeview_contract(treeview *tree, bool all);
+
/**
* Redraw a treeview object
*
@@ -372,7 +434,8 @@ nserror treeview_contract(treeview *tree, bool all);
* \param ctx Current redraw context
*/
void treeview_redraw(treeview *tree, int x, int y, struct rect *clip,
- const struct redraw_context *ctx);
+ const struct redraw_context *ctx);
+
/**
* Key press handling for treeviews.
@@ -383,6 +446,7 @@ void treeview_redraw(treeview *tree, int x, int y, struct rect *clip,
*/
bool treeview_keypress(treeview *tree, uint32_t key);
+
/**
* Handles all kinds of mouse action
*
@@ -392,16 +456,18 @@ bool treeview_keypress(treeview *tree, uint32_t key);
* \param y Y coordinate
*/
void treeview_mouse_action(treeview *tree,
- browser_mouse_state mouse, int x, int y);
+ browser_mouse_state mouse, int x, int y);
+
/**
* Determine whether treeview has a selection
*
- * \param tree Treeview object to delete node from
+ * \param tree Treeview object to delete node from
* \return true iff treeview has a selection
*/
bool treeview_has_selection(treeview *tree);
+
/**
* Get the first selected node
*
@@ -410,19 +476,21 @@ bool treeview_has_selection(treeview *tree);
* \return node type of first selected node.
*/
enum treeview_node_type treeview_get_selection(treeview *tree,
- void **node_data);
+ void **node_data);
+
/**
* Edit the first selected node
*
- * \param tree Treeview object to edit selected node in
+ * \param tree Treeview object to edit selected node in
*/
void treeview_edit_selection(treeview *tree);
+
/**
* Find current height of a treeview
*
- * \param tree Treeview object to find height of
+ * \param tree Treeview object to find height of
* \return height of treeview in px
*/
int treeview_get_height(treeview *tree);
diff --git a/desktop/version.c b/desktop/version.c
index 6126c5b99..bbe759f2e 100644
--- a/desktop/version.c
+++ b/desktop/version.c
@@ -20,11 +20,11 @@
#include "desktop/version.h"
-const char * const netsurf_version = "3.7 (Dev"
+const char * const netsurf_version = "3.8 (Dev"
#if defined(CI_BUILD)
" CI #" CI_BUILD
#endif
")"
;
const int netsurf_version_major = 3;
-const int netsurf_version_minor = 7;
+const int netsurf_version_minor = 8;
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 000000000..9f72bc186
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,2389 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = NetSurf
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = docs \
+ docs/env.sh \
+ docs/UnimplementedJavascript.txt \
+ frontends/amiga \
+ frontends/amiga/stringview \
+ frontends/atari \
+ frontends/atari/plot \
+ frontends/beos \
+ frontends/framebuffer \
+ frontends/framebuffer/fbtk \
+ frontends/gtk \
+ frontends/monkey \
+ frontends/riscos \
+ frontends/riscos/configure \
+ frontends/riscos/gui \
+ frontends/riscos/content-handlers \
+ frontends/riscos/templates \
+ frontends/riscos/scripts \
+ frontends/windows \
+ include/netsurf \
+ desktop \
+ content \
+ content/fetchers \
+ content/handlers/image \
+ content/handlers/css \
+ content/handlers/javascript \
+ content/handlers/javascript/duktape \
+ content/handlers/html \
+ content/handlers/text \
+ utils \
+ utils/http
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.h \
+ *.y \
+ *.l \
+ *.cpp \
+ *.m \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = mainpage.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = codedocs
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = gtk \
+ WITH_THEME_INSTALL
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 400
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/Docs/PACKAGING-GTK b/docs/PACKAGING-GTK
index 8f675229f..7436f238e 100644
--- a/Docs/PACKAGING-GTK
+++ b/docs/PACKAGING-GTK
@@ -24,8 +24,7 @@
The GTK port of NetSurf requires access to some resources at run time.
These are stored in gtk/res/ in the source tree. Some of these files are
- symlinks into the !NetSurf directory, which is the application container
- for the native RISC OS build. None of the other files from the !NetSurf
+ symlinks into the top level resources directory. Not all of the files in the
directory are required - the symlinks are used only as a way of making
checkouts smaller and making sure changes to one set of resources updates
the other.
diff --git a/Docs/UnimplementedJavascript.txt b/docs/UnimplementedJavascript.txt
index 1b851b8bb..1b851b8bb 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/docs/UnimplementedJavascript.txt
diff --git a/Docs/BUILDING-AmigaCross b/docs/building-AmigaCross.md
index 32762cd5b..32762cd5b 100644
--- a/Docs/BUILDING-AmigaCross
+++ b/docs/building-AmigaCross.md
diff --git a/Docs/BUILDING-AmigaOS b/docs/building-AmigaOS.md
index 3f05b9caf..3f05b9caf 100644
--- a/Docs/BUILDING-AmigaOS
+++ b/docs/building-AmigaOS.md
diff --git a/Docs/BUILDING-Framebuffer b/docs/building-Framebuffer.md
index 3c8858a32..3c8858a32 100644
--- a/Docs/BUILDING-Framebuffer
+++ b/docs/building-Framebuffer.md
diff --git a/Docs/BUILDING-GTK b/docs/building-GTK.md
index 4ac0fc89e..4ac0fc89e 100644
--- a/Docs/BUILDING-GTK
+++ b/docs/building-GTK.md
diff --git a/Docs/BUILDING-BeOS b/docs/building-Haiku.md
index 8642861d3..8642861d3 100644
--- a/Docs/BUILDING-BeOS
+++ b/docs/building-Haiku.md
diff --git a/Docs/BUILDING-Windows b/docs/building-Windows.md
index dc6769fdf..dc6769fdf 100644
--- a/Docs/BUILDING-Windows
+++ b/docs/building-Windows.md
diff --git a/docs/core-window-interface.md b/docs/core-window-interface.md
new file mode 100644
index 000000000..8f6951f9f
--- /dev/null
+++ b/docs/core-window-interface.md
@@ -0,0 +1,677 @@
+Core Window Interface
+=====================
+
+The NetSurf core provides an optional API to frontend implementations
+which allows a number of "standard" window content interfaces to be
+provided.
+
+The currently available user interfaces are:
+
+ - Cookies
+ - Global history
+ - Hotlist
+ - SSL certificate view
+ - local history
+
+Although not currently included in future additional user interfaces
+will be available for the main browser render.
+
+To be clear these are generic implementations of this functionality
+that any frontend may use. Frontends are free to implement these
+interfaces in any manner as they see fit, the corewindow interface
+simply provides a default.
+
+core window API
+---------------
+
+The API is fairly simple and simply involves passing a callback table
+and context pointer to the interface element being constructed.
+
+The header that defines the callback interface is netsurf/core_window.h
+
+The callback table contains five function pointer interfaces which the
+frontend must implement for the core.
+
+ - invalidate
+ invalidate an area of a window
+
+ - update_size
+ Update the limits of the window
+
+ - scroll_visible
+ Scroll the window to make area visible
+
+ - get_window_dimensions
+ Get window viewport dimensions
+
+ - drag_status
+ Inform corewindow owner of drag status
+
+Each callback will be passed the context pointer for the corewindow
+instance and the relevant additional information necessary to perform
+the operation.
+
+Each exported user interface element wraps this generic interface with
+a concrete implementation. For example the SSL certificate viewer is
+initialised with:
+
+ nserror sslcert_viewer_init(struct core_window_callback_table *cw_t,
+ void *core_window_handle,
+ struct sslcert_session_data *ssl_d);
+
+This call creates a context which will display and navigate the ssl
+session data passed. The frontend must service the callbacks from the
+core to provide the necessary interactions with the frontend windowing
+system.
+
+These actions should ideally use the standard frontend window
+processing. So for the GTK frontend when the core calls the invalidate
+operation it simply marks the area passed as damaged (using
+gtk_widget_queue_draw_area()) and lets the standard expose event cause
+the redraw to occur.
+
+If the frontend needs to redraw an area of a window (perhaps an expose
+event occurred or the window has had an area marked as invalid) it
+must call the core window API wrappers implementation which will
+perform the plot operations required to update an area of the window.
+
+e.g in the case of ssl certificate viewer
+
+ void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d,
+ int x, int y, struct rect *clip,
+ const struct redraw_context *ctx);
+
+would perform the plot operations for that SSL data window.
+
+Usage
+-----
+
+The usage pattern that is expected is for a frontend to create a core
+window implementation that implements the necessary five API in a
+generic way and allows the frontend to provide the specific
+specialisation for each of the user interface elements it wishes to
+use (cookies, SSL viewer etc).
+
+The GTK frontend for example:
+
+has source corewindow.[ch] which implement the five core callbacks
+using generic GTK operations (invalidate calls
+gtk_widget_queue_draw_area() etc.) and then provides additional
+operations on a GTK drawing area object to attach expose event
+processing, keypress processing etc.
+
+The GTK corewindow (not to be confused with the core window API
+itself, this is purely the gtk wrapper) is used by ssl_cert.c which
+creates a nsgtk_crtvrfy_window structure containing the
+nsgtk_corewindow structure. It attaches actual GTK window handles to
+this structure and populates elements of nsgtk_corewindow and then
+calls sslcert_viewer_init() directly.
+
+frontend skeleton
+-----------------
+
+An example core window implementation for a frontend ssl certificate
+viewer is presented here. This implements the suggested usage above
+and provides generic corewindow helpers.
+
+
+frontends/example/corewindow.h
+------------------------------
+
+ /*
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #ifndef EXAMPLE_COREWINDOW_H
+ #define EXAMPLE_COREWINDOW_H
+
+ #include "netsurf/core_window.h"
+
+ /**
+ * example core window state
+ */
+ struct example_corewindow {
+
+
+ /*
+ * Any variables common to any frontend window would go here.
+ * e.g. drawing area handles, toolkit pointers or other state
+ */
+ example_toolkit_widget *tk_widget;
+
+
+
+ /** drag status set by core */
+ core_window_drag_status drag_status;
+
+ /** table of callbacks for core window operations */
+ struct core_window_callback_table *cb_table;
+
+ /**
+ * callback to draw on drawable area of example core window
+ *
+ * \param example_cw The example core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ nserror (*draw)(struct example_corewindow *example_cw, struct rect *r);
+
+ /**
+ * callback for keypress on example core window
+ *
+ * \param example_cw The example core window structure.
+ * \param nskey The netsurf key code.
+ * \return NSERROR_OK if key processed,
+ * NSERROR_NOT_IMPLEMENTED if key not processed
+ * otherwise apropriate error code
+ */
+ nserror (*key)(struct example_corewindow *example_cw, uint32_t nskey);
+
+ /**
+ * callback for mouse event on example core window
+ *
+ * \param example_cw The example core window structure.
+ * \param mouse_state mouse state
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on sucess otherwise apropriate error code.
+ */
+ nserror (*mouse)(struct example_corewindow *example_cw, browser_mouse_state mouse_state, int x, int y);
+ };
+
+ /**
+ * initialise elements of example core window.
+ *
+ * As a pre-requisite the draw, key and mouse callbacks must be defined
+ *
+ * \param example_cw A example core window structure to initialise
+ * \return NSERROR_OK on successful initialisation otherwise error code.
+ */
+ nserror example_corewindow_init(struct example_corewindow *example_cw);
+
+ /**
+ * finalise elements of example core window.
+ *
+ * \param example_cw A example core window structure to initialise
+ * \return NSERROR_OK on successful finalisation otherwise error code.
+ */
+ nserror example_corewindow_fini(struct example_corewindow *example_cw);
+
+ #endif
+
+frontends/example/corewindow.c
+------------------------------
+
+ /*
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /**
+ * file
+ * EXAMPLE generic core window interface.
+ *
+ * Provides interface for core renderers to the example toolkit drawable area.
+ *
+ * This module is an object that must be encapsulated. Client users
+ * should embed a struct example_corewindow at the beginning of their
+ * context for this display surface, fill in relevant data and then
+ * call example_corewindow_init()
+ *
+ * The example core window structure requires the callback for draw, key and
+ * mouse operations.
+ */
+
+ #include <assert.h>
+ #include <string.h>
+ #include <math.h>
+
+ #include "utils/log.h"
+ #include "utils/utils.h"
+ #include "utils/messages.h"
+ #include "utils/utf8.h"
+ #include "netsurf/keypress.h"
+ #include "netsurf/mouse.h"
+ #include "netsurf/plot_style.h"
+
+ /* extremely likely there will be additional headers required in a real frontend */
+ #include "example/corewindow.h"
+
+
+ /* toolkit event handlers that do generic things and call internal callbacks */
+
+
+ static bool
+ example_cw_mouse_press_event(toolkit_widget *widget, toolkit_button bt, int x, int y, void *ctx)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
+
+ example_cw->mouse(example_cw, state, x, y);
+
+ return true;
+ }
+
+ static bool
+ example_cw_keyrelease_event(toolkit_widget *widget, void *ctx)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
+
+ example_cw->key(example_cw, keycode);
+
+ return true;
+ }
+
+
+
+ /* signal handler for toolkit window redraw */
+ static bool
+ example_cw_draw_event(toolkit_widget *widget,
+ toolkit_area *tk_area,
+ void *ctx)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)ctx;
+ struct rect clip;
+
+ clip.x0 = tk_area.x;
+ clip.y0 = tk_area.y;
+ clip.x1 = tk_area.width;
+ clip.y1 = tk_area.height;
+
+ example_cw->draw(example_cw, &clip);
+
+ return true;
+ }
+
+
+ /**
+ * callback from core to request a redraw
+ */
+ static nserror
+ example_cw_invalidate(struct core_window *cw, const struct rect *r)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)cw;
+
+ toolkit_widget_queue_draw_area(example_cw->widget,
+ r->x0, r->y0,
+ r->x1 - r->x0, r->y1 - r->y0);
+ }
+
+
+ static void
+ example_cw_update_size(struct core_window *cw, int width, int height)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)cw;
+
+ toolkit_widget_set_size_request(EXAMPLE_WIDGET(example_cw->drawing_area),
+ width, height);
+ }
+
+
+ static void
+ example_cw_scroll_visible(struct core_window *cw, const struct rect *r)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)cw;
+
+ toolkit_scroll_widget(example_cw->widget, r);
+ }
+
+
+ static void
+ example_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)cw;
+
+ *width = toolkit_get_widget_width(example_cw->widget);
+ *height = toolkit_get_widget_height(example_cw->widget);
+ }
+
+
+ static void
+ example_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
+ {
+ struct example_corewindow *example_cw = (struct example_corewindow *)cw;
+ example_cw->drag_status = ds;
+ }
+
+
+ struct core_window_callback_table example_cw_cb_table = {
+ .invalidate = example_cw_invalidate,
+ .update_size = example_cw_update_size,
+ .scroll_visible = example_cw_scroll_visible,
+ .get_window_dimensions = example_cw_get_window_dimensions,
+ .drag_status = example_cw_drag_status
+ };
+
+ /* exported function documented example/corewindow.h */
+ nserror example_corewindow_init(struct example_corewindow *example_cw)
+ {
+ /* setup the core window callback table */
+ example_cw->cb_table = &example_cw_cb_table;
+
+ /* frontend toolkit specific method of causing example_cw_draw_event to be called when a drawing operation is required */
+ toolkit_connect_draw_event(example_cw->tk_widget,
+ example_cw_draw_event,
+ example_cw);
+
+ /* frontend toolkit specific method of causing example_cw_button_press_event to be called when a button press occours */
+ toolkit_connect_button_press_event(example_cw->tk_widget,
+ example_cw_button_press_event,
+ example_cw);
+
+ /* frontend toolkit specific method of causing example_cw_button_release_event to be called when a button release occours */
+ toolkit_connect_button_release_event(example_cw->tk_widget,
+ example_cw_button_release_event,
+ example_cw);
+
+ /* frontend toolkit specific method of causing example_cw_motion_notify_event to be called when there is motion over the widget */
+ toolkit_connect_motion_event(example_cw->tk_widget,
+ example_cw_motion_notify_event,
+ example_cw);
+
+ /* frontend toolkit specific method of causing example_cw_key_press_event to be called when a key press occours */
+ toolkit_connect_button_press_event(example_cw->tk_widget,
+ example_cw_key_press_event,
+ example_cw);
+
+ /* frontend toolkit specific method of causing example_cw_key_release_event to be called when a key release occours */
+ toolkit_connect_button_release_event(example_cw->tk_widget,
+ example_cw_key_release_event,
+ example_cw);
+
+
+ return NSERROR_OK;
+ }
+
+ /* exported interface documented in example/corewindow.h */
+ nserror example_corewindow_fini(struct example_corewindow *example_cw)
+ {
+ return NSERROR_OK;
+ }
+
+
+frontends/example/ssl_cert.h
+----------------------------
+
+ /*
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #ifndef NETSURF_EXAMPLE_SSL_CERT_H
+ #define NETSURF_EXAMPLE_SSL_CERT_H 1
+
+ struct nsurl;
+ struct ssl_cert_info;
+
+ /**
+ * Prompt the user to verify a certificate with issuse.
+ *
+ * \param url The URL being verified.
+ * \param certs The certificate to be verified
+ * \param num The number of certificates to be verified.
+ * \param cb Callback upon user decision.
+ * \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK or error code if prompt creation failed.
+ */
+ nserror example_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+ #endif
+
+frontends/example/ssl_cert.c
+----------------------------
+
+ /*
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /**
+ * file
+ * Implementation of example certificate viewing using example core windows.
+ */
+
+ #include <stdint.h>
+ #include <stdlib.h>
+
+ #include "utils/log.h"
+ #include "netsurf/keypress.h"
+ #include "netsurf/plotters.h"
+ #include "desktop/sslcert_viewer.h"
+
+ #include "example/corewindow.h"
+
+
+ /**
+ * EXAMPLE certificate viewing window context
+ */
+ struct example_crtvrfy_window {
+ /** example core window context */
+ struct example_corewindow core;
+
+ /** SSL certificate viewer context data */
+ struct sslcert_session_data *ssl_data;
+ };
+
+ /**
+ * destroy a previously created certificate view
+ */
+ static nserror example_crtvrfy_destroy(struct example_crtvrfy_window *crtvrfy_win)
+ {
+ nserror res;
+
+ res = sslcert_viewer_fini(crtvrfy_win->ssl_data);
+ if (res == NSERROR_OK) {
+ res = example_corewindow_fini(&crtvrfy_win->core);
+ toolkit_windown_destroy(crtvrfy_win->window);
+ free(crtvrfy_win);
+ }
+ return res;
+ }
+
+ static void
+ example_crtvrfy_accept(ExampleButton *w, gpointer data)
+ {
+ struct example_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct example_crtvrfy_window *)data;
+
+ sslcert_viewer_accept(crtvrfy_win->ssl_data);
+
+ example_crtvrfy_destroy(crtvrfy_win);
+ }
+
+ static void
+ example_crtvrfy_reject(ExampleWidget *w, gpointer data)
+ {
+ struct example_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct example_crtvrfy_window *)data;
+
+ sslcert_viewer_reject(crtvrfy_win->ssl_data);
+
+ example_crtvrfy_destroy(crtvrfy_win);
+ }
+
+
+ /**
+ * callback for mouse action for certificate verify on core window
+ *
+ * \param example_cw The example core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ static nserror
+ example_crtvrfy_mouse(struct example_corewindow *example_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+ {
+ struct example_crtvrfy_window *crtvrfy_win;
+ /* technically degenerate container of */
+ crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
+
+ sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y);
+
+ return NSERROR_OK;
+ }
+
+ /**
+ * callback for keypress for certificate verify on core window
+ *
+ * \param example_cw The example core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ static nserror
+ example_crtvrfy_key(struct example_corewindow *example_cw, uint32_t nskey)
+ {
+ struct example_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
+
+ if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * callback on draw event for certificate verify on core window
+ *
+ * \param example_cw The example core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ static nserror
+ example_crtvrfy_draw(struct example_corewindow *example_cw, struct rect *r)
+ {
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &example_plotters
+ };
+ struct example_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct example_crtvrfy_window *)example_cw;
+
+ sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx);
+
+ return NSERROR_OK;
+ }
+
+ /* exported interface documented in example/ssl_cert.h */
+ nserror example_cert_verify(struct nsurl *url,
+ const struct ssl_cert_info *certs,
+ unsigned long num,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+ {
+ struct example_crtvrfy_window *ncwin;
+ nserror res;
+
+ ncwin = malloc(sizeof(struct example_crtvrfy_window));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = toolkit_create_window(&ncwin->window);
+ if (res != NSERROR_OK) {
+ LOG("SSL UI builder init failed");
+ free(ncwin);
+ return res;
+ }
+
+ /* store the widget that the toolkit is drawing into */
+ ncwin->core.widget = toolkit_get_widget(ncwin->window, "SSLDrawingArea"));
+
+ /* would typicaly setup toolkit accept/reject buttons etc. here */
+ toolkit_connect_button_press(ncwin->tk_accept_button,
+ example_crtvrfy_accept,
+ ncwin);
+
+
+ /* initialise example core window */
+ ncwin->core.draw = example_crtvrfy_draw;
+ ncwin->core.key = example_crtvrfy_key;
+ ncwin->core.mouse = example_crtvrfy_mouse;
+
+ res = example_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ /* initialise certificate viewing interface */
+ res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs,
+ &ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = sslcert_viewer_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ toolkit_widget_show(ncwin->window);
+
+ return NSERROR_OK;
+ }
diff --git a/Docs/env.sh b/docs/env.sh
index 9cfc95650..b9adb92f9 100644
--- a/Docs/env.sh
+++ b/docs/env.sh
@@ -1,57 +1,225 @@
#!/bin/sh
#
-# NetSurf Library, tool and browser support script
+# NetSurf Library, tool and browser development support script
#
-# Usage: source env.sh
-# TARGET_ABI / HOST sets the target for library builds
-# TARGET_WORKSPACE is the workspace directory to keep the sandboxes
+# Copyright 2013-2017 Vincent Sanders <vince@netsurf-browser.org>
+# Released under the MIT Licence
#
# This script allows NetSurf and its libraries to be built without
# requiring installation into a system.
#
-# Copyright 2013 Vincent Sanders <vince@netsurf-browser.org>
-# Released under the MIT Licence
+# Usage: source env.sh
+#
+# Controlling variables
+# HOST sets the target architecture for library builds
+# BUILD sets the building machines architecture
+# TARGET_WORKSPACE is the workspace directory to keep the sandboxes
+#
+# The use of HOST and BUILD here is directly comprable to the GCC
+# usage as described at:
+# http://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html
+#
+
+###############################################################################
+# OS Package installation
+###############################################################################
+
+# deb packages for dpkg based systems
+NS_DEV_DEB="build-essential pkg-config git gperf libcurl3-dev libpng-dev libjpeg-dev"
+NS_TOOL_DEB="flex bison libhtml-parser-perl"
+if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
+ NS_GTK_DEB="libgtk-3-dev librsvg2-dev"
+else
+ NS_GTK_DEB="libgtk2.0-dev librsvg2-dev"
+fi
+
+# apt get commandline to install necessary dev packages
+ns-apt-get-install()
+{
+ if /usr/bin/apt-cache show libssl1.0-dev >/dev/null 2>&1; then
+ NS_DEV_DEB="${NS_DEV_DEB} libssl1.0-dev"
+ else
+ NS_DEV_DEB="${NS_DEV_DEB} libssl-dev"
+ fi
+ sudo apt-get install $(echo ${NS_DEV_DEB} ${NS_TOOL_DEB} ${NS_GTK_DEB})
+}
-# parameters
+
+# packages for yum installer RPM based systems (tested on fedora 20)
+NS_DEV_YUM_RPM="git gcc pkgconfig expat-devel openssl-devel gperf libcurl-devel perl-Digest-MD5-File libjpeg-devel libpng-devel"
+NS_TOOL_YUM_RPM="flex bison"
+if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
+ NS_GTK_YUM_RPM="gtk3-devel librsvg2-devel"
+else
+ NS_GTK_YUM_RPM="gtk2-devel librsvg2-devel"
+fi
+
+# yum commandline to install necessary dev packages
+ns-yum-install()
+{
+ sudo yum -y install $(echo ${NS_DEV_YUM_RPM} ${NS_TOOL_YUM_RPM} ${NS_GTK_YUM_RPM})
+}
+
+
+# packages for dnf installer RPM based systems (tested on fedora 25)
+NS_DEV_DNF_RPM="java-1.8.0-openjdk-headless gcc clang pkgconfig libcurl-devel libjpeg-devel expat-devel libpng-devel openssl-devel gperf perl-HTML-Parser"
+NS_TOOL_DNF_RPM="git flex bison ccache screen"
+if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
+ NS_GTK_DNF_RPM="gtk3-devel"
+else
+ NS_GTK_DNF_RPM="gtk2-devel"
+fi
+
+# dnf commandline to install necessary dev packages
+ns-dnf-install()
+{
+ sudo dnf install $(echo ${NS_DEV_DNF_RPM} ${NS_TOOL_DNF_RPM} ${NS_GTK_DNF_RPM})
+}
+
+
+# packages for zypper installer RPM based systems (tested on openSUSE leap 42)
+NS_DEV_ZYP_RPM="java-1_8_0-openjdk-headless gcc clang pkgconfig libcurl-devel libjpeg-devel libexpat-devel libpng-devel openssl-devel gperf perl-HTML-Parser"
+NS_TOOL_ZYP_RPM="git flex bison gperf ccache screen"
+if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
+ NS_GTK_ZYP_RPM="gtk3-devel"
+else
+ NS_GTK_ZYP_RPM="gtk2-devel"
+fi
+
+# zypper commandline to install necessary dev packages
+ns-zypper-install()
+{
+ sudo zypper install -y $(echo ${NS_DEV_ZYP_RPM} ${NS_TOOL_ZYP_RPM} ${NS_GTK_ZYP_RPM})
+}
+
+
+# Packages for Haiku install
+
+# Haiku secondary arch suffix:
+# empty for primary (gcc2 on x86) or "_x86" for gcc4 secondary.
+HA=_x86
+
+NS_DEV_HPKG="devel:libcurl${HA} devel:libpng${HA} devel:libjpeg${HA} devel:libcrypto${HA} devel:libiconv${HA} devel:libexpat${HA} cmd:pkg_config${HA} cmd:gperf html_parser"
+
+# pkgman commandline to install necessary dev packages
+ns-pkgman-install()
+{
+ pkgman install $(echo ${NS_DEV_HPKG})
+}
+
+
+# MAC OS X
+NS_DEV_MACPORT="git expat openssl curl libjpeg-turbo libpng"
+
+ns-macport-install()
+{
+ PATH=/opt/local/bin:/opt/local/sbin:$PATH sudo /opt/local/bin/port install $(echo ${NS_DEV_MACPORT})
+}
+
+
+# packages for FreeBSD install
+NS_DEV_FREEBSDPKG="gmake curl"
+
+# FreeBSD package install
+ns-freebsdpkg-install()
+{
+ pkg install $(echo ${NS_DEV_FREEBSDPKG})
+}
+
+
+# generic for help text
+NS_DEV_GEN="git, gcc, pkgconfig, expat library, openssl library, libcurl, perl, perl MD5 digest, libjpeg library, libpng library"
+NS_TOOL_GEN="flex tool, bison tool"
+if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
+ NS_GTK_GEN="gtk+ 3 toolkit library, librsvg2 library"
+else
+ NS_GTK_GEN="gtk+ 2 toolkit library, librsvg2 library"
+fi
+
+# Generic OS package install
+# looks for package managers and tries to use them if present
+ns-package-install()
+{
+ if [ -x "/usr/bin/zypper" ]; then
+ ns-zypper-install
+ elif [ -x "/usr/bin/apt-get" ]; then
+ ns-apt-get-install
+ elif [ -x "/usr/bin/dnf" ]; then
+ ns-dnf-install
+ elif [ -x "/usr/bin/yum" ]; then
+ ns-yum-install
+ elif [ -x "/bin/pkgman" ]; then
+ ns-pkgman-install
+ elif [ -x "/opt/local/bin/port" ]; then
+ ns-macport-install
+ elif [ -x "/usr/sbin/pkg" ]; then
+ ns-freebsdpkg-install
+ else
+ echo "Unable to determine OS packaging system in use."
+ echo "Please ensure development packages are installed for:"
+ echo ${NS_DEV_GEN}"," ${NS_TOOL_GEN}"," ${NS_GTK_GEN}
+ fi
+}
+
+###############################################################################
+# Setup environment
+###############################################################################
+
+# find which command used to find everything else on path
+if [ -x /usr/bin/which ]; then
+ WHICH_CMD=/usr/bin/which
+else
+ WHICH_CMD=/bin/which
+fi
+
+# environment parameters
# The system doing the building
if [ "x${BUILD}" = "x" ]; then
- BUILD=$(cc -dumpmachine)
+ BUILD_CC=$(${WHICH_CMD} cc)
+ if [ $? -eq 0 ];then
+ BUILD=$(cc -dumpmachine)
+ else
+ echo "Unable to locate a compiler. Perhaps run ns-package-install"
+ return 1
+ fi
fi
# Get the host build if unset
if [ "x${HOST}" = "x" ]; then
if [ "x${TARGET_ABI}" = "x" ]; then
- HOST=${BUILD}
+ HOST=${BUILD}
else
- HOST=${TARGET_ABI}
+ HOST=${TARGET_ABI}
fi
else
HOST_CC_LIST="${HOST}-cc ${HOST}-gcc /opt/netsurf/${HOST}/cross/bin/${HOST}-cc /opt/netsurf/${HOST}/cross/bin/${HOST}-gcc"
for HOST_CC_V in $(echo ${HOST_CC_LIST});do
- HOST_CC=$(/bin/which ${HOST_CC_V})
- if [ "x${HOST_CC}" != "x" ];then
- break
- fi
+ HOST_CC=$(${WHICH_CMD} ${HOST_CC_V})
+ if [ "x${HOST_CC}" != "x" ];then
+ break
+ fi
done
if [ "x${HOST_CC}" = "x" ];then
- echo "Unable to execute host compiler for HOST=${HOST}. is it set correctly?"
- return 1
+ echo "Unable to execute host compiler for HOST=${HOST}. is it set correctly?"
+ return 1
fi
HOST_CC_MACHINE=$(${HOST_CC} -dumpmachine 2>/dev/null)
if [ "${HOST_CC_MACHINE}" != "${HOST}" ];then
- echo "Compiler dumpmachine differes from HOST setting"
- return 2
+ echo "Compiler dumpmachine differes from HOST setting"
+ return 2
fi
unset HOST_CC_LIST HOST_CC_V HOST_CC HOST_CC_MACHINE
fi
+# set up a default target workspace
if [ "x${TARGET_WORKSPACE}" = "x" ]; then
TARGET_WORKSPACE=${HOME}/dev-netsurf/workspace
fi
+# set up default parallelism
if [ "x${USE_CPUS}" = "x" ]; then
NCPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null)
NCPUS="${NCPUS:-1}"
@@ -64,20 +232,17 @@ if [ "x${NETSURF_GTK_MAJOR}" = "x" ]; then
NETSURF_GTK_MAJOR=2
fi
-
-###############################################################################
-# Setup environment
-###############################################################################
-
+# report to user
echo "BUILD=${BUILD}"
echo "HOST=${HOST}"
echo "TARGET_WORKSPACE=${TARGET_WORKSPACE}"
echo "USE_CPUS=${USE_CPUS}"
export PREFIX=${TARGET_WORKSPACE}/inst-${HOST}
+export BUILD_PREFIX=${TARGET_WORKSPACE}/inst-${BUILD}
export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}::
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${PREFIX}/lib
-export PATH=${PATH}:${PREFIX}/bin
+export PATH=${PATH}:${BUILD_PREFIX}/bin
export NETSURF_GTK_MAJOR
# make tool
@@ -90,7 +255,7 @@ NS_GIT="git://git.netsurf-browser.org"
NS_BUILDSYSTEM="buildsystem"
# internal libraries all frontends require (order is important)
-NS_INTERNAL_LIBS="libwapcaplet libparserutils libhubbub libdom libcss libnsgif libnsbmp libutf8proc libnsutils libnspsl"
+NS_INTERNAL_LIBS="libwapcaplet libparserutils libhubbub libdom libcss libnsgif libnsbmp libutf8proc libnsutils libnspsl libnslog"
# The browser itself
NS_BROWSER="netsurf"
@@ -139,8 +304,8 @@ case "${HOST}" in
NS_TOOLS=""
# libraries required for the freebsd frontend
NS_FRONTEND_LIBS=""
- # select gnu make
- MAKE=gmake
+ # select gnu make
+ MAKE=gmake
;;
*)
# default tools required to build the browser
@@ -152,109 +317,18 @@ esac
export MAKE
-################ OS Package installation ################
-
-# deb packages for dpkg based systems
-NS_DEV_DEB="build-essential pkg-config git gperf libcurl3-dev libssl-dev libpng-dev libjpeg-dev"
-NS_TOOL_DEB="flex bison libhtml-parser-perl"
-if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
- NS_GTK_DEB="libgtk-3-dev librsvg2-dev"
-else
- NS_GTK_DEB="libgtk2.0-dev librsvg2-dev"
-fi
-
-# apt get commandline to install necessary dev packages
-ns-apt-get-install()
-{
- sudo apt-get install $(echo ${NS_DEV_DEB} ${NS_TOOL_DEB} ${NS_GTK_DEB})
-}
-
-# RPM packages for rpm based systems (tested on fedora 20)
-NS_DEV_RPM="git gcc pkgconfig libexpat-devel openssl-devel libcurl-devel perl-Digest-MD5-File libjpeg-devel libpng-devel"
-NS_TOOL_RPM="flex bison"
-if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
- NS_GTK_RPM="gtk3-devel librsvg2-devel"
-else
- NS_GTK_RPM="gtk2-devel librsvg2-devel"
-fi
-
-# yum commandline to install necessary dev packages
-ns-yum-install()
-{
- sudo yum -y install $(echo ${NS_DEV_RPM} ${NS_TOOL_RPM} ${NS_GTK_RPM})
-}
-
-# Haiku secondary arch suffix:
-# empty for primary (gcc2 on x86),
-# "_x86" for gcc4 secondary.
-HA=_x86
-# Haiku packages
-NS_DEV_HPKG="devel:libcurl${HA} devel:libpng${HA} devel:libjpeg${HA} devel:libcrypto${HA} devel:libiconv${HA} devel:libexpat${HA} cmd:pkg_config${HA} cmd:gperf html_parser"
-
-# pkgman commandline to install necessary dev packages
-ns-pkgman-install()
-{
- pkgman install $(echo ${NS_DEV_HPKG})
-}
-
-# MAC OS X
-NS_DEV_MACPORT="git expat openssl curl libjpeg-turbo libpng"
-
-ns-macport-install()
-{
- PATH=/opt/local/bin:/opt/local/sbin:$PATH sudo /opt/local/bin/port install $(echo ${NS_DEV_MACPORT})
-}
-
-NS_DEV_FREEBSDPKG="gmake curl"
-
-# FreeBSD package install
-ns-freebsdpkg-install()
-{
- pkg install $(echo ${NS_DEV_FREEBSDPKG})
-}
-
-# generic for help text
-NS_DEV_GEN="git, gcc, pkgconfig, expat library, openssl library, libcurl, perl, perl MD5 digest, libjpeg library, libpng library"
-NS_TOOL_GEN="flex tool, bison tool"
-if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
- NS_GTK_GEN="gtk+ 3 toolkit library, librsvg2 library"
-else
- NS_GTK_GEN="gtk+ 2 toolkit library, librsvg2 library"
-fi
-
-# Genertic OS package install
-# looks for package managers and tries to use them if present
-ns-package-install()
-{
- if [ -x "/usr/bin/apt-get" ]; then
- ns-apt-get-install
- elif [ -x "/usr/bin/yum" ]; then
- ns-yum-install
- elif [ -x "/bin/pkgman" ]; then
- ns-pkgman-install
- elif [ -x "/opt/local/bin/port" ]; then
- ns-macport-install
- elif [ -x "/usr/sbin/pkg" ]; then
- ns-freebsdpkg-install
- else
- echo "Unable to determine OS packaging system in use."
- echo "Please ensure development packages are installed for:"
- echo ${NS_DEV_GEN}"," ${NS_TOOL_GEN}"," ${NS_GTK_GEN}
- fi
-}
-
################ Development helpers ################
# git pull in all repos parameters are passed to git pull
ns-pull()
{
- for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
- echo -n " GIT: Pulling ${REPO}: "
- if [ -f "${TARGET_WORKSPACE}/${REPO}/.git/config" ]; then
- (cd ${TARGET_WORKSPACE}/${REPO} && git pull $*; )
- else
- echo "Repository not present"
- fi
+ for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
+ echo -n " GIT: Pulling ${REPO}: "
+ if [ -f "${TARGET_WORKSPACE}/${REPO}/.git/config" ]; then
+ (cd ${TARGET_WORKSPACE}/${REPO} && git pull $*; )
+ else
+ echo "Repository not present"
+ fi
done
}
@@ -262,38 +336,42 @@ ns-pull()
ns-clone()
{
mkdir -p ${TARGET_WORKSPACE}
- for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_RISCOS_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
- echo -n " GIT: Cloning ${REPO}: "
- if [ -f ${TARGET_WORKSPACE}/${REPO}/.git/config ]; then
- echo "Repository already present"
- else
- (cd ${TARGET_WORKSPACE} && git clone ${NS_GIT}/${REPO}.git; )
- fi
+ for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_RISCOS_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
+ echo -n " GIT: Cloning ${REPO}: "
+ if [ -f ${TARGET_WORKSPACE}/${REPO}/.git/config ]; then
+ echo "Repository already present"
+ else
+ (cd ${TARGET_WORKSPACE} && git clone ${NS_GIT}/${REPO}.git; )
+ fi
done
# put current env.sh in place in workspace
- if [ ! -f "${TARGET_WORKSPACE}/env.sh" -a -f ${TARGET_WORKSPACE}/${NS_BROWSER}/Docs/env.sh ]; then
- cp ${TARGET_WORKSPACE}/${NS_BROWSER}/Docs/env.sh ${TARGET_WORKSPACE}/env.sh
+ if [ ! -f "${TARGET_WORKSPACE}/env.sh" -a -f ${TARGET_WORKSPACE}/${NS_BROWSER}/docs/env.sh ]; then
+ cp ${TARGET_WORKSPACE}/${NS_BROWSER}/docs/env.sh ${TARGET_WORKSPACE}/env.sh
fi
}
# issues a make command to all libraries
ns-make-libs()
{
- for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_TOOLS}); do
- echo " MAKE: make -C ${REPO} $USE_CPUS $*"
- ${MAKE} -C ${TARGET_WORKSPACE}/${REPO} $USE_CPUS $*
- if [ $? -ne 0 ]; then
- return $?
- fi
+ for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS}); do
+ echo " MAKE: make -C ${REPO} $USE_CPUS $*"
+ ${MAKE} -C ${TARGET_WORKSPACE}/${REPO} HOST=${HOST} $USE_CPUS $*
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
done
+}
- for REPO in $(echo ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS}); do
- echo " MAKE: make -C ${REPO} $USE_CPUS $*"
- ${MAKE} -C ${TARGET_WORKSPACE}/${REPO} HOST=${HOST} $USE_CPUS $*
- if [ $? -ne 0 ]; then
- return $?
- fi
+# issues make command for all tools
+ns-make-tools()
+{
+ for REPO in $(echo ${NS_BUILDSYSTEM} ${NS_TOOLS}); do
+ echo " MAKE: make -C ${REPO} $USE_CPUS $*"
+ ${MAKE} -C ${TARGET_WORKSPACE}/${REPO} PREFIX=${BUILD_PREFIX} HOST=${BUILD} $USE_CPUS $*
+ if [ $? -ne 0 ]; then
+ return $?
+ fi
done
}
@@ -309,6 +387,7 @@ ns-pull-install()
{
ns-pull $*
+ ns-make-tools install
ns-make-libs install
}
@@ -317,4 +396,3 @@ ns-make()
{
${MAKE} $USE_CPUS "$@"
}
-
diff --git a/Docs/gource.sh b/docs/gource.sh
index a1fbcbe13..a1fbcbe13 100755
--- a/Docs/gource.sh
+++ b/docs/gource.sh
diff --git a/Docs/ideas/cache.txt b/docs/ideas/cache.txt
index fda0617a3..fda0617a3 100644
--- a/Docs/ideas/cache.txt
+++ b/docs/ideas/cache.txt
diff --git a/Docs/ideas/css-engine.txt b/docs/ideas/css-engine.txt
index 1ea8778d5..1ea8778d5 100644
--- a/Docs/ideas/css-engine.txt
+++ b/docs/ideas/css-engine.txt
diff --git a/Docs/ideas/render-library.txt b/docs/ideas/render-library.txt
index db645c427..db645c427 100644
--- a/Docs/ideas/render-library.txt
+++ b/docs/ideas/render-library.txt
diff --git a/docs/logging.md b/docs/logging.md
new file mode 100644
index 000000000..abc852bca
--- /dev/null
+++ b/docs/logging.md
@@ -0,0 +1,96 @@
+NetSurf logging
+===============
+
+NetSurf has a large number of internal diagnostic messages which can
+be viewed by the developer (or user if they wish)
+
+Each message has a category and a level which can be used to control
+which messages are displayed.
+
+The message category is used to allow filters to separate messages of
+the same level from different sources.
+
+The logging levels, from low to high, are:
+
+ - DEEPDEBUG
+ - DEBUG
+ - VERBOSE
+ - INFO
+ - WARNING
+ - ERROR
+ - CRITICAL
+
+Compilation control
+-------------------
+
+At compilation time the logging behaviour can be controlled by using
+configuration overrides in a Makefile.config The parameters are:
+
+ - NETSURF_USE_NSLOG
+ This controls if the NetSurf logging library (nslog) is used to
+ allow comprehensive filtering of messages. The value defaults to
+ AUTO which will use pkg-config to locate the library and enable if
+ present. If set to NO or the library cannot be located the browsers
+ logging will revert to simple boolean enabled/disabled logging
+ controlled by the -v command line switch.
+
+ - NETSURF_LOG_LEVEL
+ This controls what level of message is compiled into the NetSurf
+ binary. The default value is VERBOSE and when not using nslog this
+ value is also used to select what level of logging is shown with the
+ -v command line switch.
+
+ - NETSURF_BUILTIN_LOG_FILTER
+ When using nslog this sets the default non-verbose filter. The
+ default value ("level:WARNING") shows all messages of level WARNING
+ and above
+
+ - NETSURF_BUILTIN_VERBOSE_FILTER
+ When using nslog this sets the default verbose filter. The default
+ value ("level:VERBOSE") shows all messages of level VERBOSE and
+ above. The verbose level is selected from the commandline with the
+ -v switch
+
+Command line
+------------
+
+The main command line switches that control logging are:
+
+ - -v
+ switches between the normal and verbose levels
+
+ - -V <file>
+ Send the logging to a file instead of standard output
+
+ - --log_filter=<filter>
+ Set the non verbose filter
+
+ - --verbose_filter=<filter>
+ Set the verbose filter
+
+Examples:
+
+ ./nsgtk --log_filter="level:INFO"
+ ./nsgtk -v --verbose_filter="(cat:layout && level:DEBUG)"
+ ./nsgtk -v --verbose_filter="((cat:layout && level:DEBUG) || level:INFO)"
+
+Options
+-------
+
+The logging filters can be configured by setting the log_filter and
+log_verbose_filter options.
+
+Adding messages
+---------------
+
+Messages can be easily added by including the utils/log.h header and
+he NSLOG() macro. for example
+
+ NSLOG(netsurf, INFO, "An example message %d", example_func());
+
+nslog
+-----
+
+If the nslog library is used it allows for application of a filter to
+control which messages are output. The nslog filter syntax is best
+viewed in its [documentation](http://source.netsurf-browser.org/libnslog.git/tree/docs/mainpage.md)
diff --git a/docs/mainpage.md b/docs/mainpage.md
new file mode 100644
index 000000000..fa72d1464
--- /dev/null
+++ b/docs/mainpage.md
@@ -0,0 +1,98 @@
+NetSurf web browser
+===================
+
+![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1037/badge)[*](https://bestpractices.coreinfrastructure.org/projects/1037)
+
+The NetSurf code makes use of Doxygen for code documentation.
+
+User Interface
+--------------
+
+There are some basic user guides for the
+[framebuffer](docs/using-framebuffer.md) and
+[monkey](docs/using-monkey.md) frontends.
+
+The [core user options](docs/netsurf-options.md) of the browser are
+documented which are augmented by each frontend in a specific manner.
+
+### Logging
+
+The [logging](docs/logging.md) interface controls debug and error
+messages not output through the GUI.
+
+Documented API
+--------------
+
+There are several documents which detail specific aspects of the
+codebase and APIs.
+
+### Core window
+
+The [core window API](docs/core-window-interface.md) allows frontends
+to use generic core code for user interface elements beyond the
+browser render.
+
+### Source object caching
+
+The [source object caching](docs/source-object-backing-store.md)
+provides a way for downloaded content to be kept on a persistent
+storage medium such as hard disc to make future retrieval of that
+content quickly.
+
+### Javascript
+
+JavaScript is provided by integrating the duktape library. There are [instructions](docs/updating-duktape.md) on how to update the library.
+
+A list of [unimplemented DOM and CSSOM methods](unimplemented.html)
+is available outlining the remaining API that have to be implemented.
+
+Development
+-----------
+
+Compiling a development edition of NetSurf requires a POSIX style
+environment. Typically this means a Linux based system although Free
+BSD, Open BSD, Mac OS X and Haiku all known to work.
+
+### Working with the team
+
+Generally it is sensible to check with the other developers if you are
+planning to make a change to NetSurf intended to be merged.
+
+We are often about on the IRC channel but failing that the developer
+mailing list is a good place to try.
+
+All the project sources are held in [public git repositories](http://source.netsurf-browser.org/)
+
+### Toolchains
+
+Compilation for non POSIX toolkits/frontends (e.g. RISC OS) generally
+relies upon a cross compilation environment which is generated using
+the makefiles found in our
+[toolchains](http://source.netsurf-browser.org/toolchains.git/)
+repository. These toolchains are built by the Continuous Integration
+(CI) system and the
+[results of the system](http://ci.netsurf-browser.org/builds/toolchains/)
+are published as a convenience.
+
+### Quick setup
+
+The [quick start guide](docs/quick-start.md) can be used to get a
+development environment setup quickly and uses the
+[env.sh](env_8sh_source.html) script the core team utilises.
+
+### Manual setup
+
+The Manual environment setup and compilation method is covered by the
+details in the [netsurf libraries](docs/netsurf-libraries.md) document
+for the core libraries and then one of the building documents for the
+specific frontend.
+
+- [Amiga Os cross](docs/building-AmigaCross.md) and [Amiga OS](docs/building-AmigaOS.md)
+- [Framebuffer](docs/building-Framebuffer.md)
+- [GTK](docs/building-GTK.md)
+- [Haiku (BeOS)](docs/building-Haiku.md)
+- [Windows Win32](docs/building-Windows.md)
+
+These documents are sometimes not completely up to
+date and the env.sh script should be considered canonical.
+
diff --git a/Docs/netsurf-fb.1 b/docs/netsurf-fb.1
index e4c310075..e4c310075 100644
--- a/Docs/netsurf-fb.1
+++ b/docs/netsurf-fb.1
diff --git a/Docs/netsurf-gtk.1 b/docs/netsurf-gtk.1
index 7b2f4f4f3..7b2f4f4f3 100644
--- a/Docs/netsurf-gtk.1
+++ b/docs/netsurf-gtk.1
diff --git a/Docs/LIBRARIES b/docs/netsurf-libraries.md
index dc5a98048..dc5a98048 100644
--- a/Docs/LIBRARIES
+++ b/docs/netsurf-libraries.md
diff --git a/docs/netsurf-options.md b/docs/netsurf-options.md
new file mode 100644
index 000000000..553813842
--- /dev/null
+++ b/docs/netsurf-options.md
@@ -0,0 +1,147 @@
+Common NetSurf user options
+---------------------------
+
+This document outlines the common configuration options supported by
+ the NetSurf core.
+
+Overview
+========
+
+The users configurations are generally stored in a "Choices" file and
+ are loaded at browser startup. Most user interfaces provide a way
+ to configure these parameters in a manner consistant with the
+ toolkit in use.
+
+The user choices are stored as a simple key:value list.
+
+Each entry has a type, one of: boolean, integer, unsigned integer,
+ hexadecimal colour value or string.
+
+General Options
+===============
+
+ Option Key | Type | Default | Description
+ -------------------- | ------ | --------- | --------------------------------
+ http_proxy | bool | false | An HTTP proxy should be used.
+ http_proxy | bool | false | An HTTP proxy should be used.
+ http_proxy_host | string | NULL | Hostname of proxy.
+ http_proxy_port | int | 8080 | Proxy port.
+ http_proxy_auth | int | 0 | Proxy authentication method.
+ http_proxy_auth_user | string | NULL | Proxy authentication user name
+ http_proxy_auth_pass | string | NULL | Proxy authentication password
+ http_proxy_noproxy | string | localhost | Proxy omission list
+ font_size | int | 128 | Default font size / 0.1pt.
+ font_min_size | int | 85 | Minimum font size.
+ font_sans | string | NULL | Default sans serif font
+ font_serif | string | NULL | Default serif font
+ font_mono | string | NULL | Default monospace font
+ font_cursive | string | NULL | Default cursive font
+ font_fantasy | string | NULL | Default fantasy font
+ accept_language | string | NULL | Accept-Language header.
+ accept_charset | string | NULL | Accept-Charset header.
+ memory_cache_size | int | 12MiB | Preferred maximum size of memory cache in bytes.
+ disc_cache_size | uint | 1GiB | Preferred expiry size of disc cache in bytes.
+ disc_cache_age | int | 28 | Preferred expiry age of disc cache in days.
+ block_advertisements | bool | false | Whether to block advertisements
+ do_not_track | bool | false | Disable website tracking [1]
+ minimum_gif_delay | int | 10 | Minimum GIF animation delay
+ send_referer | bool | true | Whether to send the referer HTTP header.
+ foreground_images | bool | true | Whether to fetch foreground images
+ background_images | bool | true | Whether to fetch background images
+ animate_images | bool | true | Whether to animate images
+ enable_javascript | bool | false | Whether to execute javascript
+ script_timeout | int | 10 | Maximum time to wait for a script to run in seconds
+ expire_url | int | 28 | How many days to retain URL data for.
+ font_default | int | 0 | Default font family
+ ca_bundle | string | NULL | ca-bundle location
+ ca_path | string | NULL | ca-path location
+ cookie_file | string | NULL | Cookie file location
+ cookie_jar | string | NULL | Cookie jar location
+ homepage_url | string | NULL | Home page location
+ search_url_bar | bool | false | search web from url bar
+ search_provider | int | 0 | default web search provider
+ url_suggestion | bool | true | URL completion in url bar
+ window_x | int | 0 | default x position of new windows
+ window_y | int | 0 | default y position of new windows
+ window_width | int | 0 | default width of new windows
+ window_height | int | 0 | default height of new windows
+ window_screen_width | int | 0 | width of screen when above options were saved
+ window_screen_height | int | 0 | height of screen when above options were saved
+ toolbar_status_size | int | 6667 | default size of status bar vs. h scroll bar
+ scale | int | 100 | default window scale
+ incremental_reflow | bool | true | Whether to reflow web pages while objects are fetching
+ min_reflow_period | uint | 25 | Minimum time (in cs) between HTML reflows while objects are fetching
+ core_select_menu | bool | false | Use core selection menu
+
+[1] http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas
+
+Fetcher options
+===============
+
+ Option Key | Type | Default | Description
+ ------------------------ | -----| ------- | -----------------------------------
+ max_fetchers | int | 24 | Maximum simultaneous active fetchers
+ max_fetchers_per_host | int | 5 | Maximum simultaneous active fetchers per host. (<=option_max_fetchers else it makes no sense) [2]
+ max_cached_fetch_handles | int | 6 | Maximum number of inactive fetchers cached. The total number of handles netsurf will therefore have open is this plus option_max_fetchers.
+ suppress_curl_debug | bool | true | Suppress debug output from cURL.
+ target_blank | bool | true | Whether to allow target="_blank"
+ button_2_tab | bool | true | Whether second mouse button opens in new tab.
+
+[2] Note that rfc2616 section 8.1.4 says that there should be no more
+ than two keepalive connections per host. None of the main browsers
+ follow this as it slows page fetches down considerably.
+ See https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4
+
+
+PDF / Print options
+===================
+
+ Option Key | Type | Deflt | Description
+ ---------------------- | ---- | ----- | ------------------------------------
+ margin_top | int | 10 | top margin of exported page
+ margin_bottom | int | 10 | bottom margin of exported page
+ margin_left | int | 10 | left margin of exported page
+ margin_right | int | 10 | right margin of exported page
+ export_scale | int | 70 | scale of exported content
+ suppress_images | bool | false | suppressing images in printed content
+ remove_backgrounds | bool | false | turning off all backgrounds for printed content
+ enable_loosening | bool | true | turning on content loosening for printed content
+ enable_PDF_compression | bool | true | compression of PDF documents
+ enable_PDF_password | bool | false | setting a password and encoding PDF documents
+
+System colours
+==============
+
+These are the css system colours which the browser also uses to style
+generated output.
+
+ Option Key | Type | Default
+ ------------------------------ | ------ | ----------
+ sys_colour_ActiveBorder | colour | 0x00d3d3d3
+ sys_colour_ActiveCaption | colour | 0x00f1f1f1
+ sys_colour_AppWorkspace | colour | 0x00f1f1f1
+ sys_colour_Background | colour | 0x006e6e6e
+ sys_colour_ButtonFace | colour | 0x00f9f9f9
+ sys_colour_ButtonHighlight | colour | 0x00ffffff
+ sys_colour_ButtonShadow | colour | 0x00aeaeae
+ sys_colour_ButtonText | colour | 0x004c4c4c
+ sys_colour_CaptionText | colour | 0x004c4c4c
+ sys_colour_GrayText | colour | 0x00505050
+ sys_colour_Highlight | colour | 0x00c00800
+ sys_colour_HighlightText | colour | 0x00ffffff
+ sys_colour_InactiveBorder | colour | 0x00f1f1f1
+ sys_colour_InactiveCaption | colour | 0x00e6e6e6
+ sys_colour_InactiveCaptionText | colour | 0x00a6a6a6
+ sys_colour_InfoBackground | colour | 0x008fdfef
+ sys_colour_InfoText | colour | 0x00000000
+ sys_colour_Menu | colour | 0x00f1f1f1
+ sys_colour_MenuText | colour | 0x004e4e4e
+ sys_colour_Scrollbar | colour | 0x00cccccc
+ sys_colour_ThreeDDarkShadow | colour | 0x00aeaeae
+ sys_colour_ThreeDFace | colour | 0x00f9f9f9
+ sys_colour_ThreeDHighlight | colour | 0x00ffffff
+ sys_colour_ThreeDLightShadow | colour | 0x00ffffff
+ sys_colour_ThreeDShadow | colour | 0x00d5d5d5
+ sys_colour_Window | colour | 0x00f1f1f1
+ sys_colour_WindowFrame | colour | 0x004e4e4e
+ sys_colour_WindowText | colour | 0x00000000
diff --git a/docs/quick-start.md b/docs/quick-start.md
new file mode 100644
index 000000000..601269c96
--- /dev/null
+++ b/docs/quick-start.md
@@ -0,0 +1,120 @@
+Quick Build Steps for NetSurf
+=============================
+
+Last Updated: 15th December 2017
+
+This document provides steps for building NetSurf.
+
+Native build
+============
+
+Grab a temporary env.sh
+-----------------------
+
+ $ wget https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh
+ $ unset HOST
+ $ source env.sh
+
+
+Install any packages you need
+-----------------------------
+
+Installs all packages required to build NetSurf and the NetSurf project
+libraries.
+
+ $ ns-package-install
+
+If your package manager is not supported, you will have to install third
+ party packages manually.
+
+
+Get the NetSurf project source code from Git
+--------------------------------------------
+
+All the sources for the browser and support libraries is available
+ from the public git server.
+
+Local copies may be easily obtained with the ns-clone command.
+
+ $ ns-clone
+
+
+Build and install our project libraries
+---------------------------------------
+
+Updates NetSurf project library sources to latest, builds and installs them.
+
+ $ ns-pull-install
+
+
+Switch to new NetSurf workspace
+-------------------------------
+
+Remove the bootstrap script and use the newly installed one
+
+ $ rm env.sh
+ $ cd ~/dev-netsurf/workspace
+ $ source env.sh
+
+
+Build and run NetSurf
+---------------------
+
+ $ cd netsurf
+
+To build the native front end (the GTK front end on Linux, BSDs, etc)
+ you could do:
+
+ $ make
+ $ ./nsgtk
+
+To build the framebuffer front end, you could do:
+
+ $ make TARGET=framebuffer
+ $ ./nsfb
+
+
+Cross Compiling
+===============
+
+If you are cross compiling, you can follow the above steps, but when
+ sourcing env.sh, you should set HOST environment variable to the
+ appropriate triplet for your cross compiler. For example, to cross
+ compile for RISC OS:
+
+ $ HOST=arm-unknown-riscos source env.sh
+
+After that, the commands such as `ns-package-install` and
+ `ns-pull-install` will do what is appropriate for the platform you are
+ building for.
+
+To do the final build of NetSurf, pass the appropriate TARGET to
+ make. For example, to cross compile for RISC OS:
+
+ $ make TARGET=riscos
+
+Finally, you can package up your build to transfer to the system you
+ are developing for. For example, to produce a package for RISC OS:
+
+ $ make TARGET=riscos package
+
+Getting a cross compiler set up
+-------------------------------
+
+We maintain cross compilation environments and an SDK for a number of
+ platforms. These may be found in our toolchains repository.
+
+ $ git clone git://git.netsurf-browser.org/toolchains
+
+Pre-built versions of the toolchains for 64bit x86 Debian systems are
+ available via our [automated build and test
+ infrastructure](https://ci.netsurf-browser.org/builds/toolchains/)
+
+
+Not working?
+============
+
+If the above steps are inapplicable, or don't work, you can build
+ manually. Follow the instructions in the BUILDING-* documents in the
+ docs/ directory the NetSurf browser source tree.
+
diff --git a/Docs/source-object-backing-store b/docs/source-object-backing-store.md
index 0fb3614d4..0fb3614d4 100644
--- a/Docs/source-object-backing-store
+++ b/docs/source-object-backing-store.md
diff --git a/Docs/unit-testing b/docs/unit-testing
index 49d82ed81..49d82ed81 100644
--- a/Docs/unit-testing
+++ b/docs/unit-testing
diff --git a/docs/updating-duktape.md b/docs/updating-duktape.md
new file mode 100644
index 000000000..672fccc89
--- /dev/null
+++ b/docs/updating-duktape.md
@@ -0,0 +1,29 @@
+Updating Duktape
+================
+
+1. Fetch the [latest release](http://duktape.org/download.html) archive.
+
+2. Extract it somewhere.
+
+3. That extracts to a `duktape-[VERSION]` directory.
+
+4. We need to tell duktape about our `duk_custom.h` header:
+
+ 1. Change into the `duktape-[VERSION]` directory.
+
+ 2. Run the following command:
+
+ python2 tools/configure.py \
+ --output-directory /tmp/output \
+ --source-directory src-input \
+ --config-metadata config \
+ --fixup-line '#include "duk_custom.h"'
+
+ 3. This generates a suitable set of duktape
+ sources in `/tmp/output`
+
+5. Replace the `duktape.c`, `duktape.h` and
+ `duk_config.h` files in the netsurf source
+ tree (in `content/handlers/javascript/duktape`)
+ with those generated in `/tmp/output`.
+
diff --git a/Docs/USING-Framebuffer b/docs/using-framebuffer.md
index 3af8f983f..3af8f983f 100644
--- a/Docs/USING-Framebuffer
+++ b/docs/using-framebuffer.md
diff --git a/docs/using-monkey.md b/docs/using-monkey.md
new file mode 100644
index 000000000..d6082bda9
--- /dev/null
+++ b/docs/using-monkey.md
@@ -0,0 +1,373 @@
+Usage Instructions for Monkey NetSurf
+=====================================
+
+This document provides usage instructions for the Monkey version of NetSurf.
+
+Monkey NetSurf has been tested on Ubuntu and Debian.
+
+Overview
+--------
+
+### What it is
+
+The NetSurf Monkey front end is a developer debug tool used to test how the
+core interacts with the user interface. It allows the developers to profile
+NetSurf and to interact with the core directly as though the developer were a
+front end.
+
+### What it is not
+
+Monkey is not a tool for building web-crawling robots or indeed anything other
+than a debug tool for the NetSurf developers.
+
+### How to interact with `nsmonkey`
+
+In brief, `nsmonkey` will produce tagged output on stdout and expect
+commands on stdin. Windows are numbered and for the most part
+tokens are space separated. In some cases (e.g. title or status)
+the final element on the output line is a string which might have
+spaces embedded within it. As such, output from `nsmonkey` should be
+parsed a token at a time, so that when such a string is encountered,
+the parser can stop splitting and return the rest.
+
+Commands to `nsmonkey` are namespaced. For example commands related to
+browser windows are prefixed by `WINDOW`.
+
+### Top level tags for `nsmonkey`
+
+* `QUIT`
+
+* `WINDOW`
+
+* `OPTIONS`
+
+### Top level response tags for nsmonkey
+
+* `GENERIC`: Generic messages such as poll loops etc.
+
+* `WARN`, `ERROR`, `DIE`: Error messages of varying importance
+
+* `WINDOW`: Anything about browser windows in general
+
+* `DOWNLOAD_WINDOW`: Anything about the download window.
+
+* `SSLCERT`: Anything about SSL certificates
+
+* `401LOGIN`: Anything about HTTP Basic Authentication logins
+
+* `PLOT`: Plot calls which come from the core.
+
+In the below, _%something%_ indicates a substitution made by Monkey.
+
+* _%url%_ will be a URL
+* _%id%_ will be an opaque ID
+* _%n%_ will be a number
+* _%bool%_ will be TRUE or FALSE
+* _%str%_ is a string and will only ever be at the end of an output line.
+
+### Warnings, errors etc
+
+* Warnings (tagged `WARN`) come from the NetSurf core.
+* Errors (tagged `ERROR`) tend to come from Monkey's parsers
+* Death (tagged `DIE`) comes from the core and kills Monkey dead.
+
+Commands
+--------
+
+### Generic commands
+
+* `QUIT`
+
+ Cause monkey to quit cleanly.
+ This will cleanly destroy open windows etc.
+
+* `OPTIONS` _%str_
+
+ Cause monkey to set options. The passed options should be in the same
+ form as the command line, e.g. `OPTIONS --enable_javascript=1`
+
+
+### Window commands
+
+* `WINDOW NEW` [_%url%_]
+
+ Create a new browser window, optionally giving the core
+ a URL to immediately navigate to.
+ Minimally you will receive a `WINDOW NEW WIN` _%id%_ response.
+
+* `WINDOW DESTROY` _%id%_
+
+ Destroy the given browser window.
+ Minimally you will receive a `WINDOW DESTROY WIN` _%id%_ response.
+
+* `WINDOW GO` _%id%_ _%url%_ [_%url%_]
+
+ Cause the given browser window to visit the given URL.
+ Optionally you can give a referrer URL to also use (simulating
+ a click in the browser on a link).
+ Minimally you can expect throbber, url etc responses.
+
+* `WINDOW REDRAW` _%id%_ [_%num% %num% %num% %num%_]
+
+ Cause a browser window to redraw. Optionally you can give a
+ set of coordinates to simulate a partial expose of the window.
+ Said coordinates are in traditional X0 Y0 X1 Y1 order.
+ The coordinates are in canvas, not window, coordinates. So you
+ should take into account the scroll offsets when issuing this
+ command.
+ Minimally you can expect redraw start/stop messages and you
+ can likely expect some number of `PLOT` results.
+
+* `WINDOW RELOAD` _%id%_
+
+ Cause a browser window to reload its current content.
+ Expect responses similar to a GO command.
+
+
+Responses
+---------
+
+### Generic messages
+
+* `GENERIC STARTED`
+
+ Monkey has started and is ready for commands
+
+* `GENERIC CLOSING_DOWN`
+
+ Monkey has been told to shut down and is doing so
+
+* `GENERIC FINISHED`
+
+ Monkey has finished and will now exit
+
+* `GENERIC LAUNCH URL` _%url%_
+
+ The core asked monkey to launch the given URL
+
+* `GENERIC THUMBNAIL URL` _%url%_
+
+ The core asked monkey to thumbnail a content without
+ a window.
+
+* `GENERIC POLL BLOCKING`
+* `GENERIC POLL TIMED` _%n%_
+
+ Monkey reached a point where it could sleep waiting for
+ commands or scheduled timeouts. No fetches nor redraws
+ were pending. If there are no timeouts or other pending
+ jobs then this will be a BLOCKING poll, otherwise the number
+ given is in milliseconds.
+
+### Window messages
+
+* `WINDOW NEW WIN` _%id%_ `FOR` _%id%_ `CLONE` _%id%_ `NEWTAB` _%bool%_
+
+ The core asked Monkey to open a new window. The IDs for `FOR` and
+ `CLONE` are core window IDs, the `WIN` id is a Monkey window ID.
+
+* `WINDOW SIZE WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_
+
+ The window specified has been set to the shown width and height.
+
+* `WINDOW DESTROY WIN` _%id%_
+
+ The core has instructed Monkey to destroy the named window.
+
+* `WINDOW TITLE WIN` _%id%_ `STR` _%str%_
+
+ The core supplied a titlebar title for the given window.
+
+* `WINDOW REDRAW WIN` _%id%_
+
+ The core asked that Monkey redraw the given window.
+
+* `WINDOW GET_DIMENSIONS WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_
+
+ The core asked Monkey what the dimensions of the window are.
+ Monkey has to respond immediately and returned the supplied width
+ and height values to the core.
+
+* `WINDOW NEW_CONTENT WIN` _%id%_
+
+ The core has informed Monkey that the named window has a new
+ content object.
+
+* `WINDOW NEW_ICON WIN` _%id%_
+
+ The core has informed Monkey that the named window has a new
+ icon (favicon) available.
+
+* `WINDOW START_THROBBER WIN` _%id%_
+
+ The core asked Monkey to start the throbber for the named
+ window. This indicates to the user that the window is busy.
+
+* `WINDOW STOP_THROBBER WIN` _%id%_
+
+ The core asked Monkey to stop the throbber for the named
+ window. This indicates to the user that the window is finished.
+
+* `WINDOW SET_SCROLL WIN` _%id%_ `X` _%n%_ `Y` _%n%_
+
+ The core asked Monkey to set the named window's scroll offsets
+ to the given X and Y position.
+
+* `WINDOW UPDATE_BOX WIN` _%id%_ `X` _%n%_ `Y` _%n%_ `WIDTH` _%n%_ `HEIGHT` _%n%_
+
+ The core asked Monkey to redraw the given portion of the content
+ display. Note these coordinates refer to the content, not the
+ viewport which Monkey is simulating.
+
+* `WINDOW UPDATE_EXTENT WIN` _%id%_ `WIDTH` _%n%_ `HEIGHT` _%n%_
+
+ The core has told us that the content in the given window has a
+ total width and height as shown. This allows us (along with the
+ window's width and height) to know the scroll limits.
+
+* `WINDOW SET_STATUS WIN` _%id%_ `STR` _%str%_
+
+ The core has told us that the given window needs its status bar
+ updating with the given message.
+
+* `WINDOW SET_POINTER WIN` _%id%_ `POINTER` _%id%_
+
+ The core has told us to update the mouse pointer for the given
+ window to the given pointer ID.
+
+* `WINDOW SET_SCALE WIN` _%id%_ `SCALE` _%n%_
+
+ The core has asked us to scale the given window by the given scale
+ factor.
+
+* `WINDOW SET_URL WIN` _%id%_ `URL` _%url%_
+
+ The core has informed us that the given window's URL bar needs
+ updating to the given url.
+
+* `WINDOW GET_SCROLL WIN` _%id%_ `X` _%n%_ `Y` _%n%_
+
+ The core asked Monkey for the scroll offsets. Monkey returned the
+ numbers shown for the window named.
+
+* `WINDOW SCROLL_START WIN` _%id%_
+
+ The core asked Monkey to scroll the named window to the top/left.
+
+* `WINDOW POSITION_FRAME WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to position the named window as a frame at
+ the given coordinates of its parent.
+
+* `WINDOW SCROLL_VISIBLE WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to scroll the named window until the
+ indicated box is visible.
+
+* `WINDOW PLACE_CARET WIN` _%id%_ `X` _%n%_ `Y` _%n%_ `HEIGHT` _%n%_
+
+ The core asked Monkey to render a caret in the named window at the
+ indicated position with the indicated height.
+
+* `WINDOW REMOVE_CARET WIN` _%id%_
+
+ The core asked Monkey to remove any caret in the named window.
+
+* `WINDOW SCROLL_START WIN` _%id%_ `X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to scroll the named window to the start of
+ the given box.
+
+* `WINDOW SELECT_MENU WIN` _%id%_
+
+ The core asked Monkey to produce a selection menu for the named
+ window.
+
+* `WINDOW SAVE_LINK WIN` _%id%_ `URL` _%url%_ `TITLE` _%str%_
+
+ The core asked Monkey to save a link from the given window with
+ the given URL and anchor title.
+
+* `WINDOW THUMBNAIL WIN` _%id%_ `URL` _%url%_
+
+ The core asked Monkey to render a thumbnail for the given window
+ which is currently at the given URL.
+
+* `WINDOW REDRAW WIN` _%id%_ `START`
+
+ and
+
+ `WINDOW REDRAW WIN` _%id%_ `STOP`
+
+ The core wraps redraws in these messages. Thus `PLOT` responses can
+ be allocated to the appropriate window.
+
+### Download window messages
+
+* `DOWNLOAD_WINDOW CREATE DWIN` _%id%_ `WIN` _%id%_
+
+ The core asked Monkey to create a download window owned by the
+ given browser window.
+
+* `DOWNLOAD_WINDOW DATA DWIN` _%id%_ `SIZE` _%n%_ `DATA` _%str%_
+
+ The core asked Monkey to update the named download window with
+ the given byte size and data string.
+
+* `DOWNLOAD_WINDOW ERROR DWIN` _%id%_ `ERROR` _%str%_
+
+ The core asked Monkey to update the named download window with
+ the given error message.
+
+* `DOWNLOAD_WINDOW DONE DWIN` _%id%_
+
+ The core asked Monkey to destroy the named download window.
+
+### SSL Certificate messages
+
+* `SSLCERT VERIFY CERT` _%id%_ `URL` _%url%_
+
+ The core asked Monkey to say whether or not a given SSL
+ certificate is OK.
+
+> TODO: Implement the rest of the SSL certificat verification behaviour
+
+### 401 Login messages
+
+* `401LOGIN OPEN M4` _%id%_ `URL` _%url%_ `REALM` _%str%_
+
+ The core asked Monkey to ask for identification for the named
+ realm at the given URL.
+
+> TODO: Implement support to control the 401LOGIN process
+
+### Plotter messages
+
+> **Note, Monkey won't clip coordinates, but sometimes the core does.**
+
+* `PLOT CLIP X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to clip plotting to the given clipping
+ rectangle (X0,Y0) (X1,Y1)
+
+* `PLOT TEXT X` _%n%_ `Y` _%n%_ `STR` _%str%_
+
+ The core asked Monkey to plot the given string at the
+ given coordinates.
+
+* `PLOT LINE X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to plot a line with the given start
+ and end coordinates.
+
+* `PLOT RECT X0` _%n%_ `Y0` _%n%_ `X1` _%n%_ `Y1` _%n%_
+
+ The core asked Monkey to plot a rectangle with the given
+ coordinates as the corners.
+
+* `PLOT BITMAP X` _%n%_ `Y` _%n%_ `WIDTH` _%n%_ `HEIGHT` _%n%_
+
+ The core asked Monkey to plot a bitmap at the given
+ coordinates, scaled to the given width/height.
+
+> TODO: Check if other things are implemented and add them to the docs
diff --git a/frontends/amiga/Makefile b/frontends/amiga/Makefile
index f57b4ef8a..ac05d1bf0 100644
--- a/frontends/amiga/Makefile
+++ b/frontends/amiga/Makefile
@@ -5,7 +5,7 @@
CFLAGS += -std=c99 -Dnsamiga
ifneq ($(SUBTARGET),os3)
- CFLAGS += -O2 -finline-functions -U__STRICT_ANSI__ -D__USE_INLINE__ -D__USE_BASETYPE__
+ CFLAGS += -O2 -mstrict-align -finline-functions -U__STRICT_ANSI__ -D__USE_INLINE__ -D__USE_BASETYPE__
else
CFLAGS += -O2 -DPATH_MAX=1024 -D__m68k__ -m68020
endif
@@ -67,8 +67,8 @@ package-amiga: netsurf.lha
AMIGA_LANGUAGES := de en it ja nl
AMIGA_PLATFORM_RESOURCES := Pointers Themes default.css default.css.info favicon.png LangNames mimetypes Resource.map splash.png
-AMIGA_GENERIC_RESOURCES := $(AMIGA_LANGUAGES) ca-bundle Icons
-AMIGA_RESOURCES := $(addprefix $(FRONTEND_SOURCE_DIR)/resources/,$(AMIGA_PLATFORM_RESOURCES)) $(addprefix \!NetSurf/Resources/,$(AMIGA_GENERIC_RESOURCES))
+AMIGA_GENERIC_RESOURCES := $(AMIGA_LANGUAGES) ca-bundle icons
+AMIGA_RESOURCES := $(addprefix $(FRONTEND_SOURCE_DIR)/resources/,$(AMIGA_PLATFORM_RESOURCES)) $(addprefix resources/,$(AMIGA_GENERIC_RESOURCES))
AMIGA_DISTRIBUTION_FILES := $(FRONTEND_SOURCE_DIR)/dist/*
AMIGA_PKG_DIR := $(FRONTEND_SOURCE_DIR)/pkg
AMIGA_INSTALL_TARGET_DIR := NetSurf_Amiga
@@ -80,13 +80,14 @@ netsurf.lha: $(EXETARGET)
$(Q)cp -p $(EXETARGET) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf
$(Q)$(MKDIR) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources
$(Q)cp -rp $(AMIGA_RESOURCES) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources
+ $(Q)mv $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/icons $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/Icons
$(Q)cp -rp $(AMIGA_DISTRIBUTION_FILES) $(AMIGA_INSTALL_TARGET_DIR)/NetSurf
$(Q)cat resources/SearchEngines $(AMIGA_PKG_DIR)/SearchEngines >$(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/SearchEngines
- $(Q)cp -p \!NetSurf/Resources/AdBlock,f79 $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/adblock.css
- $(Q)cp -p \!NetSurf/Resources/CSS,f79 $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/nsdefault.css
- $(Q)cp -p \!NetSurf/Resources/internal.css,f79 $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/internal.css
- $(Q)cp -p \!NetSurf/Resources/Quirks,f79 $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/quirks.css
- $(Q)cp -p \!NetSurf/Resources/netsurf.png,b60 $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/netsurf.png
+ $(Q)cp -p resources/adblock.css $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/adblock.css
+ $(Q)cp -p resources/default.css $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/nsdefault.css
+ $(Q)cp -p resources/internal.css $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/internal.css
+ $(Q)cp -p resources/quirks.css $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/quirks.css
+ $(Q)cp -p resources/netsurf.png $(AMIGA_INSTALL_TARGET_DIR)/NetSurf/Resources/netsurf.png
$(Q)cp -p $(AMIGA_PKG_DIR)/drawer.info $(AMIGA_INSTALL_TARGET_DIR)/NetSurf.info
$(Q)cp -p $(AMIGA_PKG_DIR)/AutoInstall $(AMIGA_INSTALL_TARGET_DIR)
ifeq ($(SUBTARGET),os3)
diff --git a/frontends/amiga/arexx.c b/frontends/amiga/arexx.c
index 7bb2f5882..acb0348fd 100644
--- a/frontends/amiga/arexx.c
+++ b/frontends/amiga/arexx.c
@@ -173,7 +173,7 @@ void ami_arexx_execute(char *script)
if((lock = Lock(script, ACCESS_READ))) {
DevNameFromLock(lock, full_script_path, 1024, DN_FULLPATH);
- LOG("Executing script: %s", full_script_path);
+ NSLOG(netsurf, INFO, "Executing script: %s", full_script_path);
ami_arexx_command(full_script_path, NULL);
UnLock(lock);
}
@@ -366,7 +366,7 @@ RXHOOKF(rx_save)
FWrite(fh, source_data, 1, source_size);
FClose(fh);
- SetComment((char *)cmd->ac_ArgList[0], nsurl_access(browser_window_get_url(gw->bw)));
+ SetComment((char *)cmd->ac_ArgList[0], nsurl_access(browser_window_access_url(gw->bw)));
}
ami_reset_pointer(gw->shared);
@@ -395,7 +395,7 @@ RXHOOKF(rx_geturl)
if(gw && gw->bw)
{
- strcpy(result, nsurl_access(browser_window_get_url(gw->bw)));
+ strcpy(result, nsurl_access(browser_window_access_url(gw->bw)));
}
else
{
diff --git a/frontends/amiga/bitmap.c b/frontends/amiga/bitmap.c
index 5fc772ba3..0fde677ae 100644
--- a/frontends/amiga/bitmap.c
+++ b/frontends/amiga/bitmap.c
@@ -161,7 +161,10 @@ static void amiga_bitmap_unmap_buffer(void *p)
struct bitmap *bm = p;
if((nsoption_bool(use_extmem) == true) && (bm->pixdata != NULL)) {
- LOG("Unmapping ExtMem object %p for bitmap %p", bm->iextmem, bm);
+ NSLOG(netsurf, INFO,
+ "Unmapping ExtMem object %p for bitmap %p",
+ bm->iextmem,
+ bm);
bm->iextmem->Unmap(bm->pixdata, bm->size);
bm->pixdata = NULL;
}
@@ -176,7 +179,10 @@ unsigned char *amiga_bitmap_get_buffer(void *bitmap)
#ifdef __amigaos4__
if(nsoption_bool(use_extmem) == true) {
if(bm->pixdata == NULL) {
- LOG("Mapping ExtMem object %p for bitmap %p", bm->iextmem, bm);
+ NSLOG(netsurf, INFO,
+ "Mapping ExtMem object %p for bitmap %p",
+ bm->iextmem,
+ bm);
bm->pixdata = bm->iextmem->Map(NULL, bm->size, 0LL, 0);
}
@@ -596,8 +602,12 @@ static inline struct BitMap *ami_bitmap_get_generic(struct bitmap *bitmap,
TAG_DONE);
if (err != COMPERR_Success) {
- LOG("Composite error %ld - falling back", err);
- /* If it failed, do it again the way which works in software */
+ NSLOG(netsurf, INFO,
+ "Composite error %ld - falling back",
+ err);
+ /* If it failed, do it again the way
+ * which works in software
+ */
#else
{
#endif
@@ -611,7 +621,8 @@ static inline struct BitMap *ami_bitmap_get_generic(struct bitmap *bitmap,
COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
TAG_DONE);
/* If it still fails... it's non-fatal */
- LOG("Fallback returned error %ld", err);
+ NSLOG(netsurf, INFO,
+ "Fallback returned error %ld", err);
}
} else /* Do it the old-fashioned way. This is pretty slow, even on OS4.1 */
#endif
@@ -703,11 +714,11 @@ static inline struct BitMap *ami_bitmap_get_palettemapped(struct bitmap *bitmap,
}
struct BitMap *ami_bitmap_get_native(struct bitmap *bitmap,
- int width, int height, struct BitMap *friendbm)
+ int width, int height, bool palette_mapped, struct BitMap *friendbm)
{
if(bitmap == NULL) return NULL;
- if(__builtin_expect(ami_plot_screen_is_palettemapped() == true, 0)) {
+ if(__builtin_expect(palette_mapped == true, 0)) {
return ami_bitmap_get_palettemapped(bitmap, width, height, friendbm);
} else {
return ami_bitmap_get_truecolour(bitmap, width, height, friendbm);
@@ -723,28 +734,25 @@ void ami_bitmap_fini(void)
static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
{
#ifdef __amigaos4__
- LOG("Entering bitmap_render");
-
- struct redraw_context ctx = {
- .interactive = false,
- .background_images = true,
- .plot = &amiplot
- };
+ NSLOG(netsurf, INFO, "Entering bitmap_render");
int plot_width;
int plot_height;
- struct gui_globals bm_globals;
- struct gui_globals *temp_gg = glob;
+ struct gui_globals *bm_globals;
plot_width = MIN(content_get_width(content), bitmap->width);
plot_height = ((plot_width * bitmap->height) + (bitmap->width / 2)) /
bitmap->width;
- ami_init_layers(&bm_globals, bitmap->width, bitmap->height, true);
- bm_globals.shared_pens = NULL;
+ bm_globals = ami_plot_ra_alloc(bitmap->width, bitmap->height, true, false);
+ ami_clearclipreg(bm_globals);
- glob = &bm_globals;
- ami_clearclipreg(&bm_globals);
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = true,
+ .plot = &amiplot,
+ .priv = bm_globals
+ };
content_scaled_redraw(content, plot_width, plot_height, &ctx);
@@ -752,7 +760,7 @@ static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *conte
BLITA_SrcY, 0,
BLITA_Width, bitmap->width,
BLITA_Height, bitmap->height,
- BLITA_Source, bm_globals.bm,
+ BLITA_Source, ami_plot_ra_get_bitmap(bm_globals),
BLITA_SrcType, BLITT_BITMAP,
BLITA_Dest, amiga_bitmap_get_buffer(bitmap),
BLITA_DestType, BLITT_ARGB32,
@@ -766,14 +774,8 @@ static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *conte
/**\todo In theory we should be able to move the bitmap to our native area
to try to avoid re-conversion (at the expense of memory) */
- ami_free_layers(&bm_globals);
+ ami_plot_ra_free(bm_globals);
amiga_bitmap_set_opaque(bitmap, true);
-
- /* Restore previous render area. This is set when plotting starts,
- * but if bitmap_render is called *during* a browser render then
- * having an invalid pointer here causes NetSurf to crash.
- */
- glob = temp_gg;
#else
#warning FIXME for OS3 (in current state none of bitmap_render can work!)
#endif
diff --git a/frontends/amiga/bitmap.h b/frontends/amiga/bitmap.h
index a32d740df..aaec26ac2 100755
--- a/frontends/amiga/bitmap.h
+++ b/frontends/amiga/bitmap.h
@@ -31,9 +31,10 @@
extern struct gui_bitmap_table *amiga_bitmap_table;
struct bitmap;
struct nsurl;
+struct gui_globals;
struct BitMap *ami_bitmap_get_native(struct bitmap *bitmap,
- int width, int height, struct BitMap *friendbm);
+ int width, int height, bool palette_mapped, struct BitMap *friendbm);
PLANEPTR ami_bitmap_get_mask(struct bitmap *bitmap, int width,
int height, struct BitMap *n_bm);
@@ -75,8 +76,7 @@ void ami_bitmap_set_icondata(struct bitmap *bm, ULONG *icondata);
/**
* Free an icondata pointer
*
- * \param bm a bitmap, as returned by bitmap_create()
- * \param icondata a pointer to memory
+ * \param bm a bitmap, as returned by bitmap_create()
*
* This function probably shouldn't be here!
*/
diff --git a/frontends/amiga/cookies.c b/frontends/amiga/cookies.c
index 877805cda..45e883fde 100644
--- a/frontends/amiga/cookies.c
+++ b/frontends/amiga/cookies.c
@@ -136,7 +136,7 @@ ami_cookies_mouse(struct ami_corewindow *ami_cw,
/**
* callback for keypress for cookies viewer on core window
*
- * \param example_cw The Amiga core window structure.
+ * \param ami_cw The Amiga core window structure.
* \param nskey The netsurf key code
* \return NSERROR_OK on success otherwise apropriate error code
*/
@@ -153,6 +153,8 @@ ami_cookies_key(struct ami_corewindow *ami_cw, uint32_t nskey)
* callback on draw event for cookies viewer on core window
*
* \param ami_cw The Amiga core window structure.
+ * \param x The x cordinate to plot at
+ * \param y The y cordinate to plot at
* \param r The rectangle of the window that needs updating.
* \param ctx The drawing context
* \return NSERROR_OK on success otherwise apropriate error code
@@ -362,7 +364,7 @@ nserror ami_cookies_present(void)
res = ami_cookies_create_window(ncwin);
if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
ami_utf8_free(ncwin->core.wintitle);
free(ncwin);
return res;
diff --git a/frontends/amiga/corewindow.c b/frontends/amiga/corewindow.c
index 0ed16d1ee..42ee866ea 100644
--- a/frontends/amiga/corewindow.c
+++ b/frontends/amiga/corewindow.c
@@ -47,6 +47,7 @@
#include "netsurf/plot_style.h"
#include <proto/exec.h>
+#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/layout.h>
#include <proto/utility.h>
@@ -202,15 +203,16 @@ ami_cw_key(struct ami_corewindow *ami_cw, int nskey)
/**
* Redraw functions
*
- * This is slightly over-engineered as it was taken from the main browser/old tree redraws
- * and supports deferred drawing of rectangles and tiling
+ * This is slightly over-engineered as it was taken from the main
+ * browser/old tree redraws and supports deferred drawing of
+ * rectangles and tiling
*/
/**
* Redraw an area of a core window
*
- * \param g a struct ami_corewindow
- * \param r rect (in document co-ordinates)
+ * \param ami_cw An Amiga core window structure
+ * \param r rect (in document co-ordinates)
*/
static void
@@ -219,8 +221,8 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
struct IBox *bbox;
ULONG pos_x, pos_y;
struct rect draw_rect;
- int tile_size_x = ami_cw->gg.width;
- int tile_size_y = ami_cw->gg.height;
+ int tile_size_x;
+ int tile_size_y;
int tile_x, tile_y, tile_w, tile_h;
int x = r->x0;
int y = r->y0;
@@ -230,7 +232,8 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
- .plot = &amiplot
+ .plot = &amiplot,
+ .priv = ami_cw->gg
};
if(ami_gui_get_space_box((Object *)ami_cw->objects[GID_CW_DRAW], &bbox) != NSERROR_OK) {
@@ -240,8 +243,6 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
ami_cw_scroller_top(ami_cw, &pos_x, &pos_y);
- glob = &ami_cw->gg;
-
if(x - pos_x + width > bbox->Width) width = bbox->Width - (x - pos_x);
if(y - pos_y + height > bbox->Height) height = bbox->Height - (y - pos_y);
@@ -255,6 +256,8 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
y = pos_y;
}
+ ami_plot_ra_get_size(ami_cw->gg, &tile_size_x, &tile_size_y);
+
for(tile_y = y; tile_y < (y + height); tile_y += tile_size_y) {
tile_h = tile_size_y;
if(((y + height) - tile_y) < tile_size_y)
@@ -274,7 +277,7 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
#ifdef __amigaos4__
BltBitMapTags(BLITA_SrcType, BLITT_BITMAP,
- BLITA_Source, ami_cw->gg.bm,
+ BLITA_Source, ami_plot_ra_get_bitmap(ami_cw->gg),
BLITA_SrcX, 0,
BLITA_SrcY, 0,
BLITA_DestType, BLITT_RASTPORT,
@@ -285,7 +288,7 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
BLITA_Height, tile_h,
TAG_DONE);
#else
- BltBitMapRastPort(ami_cw->gg.bm, 0, 0,
+ BltBitMapRastPort(ami_plot_ra_get_bitmap(ami_cw->gg), 0, 0,
ami_cw->win->RPort, bbox->Left + tile_x - pos_x, bbox->Top + tile_y - pos_y,
tile_w, tile_h, 0xC0);
#endif
@@ -293,15 +296,15 @@ ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
}
ami_gui_free_space_box(bbox);
- ami_clearclipreg(glob);
- ami_gui_set_default_gg();
+ ami_clearclipreg(ami_cw->gg);
}
/**
* Draw the deferred rectangles
*
- * @param draw set to false to just delete the queue
+ * \param ami_cw An Amiga core window structure to queue redraw
+ * \param draw set to false to just delete the queue
*/
static void ami_cw_redraw_queue(struct ami_corewindow *ami_cw, bool draw)
{
@@ -312,7 +315,7 @@ static void ami_cw_redraw_queue(struct ami_corewindow *ami_cw, bool draw)
if(IsMinListEmpty(ami_cw->deferred_rects)) return;
if(draw == false) {
- LOG("Ignoring deferred box redraw queue");
+ NSLOG(netsurf, INFO, "Ignoring deferred box redraw queue");
} // else should probably show busy pointer
node = (struct nsObject *)GetHead((struct List *)ami_cw->deferred_rects);
@@ -375,7 +378,8 @@ ami_cw_redraw(struct ami_corewindow *ami_cw, const struct rect *restrict r)
nsobj = AddObject(ami_cw->deferred_rects, AMINS_RECT);
nsobj->objstruct = deferred_rect;
} else {
- LOG("Ignoring duplicate or subset of queued box redraw");
+ NSLOG(netsurf, INFO,
+ "Ignoring duplicate or subset of queued box redraw");
}
ami_schedule(1, ami_cw_redraw_cb, ami_cw);
}
@@ -522,7 +526,8 @@ HOOKF(void, ami_cw_idcmp_hook, Object *, object, struct IntuiMessage *)
break;
default:
- LOG("IDCMP hook unhandled event: %ld", msg->Class);
+ NSLOG(netsurf, INFO,
+ "IDCMP hook unhandled event: %ld", msg->Class);
break;
}
}
@@ -794,15 +799,26 @@ static const struct ami_win_event_table ami_cw_table = {
ami_cw_close,
};
+
/**
- * callback from core to request a redraw
+ * callback from core to request an invalidation of a amiga core window area.
+ *
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] r area to redraw or NULL for the entire window area.
+ * \return NSERROR_OK on success or appropriate error code.
*/
-static void
-ami_cw_redraw_request(struct core_window *cw, const struct rect *r)
+static nserror
+ami_cw_invalidate_area(struct core_window *cw, const struct rect *r)
{
struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
ami_cw_redraw(ami_cw, r);
+
+ return NSERROR_OK;
}
@@ -894,7 +910,7 @@ ami_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
struct core_window_callback_table ami_cw_cb_table = {
- .redraw_request = ami_cw_redraw_request,
+ .invalidate = ami_cw_invalidate_area,
.update_size = ami_cw_update_size,
.scroll_visible = ami_cw_scroll_visible,
.get_window_dimensions = ami_cw_get_window_dimensions,
@@ -906,6 +922,7 @@ nserror ami_corewindow_init(struct ami_corewindow *ami_cw)
{
/* setup the core window callback table */
ami_cw->cb_table = &ami_cw_cb_table;
+ ami_cw->drag_status = CORE_WINDOW_DRAG_NONE;
/* clear some vars */
ami_cw->mouse_state = BROWSER_MOUSE_HOVER;
@@ -917,8 +934,7 @@ nserror ami_corewindow_init(struct ami_corewindow *ami_cw)
ami_cw->dragging = false;
/* allocate drawing area etc */
- ami_init_layers(&ami_cw->gg, 100, 100, false); // force tiles to save memory
- ami_cw->gg.shared_pens = ami_AllocMinList();
+ ami_cw->gg = ami_plot_ra_alloc(100, 100, false, true); // force tiles to save memory
ami_cw->deferred_rects = NewObjList();
ami_cw->deferred_rects_pool = ami_memory_itempool_create(sizeof(struct rect));
@@ -988,8 +1004,7 @@ nserror ami_corewindow_fini(struct ami_corewindow *ami_cw)
#endif
/* release off-screen bitmap stuff */
- ami_plot_release_pens(ami_cw->gg.shared_pens);
- ami_free_layers(&ami_cw->gg);
+ ami_plot_ra_free(ami_cw->gg);
/* free the window title */
ami_utf8_free(ami_cw->wintitle);
diff --git a/frontends/amiga/corewindow.h b/frontends/amiga/corewindow.h
index cfcd7fc5e..ea01f67f1 100644
--- a/frontends/amiga/corewindow.h
+++ b/frontends/amiga/corewindow.h
@@ -76,7 +76,7 @@ struct ami_corewindow {
char *wintitle;
/** stuff for our off-screen render bitmap */
- struct gui_globals gg;
+ struct gui_globals *gg;
struct MinList *shared_pens;
/** drag status set by core */
@@ -171,7 +171,7 @@ struct ami_corewindow {
*
* As a pre-requisite the draw, key and mouse callbacks must be defined
*
- * \param example_cw An Amiga core window structure to initialise
+ * \param ami_cw An Amiga core window structure to initialise
* \return NSERROR_OK on successful initialisation otherwise error code.
*/
nserror ami_corewindow_init(struct ami_corewindow *ami_cw);
diff --git a/frontends/amiga/ctxmenu.c b/frontends/amiga/ctxmenu.c
index 717096f52..a6755e610 100644
--- a/frontends/amiga/ctxmenu.c
+++ b/frontends/amiga/ctxmenu.c
@@ -146,7 +146,7 @@ HOOKF(void, ami_ctxmenu_item_urlopentab, APTR, window, struct IntuiMessage *)
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
nserror error = browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY | BW_CREATE_TAB,
url,
- browser_window_get_url(gwin->gw->bw),
+ browser_window_access_url(gwin->gw->bw),
gwin->gw->bw,
&bw);
@@ -163,7 +163,7 @@ HOOKF(void, ami_ctxmenu_item_urlopenwin, APTR, window, struct IntuiMessage *)
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
nserror error = browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY,
url,
- browser_window_get_url(gwin->gw->bw),
+ browser_window_access_url(gwin->gw->bw),
gwin->gw->bw,
&bw);
@@ -180,7 +180,7 @@ HOOKF(void, ami_ctxmenu_item_urldownload, APTR, window, struct IntuiMessage *)
browser_window_navigate(gwin->gw->bw,
url,
- browser_window_get_url(gwin->gw->bw),
+ browser_window_access_url(gwin->gw->bw),
BW_NAVIGATE_DOWNLOAD,
NULL,
NULL,
@@ -200,7 +200,7 @@ HOOKF(void, ami_ctxmenu_item_objshow, APTR, window, struct IntuiMessage *)
browser_window_navigate(gwin->gw->bw,
hlcache_handle_get_url(hook->h_Data),
- browser_window_get_url(gwin->gw->bw),
+ browser_window_access_url(gwin->gw->bw),
BW_NAVIGATE_HISTORY,
NULL,
NULL,
@@ -240,7 +240,7 @@ HOOKF(void, ami_ctxmenu_item_frameshow, APTR, window, struct IntuiMessage *)
browser_window_navigate(gwin->gw->bw,
hlcache_handle_get_url(hook->h_Data),
- browser_window_get_url(gwin->gw->bw),
+ browser_window_access_url(gwin->gw->bw),
BW_NAVIGATE_HISTORY,
NULL,
NULL,
diff --git a/frontends/amiga/dist/NetSurf.guide b/frontends/amiga/dist/NetSurf.guide
index 512a264e6..0bdd90076 100755
--- a/frontends/amiga/dist/NetSurf.guide
+++ b/frontends/amiga/dist/NetSurf.guide
@@ -144,8 +144,9 @@ There are a couple of Amiga-specific options which can only be changed directly
@{b}redraw_tile_size_x@{ub}/@{b}redraw_tile_size_y@{ub} Specify the size of the off-screen bitmap. Higher will speed up redraws at the expense of memory. 0 disables tiling (will use a bitmap at least the size of the screen NetSurf is running on)
@{b}web_search_width@{ub} Defaults to 0. Larger values will increase the size of the web search gadget next to the URL bar.
@{b}mask_alpha@{ub} Threshold to use when determining which alpha values to convert to full transparency (0 - 255, where 255 will convert even opaque pixels to transparent). Defaults to 0. This is only used in palette-mapped modes where alpha blending is not currently supported.
-@{b}tab_new_session{ub} If NetSurf is already running, this will cause any passed URLs to open in a new tab rather than a new window.
+@{b}tab_new_session@{ub} If NetSurf is already running, this will cause any passed URLs to open in a new tab rather than a new window.
@{b}use_extmem@{ub} Defaults to 1 (enabled). Setting to 0 will prevent NetSurf using Extended Memory to store uncompressed images - this may have a performance benefit and no disadvantage for <2GB configurations. OS4.1FEU1 only.
+@{b}download_notify_progress@{ub} Defaults to 0 (disabled). Display download progress in a Ringhio notification. Requires Enhancer Pack (Ringhio 53.65+), behaviour without it is undefined.
@{b}url_file@{ub} Path to URL database file
@{b}hotlist_file@{ub} Path to Hotlist file
@{b}arexx_dir@{ub} Path to ARexx scripts dir
diff --git a/frontends/amiga/download.c b/frontends/amiga/download.c
index 47485e0da..41ff6a689 100644
--- a/frontends/amiga/download.c
+++ b/frontends/amiga/download.c
@@ -68,6 +68,18 @@
#include "amiga/theme.h"
#include "amiga/utf8.h"
+#ifndef APPNOTIFY_DisplayTime
+#define APPNOTIFY_DisplayTime ( TAG_USER + 13 )
+#endif
+
+#ifndef APPNOTIFY_Percentage
+#define APPNOTIFY_Percentage ( TAG_USER + 14 )
+#endif
+
+#ifndef APPNOTIFY_StopBackMsg
+#define APPNOTIFY_StopBackMsg ( TAG_USER + 17 )
+#endif
+
struct gui_download_window {
struct ami_generic_window w;
struct Window *win;
@@ -75,6 +87,7 @@ struct gui_download_window {
BPTR fh;
uint32 size;
uint32 downloaded;
+ uint32 progress;
struct dlnode *dln;
struct browser_window *bw;
struct download_context *ctx;
@@ -84,7 +97,8 @@ struct gui_download_window {
};
enum {
- AMINS_DLOAD_OK = 0,
+ AMINS_DLOAD_PROGRESS = 0,
+ AMINS_DLOAD_OK,
AMINS_DLOAD_ERROR,
AMINS_DLOAD_ABORT,
};
@@ -157,7 +171,19 @@ static struct gui_download_window *gui_download_window_create(download_context *
return NULL;
}
- dw->objects[OID_MAIN] = WindowObj,
+ if((nsoption_bool(download_notify_progress) == true)) {
+ char bkm[1030];
+ snprintf(bkm, 1030, "STOP %p", dw);
+
+ Notify(ami_gui_get_app_id(), APPNOTIFY_Title, messages_get("amiDownloading"),
+ APPNOTIFY_PubScreenName, "FRONT",
+ APPNOTIFY_Text, dw->fname,
+ APPNOTIFY_DisplayTime, TRUE,
+ APPNOTIFY_Percentage, 0,
+ APPNOTIFY_StopBackMsg, bkm,
+ TAG_DONE);
+ } else {
+ dw->objects[OID_MAIN] = WindowObj,
WA_ScreenTitle, ami_gui_get_screen_title(),
WA_Title, dw->url,
WA_Activate, TRUE,
@@ -195,8 +221,11 @@ static struct gui_download_window *gui_download_window_create(download_context *
EndGroup,
EndWindow;
- dw->win = (struct Window *)RA_OpenWindow(dw->objects[OID_MAIN]);
+ dw->win = (struct Window *)RA_OpenWindow(dw->objects[OID_MAIN]);
+ }
+
dw->ctx = ctx;
+ dw->result = AMINS_DLOAD_PROGRESS;
ami_gui_win_list_add(dw, AMINS_DLWINDOW, &ami_download_table);
@@ -219,21 +248,35 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
va[1] = (APTR)dw->size;
va[2] = 0;
- if(dw->size)
- {
- RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_STATUS], dw->win, NULL,
+ if(dw->size) {
+ if((nsoption_bool(download_notify_progress) == true) &&
+ (((dw->downloaded * 100) / dw->size) > dw->progress)) {
+ dw->progress = (uint32)((dw->downloaded * 100) / dw->size);
+ Notify(ami_gui_get_app_id(),
+ APPNOTIFY_Percentage, dw->progress,
+ TAG_DONE);
+ } else {
+ RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_STATUS], dw->win, NULL,
FUELGAUGE_Level, dw->downloaded,
GA_Text, messages_get("amiDownload"),
FUELGAUGE_VarArgs, va,
TAG_DONE);
+ }
}
else
{
- RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_STATUS], dw->win, NULL,
+ if((nsoption_bool(download_notify_progress) == true)) {
+ /* unknown size, not entirely sure how to deal with this atm... */
+ Notify(ami_gui_get_app_id(),
+ APPNOTIFY_Percentage, 100,
+ TAG_DONE);
+ } else {
+ RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_STATUS], dw->win, NULL,
FUELGAUGE_Level, dw->downloaded,
GA_Text, messages_get("amiDownloadU"),
FUELGAUGE_VarArgs, va,
TAG_DONE);
+ }
}
return NSERROR_OK;
@@ -248,11 +291,23 @@ static void gui_download_window_done(struct gui_download_window *dw)
if(!dw) return;
bw = dw->bw;
+ if(dw->result == AMINS_DLOAD_PROGRESS)
+ dw->result = AMINS_DLOAD_OK;
+
+ if((nsoption_bool(download_notify_progress) == true)) {
+ Notify(ami_gui_get_app_id(),
+ APPNOTIFY_Update, TRUE,
+ TAG_DONE);
+ }
+
if((nsoption_bool(download_notify)) && (dw->result == AMINS_DLOAD_OK))
{
+ char bkm[1030];
+ snprintf(bkm, 1030, "OPEN %s", dw->fname);
+
Notify(ami_gui_get_app_id(), APPNOTIFY_Title, messages_get("amiDownloadComplete"),
APPNOTIFY_PubScreenName, "FRONT",
- APPNOTIFY_BackMsg, dw->fname,
+ APPNOTIFY_BackMsg, bkm,
APPNOTIFY_CloseOnDC, TRUE,
APPNOTIFY_Text, dw->fname,
TAG_DONE);
@@ -275,7 +330,10 @@ static void gui_download_window_done(struct gui_download_window *dw)
downloads_in_progress--;
- DisposeObject(dw->objects[OID_MAIN]);
+ if(dw->objects[OID_MAIN] != NULL) {
+ DisposeObject(dw->objects[OID_MAIN]);
+ }
+
ami_gui_win_list_remove(dw);
if(queuedl) {
nsurl *url;
@@ -305,7 +363,7 @@ static void gui_download_window_error(struct gui_download_window *dw,
static void ami_download_window_abort(void *w)
{
- struct gui_download_window *dw = (struct gui_download_window *)dw;
+ struct gui_download_window *dw = (struct gui_download_window *)w;
download_context_abort(dw->ctx);
dw->result = AMINS_DLOAD_ABORT;
gui_download_window_done(dw);
@@ -318,6 +376,8 @@ static BOOL ami_download_window_event(void *w)
ULONG result;
uint16 code;
+ if(dw == NULL) return FALSE; /* We may not have a real window */
+
while((result = RA_HandleInput(dw->objects[OID_MAIN], &code)) != WMHI_LASTMSG)
{
switch(result & WMHI_CLASSMASK) // class
@@ -449,6 +509,13 @@ BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG si
else return FALSE;
}
+void ami_download_parse_backmsg(const char *backmsg)
+{
+ if((backmsg[0] == 'O') && (backmsg[1] == 'P') && (backmsg[2] == 'E') && (backmsg[3] == 'N')) {
+ OpenWorkbenchObjectA((backmsg + 5), NULL);
+ }
+}
+
static struct gui_download_table download_table = {
.create = gui_download_window_create,
.data = gui_download_window_data,
diff --git a/frontends/amiga/download.h b/frontends/amiga/download.h
index b60b4f002..1c2a3d010 100755
--- a/frontends/amiga/download.h
+++ b/frontends/amiga/download.h
@@ -36,7 +36,7 @@ struct dlnode
void ami_free_download_list(struct List *dllist);
BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG size);
+void ami_download_parse_backmsg(const char *backmsg);
nserror gui_window_save_link(struct gui_window *g, struct nsurl *url, const char *title);
-
#endif
diff --git a/frontends/amiga/drag.c b/frontends/amiga/drag.c
index 92617dd13..ec0ee3c6a 100644
--- a/frontends/amiga/drag.c
+++ b/frontends/amiga/drag.c
@@ -110,6 +110,8 @@ void ami_drag_save(struct Window *win)
ULONG which = WBO_NONE, type;
char path[1025], dpath[1025];
+ path[0] = 0; /* ensure path is terminated */
+
ami_drag_icon_close(NULL);
ami_autoscroll = true;
@@ -186,7 +188,8 @@ void ami_drag_save(struct Window *win)
break;
default:
- LOG("Unsupported drag save operation %d", drag_save);
+ NSLOG(netsurf, INFO,
+ "Unsupported drag save operation %d", drag_save);
break;
}
diff --git a/frontends/amiga/dt_anim.c b/frontends/amiga/dt_anim.c
index a48633403..bd049206c 100644
--- a/frontends/amiga/dt_anim.c
+++ b/frontends/amiga/dt_anim.c
@@ -162,7 +162,7 @@ nserror amiga_dt_anim_create(const content_handler *handler,
bool amiga_dt_anim_convert(struct content *c)
{
- LOG("amiga_dt_anim_convert");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_convert");
amiga_dt_anim_content *plugin = (amiga_dt_anim_content *) c;
union content_msg_data msg_data;
@@ -190,7 +190,7 @@ bool amiga_dt_anim_convert(struct content *c)
plugin->bitmap = amiga_bitmap_create(width, height, bm_flags);
if (!plugin->bitmap) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -246,7 +246,7 @@ void amiga_dt_anim_destroy(struct content *c)
{
amiga_dt_anim_content *plugin = (amiga_dt_anim_content *) c;
- LOG("amiga_dt_anim_destroy");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_destroy");
if (plugin->bitmap != NULL)
amiga_bitmap_destroy(plugin->bitmap);
@@ -263,15 +263,18 @@ bool amiga_dt_anim_redraw(struct content *c,
amiga_dt_anim_content *plugin = (amiga_dt_anim_content *) c;
bitmap_flags_t flags = BITMAPF_NONE;
- LOG("amiga_dt_anim_redraw");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_redraw");
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- plugin->bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx, plugin->bitmap,
+ data->x, data->y,
+ data->width, data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
/**
@@ -287,20 +290,20 @@ bool amiga_dt_anim_redraw(struct content *c,
void amiga_dt_anim_open(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params)
{
- LOG("amiga_dt_anim_open");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_open");
return;
}
void amiga_dt_anim_close(struct content *c)
{
- LOG("amiga_dt_anim_close");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_close");
return;
}
void amiga_dt_anim_reformat(struct content *c, int width, int height)
{
- LOG("amiga_dt_anim_reformat");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_reformat");
return;
}
@@ -309,7 +312,7 @@ nserror amiga_dt_anim_clone(const struct content *old, struct content **newc)
amiga_dt_anim_content *plugin;
nserror error;
- LOG("amiga_dt_anim_clone");
+ NSLOG(netsurf, INFO, "amiga_dt_anim_clone");
plugin = calloc(1, sizeof(amiga_dt_anim_content));
if (plugin == NULL)
diff --git a/frontends/amiga/dt_picture.c b/frontends/amiga/dt_picture.c
index e7f1c9724..88ce1c834 100644
--- a/frontends/amiga/dt_picture.c
+++ b/frontends/amiga/dt_picture.c
@@ -174,7 +174,7 @@ static char *amiga_dt_picture_datatype(struct content *c)
static struct bitmap *amiga_dt_picture_cache_convert(struct content *c)
{
- LOG("amiga_dt_picture_cache_convert");
+ NSLOG(netsurf, INFO, "amiga_dt_picture_cache_convert");
union content_msg_data msg_data;
UBYTE *bm_buffer;
@@ -187,7 +187,7 @@ static struct bitmap *amiga_dt_picture_cache_convert(struct content *c)
bitmap = amiga_bitmap_create(c->width, c->height, BITMAP_NEW);
if (!bitmap) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return NULL;
}
@@ -210,7 +210,7 @@ static struct bitmap *amiga_dt_picture_cache_convert(struct content *c)
bool amiga_dt_picture_convert(struct content *c)
{
- LOG("amiga_dt_picture_convert");
+ NSLOG(netsurf, INFO, "amiga_dt_picture_convert");
int width, height;
char *title;
@@ -256,7 +256,7 @@ nserror amiga_dt_picture_clone(const struct content *old, struct content **newc)
struct content *adt;
nserror error;
- LOG("amiga_dt_picture_clone");
+ NSLOG(netsurf, INFO, "amiga_dt_picture_clone");
adt = calloc(1, sizeof(struct content));
if (adt == NULL)
diff --git a/frontends/amiga/dt_sound.c b/frontends/amiga/dt_sound.c
index 55fc60d61..f3b365ddb 100644
--- a/frontends/amiga/dt_sound.c
+++ b/frontends/amiga/dt_sound.c
@@ -33,7 +33,7 @@
#include "utils/messages.h"
#include "netsurf/plotters.h"
#include "netsurf/content.h"
-#include "render/box.h"
+#include "html/box.h"
#include "content/llcache.h"
#include "content/content_protected.h"
@@ -76,7 +76,7 @@ static const content_handler amiga_dt_sound_content_handler = {
static void amiga_dt_sound_play(Object *dto)
{
- LOG("Playing...");
+ NSLOG(netsurf, INFO, "Playing...");
IDoMethod(dto, DTM_TRIGGER, NULL, STM_PLAY, NULL);
}
@@ -126,7 +126,7 @@ nserror amiga_dt_sound_create(const content_handler *handler,
amiga_dt_sound_content *plugin;
nserror error;
- LOG("amiga_dt_sound_create");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_create");
plugin = calloc(1, sizeof(amiga_dt_sound_content));
if (plugin == NULL)
@@ -146,7 +146,7 @@ nserror amiga_dt_sound_create(const content_handler *handler,
bool amiga_dt_sound_convert(struct content *c)
{
- LOG("amiga_dt_sound_convert");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_convert");
amiga_dt_sound_content *plugin = (amiga_dt_sound_content *) c;
int width = 50, height = 50;
@@ -180,7 +180,7 @@ void amiga_dt_sound_destroy(struct content *c)
{
amiga_dt_sound_content *plugin = (amiga_dt_sound_content *) c;
- LOG("amiga_dt_sound_destroy");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_destroy");
DisposeDTObject(plugin->dto);
@@ -195,20 +195,27 @@ bool amiga_dt_sound_redraw(struct content *c,
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0xffffff,
.stroke_colour = 0x000000,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
+ struct rect rect;
- LOG("amiga_dt_sound_redraw");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_redraw");
+
+ rect.x0 = data->x;
+ rect.y0 = data->y;
+ rect.x1 = data->x + data->width;
+ rect.y1 = data->y + data->height;
/* this should be some sort of play/stop control */
- ctx->plot->rectangle(data->x, data->y, data->x + data->width,
- data->y + data->height, &pstyle);
+ ctx->plot->rectangle(ctx, &pstyle, &rect);
- return ctx->plot->text(data->x, data->y+20,
- lwc_string_data(content__get_mime_type(c)),
- lwc_string_length(content__get_mime_type(c)),
- plot_style_font);
+ return (ctx->plot->text(ctx,
+ plot_style_font,
+ data->x,
+ data->y+20,
+ lwc_string_data(content__get_mime_type(c)),
+ lwc_string_length(content__get_mime_type(c))) == NSERROR_OK);
}
@@ -219,7 +226,7 @@ void amiga_dt_sound_open(struct content *c, struct browser_window *bw,
amiga_dt_sound_content *plugin = (amiga_dt_sound_content *) c;
struct object_param *param;
- LOG("amiga_dt_sound_open");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_open");
plugin->immediate = false;
@@ -227,7 +234,8 @@ void amiga_dt_sound_open(struct content *c, struct browser_window *bw,
{
do
{
- LOG("%s = %s", param->name, param->value);
+ NSLOG(netsurf, INFO, "%s = %s", param->name,
+ param->value);
if((strcmp(param->name, "autoplay") == 0) &&
(strcmp(param->value, "true") == 0)) plugin->immediate = true;
if((strcmp(param->name, "autoStart") == 0) &&
@@ -248,7 +256,7 @@ nserror amiga_dt_sound_clone(const struct content *old, struct content **newc)
amiga_dt_sound_content *plugin;
nserror error;
- LOG("amiga_dt_sound_clone");
+ NSLOG(netsurf, INFO, "amiga_dt_sound_clone");
plugin = calloc(1, sizeof(amiga_dt_sound_content));
if (plugin == NULL)
diff --git a/frontends/amiga/filetype.c b/frontends/amiga/filetype.c
index a0449d848..0e535de07 100644
--- a/frontends/amiga/filetype.c
+++ b/frontends/amiga/filetype.c
@@ -185,7 +185,7 @@ nserror ami_mime_init(const char *mimefile)
struct nsObject *node;
struct ami_mime_entry *mimeentry;
- LOG("mimetypes file: %s", mimefile);
+ NSLOG(netsurf, INFO, "mimetypes file: %s", mimefile);
if(ami_mime_list == NULL)
ami_mime_list = NewObjList();
@@ -642,6 +642,10 @@ void ami_mime_dump(void)
struct ami_mime_entry *mimeentry;
while((mimeentry = ami_mime_entry_locate(NULL, AMI_MIME_MIMETYPE, &node))) {
- LOG("%s DT=\"%s\" TYPE=\"%s\" CMD=\"%s\"", mimeentry->mimetype ? lwc_string_data(mimeentry->mimetype) : "", mimeentry->datatype ? lwc_string_data(mimeentry->datatype) : "", mimeentry->filetype ? lwc_string_data(mimeentry->filetype) : "", mimeentry->plugincmd ? lwc_string_data(mimeentry->plugincmd) : "");
+ NSLOG(netsurf, INFO, "%s DT=\"%s\" TYPE=\"%s\" CMD=\"%s\"",
+ mimeentry->mimetype ? lwc_string_data(mimeentry->mimetype) : "",
+ mimeentry->datatype ? lwc_string_data(mimeentry->datatype) : "",
+ mimeentry->filetype ? lwc_string_data(mimeentry->filetype) : "",
+ mimeentry->plugincmd ? lwc_string_data(mimeentry->plugincmd) : "");
};
}
diff --git a/frontends/amiga/font.c b/frontends/amiga/font.c
index 22a0f4a4a..e69ff55f0 100644
--- a/frontends/amiga/font.c
+++ b/frontends/amiga/font.c
@@ -37,7 +37,7 @@ static ULONG ami_xdpi = 72;
ULONG ami_font_dpi_get_devicedpi(void)
{
- return ami_devicedpi;
+ return (ami_xdpi << 16) | ami_devicedpi;
}
ULONG ami_font_dpi_get_xdpi(void)
@@ -51,7 +51,8 @@ void ami_font_setdevicedpi(int id)
struct DisplayInfo dinfo;
if(nsoption_bool(bitmap_fonts) == true) {
- LOG("WARNING: Using diskfont.library for text. Forcing DPI to 72.");
+ NSLOG(netsurf, INFO,
+ "WARNING: Using diskfont.library for text. Forcing DPI to 72.");
nsoption_set_int(screen_ydpi, 72);
}
@@ -79,7 +80,14 @@ void ami_font_setdevicedpi(int id)
xdpi = (yres * ydpi) / xres;
- LOG("XDPI = %ld, YDPI = %ld (DisplayInfo resolution %d x %d, corrected %d x %d)", xdpi, ydpi, dinfo.Resolution.x, dinfo.Resolution.y, xres, yres);
+ NSLOG(netsurf, INFO,
+ "XDPI = %ld, YDPI = %ld (DisplayInfo resolution %d x %d, corrected %d x %d)",
+ xdpi,
+ ydpi,
+ dinfo.Resolution.x,
+ dinfo.Resolution.y,
+ xres,
+ yres);
}
}
}
diff --git a/frontends/amiga/font_bullet.c b/frontends/amiga/font_bullet.c
index fd41c29a2..62c2dde08 100644
--- a/frontends/amiga/font_bullet.c
+++ b/frontends/amiga/font_bullet.c
@@ -63,7 +63,7 @@
#define NSA_VALUE_SHEARSIN (1 << 14)
#define NSA_VALUE_SHEARCOS (1 << 16)
-#define NSA_FONT_EMWIDTH(s) (s / FONT_SIZE_SCALE) * (ami_font_dpi_get_xdpi() / 72.0)
+#define NSA_FONT_EMWIDTH(s) (s / PLOT_STYLE_SCALE) * (ami_font_dpi_get_xdpi() / 72.0)
const uint16 sc_table[] = {
0x0061, 0x1D00, /* a */
@@ -361,7 +361,7 @@ static struct ami_font_cache_node *ami_font_open(const char *font, bool critical
if(!nodedata->font)
{
- LOG("Requested font not found: %s", font);
+ NSLOG(netsurf, INFO, "Requested font not found: %s", font);
if(critical == true) amiga_warn_user("CompError", font);
free(nodedata);
return NULL;
@@ -369,21 +369,28 @@ static struct ami_font_cache_node *ami_font_open(const char *font, bool critical
nodedata->bold = (char *)GetTagData(OT_BName, 0, nodedata->font->olf_OTagList);
if(nodedata->bold)
- LOG("Bold font defined for %s is %s", font, nodedata->bold);
+ NSLOG(netsurf, INFO, "Bold font defined for %s is %s", font,
+ nodedata->bold);
else
- LOG("Warning: No designed bold font defined for %s", font);
+ NSLOG(netsurf, INFO,
+ "Warning: No designed bold font defined for %s", font);
nodedata->italic = (char *)GetTagData(OT_IName, 0, nodedata->font->olf_OTagList);
if(nodedata->italic)
- LOG("Italic font defined for %s is %s", font, nodedata->italic);
+ NSLOG(netsurf, INFO, "Italic font defined for %s is %s",
+ font, nodedata->italic);
else
- LOG("Warning: No designed italic font defined for %s", font);
+ NSLOG(netsurf, INFO,
+ "Warning: No designed italic font defined for %s", font);
nodedata->bolditalic = (char *)GetTagData(OT_BIName, 0, nodedata->font->olf_OTagList);
if(nodedata->bolditalic)
- LOG("Bold-italic font defined for %s is %s", font, nodedata->bolditalic);
+ NSLOG(netsurf, INFO, "Bold-italic font defined for %s is %s",
+ font, nodedata->bolditalic);
else
- LOG("Warning: No designed bold-italic font defined for %s", font);
+ NSLOG(netsurf, INFO,
+ "Warning: No designed bold-italic font defined for %s",
+ font);
ami_font_cache_insert(nodedata, font);
return nodedata;
@@ -505,7 +512,7 @@ static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle
}
/* Scale to 16.16 fixed point */
- ysize = fstyle->size * ((1 << 16) / FONT_SIZE_SCALE);
+ ysize = fstyle->size * ((1 << 16) / PLOT_STYLE_SCALE);
if(designed_node == NULL) {
ofont = node->font;
diff --git a/frontends/amiga/font_cache.c b/frontends/amiga/font_cache.c
index 3d8330979..86e2381c0 100644
--- a/frontends/amiga/font_cache.c
+++ b/frontends/amiga/font_cache.c
@@ -69,7 +69,10 @@ static void ami_font_cache_cleanup(struct SkipList *skiplist)
SubTime(&curtime, &node->lastused);
if(curtime.Seconds > 300)
{
- LOG("Freeing font %p not used for %ld seconds", node->skip_node.sn_Key, curtime.Seconds);
+ NSLOG(netsurf, INFO,
+ "Freeing font %p not used for %ld seconds",
+ node->skip_node.sn_Key,
+ curtime.Seconds);
ami_font_bullet_close(node);
RemoveSkipNode(skiplist, node->skip_node.sn_Key);
}
@@ -98,7 +101,10 @@ static void ami_font_cache_cleanup(struct MinList *ami_font_cache_list)
SubTime(&curtime, &fnode->lastused);
if(curtime.Seconds > 300)
{
- LOG("Freeing %s not used for %ld seconds", node->dtz_Node.ln_Name, curtime.Seconds);
+ NSLOG(netsurf, INFO,
+ "Freeing %s not used for %ld seconds",
+ node->dtz_Node.ln_Name,
+ curtime.Seconds);
DelObject(node);
}
} while((node=nnode));
@@ -146,7 +152,7 @@ struct ami_font_cache_node *ami_font_cache_locate(const char *font)
return nodedata;
}
- LOG("Font cache miss: %s (%lx)", font, hash);
+ NSLOG(netsurf, INFO, "Font cache miss: %s (%lx)", font, hash);
return NULL;
}
@@ -180,7 +186,7 @@ void ami_font_cache_insert(struct ami_font_cache_node *nodedata, const char *fon
void ami_font_cache_fini(void)
{
- LOG("Cleaning up font cache");
+ NSLOG(netsurf, INFO, "Cleaning up font cache");
ami_schedule(-1, (void *)ami_font_cache_cleanup, ami_font_cache_list);
#ifdef __amigaos4__
ami_font_cache_del_skiplist(ami_font_cache_list);
diff --git a/frontends/amiga/font_diskfont.c b/frontends/amiga/font_diskfont.c
index 8593f81b2..a587d6eaf 100644
--- a/frontends/amiga/font_diskfont.c
+++ b/frontends/amiga/font_diskfont.c
@@ -41,6 +41,7 @@
static plot_font_style_t *prev_fstyle = NULL;
static struct TextFont *prev_font = NULL;
+static struct RastPort temp_rp;
static struct TextFont *ami_font_bm_open(struct RastPort *rp, const plot_font_style_t *fstyle)
{
@@ -54,7 +55,6 @@ static struct TextFont *ami_font_bm_open(struct RastPort *rp, const plot_font_st
(fstyle->size == prev_fstyle->size) &&
(fstyle->flags == prev_fstyle->flags) &&
(fstyle->weight == prev_fstyle->weight)) {
- LOG("(using current font)");
return prev_font;
}
@@ -97,8 +97,8 @@ static struct TextFont *ami_font_bm_open(struct RastPort *rp, const plot_font_st
snprintf(font, MAX_FONT_NAME_SIZE, "%s.font", fontname);
tattr.ta_Name = font;
- tattr.ta_YSize = fstyle->size / FONT_SIZE_SCALE;
- LOG("font: %s/%d", tattr.ta_Name, tattr.ta_YSize);
+ tattr.ta_YSize = fstyle->size / PLOT_STYLE_SCALE;
+ NSLOG(netsurf, INFO, "font: %s/%d", tattr.ta_Name, tattr.ta_YSize);
if(prev_font != NULL) CloseFont(prev_font);
@@ -133,17 +133,16 @@ static nserror amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
{
char *localtext = NULL;
- if((glob == NULL) || (glob->rp == NULL)) return NSERROR_INVALID;
*width = length;
- struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
+ struct TextFont *bmfont = ami_font_bm_open(&temp_rp, fstyle);
if(bmfont == NULL) return NSERROR_INVALID;
if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
return NSERROR_INVALID;
}
- *width = TextLength(glob->rp, localtext, (UWORD)strlen(localtext));
+ *width = TextLength(&temp_rp, localtext, (UWORD)strlen(localtext));
free(localtext);
return NSERROR_OK;
@@ -170,16 +169,14 @@ static nserror amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyl
char *localtext = NULL;
UWORD co = 0;
- if((glob == NULL) || (glob->rp == NULL)) return NSERROR_INVALID;
-
- bmfont = ami_font_bm_open(glob->rp, fstyle);
+ bmfont = ami_font_bm_open(&temp_rp, fstyle);
if(bmfont == NULL) return NSERROR_INVALID;
if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
return NSERROR_INVALID;
}
- co = TextFit(glob->rp, localtext, (UWORD)strlen(localtext),
+ co = TextFit(&temp_rp, localtext, (UWORD)strlen(localtext),
&extent, NULL, 1, x, 32767);
*char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
*actual_x = extent.te_Extent.MaxX;
@@ -222,16 +219,14 @@ static nserror amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
char *charp;
char *localtext;
- if((glob == NULL) || (glob->rp == NULL)) return NSERROR_INVALID;
-
- struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
+ struct TextFont *bmfont = ami_font_bm_open(&temp_rp, fstyle);
if(bmfont == NULL) return NSERROR_INVALID;
if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
return NSERROR_INVALID;
}
- offset = TextFit(glob->rp, localtext, (UWORD)strlen(localtext),
+ offset = TextFit(&temp_rp, localtext, (UWORD)strlen(localtext),
&extent, NULL, 1, (UWORD)x, 32767);
co = offset;
@@ -253,7 +248,7 @@ static nserror amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
}
if((co > 0) && (co < strlen(localtext))) {
- *actual_x = TextLength(glob->rp, localtext, co);
+ *actual_x = TextLength(&temp_rp, localtext, co);
*char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
} else {
*actual_x = x;
@@ -298,6 +293,9 @@ void ami_font_diskfont_init(void)
/* Alloc space to hold currently open font - doesn't matter if this fails */
prev_fstyle = calloc(1, sizeof(plot_font_style_t));
+
+ /* Init temp RastPort */
+ InitRastPort(&temp_rp);
}
void ami_font_diskfont_fini(void)
diff --git a/frontends/amiga/font_scan.c b/frontends/amiga/font_scan.c
index 932179e3e..cb37f97fa 100644
--- a/frontends/amiga/font_scan.c
+++ b/frontends/amiga/font_scan.c
@@ -255,7 +255,8 @@ static ULONG ami_font_scan_font(const char *fontname, lwc_string **glypharray)
#ifdef __amigaos4__
if(EObtainInfo(AMI_OFONT_ENGINE, OT_UnicodeRanges, &unicoderanges, TAG_END) == 0) {
if(unicoderanges & UCR_SURROGATES) {
- LOG("%s supports UTF-16 surrogates", fontname);
+ NSLOG(netsurf, INFO, "%s supports UTF-16 surrogates",
+ fontname);
if (nsoption_charp(font_surrogate) == NULL) {
nsoption_set_charp(font_surrogate, (char *)strdup(fontname));
}
@@ -292,10 +293,11 @@ static ULONG ami_font_scan_fonts(struct MinList *list,
do {
nnode = (struct nsObject *)GetSucc((struct Node *)node);
ami_font_scan_gui_update(win, node->dtz_Node.ln_Name, font_num, total);
- LOG("Scanning %s", node->dtz_Node.ln_Name);
+ NSLOG(netsurf, INFO, "Scanning %s", node->dtz_Node.ln_Name);
found = ami_font_scan_font(node->dtz_Node.ln_Name, glypharray);
total += found;
- LOG("Found %ld new glyphs (total = %ld)", found, total);
+ NSLOG(netsurf, INFO, "Found %ld new glyphs (total = %ld)",
+ found, total);
font_num++;
} while((node = nnode));
@@ -344,7 +346,9 @@ static ULONG ami_font_scan_list(struct MinList *list)
if(node) {
node->dtz_Node.ln_Name = strdup(af[i].af_Attr.ta_Name);
found++;
- LOG("Added %s", af[i].af_Attr.ta_Name);
+ NSLOG(netsurf, INFO,
+ "Added %s",
+ af[i].af_Attr.ta_Name);
}
}
}
@@ -382,7 +386,8 @@ static ULONG ami_font_scan_load(const char *filename, lwc_string **glypharray)
rargs = AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
if((fh = FOpen(filename, MODE_OLDFILE, 0))) {
- LOG("Loading font glyph cache from %s", filename);
+ NSLOG(netsurf, INFO, "Loading font glyph cache from %s",
+ filename);
while(FGets(fh, (STRPTR)&buffer, 256) != 0)
{
@@ -423,7 +428,8 @@ void ami_font_scan_save(const char *filename, lwc_string **glypharray)
BPTR fh = 0;
if((fh = FOpen(filename, MODE_NEWFILE, 0))) {
- LOG("Writing font glyph cache to %s", filename);
+ NSLOG(netsurf, INFO, "Writing font glyph cache to %s",
+ filename);
FPrintf(fh, "; This file is auto-generated. To re-create the cache, delete this file.\n");
FPrintf(fh, "; This file is parsed using ReadArgs() with the following template:\n");
FPrintf(fh, "; CODE/A,FONT/A\n;\n");
@@ -482,7 +488,7 @@ void ami_font_scan_init(const char *filename, bool force_scan, bool save,
found = ami_font_scan_load(filename, glypharray);
if(found == 0) {
- LOG("Creating new font glyph cache");
+ NSLOG(netsurf, INFO, "Creating new font glyph cache");
if((list = NewObjList())) {
/* add preferred fonts list */
@@ -504,7 +510,7 @@ void ami_font_scan_init(const char *filename, bool force_scan, bool save,
if(nsoption_bool(font_unicode_only) == false)
entries += ami_font_scan_list(list);
- LOG("Found %ld fonts", entries);
+ NSLOG(netsurf, INFO, "Found %ld fonts", entries);
win = ami_font_scan_gui_open(entries);
found = ami_font_scan_fonts(list, win, glypharray);
@@ -517,6 +523,6 @@ void ami_font_scan_init(const char *filename, bool force_scan, bool save,
}
}
- LOG("Initialised with %ld glyphs", found);
+ NSLOG(netsurf, INFO, "Initialised with %ld glyphs", found);
}
diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c
index b2a489e72..e337ede0c 100644
--- a/frontends/amiga/gui.c
+++ b/frontends/amiga/gui.c
@@ -17,10 +17,11 @@
*/
-
+#ifdef __amigaos4__
/* Custom StringView class */
#include "amiga/stringview/stringview.h"
#include "amiga/stringview/urlhistory.h"
+#endif
/* AmigaOS libraries */
#ifdef __amigaos4__
@@ -89,6 +90,7 @@
#include <math.h>
#include <string.h>
#include <stdlib.h>
+#include <limits.h>
/* NetSurf core includes */
#include "utils/log.h"
@@ -114,7 +116,6 @@
#include "desktop/hotlist.h"
#include "desktop/version.h"
#include "desktop/save_complete.h"
-#include "desktop/scrollbar.h"
#include "desktop/searchweb.h"
/* NetSurf Amiga platform includes */
@@ -157,6 +158,11 @@
#define NSA_KBD_SCROLL_PX 10
#define NSA_MAX_HOTLIST_BUTTON_LEN 20
+#define SCROLL_TOP INT_MIN
+#define SCROLL_PAGE_UP (INT_MIN + 1)
+#define SCROLL_PAGE_DOWN (INT_MAX - 1)
+#define SCROLL_BOTTOM (INT_MAX)
+
/* Extra mouse button defines to match those in intuition/intuition.h */
#define SIDEDOWN (IECODE_4TH_BUTTON)
#define SIDEUP (IECODE_4TH_BUTTON | IECODE_UP_PREFIX)
@@ -196,13 +202,15 @@ static bool ami_quit = false;
static struct MsgPort *schedulermsgport = NULL;
static struct MsgPort *appport;
+#ifdef __amigaos4__
static Class *urlStringClass;
+#endif
static BOOL locked_screen = FALSE;
static int screen_signal = -1;
static bool win_destroyed;
static STRPTR nsscreentitle;
-static struct gui_globals browserglob;
+static struct gui_globals *browserglob = NULL;
static struct MsgPort *applibport = NULL;
static uint32 ami_appid = 0;
@@ -239,10 +247,10 @@ static void ami_do_redraw(struct gui_window_2 *g);
static void ami_schedule_redraw_remove(struct gui_window_2 *gwin);
static bool gui_window_get_scroll(struct gui_window *g, int *restrict sx, int *restrict sy);
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy);
+static nserror gui_window_set_scroll(struct gui_window *g, const struct rect *rect);
static void gui_window_remove_caret(struct gui_window *g);
static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, const struct rect *clip);
-static void gui_window_update_box(struct gui_window *g, const struct rect *restrict rect);
+//static void amiga_window_invalidate_area(struct gui_window *g, const struct rect *restrict rect);
/* accessors for default options - user option is updated if it is set as per default */
@@ -334,7 +342,9 @@ bool ami_gui_map_filename(char **remapped, const char *restrict path,
}
if(found == false) *remapped = strdup(file);
- else LOG("Remapped %s to %s in path %s using %s", file, *remapped, path, map);
+ else NSLOG(netsurf, INFO,
+ "Remapped %s to %s in path %s using %s", file,
+ *remapped, path, map);
free(mapfile);
@@ -357,7 +367,7 @@ static bool ami_gui_check_resource(char *fullpath, const char *file)
found = true;
}
- if(found) LOG("Found %s", fullpath);
+ if(found) NSLOG(netsurf, INFO, "Found %s", fullpath);
free(remapped);
return found;
@@ -439,7 +449,9 @@ static void ami_gui_resources_free(void)
static bool ami_gui_resources_open(void)
{
+#ifdef __amigaos4__
urlStringClass = MakeStringClass();
+#endif
if(!(appport = AllocSysObjectTags(ASOT_PORT,
ASO_NoTrack, FALSE,
@@ -832,7 +844,7 @@ static void ami_openscreen(void)
}
if(screen_signal == -1) screen_signal = AllocSignal(-1);
- LOG("Screen signal %d", screen_signal);
+ NSLOG(netsurf, INFO, "Screen signal %d", screen_signal);
scrn = OpenScreenTags(NULL,
/**\todo specify screen depth */
SA_DisplayID, id,
@@ -885,7 +897,7 @@ static void ami_openscreen(void)
static void ami_openscreenfirst(void)
{
ami_openscreen();
- if(!browserglob.bm) ami_init_layers(&browserglob, 0, 0, false);
+ if(browserglob == NULL) browserglob = ami_plot_ra_alloc(0, 0, false, false);
ami_theme_throbber_setup();
}
@@ -908,19 +920,22 @@ static struct RDArgs *ami_gui_commandline(int *restrict argc, char ** argv,
if((args = ReadArgs(template, rarray, NULL))) {
if(rarray[A_URL]) {
- LOG("URL %s specified on command line",
- (char *)rarray[A_URL]);
+ NSLOG(netsurf, INFO,
+ "URL %s specified on command line",
+ (char *)rarray[A_URL]);
temp_homepage_url = strdup((char *)rarray[A_URL]); /**\todo allow IDNs */
}
if(rarray[A_USERSDIR]) {
- LOG("USERSDIR %s specified on command line",
- (char *)rarray[A_USERSDIR]);
+ NSLOG(netsurf, INFO,
+ "USERSDIR %s specified on command line",
+ (char *)rarray[A_USERSDIR]);
users_dir = ASPrintf("%s", rarray[A_USERSDIR]);
}
if(rarray[A_FORCE]) {
- LOG("FORCE specified on command line");
+ NSLOG(netsurf, INFO,
+ "FORCE specified on command line");
cli_force = true;
}
@@ -940,7 +955,7 @@ static struct RDArgs *ami_gui_commandline(int *restrict argc, char ** argv,
*/
}
} else {
- LOG("ReadArgs failed to parse command line");
+ NSLOG(netsurf, INFO, "ReadArgs failed to parse command line");
}
FreeArgs(args);
@@ -993,11 +1008,6 @@ static STRPTR ami_gui_read_all_tooltypes(int argc, char **argv)
return current_user;
}
-void ami_gui_set_default_gg(void)
-{
- glob = &browserglob;
-}
-
static void gui_init2(int argc, char** argv)
{
struct Screen *screen;
@@ -1008,9 +1018,6 @@ static void gui_init2(int argc, char** argv)
notalreadyrunning = ami_arexx_init(&rxsig);
- /* Treeview init code ends up calling a font function which needs this */
- ami_gui_set_default_gg();
-
/* ...and this ensures the treeview at least gets the WB colour palette to work with */
if(scrn == NULL) {
if((screen = LockPubScreen("Workbench"))) {
@@ -1022,7 +1029,8 @@ static void gui_init2(int argc, char** argv)
}
/**/
- hotlist_init(nsoption_charp(hotlist_file));
+ hotlist_init(nsoption_charp(hotlist_file),
+ nsoption_charp(hotlist_file));
search_web_select_provider(nsoption_int(search_provider));
if (notalreadyrunning &&
@@ -1043,6 +1051,7 @@ static void gui_init2(int argc, char** argv)
amiga_warn_user(messages_get_errorcode(error), 0);
}
free(temp_homepage_url);
+ temp_homepage_url = NULL;
}
if(cli_force == true) {
@@ -1123,6 +1132,7 @@ static void gui_init2(int argc, char** argv)
if(temp_homepage_url) {
sendcmd = ASPrintf("OPEN \"%s\" NEW%s", temp_homepage_url, newtab);
free(temp_homepage_url);
+ temp_homepage_url = NULL;
} else {
sendcmd = ASPrintf("OPEN \"%s\" NEW%s", nsoption_charp(homepage_url), newtab);
}
@@ -1215,12 +1225,10 @@ static void ami_update_buttons(struct gui_window_2 *gwin)
}
}
-#ifdef __amigaos4__
GetAttr(GA_Disabled, gwin->objects[GID_BACK], (uint32 *)&s_back);
GetAttr(GA_Disabled, gwin->objects[GID_FORWARD], (uint32 *)&s_forward);
GetAttr(GA_Disabled, gwin->objects[GID_RELOAD], (uint32 *)&s_reload);
GetAttr(GA_Disabled, gwin->objects[GID_STOP], (uint32 *)&s_stop);
-#endif
if(BOOL_MISMATCH(s_back, back))
SetGadgetAttrs((struct Gadget *)gwin->objects[GID_BACK],
@@ -1240,9 +1248,9 @@ static void ami_update_buttons(struct gui_window_2 *gwin)
if(ClickTabBase->lib_Version < 53) {
if(gwin->tabs <= 1) tabclose = TRUE;
-#ifdef __amigaos4__
+
GetAttr(GA_Disabled, gwin->objects[GID_CLOSETAB], (uint32 *)&s_tabclose);
-#endif
+
if(BOOL_MISMATCH(s_tabclose, tabclose))
SetGadgetAttrs((struct Gadget *)gwin->objects[GID_CLOSETAB],
gwin->win, NULL, GA_Disabled, tabclose, TAG_DONE);
@@ -1494,6 +1502,7 @@ static void ami_gui_scroll_internal(struct gui_window_2 *gwin, int xs, int ys)
{
struct IBox *bbox;
int x, y;
+ struct rect rect;
if(ami_mouse_to_ns_coords(gwin, &x, &y, -1, -1) == true)
{
@@ -1560,8 +1569,9 @@ static void ami_gui_scroll_internal(struct gui_window_2 *gwin, int xs, int ys)
}
ami_gui_free_space_box(bbox);
-
- gui_window_set_scroll(gwin->gw, xs, ys);
+ rect.x0 = rect.x1 = xs;
+ rect.y0 = rect.y1 = ys;
+ gui_window_set_scroll(gwin->gw, &rect);
}
}
}
@@ -1574,6 +1584,7 @@ static struct IBox *ami_ns_rect_to_ibox(struct gui_window_2 *gwin, const struct
if(ibox == NULL) return NULL;
if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
+ free(ibox);
amiga_warn_user("NoMemory", "");
return NULL;
}
@@ -1642,15 +1653,26 @@ static void ami_gui_menu_update_all(void)
} while((node = nnode));
}
-static void gui_window_get_dimensions(struct gui_window *g,
+/**
+ * Find the current dimensions of a amiga browser window content area.
+ *
+ * \param gw The gui window to measure content area of.
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated
+ * else error code.
+ */
+static nserror gui_window_get_dimensions(struct gui_window *gw,
int *restrict width, int *restrict height, bool scaled)
{
struct IBox *bbox;
- if(!g) return;
+ nserror res;
- if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
+ res = ami_gui_get_space_box((Object *)gw->shared->objects[GID_BROWSER], &bbox);
+ if(res != NSERROR_OK) {
amiga_warn_user("NoMemory", "");
- return;
+ return res;
}
*width = bbox->Width;
@@ -1658,11 +1680,12 @@ static void gui_window_get_dimensions(struct gui_window *g,
ami_gui_free_space_box(bbox);
- if(scaled)
- {
- *width /= g->scale;
- *height /= g->scale;
+ if(scaled) {
+ *width /= gw->scale;
+ *height /= gw->scale;
}
+
+ return NSERROR_OK;
}
/* Add a horizontal scroller, if not already present
@@ -1818,7 +1841,7 @@ static void gui_window_set_icon(struct gui_window *g, struct hlcache_handle *ico
if ((icon != NULL) && ((icon_bitmap = content_get_bitmap(icon)) != NULL))
{
- bm = ami_bitmap_get_native(icon_bitmap, 16, 16,
+ bm = ami_bitmap_get_native(icon_bitmap, 16, 16, ami_plot_screen_is_palettemapped(),
g->shared->win->RPort->BitMap);
}
@@ -2502,10 +2525,9 @@ static BOOL ami_gui_event(void *w)
#ifdef __amigaos4__
case WMHI_ICONIFY:
{
- struct bitmap *bm;
-
- bm = urldb_get_thumbnail(browser_window_get_url(gwin->gw->bw));
- if(!bm) bm = content_get_bitmap(browser_window_get_content(gwin->gw->bw));
+ struct bitmap *bm = NULL;
+ browser_window_history_get_thumbnail(gwin->gw->bw,
+ &bm);
gwin->dobj = amiga_icon_from_bitmap(bm);
amiga_icon_superimpose_favicon_internal(gwin->gw->favicon,
gwin->dobj);
@@ -2548,12 +2570,15 @@ static BOOL ami_gui_event(void *w)
if(drag_x_move || drag_y_move)
{
+ struct rect rect;
+
gui_window_get_scroll(gwin->gw,
&gwin->gw->scrollx, &gwin->gw->scrolly);
- gui_window_set_scroll(gwin->gw,
- gwin->gw->scrollx + drag_x_move,
- gwin->gw->scrolly + drag_y_move);
+ rect.x0 = rect.x1 = gwin->gw->scrollx + drag_x_move;
+ rect.y0 = rect.y1 = gwin->gw->scrolly + drag_y_move;
+
+ gui_window_set_scroll(gwin->gw, &rect);
}
// ReplyMsg((struct Message *)message);
@@ -2767,8 +2792,11 @@ static void ami_handle_applib(void)
{
struct ApplicationCustomMsg *applibcustmsg =
(struct ApplicationCustomMsg *)applibmsg;
- LOG("Ringhio BackMsg received: %s", applibcustmsg->customMsg);
- OpenWorkbenchObjectA(applibcustmsg->customMsg, NULL);
+ NSLOG(netsurf, INFO,
+ "Ringhio BackMsg received: %s",
+ applibcustmsg->customMsg);
+
+ ami_download_parse_backmsg(applibcustmsg->customMsg);
}
break;
}
@@ -2802,7 +2830,7 @@ void ami_get_msg(void)
NULL, (unsigned int *)&signalmask) != -1) {
signal = signalmask;
} else {
- LOG("waitselect() returned error");
+ NSLOG(netsurf, INFO, "waitselect() returned error");
/* \todo Fix Ctrl-C handling.
* WaitSelect() from bsdsocket.library returns -1 if the task was
* signalled with a Ctrl-C. waitselect() from newlib.library does not.
@@ -2907,11 +2935,15 @@ void ami_switch_tab(struct gui_window_2 *gwin, bool redraw)
if(redraw)
{
+ struct rect rect;
+
ami_plot_clear_bbox(gwin->win->RPort, bbox);
browser_window_update(gwin->gw->bw, false);
- gui_window_set_scroll(gwin->gw,
- gwin->gw->scrollx, gwin->gw->scrolly);
+ rect.x0 = rect.x1 = gwin->gw->scrollx;
+ rect.y0 = rect.y1 = gwin->gw->scrolly;
+
+ gui_window_set_scroll(gwin->gw, &rect);
gwin->redraw_scroll = false;
browser_window_refresh_url_bar(gwin->gw->bw);
@@ -3007,11 +3039,13 @@ static void ami_gui_close_screen(struct Screen *scrn, BOOL locked_screen, BOOL d
if(donotwait == TRUE) return;
ULONG scrnsig = 1 << screen_signal;
- LOG("Waiting for visitor windows to close... (signal)");
+ NSLOG(netsurf, INFO,
+ "Waiting for visitor windows to close... (signal)");
Wait(scrnsig);
while (CloseScreen(scrn) == FALSE) {
- LOG("Waiting for visitor windows to close... (polling)");
+ NSLOG(netsurf, INFO,
+ "Waiting for visitor windows to close... (polling)");
Delay(50);
}
@@ -3041,35 +3075,37 @@ static void gui_quit(void)
urldb_save(nsoption_charp(url_file));
urldb_save_cookies(nsoption_charp(cookie_file));
- hotlist_fini(nsoption_charp(hotlist_file));
+ hotlist_fini();
#ifdef __amigaos4__
if(IApplication && ami_appid)
UnregisterApplication(ami_appid, NULL);
#endif
ami_arexx_cleanup();
- ami_free_layers(&browserglob);
+ ami_plot_ra_free(browserglob);
ami_font_fini();
ami_help_free();
- LOG("Freeing menu items");
+ NSLOG(netsurf, INFO, "Freeing menu items");
ami_ctxmenu_free();
ami_menu_free_glyphs();
- LOG("Freeing mouse pointers");
+ NSLOG(netsurf, INFO, "Freeing mouse pointers");
ami_mouse_pointers_free();
ami_file_req_free();
ami_openurl_close();
+#ifdef __amigaos4__
FreeStringClass(urlStringClass);
+#endif
FreeObjList(window_list);
ami_clipboard_free();
ami_gui_resources_free();
- LOG("Closing screen");
+ NSLOG(netsurf, INFO, "Closing screen");
ami_gui_close_screen(scrn, locked_screen, FALSE);
if(nsscreentitle) FreeVec(nsscreentitle);
}
@@ -3079,7 +3115,7 @@ char *ami_gui_get_cache_favicon_name(nsurl *url, bool only_if_avail)
STRPTR filename = NULL;
if ((filename = ASPrintf("%s/%x", current_user_faviconcache, nsurl_hash(url)))) {
- LOG("favicon cache location: %s", filename);
+ NSLOG(netsurf, INFO, "favicon cache location: %s", filename);
if (only_if_avail == true) {
BPTR lock = 0;
@@ -3529,15 +3565,18 @@ static void ami_do_redraw_tiled(struct gui_window_2 *gwin, bool busy,
int left, int top, int width, int height,
int sx, int sy, struct IBox *bbox, struct redraw_context *ctx)
{
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
int x, y;
struct rect clip;
- int tile_size_x = glob->width;
- int tile_size_y = glob->height;
+ int tile_size_x;
+ int tile_size_y;
+
+ ami_plot_ra_get_size(glob, &tile_size_x, &tile_size_y);
int tile_x_scale = (int)(tile_size_x / gwin->gw->scale);
int tile_y_scale = (int)(tile_size_y / gwin->gw->scale);
- browserglob.shared_pens = gwin->shared_pens; /* do we need this?? */
+ ami_plot_ra_set_pen_list(glob, gwin->shared_pens);
if(top < 0) {
height += top;
@@ -3588,10 +3627,10 @@ static void ami_do_redraw_tiled(struct gui_window_2 *gwin, bool busy,
clip.y0 - (int)y,
&clip, ctx))
{
- ami_clearclipreg(&browserglob);
+ ami_clearclipreg(glob);
#ifdef __amigaos4__
BltBitMapTags(BLITA_SrcType, BLITT_BITMAP,
- BLITA_Source, browserglob.bm,
+ BLITA_Source, ami_plot_ra_get_bitmap(glob),
BLITA_SrcX, 0,
BLITA_SrcY, 0,
BLITA_DestType, BLITT_RASTPORT,
@@ -3602,7 +3641,7 @@ static void ami_do_redraw_tiled(struct gui_window_2 *gwin, bool busy,
BLITA_Height, (int)(clip.y1),
TAG_DONE);
#else
- BltBitMapRastPort(browserglob.bm, 0, 0, gwin->win->RPort,
+ BltBitMapRastPort(ami_plot_ra_get_bitmap(glob), 0, 0, gwin->win->RPort,
bbox->Left + (int)((x - sx) * gwin->gw->scale),
bbox->Top + (int)((y - sy) * gwin->gw->scale),
(int)(clip.x1), (int)(clip.y1), 0xC0);
@@ -3636,7 +3675,8 @@ static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
- .plot = &amiplot
+ .plot = &amiplot,
+ .priv = browserglob
};
if(!g) return;
@@ -3660,6 +3700,45 @@ static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw
return;
}
+
+/**
+ * Invalidates an area of an amiga browser window
+ *
+ * \param g gui_window
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
+ */
+static nserror amiga_window_invalidate_area(struct gui_window *g,
+ const struct rect *restrict rect)
+{
+ struct nsObject *nsobj;
+ struct rect *restrict deferred_rect;
+
+ if(!g) return NSERROR_BAD_PARAMETER;
+
+ if (rect == NULL) {
+ if (g != g->shared->gw) {
+ return NSERROR_OK;
+ }
+ } else {
+ if (ami_gui_window_update_box_deferred_check(g->deferred_rects, rect,
+ g->deferred_rects_pool)) {
+ deferred_rect = ami_memory_itempool_alloc(g->deferred_rects_pool,
+ sizeof(struct rect));
+ CopyMem(rect, deferred_rect, sizeof(struct rect));
+ nsobj = AddObject(g->deferred_rects, AMINS_RECT);
+ nsobj->objstruct = deferred_rect;
+ } else {
+ NSLOG(netsurf, INFO,
+ "Ignoring duplicate or subset of queued box redraw");
+ }
+ }
+ ami_schedule_redraw(g->shared, false);
+
+ return NSERROR_OK;
+}
+
+
static void ami_refresh_window(struct gui_window_2 *gwin)
{
/* simplerefresh only */
@@ -3692,7 +3771,7 @@ static void ami_refresh_window(struct gui_window_2 *gwin)
regrect = gwin->win->RPort->Layer->DamageList->RegionRectangle;
- gui_window_update_box(gwin->gw, &r);
+ amiga_window_invalidate_area(gwin->gw, &r);
while(regrect)
{
@@ -3707,7 +3786,7 @@ static void ami_refresh_window(struct gui_window_2 *gwin)
regrect = regrect->Next;
- gui_window_update_box(gwin->gw, &r);
+ amiga_window_invalidate_area(gwin->gw, &r);
}
EndRefresh(gwin->win, TRUE);
@@ -3781,7 +3860,8 @@ HOOKF(void, ami_scroller_hook, Object *, object, struct IntuiMessage *)
break;
default:
- LOG("IDCMP hook unhandled event: %ld", msg->Class);
+ NSLOG(netsurf, INFO,
+ "IDCMP hook unhandled event: %ld", msg->Class);
break;
}
// ReplyMsg((struct Message *)msg);
@@ -3840,7 +3920,7 @@ gui_window_create(struct browser_window *bw,
ULONG defer_layout = TRUE;
ULONG idcmp_sizeverify = IDCMP_SIZEVERIFY;
- LOG("Creating window");
+ NSLOG(netsurf, INFO, "Creating window");
if (!scrn) ami_openscreenfirst();
@@ -3979,12 +4059,14 @@ gui_window_create(struct browser_window *bw,
ULONG addtabclosegadget = TAG_IGNORE;
ULONG iconifygadget = FALSE;
+#ifdef __amigaos4__
if (nsoption_charp(pubscreen_name) &&
(locked_screen == TRUE) &&
(strcmp(nsoption_charp(pubscreen_name), "Workbench") == 0))
iconifygadget = TRUE;
+#endif
- LOG("Creating menu");
+ NSLOG(netsurf, INFO, "Creating menu");
struct Menu *menu = ami_gui_menu_create(g->shared);
NewList(&g->shared->tab_list);
@@ -4106,7 +4188,7 @@ gui_window_create(struct browser_window *bw,
BitMapEnd;
}
- LOG("Creating window object");
+ NSLOG(netsurf, INFO, "Creating window object");
g->shared->objects[OID_MAIN] = WindowObj,
WA_ScreenTitle, ami_gui_get_screen_title(),
@@ -4384,11 +4466,11 @@ gui_window_create(struct browser_window *bw,
EndWindow;
}
- LOG("Opening window");
+ NSLOG(netsurf, INFO, "Opening window");
g->shared->win = (struct Window *)RA_OpenWindow(g->shared->objects[OID_MAIN]);
- LOG("Window opened, adding border gadgets");
+ NSLOG(netsurf, INFO, "Window opened, adding border gadgets");
if(!g->shared->win)
{
@@ -4459,8 +4541,6 @@ gui_window_create(struct browser_window *bw,
ami_gui_win_list_add(g->shared, AMINS_WINDOW, &ami_gui_table);
- ami_gui_set_default_gg();
-
if(locked_screen) {
UnlockPubScreen(NULL,scrn);
locked_screen = FALSE;
@@ -4480,9 +4560,7 @@ static void ami_gui_close_tabs(struct gui_window_2 *gwin, bool other_tabs)
struct gui_window *gw;
if((gwin->tabs > 1) && (nsoption_bool(tab_close_warn) == true)) {
- char *req_body = ami_utf8_easy(messages_get("MultiTabClose"));
- int32 res = amiga_warn_user_multi(req_body, "Yes", "No", gwin->win);
- free(req_body);
+ int32 res = amiga_warn_user_multi(messages_get("MultiTabClose"), "Yes", "No", gwin->win);
if(res == 0) return;
}
@@ -4531,7 +4609,7 @@ static void gui_window_destroy(struct gui_window *g)
if(g->hw)
{
- ami_history_close(g->hw);
+ ami_history_local_destroy(g->hw);
win_destroyed = true;
}
@@ -4701,7 +4779,7 @@ static void ami_redraw_callback(void *p)
*
* \param gwin a struct gui_window_2
* \param full_redraw set to true to schedule a full redraw,
- should only be set to false when called from gui_window_update_box()
+ should only be set to false when called from amiga_window_invalidate_area()
*/
void ami_schedule_redraw(struct gui_window_2 *gwin, bool full_redraw)
{
@@ -4716,14 +4794,6 @@ static void ami_schedule_redraw_remove(struct gui_window_2 *gwin)
ami_schedule(-1, ami_redraw_callback, gwin);
}
-static void gui_window_redraw_window(struct gui_window *g)
-{
- if(!g) return;
-
- if(g == g->shared->gw)
- ami_schedule_redraw(g->shared, true);
-}
-
static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw)
{
struct nsObject *node;
@@ -4736,7 +4806,7 @@ static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw)
if(draw == true) {
ami_set_pointer(g->shared, GUI_POINTER_WAIT, false);
} else {
- LOG("Ignoring deferred box redraw queue");
+ NSLOG(netsurf, INFO, "Ignoring deferred box redraw queue");
}
node = (struct nsObject *)GetHead((struct List *)g->deferred_rects);
@@ -4781,7 +4851,8 @@ bool ami_gui_window_update_box_deferred_check(struct MinList *deferred_rects,
(new_rect->y0 <= rect->y0) &&
(new_rect->x1 >= rect->x1) &&
(new_rect->y1 >= rect->y1)) {
- LOG("Removing queued redraw that is a subset of new box redraw");
+ NSLOG(netsurf, INFO,
+ "Removing queued redraw that is a subset of new box redraw");
ami_memory_itempool_free(mempool, node->objstruct, sizeof(struct rect));
DelObjectNoFree(node);
/* Don't return - we might find more */
@@ -4791,50 +4862,12 @@ bool ami_gui_window_update_box_deferred_check(struct MinList *deferred_rects,
return true;
}
-static void gui_window_update_box(struct gui_window *g, const struct rect *restrict rect)
-{
- struct nsObject *nsobj;
- struct rect *restrict deferred_rect;
- if(!g) return;
-
- if(ami_gui_window_update_box_deferred_check(g->deferred_rects, rect,
- g->deferred_rects_pool)) {
- deferred_rect = ami_memory_itempool_alloc(g->deferred_rects_pool, sizeof(struct rect));
- CopyMem(rect, deferred_rect, sizeof(struct rect));
- nsobj = AddObject(g->deferred_rects, AMINS_RECT);
- nsobj->objstruct = deferred_rect;
- } else {
- LOG("Ignoring duplicate or subset of queued box redraw");
- }
- ami_schedule_redraw(g->shared, false);
-}
-
-/**
- * callback from core to reformat a window.
- */
-static void amiga_window_reformat(struct gui_window *gw)
-{
- struct IBox *bbox;
-
- LOG("reformat window %p", gw);
-
- if (gw != NULL) {
- if(ami_gui_get_space_box((Object *)gw->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
- amiga_warn_user("NoMemory", "");
- return;
- }
- browser_window_reformat(gw->bw, false, bbox->Width, bbox->Height);
- gw->shared->redraw_scroll = false;
- ami_gui_free_space_box(bbox);
- }
-}
static void ami_do_redraw(struct gui_window_2 *gwin)
{
ULONG hcurrent,vcurrent,xoffset,yoffset,width=800,height=600;
struct IBox *bbox;
ULONG oldh = gwin->oldh, oldv=gwin->oldv;
- struct RastPort *temprp;
if(browser_window_redraw_ready(gwin->gw->bw) == false) return;
@@ -4879,63 +4912,39 @@ static void ami_do_redraw(struct gui_window_2 *gwin)
{
ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, 0, height - (vcurrent - oldv) - 1);
ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, width + 1, height + 1);
- gui_window_update_box(gwin->gw, &rect);
+ amiga_window_invalidate_area(gwin->gw, &rect);
}
else if(vcurrent<oldv) /* Going up */
{
ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, 0, 0);
ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, width + 1, oldv - vcurrent + 1);
- gui_window_update_box(gwin->gw, &rect);
+ amiga_window_invalidate_area(gwin->gw, &rect);
}
if(hcurrent>oldh) /* Going right */
{
ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, width - (hcurrent - oldh), 0);
ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, width + 1, height + 1);
- gui_window_update_box(gwin->gw, &rect);
+ amiga_window_invalidate_area(gwin->gw, &rect);
}
else if(hcurrent<oldh) /* Going left */
{
ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, 0, 0);
ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, oldh - hcurrent + 1, height + 1);
- gui_window_update_box(gwin->gw, &rect);
+ amiga_window_invalidate_area(gwin->gw, &rect);
}
}
else
{
- struct rect clip;
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
- .plot = &amiplot
+ .plot = &amiplot,
+ .priv = browserglob
};
- ami_gui_set_default_gg();
+ ami_do_redraw_tiled(gwin, true, hcurrent, vcurrent, width, height, hcurrent, vcurrent, bbox, &ctx);
- if(nsoption_bool(direct_render) == false)
- {
- ami_do_redraw_tiled(gwin, true, hcurrent, vcurrent, width, height, hcurrent, vcurrent, bbox, &ctx);
- }
- else
- {
- browserglob.shared_pens = gwin->shared_pens;
- temprp = browserglob.rp;
- browserglob.rp = gwin->win->RPort;
- clip.x0 = bbox->Left;
- clip.y0 = bbox->Top;
- clip.x1 = bbox->Left + bbox->Width;
- clip.y1 = bbox->Top + bbox->Height;
-
- ami_set_pointer(gwin, GUI_POINTER_WAIT, false);
-
- if(browser_window_redraw(gwin->gw->bw, clip.x0 - hcurrent, clip.y0 - vcurrent, &clip, &ctx))
- {
- ami_clearclipreg(&browserglob);
- browserglob.rp = temprp;
- }
-
- ami_reset_pointer(gwin);
- }
/* Tell NetSurf not to bother with the next queued box redraw, as we've redrawn everything. */
ami_gui_window_update_box_deferred(gwin->gw, false);
}
@@ -4952,27 +4961,26 @@ static void ami_do_redraw(struct gui_window_2 *gwin)
ami_gui_free_space_box(bbox);
}
+
void ami_get_hscroll_pos(struct gui_window_2 *gwin, ULONG *xs)
{
if(gwin->objects[GID_HSCROLL])
{
GetAttr(SCROLLER_Top, (Object *)gwin->objects[GID_HSCROLL], xs);
+ *xs /= gwin->gw->scale;
} else {
*xs = 0;
}
-
- *xs /= gwin->gw->scale;
}
void ami_get_vscroll_pos(struct gui_window_2 *gwin, ULONG *ys)
{
if(gwin->objects[GID_VSCROLL]) {
GetAttr(SCROLLER_Top, gwin->objects[GID_VSCROLL], ys);
+ *ys /= gwin->gw->scale;
} else {
*ys = 0;
}
-
- *ys /= gwin->gw->scale;
}
static bool gui_window_get_scroll(struct gui_window *g, int *restrict sx, int *restrict sy)
@@ -4983,21 +4991,44 @@ static bool gui_window_get_scroll(struct gui_window *g, int *restrict sx, int *r
return true;
}
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+/**
+ * Set the scroll position of a amiga browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The amiga implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param g gui_window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *g, const struct rect *rect)
{
struct IBox *bbox;
int width, height;
+ nserror res;
+ int sx = 0, sy = 0;
- if(!g) return;
- if(!g->bw || browser_window_has_content(g->bw) == false) return;
+ if(!g) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if(!g->bw || browser_window_has_content(g->bw) == false) {
+ return NSERROR_BAD_PARAMETER;
+ }
- if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
+ res = ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox);
+ if(res != NSERROR_OK) {
amiga_warn_user("NoMemory", "");
- return;
+ return res;
}
- if(sx < 0) sx=0;
- if(sy < 0) sy=0;
+ if (rect->x0 > 0) {
+ sx = rect->x0;
+ }
+ if (rect->y0 > 0) {
+ sy = rect->y0;
+ }
browser_window_get_extents(g->bw, false, &width, &height);
@@ -5035,6 +5066,7 @@ static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
g->scrollx = sx;
g->scrolly = sy;
}
+ return NSERROR_OK;
}
static void gui_window_update_extent(struct gui_window *g)
@@ -5166,7 +5198,7 @@ static nserror gui_search_web_provider_update(const char *provider_name,
if(nsoption_bool(kiosk_mode) == true) return NSERROR_BAD_PARAMETER;
if (ico_bitmap != NULL) {
- bm = ami_bitmap_get_native(ico_bitmap, 16, 16, NULL);
+ bm = ami_bitmap_get_native(ico_bitmap, 16, 16, ami_plot_screen_is_palettemapped(), NULL);
}
if(bm == NULL) return NSERROR_BAD_PARAMETER;
@@ -5282,7 +5314,7 @@ static void gui_window_new_content(struct gui_window *g)
c = browser_window_get_content(g->bw);
else return;
- ami_clearclipreg(&browserglob);
+ ami_clearclipreg(browserglob);
g->shared->new_content = true;
g->scrollx = 0;
g->scrolly = 0;
@@ -5391,20 +5423,20 @@ Object *ami_gui_splash_open(void)
EndWindow;
if(win_obj == NULL) {
- LOG("Splash window object not created");
+ NSLOG(netsurf, INFO, "Splash window object not created");
return NULL;
}
- LOG("Attempting to open splash window...");
+ NSLOG(netsurf, INFO, "Attempting to open splash window...");
win = RA_OpenWindow(win_obj);
if(win == NULL) {
- LOG("Splash window did not open");
+ NSLOG(netsurf, INFO, "Splash window did not open");
return NULL;
}
if(bm_obj == NULL) {
- LOG("BitMap object not created");
+ NSLOG(netsurf, INFO, "BitMap object not created");
return NULL;
}
@@ -5466,14 +5498,14 @@ void ami_gui_splash_close(Object *win_obj)
{
if(win_obj == NULL) return;
- LOG("Closing splash window");
+ NSLOG(netsurf, INFO, "Closing splash window");
DisposeObject(win_obj);
}
static void gui_file_gadget_open(struct gui_window *g, struct hlcache_handle *hl,
struct form_control *gadget)
{
- LOG("File open dialog request for %p/%p", g, gadget);
+ NSLOG(netsurf, INFO, "File open dialog request for %p/%p", g, gadget);
if(AslRequestTags(filereq,
ASLFR_Window, g->shared->win,
@@ -5508,7 +5540,7 @@ static char *ami_gui_get_user_dir(STRPTR current_user)
user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY);
current_user = ASPrintf("%s", (user == -1) ? "Default" : temp);
}
- LOG("User: %s", current_user);
+ NSLOG(netsurf, INFO, "User: %s", current_user);
if(users_dir == NULL) {
users_dir = ASPrintf("%s", USERS_DIR);
@@ -5560,7 +5592,7 @@ static char *ami_gui_get_user_dir(STRPTR current_user)
FreeVec(users_dir);
FreeVec(current_user);
- LOG("User dir: %s", current_user_dir);
+ NSLOG(netsurf, INFO, "User dir: %s", current_user_dir);
if((lock = CreateDirTree(current_user_dir)))
UnLock(lock);
@@ -5576,13 +5608,11 @@ static char *ami_gui_get_user_dir(STRPTR current_user)
static struct gui_window_table amiga_window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
+ .invalidate = amiga_window_invalidate_area,
.get_scroll = gui_window_get_scroll,
.set_scroll = gui_window_set_scroll,
.get_dimensions = gui_window_get_dimensions,
.update_extent = gui_window_update_extent,
- .reformat = amiga_window_reformat,
.set_icon = gui_window_set_icon,
.set_title = gui_window_set_title,
@@ -5789,7 +5819,7 @@ int main(int argc, char** argv)
AddPart(script, nsoption_charp(arexx_startup), 1024);
ami_arexx_execute(script);
- LOG("Entering main loop");
+ NSLOG(netsurf, INFO, "Entering main loop");
while (!ami_quit) {
ami_get_msg();
@@ -5808,6 +5838,9 @@ int main(int argc, char** argv)
free(current_user_dir);
FreeVec(current_user_faviconcache);
+ /* finalise logging */
+ nslog_finalise();
+
#ifndef __amigaos4__
/* OS3 low memory handler */
ami_memory_fini(memhandler);
diff --git a/frontends/amiga/gui.h b/frontends/amiga/gui.h
index 07ff922f7..bf4ec9139 100644
--- a/frontends/amiga/gui.h
+++ b/frontends/amiga/gui.h
@@ -87,7 +87,8 @@ enum
};
struct find_window;
-struct history_window;
+struct ami_history_local_window;
+struct ami_menu_data;
#define AMI_GUI_TOOLBAR_MAX 20
@@ -110,8 +111,6 @@ struct ami_generic_window {
const struct ami_win_event_table *tbl;
};
-struct ami_menu_data;
-
struct gui_window_2 {
struct ami_generic_window w;
struct Window *win;
@@ -174,7 +173,7 @@ struct gui_window
int c_h_temp;
int scrollx;
int scrolly;
- struct history_window *hw;
+ struct ami_history_local_window *hw;
struct List dllist;
struct hlcache_handle *favicon;
bool throbbing;
@@ -259,11 +258,6 @@ uint32 ami_gui_get_app_id(void);
STRPTR ami_gui_get_screen_title(void);
/**
- * Set gui_globals back to the default for the browser context
- */
-void ami_gui_set_default_gg(void);
-
-/**
* Switch to the most-recently-opened tab
*/
void ami_gui_switch_to_new_tab(struct gui_window_2 *gwin);
diff --git a/frontends/amiga/gui_menu.c b/frontends/amiga/gui_menu.c
index 6b9b2075d..6dbacf1ba 100644
--- a/frontends/amiga/gui_menu.c
+++ b/frontends/amiga/gui_menu.c
@@ -261,7 +261,7 @@ HOOKF(void, ami_menu_item_edit_copy, APTR, window, struct IntuiMessage *)
* the objects containing the values returned (and the
* constness cast away) is safe.
*/
- ami_bitmap_set_url(bm, browser_window_get_url(gwin->gw->bw));
+ ami_bitmap_set_url(bm, browser_window_access_url(gwin->gw->bw));
ami_bitmap_set_title(bm, browser_window_get_title(gwin->gw->bw));
ami_easy_clipboard_bitmap(bm);
}
@@ -326,7 +326,7 @@ HOOKF(void, ami_menu_item_browser_localhistory, APTR, window, struct IntuiMessag
struct gui_window_2 *gwin;
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
- ami_history_open(gwin->gw);
+ ami_history_local_present(gwin->gw);
}
HOOKF(void, ami_menu_item_browser_globalhistory, APTR, window, struct IntuiMessage *)
@@ -419,7 +419,7 @@ HOOKF(void, ami_menu_item_hotlist_add, APTR, window, struct IntuiMessage *)
if (bw == NULL || browser_window_has_content(bw) == false)
return;
- hotlist_add_url(browser_window_get_url(bw));
+ hotlist_add_url(browser_window_access_url(bw));
ami_gui_update_hotlist_button(gwin);
}
@@ -504,9 +504,9 @@ HOOKF(void, ami_menu_item_arexx_entries, APTR, window, struct IntuiMessage *)
DevNameFromLock(lock, temp, 1024, DN_FULLPATH);
AddPart(temp, script, 1024);
ami_arexx_execute(temp);
- free(temp);
UnLock(lock);
}
+ free(temp);
}
}
}
@@ -584,7 +584,8 @@ ULONG ami_gui_menu_number(int item)
break;
default:
- LOG("WARNING: Unrecognised menu item %d", item);
+ NSLOG(netsurf, INFO,
+ "WARNING: Unrecognised menu item %d", item);
menu_num = 0;
break;
}
diff --git a/frontends/amiga/gui_menu.h b/frontends/amiga/gui_menu.h
index 16fc72040..3490fe9c1 100644
--- a/frontends/amiga/gui_menu.h
+++ b/frontends/amiga/gui_menu.h
@@ -108,6 +108,7 @@ enum {
struct gui_window;
struct gui_window_2;
struct hlcache_handle;
+struct Window;
ULONG ami_gui_menu_number(int item);
struct Menu *ami_gui_menu_create(struct gui_window_2 *gwin);
diff --git a/frontends/amiga/gui_options.c b/frontends/amiga/gui_options.c
index 78dea5820..fb214d0fb 100755
--- a/frontends/amiga/gui_options.c
+++ b/frontends/amiga/gui_options.c
@@ -270,9 +270,8 @@ static void ami_gui_opts_array_to_list(struct List *list, const char *array[], i
node = AllocChooserNode(CNA_Text, array[i], TAG_DONE);
break;
case NSA_LIST_RADIO:
- /* Note: RBNA_Labels is RBNA_Label in OS4
- * Also note: These labels don't work (FIXME) */
- node = AllocRadioButtonNode(RBNA_Labels, array[i], TAG_DONE);
+ /* Note: RBNA_Labels is RBNA_Label in OS4 */
+ node = AllocRadioButtonNode(0, RBNA_Labels, array[i], TAG_DONE);
break;
default:
break;
@@ -1107,8 +1106,8 @@ void ami_gui_opts_open(void)
GA_ID, GID_OPTS_DPI_Y,
GA_RelVerify, TRUE,
INTEGER_Number, nsoption_int(screen_ydpi),
- INTEGER_Minimum, 60,
- INTEGER_Maximum, 150,
+ INTEGER_Minimum, 20,
+ INTEGER_Maximum, 200,
INTEGER_Arrows, TRUE,
GA_Disabled, nsoption_bool(bitmap_fonts),
IntegerEnd,
@@ -1748,7 +1747,7 @@ static void ami_gui_opts_use(bool save)
switch(data)
{
case 0:
- nsoption_set_charp(pubscreen_name, strdup("\0"));
+ nsoption_set_charp(pubscreen_name, NULL);
break;
case 1:
@@ -1898,6 +1897,15 @@ static void ami_gui_opts_use(bool save)
#ifndef __amigaos4__
GetAttr(GA_Selected, gow->objects[GID_OPTS_FONT_BITMAP], (ULONG *)&data);
ami_font_fini();
+
+ if((nsoption_bool(bitmap_fonts) == true) && (data == false)) {
+ nsoption_set_charp(font_sans, (char *)strdup("CGTriumvirate"));
+ nsoption_set_charp(font_serif, (char *)strdup("CGTimes"));
+ nsoption_set_charp(font_mono, (char *)strdup("LetterGothic"));
+ nsoption_set_charp(font_cursive, (char *)strdup("CGTriumvirate"));
+ nsoption_set_charp(font_fantasy, (char *)strdup("CGTimes"));
+ }
+
if(data) {
nsoption_set_bool(bitmap_fonts, true);
} else {
@@ -2134,7 +2142,7 @@ static BOOL ami_gui_opts_event(void *w)
case GID_OPTS_HOMEPAGE_CURRENT:
if(cur_gw) RefreshSetGadgetAttrs((struct Gadget *)gow->objects[GID_OPTS_HOMEPAGE],
gow->win, NULL, STRINGA_TextVal,
- nsurl_access(browser_window_get_url(cur_gw->bw)), TAG_DONE);
+ nsurl_access(browser_window_access_url(cur_gw->bw)), TAG_DONE);
break;
case GID_OPTS_HOMEPAGE_BLANK:
diff --git a/frontends/amiga/history.c b/frontends/amiga/history.c
index 12c306a9b..e724f3e70 100644
--- a/frontends/amiga/history.c
+++ b/frontends/amiga/history.c
@@ -162,12 +162,16 @@ ami_history_global_key(struct ami_corewindow *ami_cw, uint32_t nskey)
* callback on draw event for history viewer on core window
*
* \param ami_cw The Amiga core window structure.
+ * \param x The x coordinate of global history area to redraw
+ * \param y The y coordinate of global history area to redraw
* \param r The rectangle of the window that needs updating.
* \param ctx The drawing context
* \return NSERROR_OK on success otherwise apropriate error code
*/
static nserror
-ami_history_global_draw(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx)
+ami_history_global_draw(struct ami_corewindow *ami_cw,
+ int x, int y, struct rect *r,
+ struct redraw_context *ctx)
{
global_history_redraw(x, y, r, ctx);
@@ -434,7 +438,7 @@ nserror ami_history_global_present(void)
res = ami_history_global_create_window(ncwin);
if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
ami_utf8_free(ncwin->core.wintitle);
free(ncwin);
return res;
diff --git a/frontends/amiga/history_local.c b/frontends/amiga/history_local.c
index 3d1c6f39b..0ae9cc040 100755..100644
--- a/frontends/amiga/history_local.c
+++ b/frontends/amiga/history_local.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009, 2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2017 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,345 +16,300 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Browser history window (AmigaOS implementation).
- *
- * There is only one history window, not one per browser window.
+/**
+ * \file
+ * Implementation of Amiga local history using core windows.
*/
-#include "amiga/os3support.h"
-
-#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
-#include <string.h>
+
#include <proto/intuition.h>
-#include <proto/exec.h>
-#include <proto/graphics.h>
-#include <intuition/icclass.h>
-#include <proto/utility.h>
-#include <proto/window.h>
-#include <proto/space.h>
-#include <proto/layout.h>
+
#include <classes/window.h>
-#include <gadgets/space.h>
+#include <gadgets/button.h>
+#include <gadgets/layout.h>
#include <gadgets/scroller.h>
-#include <reaction/reaction.h>
+#include <gadgets/space.h>
+#include <images/label.h>
+
+#include <intuition/icclass.h>
#include <reaction/reaction_macros.h>
#include "utils/log.h"
-#include "utils/utils.h"
-#include "utils/messages.h"
-#include "desktop/browser_history.h"
-#include "netsurf/browser_window.h"
+#include "netsurf/keypress.h"
#include "netsurf/plotters.h"
-#include "netsurf/window.h"
-#include "graphics/rpattr.h"
+#include "desktop/local_history.h"
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
-#include "amiga/libs.h"
-#include "amiga/misc.h"
-#include "amiga/object.h"
-#include "amiga/plotters.h"
+#include "amiga/corewindow.h"
#include "amiga/gui.h"
+#include "amiga/libs.h"
#include "amiga/history_local.h"
+#include "amiga/utf8.h"
-struct history_window {
- struct ami_generic_window w;
- struct Window *win;
- Object *objects[GID_LAST];
- struct gui_window *gw;
- struct Hook scrollerhook;
- struct gui_globals *gg;
-};
-static void ami_history_update_extent(struct history_window *hw);
-HOOKF(void, ami_history_scroller_hook, Object *, object, struct IntuiMessage *);
+/**
+ * Amiga local history viewing window context
+ */
+struct ami_history_local_window {
+ /** Amiga core window context */
+ struct ami_corewindow core;
-static BOOL ami_history_event(void *w);
+ /** Amiga GUI stuff */
+ struct gui_window *gw;
-static const struct ami_win_event_table ami_localhistory_table = {
- ami_history_event,
- NULL, /* we don't explicitly close the local history window on quit */
+ /** local history viewer context data */
+ struct local_history_session *session;
};
+static struct ami_history_local_window *history_local_window = NULL;
+
/**
- * Redraw history window.
+ * destroy a previously created local history view
*/
-
-static void ami_history_redraw(struct history_window *hw)
+nserror
+ami_history_local_destroy(struct ami_history_local_window *history_local_win)
{
- struct IBox *bbox;
- ULONG xs,ys;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &amiplot
- };
-
- GetAttr(SCROLLER_Top,hw->objects[OID_HSCROLL],(ULONG *)&xs);
- GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys);
- if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
- amiga_warn_user("NoMemory", "");
- return;
- }
+ nserror res;
- glob = hw->gg;
-
- SetRPAttrs(glob->rp, RPTAG_APenColor, 0xffffffff, TAG_DONE);
- RectFill(glob->rp, 0, 0, bbox->Width - 1, bbox->Height - 1);
-
- browser_window_history_redraw_rectangle(hw->gw->bw, xs, ys,
- bbox->Width + xs, bbox->Height + ys, 0, 0, &ctx);
+ if (history_local_win == NULL) {
+ return NSERROR_OK;
+ }
- ami_gui_set_default_gg();
+ res = local_history_fini(history_local_win->session);
+ if (res == NSERROR_OK) {
+ history_local_win->gw->hw = NULL;
+ res = ami_corewindow_fini(&history_local_win->core); /* closes the window for us */
+ history_local_window = NULL;
+ }
+ return res;
+}
- ami_clearclipreg(hw->gg);
- ami_history_update_extent(hw);
+/**
+ * callback for mouse action for local history on core window
+ *
+ * \param ami_cw The Amiga core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+ami_history_local_mouse(struct ami_corewindow *ami_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct ami_history_local_window *history_local_win;
+ /* technically degenerate container of */
+ history_local_win = (struct ami_history_local_window *)ami_cw;
+
+ nsurl *url;
+
+ if(local_history_get_url(history_local_win->session, x, y, &url) == NSERROR_OK) {
+ if (url == NULL) {
+ SetGadgetAttrs(
+ (struct Gadget *)ami_cw->objects[GID_CW_DRAW],
+ ami_cw->win,
+ NULL,
+ GA_HintInfo,
+ NULL,
+ TAG_DONE);
+ } else {
+ SetGadgetAttrs(
+ (struct Gadget *)ami_cw->objects[GID_CW_DRAW],
+ ami_cw->win,
+ NULL,
+ GA_HintInfo,
+ nsurl_access(url),
+ TAG_DONE);
+ nsurl_unref(url);
+ }
+ }
- BltBitMapRastPort(hw->gg->bm, 0, 0, hw->win->RPort,
- bbox->Left, bbox->Top, bbox->Width, bbox->Height, 0x0C0);
+ local_history_mouse_action(history_local_win->session, mouse_state, x, y);
- ami_gui_free_space_box(bbox);
+ return NSERROR_OK;
}
-
-/* exported interface documented in amiga/history_local.h */
-void ami_history_open(struct gui_window *gw)
+/**
+ * callback for keypress for local history on core window
+ *
+ * \param ami_cw The Amiga core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+ami_history_local_key(struct ami_corewindow *ami_cw, uint32_t nskey)
{
- struct history *history;
- int width, height;
+ struct ami_history_local_window *history_local_win;
- if (gw->bw == NULL)
- return;
-
- history = browser_window_get_history(gw->bw);
- if (history == NULL)
- return;
-
- if(!gw->hw)
- {
- gw->hw = calloc(1, sizeof(struct history_window));
- gw->hw->gg = calloc(1, sizeof(struct gui_globals));
-
- ami_init_layers(gw->hw->gg, scrn->Width, scrn->Height, false);
-
- gw->hw->gw = gw;
- browser_window_history_size(gw->bw, &width, &height);
-
- gw->hw->scrollerhook.h_Entry = (void *)ami_history_scroller_hook;
- gw->hw->scrollerhook.h_Data = gw->hw;
-
- gw->hw->objects[OID_MAIN] = WindowObj,
- WA_ScreenTitle, ami_gui_get_screen_title(),
- WA_Title, messages_get("History"),
- WA_Activate, TRUE,
- WA_DepthGadget, TRUE,
- WA_DragBar, TRUE,
- WA_CloseGadget, TRUE,
- WA_SizeGadget, TRUE,
- WA_PubScreen,scrn,
- WA_InnerWidth,width,
- WA_InnerHeight,height + 10,
- WINDOW_SharedPort,sport,
- WINDOW_UserData,gw->hw,
- WINDOW_IconifyGadget, FALSE,
- WINDOW_GadgetHelp, TRUE,
- WINDOW_Position, WPOS_CENTERSCREEN,
- WINDOW_HorizProp,1,
- WINDOW_VertProp,1,
- WINDOW_IDCMPHook,&gw->hw->scrollerhook,
- WINDOW_IDCMPHookBits,IDCMP_IDCMPUPDATE,
-// WA_ReportMouse,TRUE,
- WA_IDCMP,IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE, // | IDCMP_MOUSEMOVE,
- WINDOW_ParentGroup, gw->hw->objects[GID_MAIN] = LayoutVObj,
- LAYOUT_AddChild, gw->hw->objects[GID_BROWSER] = SpaceObj,
- GA_ID,GID_BROWSER,
-// SPACE_MinWidth,width,
-// SPACE_MinHeight,height,
- SpaceEnd,
- EndGroup,
- EndWindow;
-
- gw->hw->win = (struct Window *)RA_OpenWindow(gw->hw->objects[OID_MAIN]);
- ami_gui_win_list_add(gw->hw, AMINS_HISTORYWINDOW, &ami_localhistory_table);
-
- GetAttr(WINDOW_HorizObject,gw->hw->objects[OID_MAIN],(ULONG *)&gw->hw->objects[OID_HSCROLL]);
- GetAttr(WINDOW_VertObject,gw->hw->objects[OID_MAIN],(ULONG *)&gw->hw->objects[OID_VSCROLL]);
-
- RefreshSetGadgetAttrs((APTR)gw->hw->objects[OID_VSCROLL],gw->hw->win,NULL,
- GA_ID,OID_VSCROLL,
- SCROLLER_Top,0,
- ICA_TARGET,ICTARGET_IDCMP,
- TAG_DONE);
-
- RefreshSetGadgetAttrs((APTR)gw->hw->objects[OID_HSCROLL],gw->hw->win,NULL,
- GA_ID,OID_HSCROLL,
- SCROLLER_Top,0,
- ICA_TARGET,ICTARGET_IDCMP,
- TAG_DONE);
- }
+ /* technically degenerate container of */
+ history_local_win = (struct ami_history_local_window *)ami_cw;
- ami_history_redraw(gw->hw);
+ if (local_history_keypress(history_local_win->session, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
}
-
/**
- * Handle mouse clicks in the history window.
+ * callback on draw event for certificate verify on core window
*
- * \return true if the event was handled, false to pass it on
+ * \param ami_cw The Amiga core window structure.
+ * \param x the x coordinate to draw
+ * \param y the y coordinate to draw
+ * \param r The rectangle of the window that needs updating.
+ * \param ctx The drawing context
+ * \return NSERROR_OK on success otherwise apropriate error code
*/
+static nserror
+ami_history_local_draw(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx)
+{
+ struct ami_history_local_window *history_local_win;
-static bool ami_history_click(struct history_window *hw, uint16 code)
+ /* technically degenerate container of */
+ history_local_win = (struct ami_history_local_window *)ami_cw;
+
+ //ctx->plot->clip(ctx, r); //??
+ local_history_redraw(history_local_win->session, x, y, r, ctx);
+
+ return NSERROR_OK;
+}
+
+static nserror
+ami_history_local_create_window(struct ami_history_local_window *history_local_win)
{
- int x, y;
- struct IBox *bbox;
- ULONG xs, ys;
+ struct ami_corewindow *ami_cw = (struct ami_corewindow *)&history_local_win->core;
+ ULONG refresh_mode = WA_SmartRefresh;
- if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
- amiga_warn_user("NoMemory", "");
- return false;
+ if(nsoption_bool(window_simple_refresh) == true) {
+ refresh_mode = WA_SimpleRefresh;
}
- GetAttr(SCROLLER_Top,hw->objects[OID_HSCROLL],(ULONG *)&xs);
- x = hw->win->MouseX - bbox->Left +xs;
- GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys);
- y = hw->win->MouseY - bbox->Top + ys;
-
- ami_gui_free_space_box(bbox);
-
- switch(code)
- {
- case SELECTUP:
- browser_window_history_click(hw->gw->bw, x, y, false);
- ami_history_redraw(hw);
- ami_schedule_redraw(hw->gw->shared, true);
- break;
-
- case MIDDLEUP:
- browser_window_history_click(hw->gw->bw, x, y, true);
- ami_history_redraw(hw);
- break;
+ ami_cw->objects[GID_CW_WIN] = WindowObj,
+ WA_ScreenTitle, ami_gui_get_screen_title(),
+ WA_Title, ami_cw->wintitle,
+ WA_Activate, TRUE,
+ WA_DepthGadget, TRUE,
+ WA_DragBar, TRUE,
+ WA_CloseGadget, TRUE,
+ WA_SizeGadget, TRUE,
+ WA_SizeBRight, TRUE,
+ WA_Width, 100,
+ WA_Height, 100,
+ WA_PubScreen, scrn,
+ WA_ReportMouse, TRUE,
+ refresh_mode, TRUE,
+ WA_IDCMP, IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
+ IDCMP_RAWKEY | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE |
+ IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW,
+ WINDOW_IDCMPHook, &ami_cw->idcmp_hook,
+ WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE |
+ IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW,
+ WINDOW_SharedPort, sport,
+ WINDOW_HorizProp, 1,
+ WINDOW_VertProp, 1,
+ WINDOW_UserData, history_local_win,
+// WINDOW_MenuStrip, NULL,
+ WINDOW_MenuUserData, WGUD_HOOK,
+ WINDOW_IconifyGadget, FALSE,
+ WINDOW_Position, WPOS_CENTERSCREEN,
+ WINDOW_ParentGroup, ami_cw->objects[GID_CW_MAIN] = LayoutVObj,
+ LAYOUT_AddChild, ami_cw->objects[GID_CW_DRAW] = SpaceObj,
+ GA_ID, GID_CW_DRAW,
+ SPACE_Transparent, TRUE,
+ SPACE_BevelStyle, BVS_DISPLAY,
+ GA_RelVerify, TRUE,
+ SpaceEnd,
+ EndGroup,
+ EndWindow;
+
+ if(ami_cw->objects[GID_CW_WIN] == NULL) {
+ return NSERROR_NOMEM;
}
- return true;
+ return NSERROR_OK;
}
-void ami_history_close(struct history_window *hw)
+/* exported interface documented in amiga/history_local.h */
+nserror ami_history_local_present(struct gui_window *gw)
{
- ami_free_layers(hw->gg);
- free(hw->gg);
- hw->gw->hw = NULL;
- DisposeObject(hw->objects[OID_MAIN]);
- ami_gui_win_list_remove(hw);
-}
+ struct ami_history_local_window *ncwin;
+ nserror res;
+ int width, height;
-static BOOL ami_history_event(void *w)
-{
- /* return TRUE if window destroyed */
- struct history_window *hw = (struct history_window *)w;
- ULONG result = 0;
- uint16 code;
- const char *url;
- struct IBox *bbox;
- ULONG xs, ys;
-
- while((result = RA_HandleInput(hw->objects[OID_MAIN],&code)) != WMHI_LASTMSG)
- {
- switch(result & WMHI_CLASSMASK) // class
- {
-/* no menus yet, copied in as will probably need it later
- case WMHI_MENUPICK:
- item = ItemAddress(gwin->win->MenuStrip,code);
- while (code != MENUNULL)
- {
- ami_menupick(code,gwin);
- if(win_destroyed) break;
- code = item->NextSelect;
- }
- break;
-*/
-
- case WMHI_MOUSEMOVE:
- GetAttr(SCROLLER_Top, hw->objects[OID_HSCROLL], (ULONG *)&xs);
- GetAttr(SCROLLER_Top, hw->objects[OID_VSCROLL], (ULONG *)&ys);
-
- if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
- amiga_warn_user("NoMemory", "");
- break;
- }
-
- url = browser_window_history_position_url(hw->gw->bw,
- hw->win->MouseX - bbox->Left + xs,
- hw->win->MouseY - bbox->Top + ys);
-
- ami_gui_free_space_box(bbox);
-
- RefreshSetGadgetAttrs((APTR)hw->objects[GID_BROWSER],
- hw->win, NULL,
- GA_HintInfo, url,
- TAG_DONE);
- break;
-
- case WMHI_NEWSIZE:
- ami_history_redraw(hw);
- break;
-
- case WMHI_MOUSEBUTTONS:
- ami_history_click(hw,code);
- break;
-
- case WMHI_CLOSEWINDOW:
- ami_history_close(hw);
- return TRUE;
- break;
+ if(history_local_window != NULL) {
+ //windowtofront()
+
+ if (gw->hw != NULL) {
+ res = local_history_set(gw->hw->session, gw->bw);
+ return res;
}
+
+ return NSERROR_OK;
}
- return FALSE;
-}
-static void ami_history_update_extent(struct history_window *hw)
-{
- struct IBox *bbox;
- int width, height;
+ ncwin = calloc(1, sizeof(struct ami_history_local_window));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
- browser_window_history_size(hw->gw->bw, &width, &height);
- if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
- amiga_warn_user("NoMemory", "");
- return;
+ ncwin->core.wintitle = ami_utf8_easy((char *)messages_get("History"));
+
+ res = ami_history_local_create_window(ncwin);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
+ ami_utf8_free(ncwin->core.wintitle);
+ free(ncwin);
+ return res;
}
- RefreshSetGadgetAttrs((APTR)hw->objects[OID_VSCROLL], hw->win, NULL,
- GA_ID, OID_VSCROLL,
- SCROLLER_Total, height,
- SCROLLER_Visible, bbox->Height,
- ICA_TARGET, ICTARGET_IDCMP,
- TAG_DONE);
+ /* initialise Amiga core window */
+ ncwin->core.draw = ami_history_local_draw;
+ ncwin->core.key = ami_history_local_key;
+ ncwin->core.mouse = ami_history_local_mouse;
+ ncwin->core.close = ami_history_local_destroy;
+ ncwin->core.event = NULL;
+ ncwin->core.drag_end = NULL;
+ ncwin->core.icon_drop = NULL;
+
+ res = ami_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ ami_utf8_free(ncwin->core.wintitle);
+ DisposeObject(ncwin->core.objects[GID_CW_WIN]);
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ gw->bw,
+ &ncwin->session);
+ if (res != NSERROR_OK) {
+ ami_utf8_free(ncwin->core.wintitle);
+ DisposeObject(ncwin->core.objects[GID_CW_WIN]);
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_get_size(ncwin->session,
+ &width,
+ &height);
- RefreshSetGadgetAttrs((APTR)hw->objects[OID_HSCROLL], hw->win, NULL,
- GA_ID, OID_HSCROLL,
- SCROLLER_Total, width,
- SCROLLER_Visible, bbox->Width,
- ICA_TARGET, ICTARGET_IDCMP,
+ /*TODO: Adjust these to account for window borders */
+
+ SetAttrs(ncwin->core.objects[GID_CW_WIN],
+ WA_Width, width,
+ WA_Height, height,
TAG_DONE);
- ami_gui_free_space_box(bbox);
+ ncwin->gw = gw;
+ history_local_window = ncwin;
+ gw->hw = ncwin;
+
+ return NSERROR_OK;
}
-HOOKF(void, ami_history_scroller_hook, Object *, object, struct IntuiMessage *)
-{
- ULONG gid;
- struct history_window *hw = hook->h_Data;
-
- if (msg->Class == IDCMP_IDCMPUPDATE)
- {
- gid = GetTagData( GA_ID, 0, msg->IAddress );
-
- switch( gid )
- {
- case OID_HSCROLL:
- case OID_VSCROLL:
- ami_history_redraw(hw);
- break;
- }
- }
-// ReplyMsg((struct Message *)msg);
-}
diff --git a/frontends/amiga/history_local.h b/frontends/amiga/history_local.h
index 97aea0579..72ba7fa8b 100755..100644
--- a/frontends/amiga/history_local.h
+++ b/frontends/amiga/history_local.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2017 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,23 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef AMIGA_HISTORY_LOCAL_H
-#define AMIGA_HISTORY_LOCAL_H
-
-#include <exec/types.h>
-#include <intuition/classusr.h>
+#ifndef AMIGA_HISTORY_GLOBAL_H
+#define AMIGA_HISTORY_GLOBAL_H
struct gui_window;
-struct gui_globals;
-struct history_window;
-
-/**
- * Open history window.
- *
- * \param gw gui_window to open history for
- */
-void ami_history_open(struct gui_window *gw);
+struct ami_history_local_window;
-void ami_history_close(struct history_window *hw);
+/** Open the global history viewer */
+nserror ami_history_local_present(struct gui_window *gw);
+nserror ami_history_local_destroy(struct ami_history_local_window *history_local_win);
#endif
diff --git a/frontends/amiga/hotlist.c b/frontends/amiga/hotlist.c
index 008e45a24..c7efe9148 100644
--- a/frontends/amiga/hotlist.c
+++ b/frontends/amiga/hotlist.c
@@ -213,12 +213,15 @@ ami_hotlist_key(struct ami_corewindow *ami_cw, uint32_t nskey)
* callback on draw event for hotlist viewer on core window
*
* \param ami_cw The Amiga core window structure.
+ * \param x The x coordinate of hotlist area to redraw
+ * \param y The y coordinate of hotlist area to redraw
* \param r The rectangle of the window that needs updating.
* \param ctx The drawing context
* \return NSERROR_OK on success otherwise apropriate error code
*/
static nserror
-ami_hotlist_draw(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx)
+ami_hotlist_draw(struct ami_corewindow *ami_cw,
+ int x, int y, struct rect *r, struct redraw_context *ctx)
{
hotlist_redraw(x, y, r, ctx);
@@ -560,7 +563,7 @@ nserror ami_hotlist_present(void)
res = ami_hotlist_create_window(ncwin);
if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
ami_utf8_free(ncwin->core.wintitle);
free(ncwin);
return res;
diff --git a/frontends/amiga/icon.c b/frontends/amiga/icon.c
index 3f597a1ba..582d355b6 100644
--- a/frontends/amiga/icon.c
+++ b/frontends/amiga/icon.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Content for image/x-amiga-icon (icon.library implementation).
*
*/
@@ -154,7 +155,7 @@ bool amiga_icon_convert(struct content *c)
if(filename == NULL)
{
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -166,7 +167,7 @@ bool amiga_icon_convert(struct content *c)
if(dobj == NULL)
{
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -186,14 +187,14 @@ bool amiga_icon_convert(struct content *c)
icon_c->bitmap = amiga_bitmap_create(width, height, BITMAP_NEW);
if (!icon_c->bitmap) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
if(dobj) FreeDiskObject(dobj);
return false;
}
imagebuf = (ULONG *) amiga_bitmap_get_buffer(icon_c->bitmap);
if (!imagebuf) {
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
if(dobj) FreeDiskObject(dobj);
return false;
}
@@ -273,8 +274,14 @@ bool amiga_icon_redraw(struct content *c,
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- icon_c->bitmap, data->background_colour, flags);
+ return (ctx->plot->bitmap(ctx,
+ icon_c->bitmap,
+ data->x,
+ data->y,
+ data->width,
+ data->height,
+ data->background_colour,
+ flags) == NSERROR_OK);
}
@@ -329,7 +336,10 @@ static ULONG *amiga_icon_convertcolouricon32(UBYTE *icondata, ULONG width, ULONG
if (!argbicon) return(NULL);
cmap=GetColorMap(pals1);
- if(!cmap) return(NULL);
+ if(!cmap) {
+ free(argbicon);
+ return(NULL);
+ }
for(i=0;i<(width*height);i++)
{
@@ -378,7 +388,7 @@ void amiga_icon_superimpose_favicon_internal(struct hlcache_handle *icon, struct
if(format != IDFMT_DIRECTMAPPED) return;
#ifdef __amigaos4__
if ((icon != NULL) && (content_get_bitmap(icon) != NULL)) {
- bm = ami_bitmap_get_native(content_get_bitmap(icon), 16, 16, NULL);
+ bm = ami_bitmap_get_native(content_get_bitmap(icon), 16, 16, false, NULL);
}
if(bm) {
@@ -499,7 +509,7 @@ struct DiskObject *amiga_icon_from_bitmap(struct bitmap *bm)
if(bm)
{
bitmap = ami_bitmap_get_native(bm, THUMBNAIL_WIDTH,
- THUMBNAIL_HEIGHT, NULL);
+ THUMBNAIL_HEIGHT, false, NULL);
icondata = malloc(THUMBNAIL_WIDTH * 4 * THUMBNAIL_HEIGHT);
ami_bitmap_set_icondata(bm, icondata);
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index 4c242d214..305818076 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -23,6 +23,7 @@
#include "utils/utils.h"
#include "utils/log.h"
+#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/utility.h>
@@ -56,11 +57,11 @@
#ifdef __amigaos4__
#define AMINS_LIB_OPEN(LIB, LIBVER, PREFIX, INTERFACE, INTVER, FAIL) \
- LOG("Opening %s v%d", LIB, LIBVER); \
+ NSLOG(netsurf, INFO, "Opening %s v%d", LIB, LIBVER); \
if((PREFIX##Base = (struct PREFIX##Base *)OpenLibrary(LIB, LIBVER))) { \
I##PREFIX = (struct PREFIX##IFace *)GetInterface((struct Library *)PREFIX##Base, INTERFACE, INTVER, NULL); \
if(I##PREFIX == NULL) { \
- LOG("Failed to get %s interface v%d of %s", INTERFACE, INTVER, LIB); \
+ NSLOG(netsurf, INFO, "Failed to get %s interface v%d of %s", INTERFACE, INTVER, LIB); \
AMINS_LIB_CLOSE(PREFIX) \
if(FAIL == true) { \
STRPTR error = ASPrintf("Unable to open interface %s v%d\nof %s v%ld (fatal error - not an OS4 lib?)", INTERFACE, INTVER, LIB, LIBVER); \
@@ -70,7 +71,7 @@
} \
} \
} else { \
- LOG("Failed to open %s v%d", LIB, LIBVER); \
+ NSLOG(netsurf, INFO, "Failed to open %s v%d", LIB, LIBVER); \
if(FAIL == true) { \
STRPTR error = ASPrintf("Unable to open %s v%ld (fatal error)", LIB, LIBVER); \
ami_misc_fatal_error(error); \
@@ -90,13 +91,13 @@
struct PREFIX##IFace *I##PREFIX = NULL;
#define AMINS_CLASS_OPEN(CLASS, CLASSVER, PREFIX, CLASSGET, NEEDINTERFACE) \
- LOG("Opening %s v%d", CLASS, CLASSVER); \
+ NSLOG(netsurf, INFO, "Opening %s v%d", CLASS, CLASSVER); \
if((PREFIX##Base = OpenClass(CLASS, CLASSVER, &PREFIX##Class))) { \
if(NEEDINTERFACE == true) { \
- LOG(" + interface"); \
+ NSLOG(netsurf, INFO, " + interface"); \
I##PREFIX = (struct PREFIX##IFace *)GetInterface((struct Library *)PREFIX##Base, "main", 1, NULL); \
if(I##PREFIX == NULL) { \
- LOG("Failed to get main interface v1 of %s", CLASS); \
+ NSLOG(netsurf, INFO, "Failed to get main interface v1 of %s", CLASS); \
} \
} \
} \
@@ -118,10 +119,10 @@
#else
#define AMINS_LIB_OPEN(LIB, LIBVER, PREFIX, INTERFACE, INTVER, FAIL) \
- LOG("Opening %s v%d", LIB, LIBVER); \
+ NSLOG(netsurf, INFO, "Opening %s v%d", LIB, LIBVER); \
if((PREFIX##Base = (struct PREFIX##Base *)OpenLibrary(LIB, LIBVER))) { \
} else { \
- LOG("Failed to open %s v%d", LIB, LIBVER); \
+ NSLOG(netsurf, INFO, "Failed to open %s v%d", LIB, LIBVER); \
if(FAIL == true) { \
STRPTR error = ASPrintf("Unable to open %s v%d (fatal error)", LIB, LIBVER); \
ami_misc_fatal_error(error); \
@@ -137,7 +138,7 @@
struct PREFIX##Base *PREFIX##Base = NULL;
#define AMINS_CLASS_OPEN(CLASS, CLASSVER, PREFIX, CLASSGET, NEEDINTERFACE) \
- LOG("Opening %s v%d", CLASS, CLASSVER); \
+ NSLOG(netsurf, INFO, "Opening %s v%d", CLASS, CLASSVER); \
if((PREFIX##Base = OpenLibrary(CLASS, CLASSVER))) { \
PREFIX##Class = CLASSGET##_GetClass(); \
} \
@@ -219,6 +220,7 @@ bool ami_libs_open(void)
AMINS_LIB_OPEN("asl.library", 37, Asl, "main", 1, true)
AMINS_LIB_OPEN("datatypes.library", 39, DataTypes, "main", 1, true)
AMINS_LIB_OPEN("diskfont.library", 40, Diskfont, "main", 1, true)
+ AMINS_LIB_OPEN("dos.library", 37, DOS, "main", 1, true)
AMINS_LIB_OPEN("gadtools.library", 37, GadTools, "main", 1, true)
AMINS_LIB_OPEN("graphics.library", 40, Graphics, "main", 1, true)
AMINS_LIB_OPEN("icon.library", 44, Icon, "main", 1, true)
@@ -254,29 +256,32 @@ bool ami_libs_open(void)
* NB: the last argument should be "true" only if the class also has
* library functions we use.
*/
- AMINS_CLASS_OPEN("arexx.class", 44, ARexx, AREXX, false)
- AMINS_CLASS_OPEN("images/bevel.image", 44, Bevel, BEVEL, false)
- AMINS_CLASS_OPEN("images/bitmap.image", 44, BitMap, BITMAP, false)
- AMINS_CLASS_OPEN("gadgets/button.gadget", 44, Button, BUTTON, false)
- AMINS_CLASS_OPEN("gadgets/checkbox.gadget", 44, CheckBox, CHECKBOX, false)
- AMINS_CLASS_OPEN("gadgets/chooser.gadget", 44, Chooser, CHOOSER, true)
- AMINS_CLASS_OPEN("gadgets/clicktab.gadget", 44, ClickTab, CLICKTAB, true)
- AMINS_CLASS_OPEN("gadgets/fuelgauge.gadget", 44, FuelGauge, FUELGAUGE, false)
- AMINS_CLASS_OPEN("gadgets/getfile.gadget", 44, GetFile, GETFILE, false)
- AMINS_CLASS_OPEN("gadgets/getfont.gadget", 44, GetFont, GETFONT, false)
- AMINS_CLASS_OPEN("gadgets/getscreenmode.gadget", 44, GetScreenMode, GETSCREENMODE, false)
- AMINS_CLASS_OPEN("gadgets/integer.gadget", 44, Integer, INTEGER, false)
- AMINS_CLASS_OPEN("images/label.image", 44, Label, LABEL, false)
- AMINS_CLASS_OPEN("gadgets/layout.gadget", 44, Layout, LAYOUT, true)
- AMINS_CLASS_OPEN("gadgets/listbrowser.gadget", 44, ListBrowser, LISTBROWSER, true)
- AMINS_CLASS_OPEN("gadgets/radiobutton.gadget", 44, RadioButton, RADIOBUTTON, false)
- AMINS_CLASS_OPEN("gadgets/scroller.gadget", 44, Scroller, SCROLLER, false)
- AMINS_CLASS_OPEN("gadgets/space.gadget", 44, Space, SPACE, false)
- AMINS_CLASS_OPEN("gadgets/speedbar.gadget", 44, SpeedBar, SPEEDBAR, true)
- AMINS_CLASS_OPEN("gadgets/string.gadget", 44, String, STRING, false)
- AMINS_CLASS_OPEN("window.class", 44, Window, WINDOW, false)
+ AMINS_CLASS_OPEN("arexx.class", 41, ARexx, AREXX, false)
+ AMINS_CLASS_OPEN("images/bevel.image", 41, Bevel, BEVEL, false)
+ AMINS_CLASS_OPEN("images/bitmap.image", 41, BitMap, BITMAP, false)
+ AMINS_CLASS_OPEN("gadgets/button.gadget", 42, Button, BUTTON, false)
+ AMINS_CLASS_OPEN("gadgets/checkbox.gadget", 41, CheckBox, CHECKBOX, false)
+ AMINS_CLASS_OPEN("gadgets/chooser.gadget", 41, Chooser, CHOOSER, true)
+ AMINS_CLASS_OPEN("gadgets/clicktab.gadget", 42, ClickTab, CLICKTAB, true)
+ AMINS_CLASS_OPEN("gadgets/fuelgauge.gadget", 41, FuelGauge, FUELGAUGE, false)
+ AMINS_CLASS_OPEN("gadgets/getfile.gadget", 41, GetFile, GETFILE, false)
+ AMINS_CLASS_OPEN("gadgets/getfont.gadget", 41, GetFont, GETFONT, false)
+ AMINS_CLASS_OPEN("gadgets/getscreenmode.gadget", 41, GetScreenMode, GETSCREENMODE, false)
+ AMINS_CLASS_OPEN("gadgets/integer.gadget", 41, Integer, INTEGER, false)
+ AMINS_CLASS_OPEN("images/label.image", 41, Label, LABEL, false)
+ AMINS_CLASS_OPEN("gadgets/layout.gadget", 43, Layout, LAYOUT, true)
+ AMINS_CLASS_OPEN("gadgets/radiobutton.gadget", 41, RadioButton, RADIOBUTTON, false)
+ AMINS_CLASS_OPEN("gadgets/scroller.gadget", 42, Scroller, SCROLLER, false)
+ AMINS_CLASS_OPEN("gadgets/space.gadget", 41, Space, SPACE, false)
+ AMINS_CLASS_OPEN("gadgets/speedbar.gadget", 41, SpeedBar, SPEEDBAR, true)
+ AMINS_CLASS_OPEN("gadgets/string.gadget", 41, String, STRING, false)
+ AMINS_CLASS_OPEN("window.class", 42, Window, WINDOW, false)
-#ifndef __amigaos4__
+#ifdef __amigaos4__
+ /* BOOPSI classes only required on OS4 */
+ AMINS_CLASS_OPEN("gadgets/listbrowser.gadget", 45, ListBrowser, LISTBROWSER, true)
+#else
+ /* BOOPSI classes only required prior to OS4 */
PageClass = PAGE_GetClass();
#endif
@@ -302,13 +307,15 @@ void ami_libs_close(void)
AMINS_CLASS_CLOSE(Integer)
AMINS_CLASS_CLOSE(Label)
AMINS_CLASS_CLOSE(Layout)
- AMINS_CLASS_CLOSE(ListBrowser)
AMINS_CLASS_CLOSE(RadioButton)
AMINS_CLASS_CLOSE(Scroller)
AMINS_CLASS_CLOSE(Space)
AMINS_CLASS_CLOSE(SpeedBar)
AMINS_CLASS_CLOSE(String)
AMINS_CLASS_CLOSE(Window)
+#ifdef __amigaos4__
+ AMINS_CLASS_CLOSE(ListBrowser)
+#endif
/* Libraries */
AMINS_LIB_CLOSE(GuiGFX)
@@ -316,6 +323,7 @@ void ami_libs_close(void)
AMINS_LIB_CLOSE(Asl)
AMINS_LIB_CLOSE(DataTypes)
AMINS_LIB_CLOSE(Diskfont)
+ AMINS_LIB_CLOSE(DOS)
AMINS_LIB_CLOSE(GadTools)
AMINS_LIB_CLOSE(Graphics)
AMINS_LIB_CLOSE(Icon)
diff --git a/frontends/amiga/memory.c b/frontends/amiga/memory.c
index d371d2585..35ca9697f 100755
--- a/frontends/amiga/memory.c
+++ b/frontends/amiga/memory.c
@@ -50,23 +50,38 @@ void *ami_memory_clear_alloc(size_t size, UBYTE value)
static int ami_memory_slab_usage_cb(const struct __slab_usage_information * sui)
{
if(sui->sui_slab_index <= 1) {
- LOG("clib2 slab usage:");
- LOG(" The size of all slabs, in bytes: %ld", sui->sui_slab_size);
- LOG(" Number of allocations which are not managed by slabs: %ld",
- sui->sui_num_single_allocations);
- LOG(" Total number of bytes allocated for memory not managed by slabs: %ld",
- sui->sui_total_single_allocation_size);
- LOG(" Number of slabs currently in play: %ld", sui->sui_num_slabs);
- LOG(" Number of currently unused slabs: %ld", sui->sui_num_empty_slabs);
- LOG(" Number of slabs in use which are completely filled with data: %ld",
- sui->sui_num_full_slabs);
- LOG(" Total number of bytes allocated for all slabs: %ld",
- sui->sui_total_slab_allocation_size);
+ NSLOG(netsurf, INFO, "clib2 slab usage:");
+ NSLOG(netsurf, INFO,
+ " The size of all slabs, in bytes: %ld",
+ sui->sui_slab_size);
+ NSLOG(netsurf, INFO,
+ " Number of allocations which are not managed by slabs: %ld",
+ sui->sui_num_single_allocations);
+ NSLOG(netsurf, INFO,
+ " Total number of bytes allocated for memory not managed by slabs: %ld",
+ sui->sui_total_single_allocation_size);
+ NSLOG(netsurf, INFO,
+ " Number of slabs currently in play: %ld",
+ sui->sui_num_slabs);
+ NSLOG(netsurf, INFO,
+ " Number of currently unused slabs: %ld",
+ sui->sui_num_empty_slabs);
+ NSLOG(netsurf, INFO,
+ " Number of slabs in use which are completely filled with data: %ld",
+ sui->sui_num_full_slabs);
+ NSLOG(netsurf, INFO,
+ " Total number of bytes allocated for all slabs: %ld",
+ sui->sui_total_slab_allocation_size);
}
- LOG("Slab %d", sui->sui_slab_index);
- LOG(" Memory chunk size managed by this slab: %ld", sui->sui_chunk_size);
- LOG(" Number of memory chunks that fit in this slab: %ld", sui->sui_num_chunks);
- LOG(" Number of memory chunks used in this slab: %ld", sui->sui_num_chunks_used);
+ NSLOG(netsurf, INFO, "Slab %d", sui->sui_slab_index);
+ NSLOG(netsurf, INFO, " Memory chunk size managed by this slab: %ld",
+ sui->sui_chunk_size);
+ NSLOG(netsurf, INFO,
+ " Number of memory chunks that fit in this slab: %ld",
+ sui->sui_num_chunks);
+ NSLOG(netsurf, INFO,
+ " Number of memory chunks used in this slab: %ld",
+ sui->sui_num_chunks_used);
return 0;
}
@@ -74,16 +89,20 @@ static int ami_memory_slab_usage_cb(const struct __slab_usage_information * sui)
static int ami_memory_slab_alloc_cb(const struct __slab_allocation_information *sai)
{
if(sai->sai_allocation_index <= 1) {
- LOG("clib2 allocation usage:");
- LOG(" Number of allocations which are not managed by slabs: %ld",
- sai->sai_num_single_allocations);
- LOG(" Total number of bytes allocated for memory not managed by slabs: %ld",
- sai->sai_total_single_allocation_size);
+ NSLOG(netsurf, INFO, "clib2 allocation usage:");
+ NSLOG(netsurf, INFO,
+ " Number of allocations which are not managed by slabs: %ld",
+ sai->sai_num_single_allocations);
+ NSLOG(netsurf, INFO,
+ " Total number of bytes allocated for memory not managed by slabs: %ld",
+ sai->sai_total_single_allocation_size);
}
- LOG("Alloc %d", sai->sai_allocation_index);
- LOG(" Size of this allocation, as requested: %ld", sai->sai_allocation_size);
- LOG(" Total size of this allocation, including management data: %ld",
- sai->sai_total_allocation_size);
+ NSLOG(netsurf, INFO, "Alloc %d", sai->sai_allocation_index);
+ NSLOG(netsurf, INFO, " Size of this allocation, as requested: %ld",
+ sai->sai_allocation_size);
+ NSLOG(netsurf, INFO,
+ " Total size of this allocation, including management data: %ld",
+ sai->sai_total_allocation_size);
return 0;
}
@@ -111,13 +130,13 @@ void ami_memory_slab_dump(BPTR fh)
static void ami_memory_low_mem_handler(void *p)
{
if(low_mem_status == PURGE_STEP1) {
- LOG("Purging llcache");
+ NSLOG(netsurf, INFO, "Purging llcache");
llcache_clean(true);
low_mem_status = PURGE_DONE_STEP1;
}
if(low_mem_status == PURGE_STEP2) {
- LOG("Purging unused slabs");
+ NSLOG(netsurf, INFO, "Purging unused slabs");
__free_unused_slabs();
low_mem_status = PURGE_DONE_STEP2;
}
diff --git a/frontends/amiga/menu.c b/frontends/amiga/menu.c
index 249ca0755..1f3f981ea 100644
--- a/frontends/amiga/menu.c
+++ b/frontends/amiga/menu.c
@@ -263,7 +263,9 @@ static int ami_menu_layout_mc_recursive(Object *menu_parent, struct ami_menu_dat
TAG_DONE);
}
- //LOG("Adding item %p ID %d (%s) to parent %p", menu_item, j, md[j]->menulab, menu_parent);
+ NSLOG(netsurf, DEEPDEBUG,
+ "Adding item %p ID %d (%s) to parent %p",
+ menu_item, j, md[j]->menulab, menu_parent);
IDoMethod(menu_parent, OM_ADDMEMBER, menu_item);
continue;
} else if (md[j]->menutype > level) {
@@ -389,7 +391,7 @@ static struct Menu *ami_menu_layout_gt(struct ami_menu_data **md, int max)
else
nm[i].nm_Label = md[i]->menulab;
- if((md[i]->menukey) && (strlen(md[i]->menukey) > 1)) {
+ if((md[i]->menukey) && (strlen(md[i]->menukey) == 1)) {
nm[i].nm_CommKey = md[i]->menukey;
}
nm[i].nm_Flags = md[i]->flags;
diff --git a/frontends/amiga/misc.c b/frontends/amiga/misc.c
index 5ca4f906a..532d2f182 100755
--- a/frontends/amiga/misc.c
+++ b/frontends/amiga/misc.c
@@ -46,7 +46,7 @@ static LONG ami_misc_req(const char *message, uint32 type)
{
LONG ret = 0;
- LOG("%s", message);
+ NSLOG(netsurf, INFO, "%s", message);
#ifdef __amigaos4__
ret = TimedDosRequesterTags(
TDR_TitleString, messages_get("NetSurf"),
diff --git a/frontends/amiga/options.h b/frontends/amiga/options.h
index b5b2b3b07..a23435ca6 100644
--- a/frontends/amiga/options.h
+++ b/frontends/amiga/options.h
@@ -49,6 +49,7 @@ NSOPTION_STRING(arexx_startup, "Startup.nsrx")
NSOPTION_STRING(arexx_shutdown, "Shutdown.nsrx")
NSOPTION_STRING(download_dir, NULL)
NSOPTION_BOOL(download_notify, true)
+NSOPTION_BOOL(download_notify_progress, false)
NSOPTION_BOOL(faster_scroll, true)
NSOPTION_BOOL(scale_quality, false)
NSOPTION_INTEGER(dither_quality, 0)
@@ -79,7 +80,6 @@ NSOPTION_INTEGER(cookies_window_ypos, 0)
NSOPTION_INTEGER(cookies_window_xsize, 0)
NSOPTION_INTEGER(cookies_window_ysize, 0)
NSOPTION_INTEGER(web_search_width, 0)
-NSOPTION_BOOL(direct_render, false)
NSOPTION_BOOL(window_simple_refresh, false)
NSOPTION_BOOL(resize_with_contents, false)
NSOPTION_INTEGER(reformat_delay, 0)
diff --git a/frontends/amiga/os3support.c b/frontends/amiga/os3support.c
index c08260209..645496b73 100644
--- a/frontends/amiga/os3support.c
+++ b/frontends/amiga/os3support.c
@@ -216,13 +216,13 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
fh = Open(fontpath, MODE_OLDFILE);
if(fh == 0) {
- LOG("Unable to open FONT %s", fontpath);
+ NSLOG(netsurf, INFO, "Unable to open FONT %s", fontpath);
FreeVec(fontpath);
return NULL;
}
if(Read(fh, &fch, sizeof(struct FontContentsHeader)) != sizeof(struct FontContentsHeader)) {
- LOG("Unable to read FONT %s", fontpath);
+ NSLOG(netsurf, INFO, "Unable to read FONT %s", fontpath);
FreeVec(fontpath);
Close(fh);
return NULL;
@@ -231,7 +231,7 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
Close(fh);
if(fch.fch_FileID != OFCH_ID) {
- LOG("%s is not an outline font!", fontpath);
+ NSLOG(netsurf, INFO, "%s is not an outline font!", fontpath);
FreeVec(fontpath);
return NULL;
}
@@ -242,7 +242,7 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
if(p) *p = '.';
if(fh == 0) {
- LOG("Unable to open OTAG %s", otagpath);
+ NSLOG(netsurf, INFO, "Unable to open OTAG %s", otagpath);
FreeVec(otagpath);
return NULL;
}
@@ -250,7 +250,7 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
size = GetFileSize(fh);
buffer = (UBYTE *)malloc(size);
if(buffer == NULL) {
- LOG("Unable to allocate memory");
+ NSLOG(netsurf, INFO, "Unable to allocate memory");
Close(fh);
FreeVec(otagpath);
return NULL;
@@ -262,7 +262,7 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
/* The first tag is supposed to be OT_FileIdent and should equal 'size' */
struct TagItem *tag = (struct TagItem *)buffer;
if((tag->ti_Tag != OT_FileIdent) || (tag->ti_Data != (ULONG)size)) {
- LOG("Invalid OTAG file");
+ NSLOG(netsurf, INFO, "Invalid OTAG file");
free(buffer);
FreeVec(otagpath);
return NULL;
@@ -277,10 +277,10 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
/* Find OT_Engine and open the font engine */
if(ti = FindTagItem(OT_Engine, buffer)) {
- LOG("Using font engine %s", ti->ti_Data);
+ NSLOG(netsurf, INFO, "Using font engine %s", ti->ti_Data);
fname = ASPrintf("%s.library", ti->ti_Data);
} else {
- LOG("Cannot find OT_Engine tag");
+ NSLOG(netsurf, INFO, "Cannot find OT_Engine tag");
free(buffer);
FreeVec(otagpath);
return NULL;
@@ -289,7 +289,7 @@ struct OutlineFont *OpenOutlineFont(STRPTR fileName, struct List *list, ULONG fl
BulletBase = (struct BulletBase *)OpenLibrary(fname, 0L);
if(BulletBase == NULL) {
- LOG("Unable to open font engine %s", fname);
+ NSLOG(netsurf, INFO, "Unable to open font engine %s", fname);
free(buffer);
FreeVec(fname);
FreeVec(otagpath);
@@ -332,13 +332,13 @@ void CloseOutlineFont(struct OutlineFont *of, struct List *list)
int64 GetFileSize(BPTR fh)
{
int32 size = 0;
- struct FileInfoBlock *fib = malloc(sizeof(struct FileInfoBlock));
+ struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
if(fib == NULL) return 0;
ExamineFH(fh, fib);
size = fib->fib_Size;
- free(fib);
+ FreeDosObject(DOS_FIB, fib);
return (int64)size;
}
@@ -405,9 +405,10 @@ ULONG RefreshSetGadgetAttrsA(struct Gadget *g, struct Window *w, struct Requeste
ULONG retval;
BOOL changedisabled = FALSE;
BOOL disabled;
+ struct TagItem *ti;
if (w) {
- if (FindTagItem(GA_Disabled,tags)) {
+ if ((ti = FindTagItem(GA_Disabled,tags)) && (ti->ti_Data != FALSE)) {
changedisabled = TRUE;
disabled = g->Flags & GFLG_DISABLED;
}
diff --git a/frontends/amiga/os3support.h b/frontends/amiga/os3support.h
index 856439bd8..aa3027d36 100644
--- a/frontends/amiga/os3support.h
+++ b/frontends/amiga/os3support.h
@@ -116,6 +116,7 @@
#define BGBACKFILL JAM1
#define OFF_OPEN 0
#define AFF_OTAG 0
+#define ML_SEPARATOR NM_BARLABEL
/* Renamed structures */
#define AnchorPathOld AnchorPath
diff --git a/frontends/amiga/pkg/makereslinks b/frontends/amiga/pkg/makereslinks
index 4302dbd23..a9f7dfb94 100755
--- a/frontends/amiga/pkg/makereslinks
+++ b/frontends/amiga/pkg/makereslinks
@@ -3,26 +3,26 @@
failat 50
makedir Resources
cd Resources
-makelink AdBlock.css /!NetSurf/Resources/AdBlock,f79 soft
+makelink AdBlock.css /resources/adblock.css soft
makelink default.css /amiga/resources/default.css soft
-makelink ca-bundle /!NetSurf/Resources/ca-bundle soft
-makelink de /!NetSurf/Resources/de soft
-makelink nsdefault.css /!NetSurf/Resources/CSS,f79 soft
+makelink ca-bundle /resources/ca-bundle soft
+makelink de /resources/de soft
+makelink nsdefault.css /resources/default.css soft
makelink favicon.png /amiga/resources/favicon.png soft
makelink Resource.map /amiga/resources/Resource.map soft
-makelink en /!NetSurf/Resources/en soft
-makelink fr /!NetSurf/Resources/fr soft
-makelink internal.css /!NetSurf/Resources/internal.css,f79 soft
-makelink it /!NetSurf/Resources/it soft
+makelink en /resources/en soft
+makelink fr /resources/fr soft
+makelink internal.css /resources/internal.css soft
+makelink it /resources/it soft
makelink LangNames /amiga/resources/LangNames soft
-makelink netsurf.png /!NetSurf/Resources/netsurf.png,b60 soft
-makelink nl /!NetSurf/Resources/nl soft
+makelink netsurf.png /resources/netsurf.png soft
+makelink nl /resources/nl soft
makelink Pointers /amiga/resources/Pointers soft
-makelink quirks.css /!NetSurf/Resources/Quirks,f79 soft
+makelink quirks.css /resources/quirks.css soft
makelink SearchEngines /amiga/resources/SearchEngines soft
makelink splash.png /amiga/resources/splash.png soft
makelink Themes /amiga/resources/Themes soft
makelink mimetypes /amiga/resources/mimetypes soft
/
-makelink amiga/resources/nsdefault.css //!NetSurf/Resources/CSS,f79 soft
+makelink amiga/resources/nsdefault.css //resources/default.css soft
diff --git a/frontends/amiga/plotters.c b/frontends/amiga/plotters.c
index 6bae6346a..4623afad2 100644
--- a/frontends/amiga/plotters.c
+++ b/frontends/amiga/plotters.c
@@ -20,6 +20,8 @@
#include <proto/exec.h>
#include <proto/intuition.h>
+#include <proto/layers.h>
+#include <proto/graphics.h>
#include <intuition/intuition.h>
#include <graphics/rpattr.h>
@@ -51,8 +53,6 @@
#include "amiga/rtg.h"
#include "amiga/utf8.h"
-//#define AMI_PLOTTER_DEBUG 1
-
HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *);
struct bfbitmap {
@@ -62,6 +62,7 @@ struct bfbitmap {
int offsetx;
int offsety;
APTR mask;
+ bool palette_mapped;
};
struct ami_plot_pen {
@@ -74,10 +75,27 @@ struct bez_point {
float y;
};
-struct gui_globals *glob;
+struct gui_globals {
+ struct BitMap *bm;
+ struct RastPort *rp;
+ struct Layer_Info *layerinfo;
+ APTR areabuf;
+ APTR tmprasbuf;
+ struct Rectangle rect;
+ struct MinList *shared_pens;
+ bool managed_pen_list;
+ bool palette_mapped;
+ ULONG apen;
+ ULONG open;
+ LONG apen_num;
+ LONG open_num;
+ int width; /* size of bm and */
+ int height; /* associated memory */
+};
static int init_layers_count = 0;
static APTR pool_pens = NULL;
+static bool palette_mapped = true; /* palette-mapped state for the screen */
#ifndef M_PI /* For some reason we don't always get this from math.h */
#define M_PI 3.14159265358979323846
@@ -92,26 +110,24 @@ static APTR pool_pens = NULL;
*/
#define AREA_SIZE 25000
-/* Define the below to get additional debug */
-#undef AMI_PLOTTER_DEBUG
-
-void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool force32bit)
+struct gui_globals *ami_plot_ra_alloc(ULONG width, ULONG height, bool force32bit, bool alloc_pen_list)
{
- /* init shared bitmaps *
- * Height is set to screen width to give enough space for thumbnails *
- * Also applies to the further gfx/layers functions and memory below */
-
- int depth = 32;
+ /* init shared bitmaps */
+ int depth = 32;
struct BitMap *friend = NULL;
+ struct gui_globals *gg = malloc(sizeof(struct gui_globals));
+
if(force32bit == false) depth = GetBitMapAttr(scrn->RastPort.BitMap, BMA_DEPTH);
- LOG("Screen depth = %d", depth);
+ NSLOG(netsurf, INFO, "Screen depth = %d", depth);
#ifdef __amigaos4__
if(depth < 16) {
gg->palette_mapped = true;
+ if(force32bit == false) palette_mapped = true;
} else {
gg->palette_mapped = false;
+ if(force32bit == false) palette_mapped = false;
}
#else
/* Friend BitMaps are weird.
@@ -135,6 +151,7 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for
*/
#warning OS3 locked to palette-mapped modes
gg->palette_mapped = true;
+ palette_mapped = true;
if(depth > 8) depth = 8;
#endif
@@ -192,8 +209,18 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for
InitTmpRas(gg->rp->TmpRas, gg->tmprasbuf, width*height);
- if((gg->palette_mapped == true) && (pool_pens == NULL)) {
- pool_pens = ami_memory_itempool_create(sizeof(struct ami_plot_pen));
+ gg->shared_pens = NULL;
+ gg->managed_pen_list = false;
+
+ if(gg->palette_mapped == true) {
+ if(pool_pens == NULL) {
+ pool_pens = ami_memory_itempool_create(sizeof(struct ami_plot_pen));
+ }
+
+ if(alloc_pen_list == true) {
+ gg->shared_pens = ami_AllocMinList();
+ gg->managed_pen_list = true;
+ }
}
gg->apen = 0x00000000;
@@ -202,20 +229,25 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for
gg->open_num = -1;
init_layers_count++;
- LOG("Layer initialised (total: %d)", init_layers_count);
+ NSLOG(netsurf, INFO, "Layer initialised (total: %d)",
+ init_layers_count);
+
+ return gg;
}
-void ami_free_layers(struct gui_globals *gg)
+void ami_plot_ra_free(struct gui_globals *gg)
{
init_layers_count--;
+ if(init_layers_count < 0) return;
+
if((init_layers_count == 0) && (pool_pens != NULL)) {
ami_memory_itempool_delete(pool_pens);
pool_pens = NULL;
}
if(gg->rp) {
- DeleteLayer(0,gg->rp->Layer);
+ if(gg->rp->Layer != NULL) DeleteLayer(0, gg->rp->Layer);
free(gg->rp->TmpRas);
free(gg->rp->AreaInfo);
free(gg->rp);
@@ -229,6 +261,35 @@ void ami_free_layers(struct gui_globals *gg)
} else {
if(gg->bm) FreeBitMap(gg->bm);
}
+
+ if(gg->managed_pen_list == true) {
+ ami_plot_release_pens(gg->shared_pens);
+ free(gg->shared_pens);
+ gg->shared_pens = NULL;
+ }
+
+ free(gg);
+}
+
+struct RastPort *ami_plot_ra_get_rastport(struct gui_globals *gg)
+{
+ return gg->rp;
+}
+
+struct BitMap *ami_plot_ra_get_bitmap(struct gui_globals *gg)
+{
+ return gg->bm;
+}
+
+void ami_plot_ra_get_size(struct gui_globals *gg, int *width, int *height)
+{
+ *width = gg->width;
+ *height = gg->height;
+}
+
+void ami_plot_ra_set_pen_list(struct gui_globals *gg, struct MinList *pen_list)
+{
+ gg->shared_pens = pen_list;
}
void ami_clearclipreg(struct gui_globals *gg)
@@ -242,6 +303,11 @@ void ami_clearclipreg(struct gui_globals *gg)
gg->rect.MinY = 0;
gg->rect.MaxX = scrn->Width-1;
gg->rect.MaxY = scrn->Height-1;
+
+ gg->apen = 0x00000000;
+ gg->open = 0x00000000;
+ gg->apen_num = -1;
+ gg->open_num = -1;
}
static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colr)
@@ -253,7 +319,8 @@ static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colr)
(colr & 0x00ff0000) << 8,
NULL);
- if(pen == -1) LOG("WARNING: Cannot allocate pen for ABGR:%lx", colr);
+ if(pen == -1) NSLOG(netsurf, INFO,
+ "WARNING: Cannot allocate pen for ABGR:%lx", colr);
if((shared_pens != NULL) && (pool_pens != NULL)) {
if((node = (struct ami_plot_pen *)ami_memory_itempool_alloc(pool_pens, sizeof(struct ami_plot_pen)))) {
@@ -282,14 +349,9 @@ void ami_plot_release_pens(struct MinList *shared_pens)
Remove((struct Node *)node);
ami_memory_itempool_free(pool_pens, node, sizeof(struct ami_plot_pen));
} while((node = nnode));
-
- glob->apen = 0x00000000;
- glob->open = 0x00000000;
- glob->apen_num = -1;
- glob->open_num = -1;
}
-static void ami_plot_setapen(struct RastPort *rp, ULONG colr)
+static void ami_plot_setapen(struct gui_globals *glob, struct RastPort *rp, ULONG colr)
{
if(glob->apen == colr) return;
@@ -308,7 +370,7 @@ static void ami_plot_setapen(struct RastPort *rp, ULONG colr)
glob->apen = colr;
}
-static void ami_plot_setopen(struct RastPort *rp, ULONG colr)
+static void ami_plot_setopen(struct gui_globals *glob, struct RastPort *rp, ULONG colr)
{
if(glob->open == colr) return;
@@ -336,172 +398,7 @@ void ami_plot_clear_bbox(struct RastPort *rp, struct IBox *bbox)
}
-static bool ami_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_rectangle()");
- #endif
-
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- ami_plot_setapen(glob->rp, style->fill_colour);
- RectFill(glob->rp, x0, y0, x1-1, y1-1);
- }
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- glob->rp->PenWidth = style->stroke_width;
- glob->rp->PenHeight = style->stroke_width;
-
- switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
- default:
- glob->rp->LinePtrn = PATT_LINE;
- break;
-
- case PLOT_OP_TYPE_DOT: /**< Dotted plot */
- glob->rp->LinePtrn = PATT_DOT;
- break;
-
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
- glob->rp->LinePtrn = PATT_DASH;
- break;
- }
-
- ami_plot_setapen(glob->rp, style->stroke_colour);
- Move(glob->rp, x0,y0);
- Draw(glob->rp, x1, y0);
- Draw(glob->rp, x1, y1);
- Draw(glob->rp, x0, y1);
- Draw(glob->rp, x0, y0);
-
- glob->rp->PenWidth = 1;
- glob->rp->PenHeight = 1;
- glob->rp->LinePtrn = PATT_LINE;
- }
-
- return true;
-}
-
-static bool ami_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_line()");
- #endif
-
- glob->rp->PenWidth = style->stroke_width;
- glob->rp->PenHeight = style->stroke_width;
-
- switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
- default:
- glob->rp->LinePtrn = PATT_LINE;
- break;
-
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
- glob->rp->LinePtrn = PATT_DOT;
- break;
-
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
- glob->rp->LinePtrn = PATT_DASH;
- break;
- }
-
- ami_plot_setapen(glob->rp, style->stroke_colour);
- Move(glob->rp,x0,y0);
- Draw(glob->rp,x1,y1);
-
- glob->rp->PenWidth = 1;
- glob->rp->PenHeight = 1;
- glob->rp->LinePtrn = PATT_LINE;
-
- return true;
-}
-
-static bool ami_polygon(const int *p, unsigned int n, const plot_style_t *style)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_polygon()");
- #endif
-
- ami_plot_setapen(glob->rp, style->fill_colour);
-
- if(AreaMove(glob->rp,p[0],p[1]) == -1)
- LOG("AreaMove: vector list full");
-
- for(uint32 k = 1; k < n; k++) {
- if(AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1)
- LOG("AreaDraw: vector list full");
- }
-
- if(AreaEnd(glob->rp) == -1)
- LOG("AreaEnd: error");
-
- return true;
-}
-
-
-static bool ami_clip(const struct rect *clip)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_clip()");
- #endif
-
- struct Region *reg = NULL;
-
- if(glob->rp->Layer)
- {
- reg = NewRegion();
-
- glob->rect.MinX = clip->x0;
- glob->rect.MinY = clip->y0;
- glob->rect.MaxX = clip->x1-1;
- glob->rect.MaxY = clip->y1-1;
-
- OrRectRegion(reg,&glob->rect);
-
- reg = InstallClipRegion(glob->rp->Layer,reg);
-
- if(reg) DisposeRegion(reg);
- }
-
- return true;
-}
-
-static bool ami_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_text()");
- #endif
-
- if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
-
- ami_plot_setapen(glob->rp, fstyle->foreground);
- ami_nsfont->text(glob->rp, text, length, fstyle, x, y, nsoption_bool(font_antialiasing));
-
- return true;
-}
-
-static bool ami_disc(int x, int y, int radius, const plot_style_t *style)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_disc()");
- #endif
-
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- ami_plot_setapen(glob->rp, style->fill_colour);
- AreaCircle(glob->rp,x,y,radius);
- AreaEnd(glob->rp);
- }
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- ami_plot_setapen(glob->rp, style->stroke_colour);
- DrawEllipse(glob->rp,x,y,radius,radius);
- }
-
- return true;
-}
-
-static void ami_arc_gfxlib(int x, int y, int radius, int angle1, int angle2)
+static void ami_arc_gfxlib(struct RastPort *rp, int x, int y, int radius, int angle1, int angle2)
{
double angle1_r = (double)(angle1) * (M_PI / 180.0);
double angle2_r = (double)(angle2) * (M_PI / 180.0);
@@ -517,55 +414,45 @@ static void ami_arc_gfxlib(int x, int y, int radius, int angle1, int angle2)
x1 = (int)(cos(b) * (double)radius);
y1 = (int)(sin(b) * (double)radius);
- Move(glob->rp, x0 + x1, y0 - y1);
+ Move(rp, x0 + x1, y0 - y1);
for(angle = (b + step); angle <= c; angle += step) {
x1 = (int)(cos(angle) * (double)radius);
y1 = (int)(sin(angle) * (double)radius);
- Draw(glob->rp, x0 + x1, y0 - y1);
+ Draw(rp, x0 + x1, y0 - y1);
}
}
-static bool ami_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_arc()");
- #endif
-
- if (angle2 < angle1) angle2 += 360;
-
- ami_plot_setapen(glob->rp, style->fill_colour);
- ami_arc_gfxlib(x, y, radius, angle1, angle2);
-
- return true;
-}
-
-static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitmap)
+/**
+ */
+static nserror
+ami_bitmap(struct gui_globals *glob, int x, int y, int width, int height, struct bitmap *bitmap)
{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_bitmap()");
- #endif
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_bitmap()");
struct BitMap *tbm;
- if(!width || !height) return true;
+ if (!width || !height) {
+ return NSERROR_OK;
+ }
- if(((x + width) < glob->rect.MinX) ||
- ((y + height) < glob->rect.MinY) ||
- (x > glob->rect.MaxX) ||
- (y > glob->rect.MaxY))
- return true;
+ if (((x + width) < glob->rect.MinX) ||
+ ((y + height) < glob->rect.MinY) ||
+ (x > glob->rect.MaxX) ||
+ (y > glob->rect.MaxY)) {
+ return NSERROR_OK;
+ }
- tbm = ami_bitmap_get_native(bitmap, width, height, glob->rp->BitMap);
- if(!tbm) return true;
+ tbm = ami_bitmap_get_native(bitmap, width, height, glob->palette_mapped, glob->rp->BitMap);
+ if (!tbm) {
+ return NSERROR_OK;
+ }
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] ami_bitmap() got native bitmap");
- #endif
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] ami_bitmap() got native bitmap");
#ifdef __amigaos4__
- if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) && (glob->palette_mapped == false) &&
- (nsoption_bool(direct_render) == false), 1)) {
+ if (__builtin_expect((GfxBase->LibNode.lib_Version >= 53) &&
+ (glob->palette_mapped == false), 1)) {
uint32 comptype = COMPOSITE_Src_Over_Dest;
uint32 compflags = COMPFLAG_IgnoreDestAlpha;
if(amiga_bitmap_get_opaque(bitmap)) {
@@ -585,19 +472,18 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma
COMPTAG_OffsetY,y,
COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
TAG_DONE);
- }
- else
+ } else
#endif
{
ULONG tag, tag_data, minterm = 0xc0;
- if(glob->palette_mapped == false) {
+ if (glob->palette_mapped == false) {
tag = BLITA_UseSrcAlpha;
tag_data = !amiga_bitmap_get_opaque(bitmap);
minterm = 0xc0;
} else {
tag = BLITA_MaskPlane;
- if((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm)))
+ if ((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm)))
minterm = MINTERM_SRCMASK;
}
#ifdef __amigaos4__
@@ -613,7 +499,7 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma
tag, tag_data,
TAG_DONE);
#else
- if(tag_data) {
+ if (tag_data) {
BltMaskBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, minterm, tag_data);
} else {
BltBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, 0xc0);
@@ -621,118 +507,13 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma
#endif
}
- if((ami_bitmap_is_nativebm(bitmap, tbm) == false)) {
+ if ((ami_bitmap_is_nativebm(bitmap, tbm) == false)) {
ami_rtg_freebitmap(tbm);
}
- return true;
+ return NSERROR_OK;
}
-static bool ami_bitmap_tile(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
-{
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_bitmap_tile()");
- #endif
-
- int xf,yf,xm,ym,oy,ox;
- struct BitMap *tbm = NULL;
- struct Hook *bfh = NULL;
- struct bfbitmap bfbm;
- bool repeat_x = (flags & BITMAPF_REPEAT_X);
- bool repeat_y = (flags & BITMAPF_REPEAT_Y);
-
- if((width == 0) || (height == 0)) return true;
-
- if(!(repeat_x || repeat_y))
- return ami_bitmap(x, y, width, height, bitmap);
-
- /* If it is a one pixel transparent image, we are wasting our time */
- if((amiga_bitmap_get_opaque(bitmap) == false) &&
- (bitmap_get_width(bitmap) == 1) && (bitmap_get_height(bitmap) == 1))
- return true;
-
- tbm = ami_bitmap_get_native(bitmap,width,height,glob->rp->BitMap);
- if(!tbm) return true;
-
- ox = x;
- oy = y;
-
- /* get left most tile position */
- for (; ox > 0; ox -= width)
- ;
-
- /* get top most tile position */
- for (; oy > 0; oy -= height)
- ;
-
- if(ox<0) ox = -ox;
- if(oy<0) oy = -oy;
-
- if(repeat_x)
- {
- xf = glob->rect.MaxX;
- xm = glob->rect.MinX;
- }
- else
- {
- xf = x + width;
- xm = x;
- }
-
- if(repeat_y)
- {
- yf = glob->rect.MaxY;
- ym = glob->rect.MinY;
- }
- else
- {
- yf = y + height;
- ym = y;
- }
-#ifdef __amigaos4__
- if(amiga_bitmap_get_opaque(bitmap))
- {
- bfh = CreateBackFillHook(BFHA_BitMap,tbm,
- BFHA_Width,width,
- BFHA_Height,height,
- BFHA_OffsetX,ox,
- BFHA_OffsetY,oy,
- TAG_DONE);
- }
- else
-#endif
- {
- bfbm.bm = tbm;
- bfbm.width = width;
- bfbm.height = height;
- bfbm.offsetx = ox;
- bfbm.offsety = oy;
- bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm);
- bfh = calloc(1, sizeof(struct Hook));
- bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook;
- bfh->h_SubEntry = 0;
- bfh->h_Data = &bfbm;
- }
-
- InstallLayerHook(glob->rp->Layer,bfh);
- EraseRect(glob->rp,xm,ym,xf,yf);
- InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL);
-
-#ifdef __amigaos4__
- if(amiga_bitmap_get_opaque(bitmap)) DeleteBackFillHook(bfh);
- else
-#endif
- free(bfh);
-
- if((ami_bitmap_is_nativebm(bitmap, tbm) == false)) {
- /**\todo is this logic logical? */
- ami_rtg_freebitmap(tbm);
- }
-
- return true;
-}
HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *)
{
@@ -744,7 +525,7 @@ HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage
for (yf = -bfbm->offsety; yf < msg->Bounds.MaxY; yf += bfbm->height) {
#ifdef __amigaos4__
if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) &&
- (glob->palette_mapped == false), 1)) {
+ (bfbm->palette_mapped == false), 1)) {
CompositeTags(COMPOSITE_Src_Over_Dest, bfbm->bm, rp->BitMap,
COMPTAG_Flags, COMPFLAG_IgnoreDestAlpha,
COMPTAG_DestX, msg->Bounds.MinX,
@@ -757,13 +538,12 @@ HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage
COMPTAG_OffsetY, yf,
COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
TAG_DONE);
- }
- else
+ } else
#endif
{
ULONG tag, tag_data, minterm = 0xc0;
- if(glob->palette_mapped == false) {
+ if(bfbm->palette_mapped == false) {
tag = BLITA_UseSrcAlpha;
tag_data = TRUE;
minterm = 0xc0;
@@ -805,42 +585,336 @@ static void ami_bezier(struct bez_point *restrict a, struct bez_point *restrict
p->y = pow((1 - t), 3) * a->y + 3 * t * pow((1 -t), 2) * b->y + 3 * (1-t) * pow(t, 2)* c->y + pow (t, 3)* d->y;
}
-static bool ami_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
+
+bool ami_plot_screen_is_palettemapped(void)
+{
+ /* This may not be entirely correct - previously we returned the state of the current BitMap */
+ return palette_mapped;
+}
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+ struct Region *reg = NULL;
+
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_clip()");
+
+ if (glob->rp->Layer) {
+ reg = NewRegion();
+
+ glob->rect.MinX = clip->x0;
+ glob->rect.MinY = clip->y0;
+ glob->rect.MaxX = clip->x1-1;
+ glob->rect.MaxY = clip->y1-1;
+
+ OrRectRegion(reg,&glob->rect);
+
+ reg = InstallClipRegion(glob->rp->Layer,reg);
+
+ if(reg) {
+ DisposeRegion(reg);
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
+{
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_arc()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if (angle2 < angle1) {
+ angle2 += 360;
+ }
+
+ ami_plot_setapen(glob, glob->rp, style->fill_colour);
+ ami_arc_gfxlib(glob->rp, x, y, radius, angle1, angle2);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_disc()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ ami_plot_setapen(glob, glob->rp, style->fill_colour);
+ AreaCircle(glob->rp,x,y,radius);
+ AreaEnd(glob->rp);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ ami_plot_setapen(glob, glob->rp, style->stroke_colour);
+ DrawEllipse(glob->rp,x,y,radius,radius);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
+{
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_line()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ glob->rp->PenWidth = plot_style_fixed_to_int(style->stroke_width);
+ glob->rp->PenHeight = plot_style_fixed_to_int(style->stroke_width);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ glob->rp->LinePtrn = PATT_LINE;
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ glob->rp->LinePtrn = PATT_DOT;
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ glob->rp->LinePtrn = PATT_DASH;
+ break;
+ }
+
+ ami_plot_setapen(glob, glob->rp, style->stroke_colour);
+ Move(glob->rp, line->x0, line->y0);
+ Draw(glob->rp, line->x1, line->y1);
+
+ glob->rp->PenWidth = 1;
+ glob->rp->PenHeight = 1;
+ glob->rp->LinePtrn = PATT_LINE;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
+{
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_rectangle()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ ami_plot_setapen(glob, glob->rp, style->fill_colour);
+ RectFill(glob->rp, rect->x0, rect->y0, rect->x1- 1 , rect->y1 - 1);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ glob->rp->PenWidth = plot_style_fixed_to_int(style->stroke_width);
+ glob->rp->PenHeight = plot_style_fixed_to_int(style->stroke_width);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ glob->rp->LinePtrn = PATT_LINE;
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Dotted plot */
+ glob->rp->LinePtrn = PATT_DOT;
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ glob->rp->LinePtrn = PATT_DASH;
+ break;
+ }
+
+ ami_plot_setapen(glob, glob->rp, style->stroke_colour);
+ Move(glob->rp, rect->x0, rect->y0);
+ Draw(glob->rp, rect->x1, rect->y0);
+ Draw(glob->rp, rect->x1, rect->y1);
+ Draw(glob->rp, rect->x0, rect->y1);
+ Draw(glob->rp, rect->x0, rect->y0);
+
+ glob->rp->PenWidth = 1;
+ glob->rp->PenHeight = 1;
+ glob->rp->LinePtrn = PATT_LINE;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
+{
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_polygon()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ ami_plot_setapen(glob, glob->rp, style->fill_colour);
+
+ if (AreaMove(glob->rp,p[0],p[1]) == -1) {
+ NSLOG(netsurf, INFO, "AreaMove: vector list full");
+ }
+
+ for (uint32 k = 1; k < n; k++) {
+ if (AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1) {
+ NSLOG(netsurf, INFO, "AreaDraw: vector list full");
+ }
+ }
+
+ if (AreaEnd(glob->rp) == -1) {
+ NSLOG(netsurf, INFO, "AreaEnd: error");
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
unsigned int i;
struct bez_point start_p = {0, 0}, cur_p = {0, 0}, p_a, p_b, p_c, p_r;
-
- #ifdef AMI_PLOTTER_DEBUG
- LOG("[ami_plotter] Entered ami_path()");
- #endif
- if (n == 0)
- return true;
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_path()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if (n == 0) {
+ return NSERROR_OK;
+ }
if (p[0] != PLOTTER_PATH_MOVE) {
- LOG("Path does not start with move");
- return false;
+ NSLOG(netsurf, INFO, "Path does not start with move");
+ return NSERROR_INVALID;
}
- if (fill != NS_TRANSPARENT) {
- ami_plot_setapen(glob->rp, fill);
- if (c != NS_TRANSPARENT)
- ami_plot_setopen(glob->rp, c);
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ ami_plot_setapen(glob, glob->rp, pstyle->fill_colour);
+ if (pstyle->stroke_colour != NS_TRANSPARENT) {
+ ami_plot_setopen(glob, glob->rp, pstyle->stroke_colour);
+ }
} else {
- if (c != NS_TRANSPARENT) {
- ami_plot_setapen(glob->rp, c);
+ if (pstyle->stroke_colour != NS_TRANSPARENT) {
+ ami_plot_setapen(glob, glob->rp, pstyle->stroke_colour);
} else {
- return true; /* wholly transparent */
+ return NSERROR_OK; /* wholly transparent */
}
}
/* Construct path */
for (i = 0; i < n; ) {
if (p[i] == PLOTTER_PATH_MOVE) {
- if (fill != NS_TRANSPARENT) {
- if(AreaMove(glob->rp, p[i+1], p[i+2]) == -1)
- LOG("AreaMove: vector list full");
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ if (AreaMove(glob->rp, p[i+1], p[i+2]) == -1) {
+ NSLOG(netsurf, INFO,
+ "AreaMove: vector list full");
+ }
} else {
Move(glob->rp, p[i+1], p[i+2]);
}
@@ -851,17 +925,20 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width,
cur_p.y = start_p.y;
i += 3;
} else if (p[i] == PLOTTER_PATH_CLOSE) {
- if (fill != NS_TRANSPARENT) {
- if(AreaEnd(glob->rp) == -1)
- LOG("AreaEnd: error");
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ if (AreaEnd(glob->rp) == -1) {
+ NSLOG(netsurf, INFO, "AreaEnd: error");
+ }
} else {
Draw(glob->rp, start_p.x, start_p.y);
}
i++;
} else if (p[i] == PLOTTER_PATH_LINE) {
- if (fill != NS_TRANSPARENT) {
- if(AreaDraw(glob->rp, p[i+1], p[i+2]) == -1)
- LOG("AreaDraw: vector list full");
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ if (AreaDraw(glob->rp, p[i+1], p[i+2]) == -1) {
+ NSLOG(netsurf, INFO,
+ "AreaDraw: vector list full");
+ }
} else {
Draw(glob->rp, p[i+1], p[i+2]);
}
@@ -876,11 +953,13 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width,
p_c.x = p[i+5];
p_c.y = p[i+6];
- for(double t = 0.0; t <= 1.0; t += 0.1) {
+ for (double t = 0.0; t <= 1.0; t += 0.1) {
ami_bezier(&cur_p, &p_a, &p_b, &p_c, t, &p_r);
- if (fill != NS_TRANSPARENT) {
- if(AreaDraw(glob->rp, p_r.x, p_r.y) == -1)
- LOG("AreaDraw: vector list full");
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ if (AreaDraw(glob->rp, p_r.x, p_r.y) == -1) {
+ NSLOG(netsurf, INFO,
+ "AreaDraw: vector list full");
+ }
} else {
Draw(glob->rp, p_r.x, p_r.y);
}
@@ -889,27 +968,194 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width,
cur_p.y = p_c.y;
i += 7;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
/* End path for safety if using Area commands */
- if (fill != NS_TRANSPARENT) {
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
AreaEnd(glob->rp);
BNDRYOFF(glob->rp);
}
- return false;
+ return NSERROR_INVALID;
}
}
- if (fill != NS_TRANSPARENT)
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
BNDRYOFF(glob->rp);
+ }
- return true;
+ return NSERROR_OK;
}
-bool ami_plot_screen_is_palettemapped(void)
+
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_bitmap_tile(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
+{
+ int xf,yf,xm,ym,oy,ox;
+ struct BitMap *tbm = NULL;
+ struct Hook *bfh = NULL;
+ struct bfbitmap bfbm;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_bitmap_tile()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if ((width == 0) || (height == 0)) {
+ return NSERROR_OK;
+ }
+
+ if (!(repeat_x || repeat_y)) {
+ return ami_bitmap(glob, x, y, width, height, bitmap);
+ }
+
+ /* If it is a one pixel transparent image, we are wasting our time */
+ if ((amiga_bitmap_get_opaque(bitmap) == false) &&
+ (bitmap_get_width(bitmap) == 1) &&
+ (bitmap_get_height(bitmap) == 1)) {
+ return NSERROR_OK;
+ }
+
+ tbm = ami_bitmap_get_native(bitmap, width, height, glob->palette_mapped, glob->rp->BitMap);
+ if (!tbm) {
+ return NSERROR_OK;
+ }
+
+ ox = x;
+ oy = y;
+
+ /* get left most tile position */
+ for (; ox > 0; ox -= width)
+
+ /* get top most tile position */
+ for (; oy > 0; oy -= height);
+
+ if (ox < 0) {
+ ox = -ox;
+ }
+ if (oy < 0) {
+ oy = -oy;
+ }
+ if (repeat_x) {
+ xf = glob->rect.MaxX;
+ xm = glob->rect.MinX;
+ } else {
+ xf = x + width;
+ xm = x;
+ }
+
+ if (repeat_y) {
+ yf = glob->rect.MaxY;
+ ym = glob->rect.MinY;
+ } else {
+ yf = y + height;
+ ym = y;
+ }
+#ifdef __amigaos4__
+ if(amiga_bitmap_get_opaque(bitmap)) {
+ bfh = CreateBackFillHook(BFHA_BitMap,tbm,
+ BFHA_Width,width,
+ BFHA_Height,height,
+ BFHA_OffsetX,ox,
+ BFHA_OffsetY,oy,
+ TAG_DONE);
+ } else
+#endif
+ {
+ bfbm.bm = tbm;
+ bfbm.width = width;
+ bfbm.height = height;
+ bfbm.offsetx = ox;
+ bfbm.offsety = oy;
+ bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm);
+ bfbm.palette_mapped = glob->palette_mapped;
+ bfh = calloc(1, sizeof(struct Hook));
+ bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook;
+ bfh->h_SubEntry = 0;
+ bfh->h_Data = &bfbm;
+ }
+
+ InstallLayerHook(glob->rp->Layer,bfh);
+ EraseRect(glob->rp,xm,ym,xf,yf);
+ InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL);
+
+#ifdef __amigaos4__
+ if (amiga_bitmap_get_opaque(bitmap)) {
+ DeleteBackFillHook(bfh);
+ } else
+#endif
+ free(bfh);
+
+ if ((ami_bitmap_is_nativebm(bitmap, tbm) == false)) {
+ /**\todo is this logic logical? */
+ ami_rtg_freebitmap(tbm);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ami_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- return glob->palette_mapped;
+ NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_text()");
+
+ struct gui_globals *glob = (struct gui_globals *)ctx->priv;
+
+ if (__builtin_expect(ami_nsfont == NULL, 0)) {
+ return NSERROR_OK;
+ }
+ ami_plot_setapen(glob, glob->rp, fstyle->foreground);
+ ami_nsfont->text(glob->rp, text, length, fstyle, x, y, nsoption_bool(font_antialiasing));
+
+ return NSERROR_OK;
}
-struct plotter_table plot;
+
const struct plotter_table amiplot = {
.rectangle = ami_rectangle,
.line = ami_line,
diff --git a/frontends/amiga/plotters.h b/frontends/amiga/plotters.h
index 7cb994f9d..94259234b 100644
--- a/frontends/amiga/plotters.h
+++ b/frontends/amiga/plotters.h
@@ -20,38 +20,64 @@
#define AMIGA_PLOTTERS_H
#include "netsurf/plotters.h"
-#include <proto/layers.h>
-#include <proto/graphics.h>
struct IBox;
-
-struct gui_globals
-{
- struct BitMap *bm;
- struct RastPort *rp;
- struct Layer_Info *layerinfo;
- APTR areabuf;
- APTR tmprasbuf;
- struct Rectangle rect;
- struct MinList *shared_pens;
- bool palette_mapped;
- ULONG apen;
- ULONG open;
- LONG apen_num;
- LONG open_num;
- int width; /* size of bm and */
- int height; /* associated memory */
-};
+struct gui_globals;
extern const struct plotter_table amiplot;
-extern struct gui_globals *glob;
-
-void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool force32bit);
-void ami_free_layers(struct gui_globals *gg);
void ami_clearclipreg(struct gui_globals *gg);
void ami_plot_clear_bbox(struct RastPort *rp, struct IBox *bbox);
void ami_plot_release_pens(struct MinList *shared_pens);
bool ami_plot_screen_is_palettemapped(void);
+/* Plotter render area management */
+
+/**
+ * Alloc a plotter render area
+ * \param width of render bitmap
+ * \param height of render bitmap
+ * \param force32bit allocate a 32-bit bitmap even if this does not match the screen
+ * \param alloc_pen_list set to false to use own pen list (eg. if multiple pen lists will be required)
+ * \returns pointer to render area
+ */
+struct gui_globals *ami_plot_ra_alloc(ULONG width, ULONG height, bool force32bit, bool alloc_pen_list);
+
+/**
+ * Free a plotter render area
+ * \param gg render area to free
+ */
+void ami_plot_ra_free(struct gui_globals *gg);
+
+/**
+ * Get RastPort associated with a render area
+ * \param gg render area
+ * \returns pointer to render area BitMap
+ */
+struct RastPort *ami_plot_ra_get_rastport(struct gui_globals *gg);
+
+/**
+ * Get a drawing BitMap associated with a render area
+ * \param gg render area
+ * \returns pointer to render area BitMap
+ */
+struct BitMap *ami_plot_ra_get_bitmap(struct gui_globals *gg);
+
+/**
+ * Get size of BitMap associated with a render area
+ * \param gg render area
+ * \param width updated to BitMap width
+ * \param height updated to BitMap height
+ */
+void ami_plot_ra_get_size(struct gui_globals *gg, int *width, int *height);
+
+/**
+ * Set a list of shared pens for a render area to use
+ * Only relevant for palette-mapped screens
+ * \param gg render area
+ * \param pen_list allocated by ami_AllocMinList()
+ */
+void ami_plot_ra_set_pen_list(struct gui_globals *gg, struct MinList *pen_list);
+
#endif
+
diff --git a/frontends/amiga/plugin_hack.c b/frontends/amiga/plugin_hack.c
index 7fe78b9b0..5d7ec19c1 100644
--- a/frontends/amiga/plugin_hack.c
+++ b/frontends/amiga/plugin_hack.c
@@ -82,7 +82,8 @@ nserror amiga_plugin_hack_init(void)
if(node)
{
- LOG("plugin_hack registered %s", lwc_string_data(type));
+ NSLOG(netsurf, INFO, "plugin_hack registered %s",
+ lwc_string_data(type));
error = content_factory_register_handler(
lwc_string_data(type),
@@ -123,7 +124,7 @@ nserror amiga_plugin_hack_create(const content_handler *handler,
bool amiga_plugin_hack_convert(struct content *c)
{
- LOG("amiga_plugin_hack_convert");
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_convert");
content_set_ready(c);
content_set_done(c);
@@ -137,7 +138,7 @@ void amiga_plugin_hack_destroy(struct content *c)
{
amiga_plugin_hack_content *plugin = (amiga_plugin_hack_content *) c;
- LOG("amiga_plugin_hack_destroy %p", plugin);
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_destroy %p", plugin);
return;
}
@@ -150,18 +151,29 @@ bool amiga_plugin_hack_redraw(struct content *c,
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0xffffff,
.stroke_colour = 0x000000,
- .stroke_width = 1,
+ .stroke_width = plot_style_int_to_fixed(1),
};
+ struct rect rect;
+ nserror res;
- LOG("amiga_plugin_hack_redraw");
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_redraw");
- ctx->plot->rectangle(data->x, data->y, data->x + data->width,
- data->y + data->height, &pstyle);
+ rect.x0 = data->x;
+ rect.y0 = data->y;
+ rect.x1 = data->x + data->width;
+ rect.y1 = data->y + data->height;
- return ctx->plot->text(data->x, data->y+20,
- lwc_string_data(content__get_mime_type(c)),
- lwc_string_length(content__get_mime_type(c)),
- plot_style_font);
+ ctx->plot->rectangle(ctx, &pstyle, &rect);
+
+ res = ctx->plot->text(ctx,
+ plot_style_font,
+ data->x, data->y+20,
+ lwc_string_data(content__get_mime_type(c)),
+ lwc_string_length(content__get_mime_type(c)));
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ return true;
}
/**
@@ -176,7 +188,8 @@ bool amiga_plugin_hack_redraw(struct content *c,
void amiga_plugin_hack_open(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params)
{
- LOG("amiga_plugin_hack_open %s", nsurl_access(content_get_url(c)));
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_open %s",
+ nsurl_access(content_get_url(c)));
if(c)
{
@@ -190,13 +203,13 @@ void amiga_plugin_hack_open(struct content *c, struct browser_window *bw,
void amiga_plugin_hack_close(struct content *c)
{
- LOG("amiga_plugin_hack_close");
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_close");
return;
}
void amiga_plugin_hack_reformat(struct content *c, int width, int height)
{
- LOG("amiga_plugin_hack_reformat");
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_reformat");
c->width = width;
c->height = height;
@@ -209,7 +222,7 @@ nserror amiga_plugin_hack_clone(const struct content *old, struct content **newc
amiga_plugin_hack_content *plugin;
nserror error;
- LOG("amiga_plugin_hack_clone");
+ NSLOG(netsurf, INFO, "amiga_plugin_hack_clone");
plugin = calloc(1, sizeof(amiga_plugin_hack_content));
if (plugin == NULL)
@@ -256,7 +269,7 @@ void amiga_plugin_hack_execute(struct hlcache_handle *c)
if(full_cmd)
{
#ifdef __amigaos4__
- LOG("Attempting to execute %s", full_cmd);
+ NSLOG(netsurf, INFO, "Attempting to execute %s", full_cmd);
in = Open("NIL:", MODE_OLDFILE);
out = Open("NIL:", MODE_NEWFILE);
diff --git a/frontends/amiga/print.c b/frontends/amiga/print.c
index 5fab0f968..8c8565478 100644
--- a/frontends/amiga/print.c
+++ b/frontends/amiga/print.c
@@ -436,6 +436,7 @@ void ami_print(struct hlcache_handle *c, int copies)
ami_print_info.ps->page_width = ami_print_info.PED->ped_MaxXDots;
ami_print_info.ps->page_height = ami_print_info.PED->ped_MaxYDots;
ami_print_info.ps->scale = scale;
+ ami_print_info.ps->priv = ami_print_info.gg;
if(!print_set_up(c, &amiprinter, ami_print_info.ps, &height))
{
@@ -459,10 +460,8 @@ bool ami_print_cont(void)
if(ami_print_info.page <= ami_print_info.pages)
{
- glob = ami_print_info.gg;
print_draw_next_page(&amiprinter, ami_print_info.ps);
ami_print_dump();
- ami_gui_set_default_gg();
ret = true;
}
else
@@ -496,13 +495,10 @@ struct MsgPort *ami_print_get_msgport(void)
bool ami_print_begin(struct print_settings *ps)
{
- ami_print_info.gg = calloc(1, sizeof(struct gui_globals));
- if(!ami_print_info.gg) return false;
-
- ami_init_layers(ami_print_info.gg,
- ami_print_info.PED->ped_MaxXDots,
+ ami_print_info.gg = ami_plot_ra_alloc(ami_print_info.PED->ped_MaxXDots,
ami_print_info.PED->ped_MaxYDots,
- true);
+ true, false);
+ if(!ami_print_info.gg) return false;
ami_print_info.page = 0;
@@ -522,10 +518,8 @@ bool ami_print_next_page(void)
void ami_print_end(void)
{
- ami_free_layers(ami_print_info.gg);
- free(ami_print_info.gg);
+ ami_plot_ra_free(ami_print_info.gg);
DisposeObject(ami_print_info.objects[OID_MAIN]);
- ami_gui_set_default_gg();
ami_print_close_device();
ami_print_free();
@@ -542,7 +536,7 @@ bool ami_print_dump(void)
ami_print_info.PReq->io_Command = PRD_DUMPRPORT;
ami_print_info.PReq->io_Flags = 0;
ami_print_info.PReq->io_Error = 0;
- ami_print_info.PReq->io_RastPort = ami_print_info.gg->rp;
+ ami_print_info.PReq->io_RastPort = ami_plot_ra_get_rastport(ami_print_info.gg);
ami_print_info.PReq->io_ColorMap = NULL;
ami_print_info.PReq->io_Modes = 0;
ami_print_info.PReq->io_SrcX = 0;
diff --git a/frontends/amiga/resources/AdBlock.css b/frontends/amiga/resources/AdBlock.css
index e3811f62b..0d12aaa7c 120000
--- a/frontends/amiga/resources/AdBlock.css
+++ b/frontends/amiga/resources/AdBlock.css
@@ -1 +1 @@
-../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
+../../../resources/adblock.css \ No newline at end of file
diff --git a/frontends/amiga/resources/ca-bundle b/frontends/amiga/resources/ca-bundle
index ad2dd6b55..1187fa51a 120000
--- a/frontends/amiga/resources/ca-bundle
+++ b/frontends/amiga/resources/ca-bundle
@@ -1 +1 @@
-../../!NetSurf/Resources/ca-bundle \ No newline at end of file
+../../../resources/ca-bundle \ No newline at end of file
diff --git a/frontends/amiga/resources/de b/frontends/amiga/resources/de
deleted file mode 120000
index 38128816c..000000000
--- a/frontends/amiga/resources/de
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/de \ No newline at end of file
diff --git a/frontends/amiga/resources/en b/frontends/amiga/resources/en
deleted file mode 120000
index d1dfaa9d2..000000000
--- a/frontends/amiga/resources/en
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/en \ No newline at end of file
diff --git a/frontends/amiga/resources/fr b/frontends/amiga/resources/fr
deleted file mode 120000
index df1cbe3a1..000000000
--- a/frontends/amiga/resources/fr
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/fr \ No newline at end of file
diff --git a/frontends/amiga/resources/it b/frontends/amiga/resources/it
deleted file mode 120000
index 6177e9176..000000000
--- a/frontends/amiga/resources/it
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/it \ No newline at end of file
diff --git a/frontends/amiga/resources/nl b/frontends/amiga/resources/nl
deleted file mode 120000
index a07bd0469..000000000
--- a/frontends/amiga/resources/nl
+++ /dev/null
@@ -1 +0,0 @@
-../../!NetSurf/Resources/nl \ No newline at end of file
diff --git a/frontends/amiga/resources/nsdefault.css b/frontends/amiga/resources/nsdefault.css
index 6d2d4da5b..fa3ae6c26 120000
--- a/frontends/amiga/resources/nsdefault.css
+++ b/frontends/amiga/resources/nsdefault.css
@@ -1 +1 @@
-../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
+../../../resources/default.css \ No newline at end of file
diff --git a/frontends/amiga/resources/quirks.css b/frontends/amiga/resources/quirks.css
index d9fb80334..1e752cb9e 120000
--- a/frontends/amiga/resources/quirks.css
+++ b/frontends/amiga/resources/quirks.css
@@ -1 +1 @@
-../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
+../../../resources/quirks.css \ No newline at end of file
diff --git a/frontends/amiga/schedule.c b/frontends/amiga/schedule.c
index bfafe9c88..043edc7fe 100644
--- a/frontends/amiga/schedule.c
+++ b/frontends/amiga/schedule.c
@@ -218,22 +218,25 @@ static void ami_schedule_dump(void)
GetSysTime(&tv);
Amiga2Date(tv.Seconds, &clockdata);
- LOG("Current time = %d-%d-%d %d:%d:%d.%d", clockdata.mday, clockdata.month, clockdata.year,
- clockdata.hour, clockdata.min, clockdata.sec, tv.Microseconds);
- LOG("Events remaining in queue:");
+ NSLOG(netsurf, INFO, "Current time = %d-%d-%d %d:%d:%d.%d",
+ clockdata.mday, clockdata.month, clockdata.year,
+ clockdata.hour, clockdata.min, clockdata.sec, tv.Microseconds);
+ NSLOG(netsurf, INFO, "Events remaining in queue:");
iterator = pblHeapIterator(schedule_list);
while ((nscb = pblIteratorNext(iterator)) != -1)
{
Amiga2Date(nscb->tv.Seconds, &clockdata);
- LOG("nscb: %p, at %d-%d-%d %d:%d:%d.%d, callback: %p, %p",
- nscb, clockdata.mday, clockdata.month, clockdata.year, clockdata.hour, clockdata.min, clockdata.sec,
- nscb->tv.Microseconds, nscb->callback, nscb->p);
+ NSLOG(netsurf, INFO,
+ "nscb: %p, at %d-%d-%d %d:%d:%d.%d, callback: %p, %p",
+ nscb, clockdata.mday, clockdata.month, clockdata.year,
+ clockdata.hour, clockdata.min, clockdata.sec,
+ nscb->tv.Microseconds, nscb->callback, nscb->p);
if(CheckIO((struct IORequest *)nscb) == NULL) {
- LOG("-> ACTIVE");
+ NSLOG(netsurf, INFO, "-> ACTIVE");
} else {
- LOG("-> COMPLETE");
+ NSLOG(netsurf, INFO, "-> COMPLETE");
}
};
diff --git a/frontends/amiga/selectmenu.c b/frontends/amiga/selectmenu.c
index f3a11b67a..8a8614136 100644
--- a/frontends/amiga/selectmenu.c
+++ b/frontends/amiga/selectmenu.c
@@ -58,7 +58,8 @@ BOOL ami_selectmenu_is_safe(void)
BOOL popupmenu_lib_ok = FALSE;
if((PopupMenuBase = OpenLibrary("popupmenu.library", 53))) {
- LOG("popupmenu.library v%d.%d", PopupMenuBase->lib_Version, PopupMenuBase->lib_Revision);
+ NSLOG(netsurf, INFO, "popupmenu.library v%d.%d",
+ PopupMenuBase->lib_Version, PopupMenuBase->lib_Revision);
if(LIB_IS_AT_LEAST((struct Library *)PopupMenuBase, 53, 11))
popupmenu_lib_ok = TRUE;
CloseLibrary(PopupMenuBase);
diff --git a/frontends/amiga/sslcert.c b/frontends/amiga/sslcert.c
index 5929f7e89..136b918fc 100644
--- a/frontends/amiga/sslcert.c
+++ b/frontends/amiga/sslcert.c
@@ -172,7 +172,7 @@ ami_crtvrfy_mouse(struct ami_corewindow *ami_cw,
/**
* callback for keypress for certificate verify on core window
*
- * \param example_cw The Amiga core window structure.
+ * \param ami_cw The Amiga core window structure.
* \param nskey The netsurf key code
* \return NSERROR_OK on success otherwise apropriate error code
*/
@@ -194,6 +194,8 @@ ami_crtvrfy_key(struct ami_corewindow *ami_cw, uint32_t nskey)
* callback on draw event for certificate verify on core window
*
* \param ami_cw The Amiga core window structure.
+ * \param x the x coordinate to draw
+ * \param y the y coordinate to draw
* \param r The rectangle of the window that needs updating.
* \param ctx The drawing context
* \return NSERROR_OK on success otherwise apropriate error code
@@ -315,7 +317,7 @@ nserror ami_cert_verify(struct nsurl *url,
res = ami_crtvrfy_create_window(ncwin);
if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
ami_utf8_free(ncwin->core.wintitle);
ami_utf8_free(ncwin->sslerr);
ami_utf8_free(ncwin->sslaccept);
diff --git a/frontends/amiga/stringview/stringview.c b/frontends/amiga/stringview/stringview.c
index e875f3b5a..245782b43 100755
--- a/frontends/amiga/stringview/stringview.c
+++ b/frontends/amiga/stringview/stringview.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef __amigaos4__
/// Include
#include <proto/dos.h>
@@ -32,7 +33,6 @@
#include <gadgets/layout.h>
#include <gadgets/listbrowser.h>
-#include "amiga/os3support.h"
#include "amiga/libs.h"
#include "stringview.h"
@@ -867,4 +867,5 @@ void FreeStringClass(Class *cl)
///
/* The End */
+#endif //__amigaos4__
diff --git a/frontends/amiga/stringview/stringview.h b/frontends/amiga/stringview/stringview.h
index f989b2a0f..776705f0f 100755
--- a/frontends/amiga/stringview/stringview.h
+++ b/frontends/amiga/stringview/stringview.h
@@ -17,7 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "amiga/os3support.h"
+#ifndef AMIGA_STRINGVIEW_H
+#define AMIGA_STRINGVIEW_H 1
#include <exec/semaphores.h>
#include <intuition/classes.h>
@@ -58,3 +59,5 @@ void FreeStringClass(Class *);
#ifdef __cplusplus
}
#endif
+#endif
+
diff --git a/frontends/amiga/stringview/urlhistory.c b/frontends/amiga/stringview/urlhistory.c
index 7405fbb57..c1e37ea7e 100644
--- a/frontends/amiga/stringview/urlhistory.c
+++ b/frontends/amiga/stringview/urlhistory.c
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef __amigaos4__
#include <stdio.h>
#include <ctype.h>
#include <string.h>
@@ -123,3 +124,5 @@ void URLHistory_AddPage( const char * urlString )
urldb_iterate_partial(urlString, URLHistoryFound);
}
}
+#endif //__amigaos4__
+
diff --git a/frontends/amiga/stringview/urlhistory.h b/frontends/amiga/stringview/urlhistory.h
index b72792db4..962713e9e 100644
--- a/frontends/amiga/stringview/urlhistory.h
+++ b/frontends/amiga/stringview/urlhistory.h
@@ -17,6 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef AMIGA_URLHISTORY_H
+#define AMIGA_URLHISTORY_H 1
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -31,3 +34,5 @@ void URLHistory_AddPage( const char * urlString );
#ifdef __cplusplus
}
#endif
+#endif
+
diff --git a/frontends/amiga/theme.c b/frontends/amiga/theme.c
index 496fc5470..63982c879 100644
--- a/frontends/amiga/theme.c
+++ b/frontends/amiga/theme.c
@@ -47,13 +47,15 @@
#include "amiga/gui.h"
#include "amiga/drag.h"
#include "amiga/bitmap.h"
+#include "amiga/plotters.h"
#include "amiga/schedule.h"
#include "amiga/theme.h"
#include "amiga/misc.h"
static struct BitMap *throbber = NULL;
static struct bitmap *throbber_nsbm = NULL;
-static int throbber_frames, throbber_update_interval;
+static int throbber_frames = 1;
+static int throbber_update_interval;
static Object *mouseptrobj[AMI_LASTPOINTER+1];
static struct BitMap *mouseptrbm[AMI_LASTPOINTER+1];
@@ -175,11 +177,13 @@ void ami_theme_throbber_setup(void)
ami_get_theme_filename(throbberfile,"theme_throbber",false);
throbber_frames=atoi(messages_get("theme_throbber_frames"));
+ if(throbber_frames == 0) throbber_frames = 1;
throbber_update_interval = atoi(messages_get("theme_throbber_delay"));
if(throbber_update_interval == 0) throbber_update_interval = 250;
bm = ami_bitmap_from_datatype(throbberfile);
- throbber = ami_bitmap_get_native(bm, bitmap_get_width(bm), bitmap_get_height(bm), NULL);
+ throbber = ami_bitmap_get_native(bm, bitmap_get_width(bm), bitmap_get_height(bm),
+ ami_plot_screen_is_palettemapped(), NULL);
throbber_nsbm = bm;
}
diff --git a/frontends/amiga/version.c b/frontends/amiga/version.c
index c3cd9e2b5..61fbd7176 100644
--- a/frontends/amiga/version.c
+++ b/frontends/amiga/version.c
@@ -25,7 +25,7 @@
* problems created by "0" not being a valid AmigaOS revision number.
*/
#define NETSURF_VERSION_MAJOR "3"
-#define NETSURF_VERSION_MINOR_EXTERNAL "7"
+#define NETSURF_VERSION_MINOR_EXTERNAL "8"
#if defined(CI_BUILD)
#define NETSURF_VERSION_MINOR CI_BUILD
#else
diff --git a/frontends/atari/Makefile b/frontends/atari/Makefile
index 7bc441c33..585f0b217 100644
--- a/frontends/atari/Makefile
+++ b/frontends/atari/Makefile
@@ -47,6 +47,7 @@ CFLAGS += -U__STRICT_ANSI__ -std=c99 -Dsmall -Dnsatari \
-D_BSD_SOURCE \
-D_XOPEN_SOURCE=600 \
-D_POSIX_C_SOURCE=200112L \
+ -DNSLOG_LEVEL_0x0010=NSLOG_LEVEL_INFO \
$(shell $(PKG_CONFIG) --cflags openssl ) \
$(shell $(PKG_CONFIG) --cflags libcurl )
@@ -117,8 +118,8 @@ ATARI_FONT_SOURCE_URL := http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-ve
#ATARI_FONT_SOURCE_URL := http://localhost/$(ATARI_FONT_NAME).tar.gz
ATARI_FONT_TMP_DIR := $(DEPROOT)/../
ATARI_FONT_SOURCE_DIR := $(ATARI_FONT_TMP_DIR)$(ATARI_FONT_NAME)/
-ATARI_GENERIC_RESOURCES := de en it ja
-ATARI_RESOURCES := $(addprefix \!NetSurf/Resources/,$(ATARI_GENERIC_RESOURCES))
+ATARI_GENERIC_RESOURCES := de en it ja nl
+ATARI_RESOURCES := $(addprefix resources/,$(ATARI_GENERIC_RESOURCES))
# ----------------------------------------------------------------------------
# Install target
@@ -167,21 +168,21 @@ endif
$(Q)cp $(ATARI_RES_DIR)/netsurf.rsc $(ATARI_TARGET_DIR)res/netsurf.rsc
$(Q)cp $(ATARI_RES_DIR)/languages $(ATARI_TARGET_DIR)res/languages
$(Q)cp $(ATARI_RES_DIR)/icons/toolbar -R $(ATARI_TARGET_DIR)res/icons
- $(Q)cp \!NetSurf/Resources/Icons/* -R $(ATARI_TARGET_DIR)res/icons/
-
- $(Q)cp \!NetSurf/Resources/netsurf.png,b60 $(ATARI_TARGET_DIR)res/netsurf.png
- $(Q)cp \!NetSurf/Resources/AdBlock,f79 $(ATARI_TARGET_DIR)res/adblock.css
- $(Q)cp \!NetSurf/Resources/CSS,f79 $(ATARI_TARGET_DIR)res/default.css
- $(Q)cp \!NetSurf/Resources/Quirks,f79 $(ATARI_TARGET_DIR)res/quirks.css
- $(Q)cp \!NetSurf/Resources/internal.css,f79 $(ATARI_TARGET_DIR)res/internal.css
- $(Q)cp \!NetSurf/Resources/SearchEngines $(ATARI_TARGET_DIR)res/search
- $(Q)cp \!NetSurf/Resources/ca-bundle $(ATARI_TARGET_DIR)res/cabundle
- $(Q)cp \!NetSurf/Resources/ca-bundle $(ATARI_TARGET_DIR)res/cabundle
- $(Q)$(SPLIT_MESSAGES) -l en -p atari -f messages resources/FatMessages > $(ATARI_TARGET_DIR)res/messages
- $(Q)cp \!NetSurf/Resources/en/welcome.html,faf $(ATARI_TARGET_DIR)res/welcome.html
- $(Q)cp \!NetSurf/Resources/en/maps.html,faf $(ATARI_TARGET_DIR)res/maps.html
- $(Q)cp \!NetSurf/Resources/en/licence.html,faf $(ATARI_TARGET_DIR)res/licence.html
- $(Q)cp \!NetSurf/Resources/en/credits.html,faf $(ATARI_TARGET_DIR)res/credits.html
+ $(Q)cp resources/icons/* -R $(ATARI_TARGET_DIR)res/icons/
+
+ $(Q)cp resources/netsurf.png $(ATARI_TARGET_DIR)res/netsurf.png
+ $(Q)cp resources/adblock.css $(ATARI_TARGET_DIR)res/adblock.css
+ $(Q)cp resources/default.css $(ATARI_TARGET_DIR)res/default.css
+ $(Q)cp resources/quirks.css $(ATARI_TARGET_DIR)res/quirks.css
+ $(Q)cp resources/internal.css $(ATARI_TARGET_DIR)res/internal.css
+ $(Q)cp resources/SearchEngines $(ATARI_TARGET_DIR)res/search
+ $(Q)cp resources/ca-bundle $(ATARI_TARGET_DIR)res/cabundle
+ $(Q)$(RM) $(ATARI_TARGET_DIR)res/messages
+ $(Q)$(SPLIT_MESSAGES) -l en -p atari -f messages -o $(ATARI_TARGET_DIR)res/messages resources/FatMessages
+ $(Q)cp resources/en/welcome.html $(ATARI_TARGET_DIR)res/welcome.html
+ $(Q)cp resources/en/maps.html $(ATARI_TARGET_DIR)res/maps.html
+ $(Q)cp resources/en/licence.html $(ATARI_TARGET_DIR)res/licence.html
+ $(Q)cp resources/en/credits.html $(ATARI_TARGET_DIR)res/credits.html
# copy "Bitstream Vera" font:
$(Q)cp $(ATARI_FONT_SOURCE_DIR)RELEASENOTES.TXT $(ATARI_TARGET_DIR)res/fonts/
diff --git a/frontends/atari/bitmap.c b/frontends/atari/bitmap.c
index cbb719586..ae42da837 100644
--- a/frontends/atari/bitmap.c
+++ b/frontends/atari/bitmap.c
@@ -81,7 +81,9 @@ static void *atari_bitmap_create_ex( int w, int h, short bpp, int rowstride, uns
{
struct bitmap * bitmap;
- LOG("width %d (rowstride: %d, bpp: %d), height %d, state %u", w, rowstride, bpp, h, state);
+ NSLOG(netsurf, INFO,
+ "width %d (rowstride: %d, bpp: %d), height %d, state %u", w,
+ rowstride, bpp, h, state);
if( rowstride == 0) {
rowstride = bpp * w;
@@ -107,10 +109,10 @@ static void *atari_bitmap_create_ex( int w, int h, short bpp, int rowstride, uns
} else {
free(bitmap);
bitmap=NULL;
- LOG("Out of memory!");
+ NSLOG(netsurf, INFO, "Out of memory!");
}
}
- LOG("bitmap %p", bitmap);
+ NSLOG(netsurf, INFO, "bitmap %p", bitmap);
return bitmap;
}
@@ -194,7 +196,7 @@ static unsigned char *bitmap_get_buffer(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return NULL;
}
@@ -218,7 +220,7 @@ size_t atari_bitmap_get_rowstride(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
return bm->rowstride;
@@ -231,7 +233,7 @@ void atari_bitmap_destroy(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return;
}
@@ -272,11 +274,12 @@ static void bitmap_set_opaque(void *bitmap, bool opaque)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return;
}
- LOG("setting bitmap %p to %s", bm, opaque ? "opaque" : "transparent");
+ NSLOG(netsurf, INFO, "setting bitmap %p to %s", bm,
+ opaque ? "opaque" : "transparent");
bm->opaque = opaque;
}
@@ -293,7 +296,7 @@ static bool bitmap_test_opaque(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return false;
}
@@ -305,11 +308,12 @@ static bool bitmap_test_opaque(void *bitmap)
while (tst-- > 0) {
if (bm->pixdata[(tst << 2) + 3] != 0xff) {
- LOG("bitmap %p has transparency", bm);
+ NSLOG(netsurf, INFO,
+ "bitmap %p has transparency", bm);
return false;
}
}
- LOG("bitmap %p is opaque", bm);
+ NSLOG(netsurf, INFO, "bitmap %p is opaque", bm);
return true;
}
@@ -320,7 +324,7 @@ bool atari_bitmap_get_opaque(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return false;
}
@@ -334,7 +338,7 @@ int atari_bitmap_get_width(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
@@ -348,7 +352,7 @@ int atari_bitmap_get_height(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
return(bm->height);
diff --git a/frontends/atari/certview.c b/frontends/atari/certview.c
index 6950d31f8..80d18a059 100644
--- a/frontends/atari/certview.c
+++ b/frontends/atari/certview.c
@@ -81,7 +81,7 @@ static nserror atari_sslcert_viewer_init_phase2(struct core_window *cw,
assert(ssl_d);
- LOG("cw %p", cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
return(sslcert_viewer_init(cb_t, cw, ssl_d));
}
@@ -97,7 +97,7 @@ static void atari_sslcert_viewer_finish(struct core_window *cw)
/* This will also free the session data: */
sslcert_viewer_fini(cvwin->ssl_session_data);
- LOG("cw %p", cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
}
static void atari_sslcert_viewer_draw(struct core_window *cw, int x,
@@ -123,7 +123,7 @@ static void atari_sslcert_viewer_keypress(struct core_window *cw, uint32_t ucs4)
cvwin = (struct atari_sslcert_viewer_s *)atari_treeview_get_user_data(cw);
- LOG("ucs4: %"PRIu32, ucs4);
+ NSLOG(netsurf, INFO, "ucs4: %"PRIu32, ucs4);
sslcert_viewer_keypress(cvwin->ssl_session_data, ucs4);
}
@@ -150,14 +150,14 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
short retval = 0;
OBJECT *toolbar;
- LOG("win %p", win);
+ NSLOG(netsurf, INFO, "win %p", win);
if(ev_out->emo_events & MU_MESAG){
switch (msg[0]) {
case WM_TOOLBAR:
toolbar = gemtk_obj_get_tree(TOOLBAR_SSL_CERT);
- LOG("CERTVIEWER WM_TOOLBAR");
+ NSLOG(netsurf, INFO, "CERTVIEWER WM_TOOLBAR");
tv = (struct core_window*) gemtk_wm_get_user_data(win);
assert(tv);
cvwin = (struct atari_sslcert_viewer_s *)
@@ -238,7 +238,7 @@ static void atari_sslcert_viewer_init(struct atari_sslcert_viewer_s * cvwin,
if (cvwin->tv == NULL) {
/* handle it properly, clean up previous allocs */
- LOG("Failed to allocate treeview");
+ NSLOG(netsurf, INFO, "Failed to allocate treeview");
return;
}
@@ -280,7 +280,7 @@ static void atari_sslcert_viewer_destroy(struct atari_sslcert_viewer_s * cvwin)
assert(cvwin->init);
assert(cvwin->window);
- LOG("cvwin %p", cvwin);
+ NSLOG(netsurf, INFO, "cvwin %p", cvwin);
if (atari_treeview_is_open(cvwin->tv))
atari_treeview_close(cvwin->tv);
@@ -289,5 +289,5 @@ static void atari_sslcert_viewer_destroy(struct atari_sslcert_viewer_s * cvwin)
cvwin->window = NULL;
atari_treeview_delete(cvwin->tv);
free(cvwin);
- LOG("done");
+ NSLOG(netsurf, INFO, "done");
}
diff --git a/frontends/atari/cookies.c b/frontends/atari/cookies.c
index 9045009fc..df2de0d4c 100644
--- a/frontends/atari/cookies.c
+++ b/frontends/atari/cookies.c
@@ -63,7 +63,7 @@ static nserror
atari_cookie_manager_init_phase2(struct core_window *cw,
struct core_window_callback_table *cb_t)
{
- LOG("cw %p",cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
return(cookie_manager_init(cb_t, cw));
}
@@ -71,7 +71,7 @@ atari_cookie_manager_init_phase2(struct core_window *cw,
static void
atari_cookie_manager_finish(struct core_window *cw)
{
- LOG("cw %p",cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
cookie_manager_fini();
}
@@ -89,7 +89,7 @@ atari_cookie_manager_draw(struct core_window *cw,
static void
atari_cookie_manager_keypress(struct core_window *cw, uint32_t ucs4)
{
- LOG("ucs4: %"PRIu32, ucs4);
+ NSLOG(netsurf, INFO, "ucs4: %"PRIu32, ucs4);
cookie_manager_keypress(ucs4);
}
@@ -108,13 +108,13 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
{
short retval = 0;
- LOG("win %p", win);
+ NSLOG(netsurf, INFO, "win %p", win);
if (ev_out->emo_events & MU_MESAG) {
switch (msg[0]) {
case WM_TOOLBAR:
- LOG("WM_TOOLBAR");
+ NSLOG(netsurf, INFO, "WM_TOOLBAR");
break;
case WM_CLOSED:
@@ -158,7 +158,8 @@ void atari_cookie_manager_init(void)
if (atari_cookie_manager.tv == NULL) {
/* handle it properly, clean up previous allocs */
- LOG("Failed to allocate treeview");
+ NSLOG(netsurf, INFO,
+ "Failed to allocate treeview");
return;
}
@@ -209,7 +210,7 @@ void atari_cookie_manager_destroy(void)
atari_treeview_delete(atari_cookie_manager.tv);
atari_cookie_manager.init = false;
}
- LOG("done");
+ NSLOG(netsurf, INFO, "done");
}
diff --git a/frontends/atari/ctxmenu.c b/frontends/atari/ctxmenu.c
index e25d8e522..eb6cc1611 100644
--- a/frontends/atari/ctxmenu.c
+++ b/frontends/atari/ctxmenu.c
@@ -216,7 +216,7 @@ void context_popup(struct gui_window * gw, short x, short y)
browser_window_navigate(
gw->browser->bw,
hlcache_handle_get_url(ctx->ccdata.object),
- browser_window_get_url(gw->browser->bw),
+ browser_window_access_url(gw->browser->bw),
BW_NAVIGATE_DOWNLOAD,
NULL,
NULL,
@@ -232,7 +232,7 @@ void context_popup(struct gui_window * gw, short x, short y)
error = browser_window_navigate(
gw->browser->bw,
ctx->ccdata.link,
- browser_window_get_url(gw->browser->bw),
+ browser_window_access_url(gw->browser->bw),
BW_NAVIGATE_DOWNLOAD,
NULL,
NULL,
@@ -269,7 +269,7 @@ void context_popup(struct gui_window * gw, short x, short y)
error = browser_window_create(
BW_CREATE_HISTORY | BW_CREATE_CLONE,
ctx->ccdata.link,
- browser_window_get_url(gw->browser->bw),
+ browser_window_access_url(gw->browser->bw),
gw->browser->bw,
NULL);
if (error != NSERROR_OK) {
@@ -288,7 +288,9 @@ void context_popup(struct gui_window * gw, short x, short y)
/* the GEMDOS cmdline contains the length of the commandline
in the first byte: */
cmdline[0] = (unsigned char)strlen(tempfile);
- LOG("Creating temporay source file: %s\n", tempfile);
+ NSLOG(netsurf, INFO,
+ "Creating temporay source file: %s\n",
+ tempfile);
fp_tmpfile = fopen(tempfile, "w");
if (fp_tmpfile != NULL){
fwrite(data, size, 1, fp_tmpfile);
@@ -306,7 +308,8 @@ void context_popup(struct gui_window * gw, short x, short y)
}
} else {
- LOG("Invalid content!");
+ NSLOG(netsurf, INFO,
+ "Invalid content!");
}
} else {
form_alert(0, "[1][Set option \"atari_editor\".][OK]");
diff --git a/frontends/atari/deskmenu.c b/frontends/atari/deskmenu.c
index addba2764..34d7be0b8 100644
--- a/frontends/atari/deskmenu.c
+++ b/frontends/atari/deskmenu.c
@@ -181,7 +181,7 @@ static void __CDECL menu_about(short item, short title, void *data)
nserror error;
char buf[PATH_MAX];
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "abort menu");
strcpy((char*)&buf, "file://");
strncat((char*)&buf, (char*)"./doc/README.TXT",
PATH_MAX - (strlen("file://")+1) );
@@ -208,7 +208,7 @@ static void __CDECL menu_new_win(short item, short title, void *data)
nserror error;
const char *addr;
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if (nsoption_charp(homepage_url) != NULL) {
addr = nsoption_charp(homepage_url);
@@ -236,7 +236,7 @@ static void __CDECL menu_open_url(short item, short title, void *data)
{
struct gui_window * gw;
struct browser_window * bw ;
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
gw = input_window;
if( gw == NULL ) {
@@ -251,7 +251,7 @@ static void __CDECL menu_open_url(short item, short title, void *data)
static void __CDECL menu_open_file(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
const char * filename = file_select(messages_get("OpenFile"), "");
if( filename != NULL ){
@@ -280,7 +280,7 @@ static void __CDECL menu_open_file(short item, short title, void *data)
static void __CDECL menu_close_win(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
gui_window_destroy( input_window );
@@ -288,7 +288,7 @@ static void __CDECL menu_close_win(short item, short title, void *data)
static void __CDECL menu_save_page(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
static bool init = true;
bool is_folder=false;
const char * path;
@@ -319,7 +319,7 @@ static void __CDECL menu_quit(short item, short title, void *data)
{
short buff[8];
memset( &buff, 0, sizeof(short)*8 );
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
gemtk_wm_send_msg(NULL, AP_TERM, 0, 0, 0, 0);
}
@@ -331,21 +331,21 @@ static void __CDECL menu_cut(short item, short title, void *data)
static void __CDECL menu_copy(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window != NULL )
browser_window_key_press( input_window->browser->bw, NS_KEY_COPY_SELECTION);
}
static void __CDECL menu_paste(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window != NULL )
browser_window_key_press( input_window->browser->bw, NS_KEY_PASTE);
}
static void __CDECL menu_find(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if (input_window != NULL) {
if (input_window->search) {
window_close_search(input_window->root);
@@ -358,13 +358,13 @@ static void __CDECL menu_find(short item, short title, void *data)
static void __CDECL menu_choices(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
open_settings();
}
static void __CDECL menu_stop(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
@@ -378,7 +378,7 @@ static void __CDECL menu_reload(short item, short title, void *data)
if(input_window == NULL)
return;
toolbar_reload_click(input_window->root->toolbar);
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
}
@@ -408,7 +408,7 @@ static void __CDECL menu_dec_scale(short item, short title, void *data)
static void __CDECL menu_toolbars(short item, short title, void *data)
{
static int state = 0;
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window != null && input_window->root->toolbar != null ){
state = !state;
// TODO: implement toolbar hide
@@ -418,7 +418,7 @@ static void __CDECL menu_toolbars(short item, short title, void *data)
static void __CDECL menu_savewin(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if (input_window && input_window->browser) {
GRECT rect;
wind_get_grect(gemtk_wm_get_handle(input_window->root->win), WF_CURRXYWH,
@@ -438,7 +438,7 @@ static void __CDECL menu_savewin(short item, short title, void *data)
static void __CDECL menu_debug_render(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
html_redraw_debug = !html_redraw_debug;
if( input_window != NULL ) {
if ( input_window->browser != NULL
@@ -469,7 +469,7 @@ static void __CDECL menu_bg_images(short item, short title, void *data)
static void __CDECL menu_back(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
toolbar_back_click(input_window->root->toolbar);
@@ -477,7 +477,7 @@ static void __CDECL menu_back(short item, short title, void *data)
static void __CDECL menu_forward(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
toolbar_forward_click(input_window->root->toolbar);
@@ -485,7 +485,7 @@ static void __CDECL menu_forward(short item, short title, void *data)
static void __CDECL menu_home(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
toolbar_home_click(input_window->root->toolbar);
@@ -493,24 +493,24 @@ static void __CDECL menu_home(short item, short title, void *data)
static void __CDECL menu_lhistory(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if( input_window == NULL )
return;
}
static void __CDECL menu_ghistory(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
atari_global_history_open();
}
static void __CDECL menu_add_bookmark(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
if (input_window) {
if( browser_window_has_content(input_window->browser->bw) ){
atari_hotlist_add_page(
- nsurl_access(browser_window_get_url(input_window->browser->bw)),
+ nsurl_access(browser_window_access_url(input_window->browser->bw)),
NULL
);
}
@@ -519,26 +519,26 @@ static void __CDECL menu_add_bookmark(short item, short title, void *data)
static void __CDECL menu_bookmarks(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
atari_hotlist_open();
}
static void __CDECL menu_cookies(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
atari_cookie_manager_open();
}
static void __CDECL menu_vlog(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
verbose_log = !verbose_log;
menu_icheck(h_gem_menu, MAINMENU_M_VLOG, (verbose_log) ? 1 : 0);
}
static void __CDECL menu_help_content(short item, short title, void *data)
{
- LOG("%s", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s", __FUNCTION__);
}
/*
@@ -580,14 +580,16 @@ static void register_menu_str( struct s_menu_item_evnt * mi )
while (i > 2) {
if ((strncmp(" ", &str[i], 2) == 0) && (strlen(&str[i]) > 2)) {
// "Standard" Keyboard Shortcut Element found:
- LOG("Standard Keyboard Shortcut: \"%s\"\n", &str[i]);
+ NSLOG(netsurf, INFO,
+ "Standard Keyboard Shortcut: \"%s\"\n", &str[i]);
x = i+2;
is_std_shortcut = true;
break;
}
if( str[i] == '['){
- LOG("Keyboard Shortcut: \"%s\"\n", &str[i]);
+ NSLOG(netsurf, INFO, "Keyboard Shortcut: \"%s\"\n",
+ &str[i]);
// "Custom" Keyboard Shortcut Element found (identified by [):
x = i;
break;
@@ -662,8 +664,12 @@ static void register_menu_str( struct s_menu_item_evnt * mi )
}
}
- LOG("Registered keyboard shortcut for \"%s\" => mod: %d, ""keycode: %ld, ascii: %c\n",
- str, accel->mod, accel->keycode, accel->ascii);
+ NSLOG(netsurf, INFO,
+ "Registered keyboard shortcut for \"%s\" => mod: %d, ""keycode: %ld, ascii: %c\n",
+ str,
+ accel->mod,
+ accel->keycode,
+ accel->ascii);
}
}
diff --git a/frontends/atari/download.c b/frontends/atari/download.c
index d756e6694..7a1c7d2b7 100644
--- a/frontends/atari/download.c
+++ b/frontends/atari/download.c
@@ -194,7 +194,7 @@ static void on_close(struct gui_download_window * dw)
static void gui_download_window_destroy( struct gui_download_window * gdw)
{
- LOG("gdw %p", gdw);
+ NSLOG(netsurf, INFO, "gdw %p", gdw);
if (gdw->status == NSATARI_DOWNLOAD_WORKING) {
download_context_abort(gdw->ctx);
@@ -253,7 +253,8 @@ gui_download_window_create(download_context *ctx, struct gui_window *parent)
char alert[200];
- LOG("Creating download window for gui window: %p", parent);
+ NSLOG(netsurf, INFO, "Creating download window for gui window: %p",
+ parent);
/* TODO: Implement real form and use messages file strings! */
@@ -330,7 +331,8 @@ gui_download_window_create(download_context *ctx, struct gui_window *parent)
gemtk_wm_set_toolbar_redraw_func(gdw->guiwin, toolbar_redraw_cb);
strncpy((char*)&gdw->lbl_file, filename, MAX_SLEN_LBL_FILE-1);
- LOG("created download: %s (total size: %d)", gdw->destination, gdw->size_total);
+ NSLOG(netsurf, INFO, "created download: %s (total size: %d)",
+ gdw->destination, gdw->size_total);
GRECT work, curr;
work.g_x = 0;
@@ -357,7 +359,7 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
uint32_t tnow = clck / (CLOCKS_PER_SEC>>3);
uint32_t sdiff = (clck / (CLOCKS_PER_SEC)) - dw->start;
- LOG("dw %p",dw);
+ NSLOG(netsurf, INFO, "dw %p", dw);
if (dw->abort == true){
dw->status = NSATARI_DOWNLOAD_CANCELED;
@@ -405,7 +407,7 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
static void gui_download_window_error(struct gui_download_window *dw,
const char *error_msg)
{
- LOG("%s", error_msg);
+ NSLOG(netsurf, INFO, "%s", error_msg);
strncpy((char*)&dw->lbl_file, error_msg, MAX_SLEN_LBL_FILE-1);
dw->status = NSATARI_DOWNLOAD_ERROR;
@@ -416,7 +418,7 @@ static void gui_download_window_error(struct gui_download_window *dw,
static void gui_download_window_done(struct gui_download_window *dw)
{
- LOG("dw %p", dw);
+ NSLOG(netsurf, INFO, "dw %p", dw);
// TODO: change abort to close
dw->status = NSATARI_DOWNLOAD_COMPLETE;
diff --git a/frontends/atari/filetype.c b/frontends/atari/filetype.c
index d27076e9c..706347137 100644
--- a/frontends/atari/filetype.c
+++ b/frontends/atari/filetype.c
@@ -36,7 +36,7 @@ const char *fetch_filetype(const char *unix_path)
char * res = (char*)"text/html";
l = strlen(unix_path);
- LOG("unix path: %s", unix_path);
+ NSLOG(netsurf, INFO, "unix path: %s", unix_path);
/* This line is added for devlopment versions running from the root dir: */
if( strchr( unix_path, (int)'.' ) ){
@@ -85,6 +85,6 @@ const char *fetch_filetype(const char *unix_path)
}
}
- LOG("mime type: %s", res);
+ NSLOG(netsurf, INFO, "mime type: %s", res);
return( res );
}
diff --git a/frontends/atari/findfile.c b/frontends/atari/findfile.c
index 45ca6d916..8784727bc 100644
--- a/frontends/atari/findfile.c
+++ b/frontends/atari/findfile.c
@@ -31,7 +31,7 @@ char * local_file_to_url( const char * filename )
#define BACKSLASH 0x5C
char * url;
- LOG("in: %s", filename);
+ NSLOG(netsurf, INFO, "in: %s", filename);
if( strlen(filename) <= 2){
return( NULL );
@@ -55,7 +55,7 @@ char * local_file_to_url( const char * filename )
free(fname_local);
- LOG("out: %s", url);
+ NSLOG(netsurf, INFO, "out: %s", url);
return( url );
#undef BACKSLASH
@@ -81,10 +81,10 @@ char * atari_find_resource(char *buf, const char *filename, const char *def)
{
char *cdir = NULL;
char t[PATH_MAX];
- LOG("%s (def: %s)", filename, def);
+ NSLOG(netsurf, INFO, "%s (def: %s)", filename, def);
strcpy(t, NETSURF_GEM_RESPATH);
strcat(t, filename);
- LOG("checking %s", (char *)&t);
+ NSLOG(netsurf, INFO, "checking %s", (char *)&t);
if (gemdos_realpath(t, buf) != NULL) {
if (access(buf, R_OK) == 0) {
return buf;
@@ -92,7 +92,7 @@ char * atari_find_resource(char *buf, const char *filename, const char *def)
}
strcpy(t, "./");
strcat(t, filename);
- LOG("checking %s", (char *)&t);
+ NSLOG(netsurf, INFO, "checking %s", (char *)&t);
if (gemdos_realpath(t, buf) != NULL) {
if (access(buf, R_OK) == 0) {
return buf;
@@ -104,7 +104,7 @@ char * atari_find_resource(char *buf, const char *filename, const char *def)
strcpy(t, cdir);
strcat(t, "/.netsurf/");
strcat(t, filename);
- LOG("checking %s", (char *)&t);
+ NSLOG(netsurf, INFO, "checking %s", (char *)&t);
if (gemdos_realpath(t, buf) != NULL) {
if (access(buf, R_OK) == 0)
return buf;
@@ -116,19 +116,19 @@ char * atari_find_resource(char *buf, const char *filename, const char *def)
if (gemdos_realpath(cdir, buf) != NULL) {
strcat(buf, "/");
strcat(buf, filename);
- LOG("checking %s", (char *)&t);
+ NSLOG(netsurf, INFO, "checking %s", (char *)&t);
if (access(buf, R_OK) == 0)
return buf;
}
}
if (def[0] == '~') {
snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1);
- LOG("checking %s", (char *)&t);
+ NSLOG(netsurf, INFO, "checking %s", (char *)&t);
if (gemdos_realpath(t, buf) == NULL) {
strcpy(buf, t);
}
} else {
- LOG("checking %s", (char *)def);
+ NSLOG(netsurf, INFO, "checking %s", (char *)def);
if (gemdos_realpath(def, buf) == NULL) {
strcpy(buf, def);
}
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index d4a6915cd..6ee63b301 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -39,6 +39,7 @@
#include "netsurf/content.h"
#include "netsurf/cookie_db.h"
#include "netsurf/url_db.h"
+#include "netsurf/plotters.h"
#include "content/backing_store.h"
#include "atari/gemtk/gemtk.h"
@@ -138,11 +139,11 @@ static void atari_poll(void)
evnt_multi_fast(&aes_event_in, aes_msg_out, &aes_event_out);
if(gemtk_wm_dispatch_event(&aes_event_in, &aes_event_out, aes_msg_out) == 0) {
if( (aes_event_out.emo_events & MU_MESAG) != 0 ) {
- LOG("WM: %d\n", aes_msg_out[0]);
+ NSLOG(netsurf, INFO, "WM: %d\n", aes_msg_out[0]);
switch(aes_msg_out[0]) {
case MN_SELECTED:
- LOG("Menu Item: %d\n", aes_msg_out[4]);
+ NSLOG(netsurf, INFO, "Menu Item: %d\n", aes_msg_out[4]);
deskmenu_dispatch_item(aes_msg_out[3], aes_msg_out[4]);
break;
@@ -194,13 +195,14 @@ gui_window_create(struct browser_window *bw,
gui_window_create_flags flags)
{
struct gui_window *gw=NULL;
- LOG("gw: %p, BW: %p, existing %p, flags: %d\n", gw, bw, existing, (int)flags);
+ NSLOG(netsurf, INFO, "gw: %p, BW: %p, existing %p, flags: %d\n", gw, bw,
+ existing, (int)flags);
gw = calloc(1, sizeof(struct gui_window));
if (gw == NULL)
return NULL;
- LOG("new window: %p, bw: %p\n", gw, bw);
+ NSLOG(netsurf, INFO, "new window: %p, bw: %p\n", gw, bw);
window_create(gw, bw, existing, WIDGET_STATUSBAR|WIDGET_TOOLBAR|WIDGET_RESIZE\
|WIDGET_SCROLL);
if (gw->root->win) {
@@ -252,7 +254,7 @@ void gui_window_destroy(struct gui_window *gw)
if (gw == NULL)
return;
- LOG("%s\n", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s\n", __FUNCTION__);
if (input_window == gw) {
gui_set_input_gui_window(NULL);
@@ -292,25 +294,27 @@ void gui_window_destroy(struct gui_window *gw)
}
/**
- * Find the current dimensions of a browser window's content area.
+ * Find the current dimensions of a atari browser window content area.
*
- * \param w gui_window to measure
- * \param width receives width of window
+ * \param gw The gui window to measure content area of.
+ * \param width receives width of window
* \param height receives height of window
* \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated
+ * else error code.
*/
-static void
-gui_window_get_dimensions(struct gui_window *w,
+static nserror
+gui_window_get_dimensions(struct gui_window *gw,
int *width,
int *height,
bool scaled)
{
- if (w == NULL)
- return;
GRECT rect;
- window_get_grect(w->root, BROWSER_AREA_CONTENT, &rect);
+ window_get_grect(gw->root, BROWSER_AREA_CONTENT, &rect);
*width = rect.g_w;
*height = rect.g_h;
+
+ return NSERROR_OK;
}
/**
@@ -374,44 +378,41 @@ void atari_window_set_status(struct gui_window *w, const char *text)
window_set_stauts(w->root, (char*)text);
}
-static void atari_window_reformat(struct gui_window *gw)
+
+/**
+ * Invalidates an area of an atari browser window
+ *
+ * \param gw gui_window
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
+ */
+static nserror
+atari_window_invalidate_area(struct gui_window *gw,
+ const struct rect *rect)
{
- int width = 0, height = 0;
+ GRECT area;
- if (gw != NULL) {
- gui_window_get_dimensions(gw, &width, &height, true);
- browser_window_reformat(gw->browser->bw, false, width, height);
+ if (gw == NULL) {
+ return NSERROR_BAD_PARAMETER;
}
-}
-static void gui_window_redraw_window(struct gui_window *gw)
-{
- //CMP_BROWSER b;
- GRECT rect;
- if (gw == NULL)
- return;
- //b = gw->browser;
- window_get_grect(gw->root, BROWSER_AREA_CONTENT, &rect);
- window_schedule_redraw_grect(gw->root, &rect);
-}
+ window_get_grect(gw->root, BROWSER_AREA_CONTENT, &area);
-static void gui_window_update_box(struct gui_window *gw, const struct rect *rect)
-{
- GRECT area;
- struct gemtk_wm_scroll_info_s *slid;
+ if (rect != NULL) {
+ struct gemtk_wm_scroll_info_s *slid;
- if (gw == NULL)
- return;
+ slid = gemtk_wm_get_scroll_info(gw->root->win);
- slid = gemtk_wm_get_scroll_info(gw->root->win);
+ area.g_x += rect->x0 - (slid->x_pos * slid->x_unit_px);
+ area.g_y += rect->y0 - (slid->y_pos * slid->y_unit_px);
+ area.g_w = rect->x1 - rect->x0;
+ area.g_h = rect->y1 - rect->y0;
+ }
- window_get_grect(gw->root, BROWSER_AREA_CONTENT, &area);
- area.g_x += rect->x0 - (slid->x_pos * slid->x_unit_px);
- area.g_y += rect->y0 - (slid->y_pos * slid->y_unit_px);
- area.g_w = rect->x1 - rect->x0;
- area.g_h = rect->y1 - rect->y0;
//dbg_grect("update box", &area);
window_schedule_redraw_grect(gw->root, &area);
+
+ return NSERROR_OK;
}
bool gui_window_get_scroll(struct gui_window *w, int *sx, int *sy)
@@ -424,17 +425,31 @@ bool gui_window_get_scroll(struct gui_window *w, int *sx, int *sy)
return( true );
}
-static void gui_window_set_scroll(struct gui_window *w, int sx, int sy)
+/**
+ * Set the scroll position of a atari browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The atari implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param gw gui window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *gw, const struct rect *rect)
{
- if ( (w == NULL)
- || (w->browser->bw == NULL)
- || (!browser_window_has_content(w->browser->bw)))
- return;
+ if ((gw == NULL) ||
+ (gw->browser->bw == NULL) ||
+ (!browser_window_has_content(gw->browser->bw))) {
+ return NSERROR_BAD_PARAMETER;
+ }
- LOG("scroll (gui_window: %p) %d, %d\n", w, sx, sy);
- window_scroll_by(w->root, sx, sy);
- return;
+ NSLOG(netsurf, INFO, "scroll (gui_window: %p) %d, %d\n", gw, rect->x0,
+ rect->y0);
+ window_scroll_by(gw->root, rect->x0, rect->y0);
+ return NSERROR_OK;
}
/**
@@ -679,7 +694,7 @@ static void gui_window_new_content(struct gui_window *w)
slid->x_pos = 0;
slid->y_pos = 0;
gemtk_wm_update_slider(w->root->win, GEMTK_WM_VH_SLIDER);
- gui_window_redraw_window(w);
+ atari_window_invalidate_area(w, NULL);
}
@@ -758,7 +773,8 @@ static void gui_401login_open(nsurl *url, const char *realm,
char * out = NULL;
bres = login_form_do( url, (char*)realm, &out);
if (bres) {
- LOG("url: %s, realm: %s, auth: %s\n", nsurl_access(url), realm, out);
+ NSLOG(netsurf, INFO, "url: %s, realm: %s, auth: %s\n",
+ nsurl_access(url), realm, out);
urldb_set_auth_details(url, realm, out);
}
if (out != NULL) {
@@ -776,7 +792,7 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
void *cbpw)
{
struct sslcert_session_data *data;
- LOG("url %s", nsurl_access(url));
+ NSLOG(netsurf, INFO, "url %s", nsurl_access(url));
// TODO: localize string
int b = form_alert(1, "[2][SSL Verify failed, continue?][Continue|Abort|Details...]");
@@ -799,7 +815,8 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
void gui_set_input_gui_window(struct gui_window *gw)
{
- LOG("Setting input window from: %p to %p\n", input_window, gw);
+ NSLOG(netsurf, INFO, "Setting input window from: %p to %p\n",
+ input_window, gw);
input_window = gw;
}
@@ -810,7 +827,7 @@ struct gui_window * gui_get_input_window(void)
static void gui_quit(void)
{
- LOG("quitting");
+ NSLOG(netsurf, INFO, "quitting");
struct gui_window *gw = window_list;
struct gui_window *tmp = window_list;
@@ -839,9 +856,9 @@ static void gui_quit(void)
rsrc_free();
- LOG("Shutting down plotter");
+ NSLOG(netsurf, INFO, "Shutting down plotter");
plot_finalise();
- LOG("done");
+ NSLOG(netsurf, INFO, "done");
}
/**
@@ -853,7 +870,7 @@ process_cmdline(int argc, char** argv)
int opt;
bool set_default_dimensions = true;
- LOG("argc %d, argv %p", argc, argv);
+ NSLOG(netsurf, INFO, "argc %d, argv %p", argc, argv);
if ((nsoption_int(window_width) != 0) && (nsoption_int(window_height) != 0)) {
@@ -946,7 +963,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
/* Set defaults for absent option strings */
nsoption_setnull_charp(cookie_file, strdup("cookies"));
if (nsoption_charp(cookie_file) == NULL) {
- LOG("Failed initialising string options");
+ NSLOG(netsurf, INFO, "Failed initialising string options");
return NSERROR_BAD_PARAMETER;
}
return NSERROR_OK;
@@ -963,7 +980,7 @@ static void gui_init(int argc, char** argv)
OBJECT * cursors;
atari_find_resource(buf, "netsurf.rsc", "./res/netsurf.rsc");
- LOG("Using RSC file: %s ", (char *)&buf);
+ NSLOG(netsurf, INFO, "Using RSC file: %s ", (char *)&buf);
if (rsrc_load(buf)==0) {
char msg[1024];
@@ -999,15 +1016,16 @@ static void gui_init(int argc, char** argv)
create_cursor(MFORM_EX_FLAG_USERFORM, CURSOR_HELP,
cursors, &gem_cursors.help);
- LOG("Enabling core select menu");
+ NSLOG(netsurf, INFO, "Enabling core select menu");
nsoption_set_bool(core_select_menu, true);
- LOG("Loading url.db from: %s", nsoption_charp(url_file));
+ NSLOG(netsurf, INFO, "Loading url.db from: %s", nsoption_charp(url_file));
if( strlen(nsoption_charp(url_file)) ) {
urldb_load(nsoption_charp(url_file));
}
- LOG("Loading cookies from: %s", nsoption_charp(cookie_file));
+ NSLOG(netsurf, INFO, "Loading cookies from: %s",
+ nsoption_charp(cookie_file));
if( strlen(nsoption_charp(cookie_file)) ) {
urldb_load_cookies(nsoption_charp(cookie_file));
}
@@ -1015,11 +1033,16 @@ static void gui_init(int argc, char** argv)
if (process_cmdline(argc,argv) != true)
die("unable to process command line.\n");
- LOG("Initializing NKC...");
+ NSLOG(netsurf, INFO, "Initializing NKC...");
nkc_init();
- LOG("Initializing plotters...");
- plot_init(nsoption_charp(atari_font_driver));
+ NSLOG(netsurf, INFO, "Initializing plotters...");
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &atari_plotters
+ };
+ plot_init(&ctx, nsoption_charp(atari_font_driver));
aes_event_in.emi_m1leave = MO_LEAVE;
aes_event_in.emi_m1.g_w = 1;
@@ -1045,13 +1068,11 @@ static void gui_init(int argc, char** argv)
static struct gui_window_table atari_window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
+ .invalidate = atari_window_invalidate_area,
.get_scroll = gui_window_get_scroll,
.set_scroll = gui_window_set_scroll,
.get_dimensions = gui_window_get_dimensions,
.update_extent = gui_window_update_extent,
- .reformat = atari_window_reformat,
.set_title = gui_window_set_title,
.set_url = gui_window_set_url,
@@ -1156,18 +1177,18 @@ int main(int argc, char** argv)
ret = messages_add_from_file(messages);
/* common initialisation */
- LOG("Initialising core...");
+ NSLOG(netsurf, INFO, "Initialising core...");
ret = netsurf_init(store);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
- LOG("Initializing GUI...");
+ NSLOG(netsurf, INFO, "Initializing GUI...");
gui_init(argc, argv);
graf_mouse( ARROW , NULL);
- LOG("Creating initial browser window...");
+ NSLOG(netsurf, INFO, "Creating initial browser window...");
addr = option_homepage_url;
if (strncmp(addr, "file://", 7) && strncmp(addr, "http://", 7)) {
if (stat(addr, &stat_buf) == 0) {
@@ -1189,7 +1210,7 @@ int main(int argc, char** argv)
if (ret != NSERROR_OK) {
atari_warn_user(messages_get_errorcode(ret), 0);
} else {
- LOG("Entering Atari event mainloop...");
+ NSLOG(netsurf, INFO, "Entering Atari event mainloop...");
while (!atari_quit) {
atari_poll();
}
@@ -1203,7 +1224,11 @@ int main(int argc, char** argv)
fclose(stdout);
fclose(stderr);
#endif
- LOG("exit_gem");
+ NSLOG(netsurf, INFO, "exit_gem");
+
+ /* finalise logging */
+ nslog_finalise();
+
exit_gem();
return 0;
diff --git a/frontends/atari/history.c b/frontends/atari/history.c
index 56aafd056..ec602684f 100644
--- a/frontends/atari/history.c
+++ b/frontends/atari/history.c
@@ -39,13 +39,13 @@ static nserror
atari_global_history_init_phase2(struct core_window *cw,
struct core_window_callback_table *cb_t)
{
- LOG("cw %p", cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
return(global_history_init(cb_t, cw));
}
static void atari_global_history_finish(struct core_window *cw)
{
- LOG("cw %p", cw);
+ NSLOG(netsurf, INFO, "cw %p", cw);
global_history_fini();
}
@@ -58,7 +58,7 @@ static void atari_global_history_draw(struct core_window *cw, int x,
static void atari_global_history_keypress(struct core_window *cw, uint32_t ucs4)
{
- LOG("ucs4: %"PRIu32, ucs4);
+ NSLOG(netsurf, INFO, "ucs4: %"PRIu32, ucs4);
global_history_keypress(ucs4);
}
@@ -67,7 +67,7 @@ atari_global_history_mouse_action(struct core_window *cw,
browser_mouse_state mouse,
int x, int y)
{
- LOG("x: %d, y: %d\n", x, y);
+ NSLOG(netsurf, INFO, "x: %d, y: %d\n", x, y);
global_history_mouse_action(mouse, x, y);
}
@@ -82,7 +82,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
{
short retval = 0;
- LOG("win %p", win);
+ NSLOG(netsurf, INFO, "win %p", win);
if (ev_out->emo_events & MU_MESAG) {
switch (msg[0]) {
@@ -134,7 +134,8 @@ void atari_global_history_init(void)
if (atari_global_history.tv == NULL) {
/* handle it properly, clean up previous allocs */
- LOG("Failed to allocate treeview");
+ NSLOG(netsurf, INFO,
+ "Failed to allocate treeview");
return;
}
}
@@ -181,7 +182,7 @@ void atari_global_history_destroy(void)
atari_treeview_delete(atari_global_history.tv);
atari_global_history.init = false;
}
- LOG("done");
+ NSLOG(netsurf, INFO, "done");
}
void atari_global_history_redraw(void)
diff --git a/frontends/atari/hotlist.c b/frontends/atari/hotlist.c
index da599161b..3a54c98eb 100644
--- a/frontends/atari/hotlist.c
+++ b/frontends/atari/hotlist.c
@@ -72,14 +72,14 @@ static struct atari_treeview_callbacks atari_hotlist_treeview_callbacks = {
static nserror atari_hotlist_init_phase2(struct core_window *cw,
struct core_window_callback_table *cb_t)
{
- LOG("cw:%p", cw);
+ NSLOG(netsurf, INFO, "cw:%p", cw);
return hotlist_manager_init(cb_t, cw);
}
static void atari_hotlist_finish(struct core_window *cw)
{
- LOG("cw:%p", cw);
- hotlist_fini(hl.path);
+ NSLOG(netsurf, INFO, "cw:%p", cw);
+ hotlist_fini();
}
static void atari_hotlist_draw(struct core_window *cw, int x,
@@ -93,7 +93,7 @@ static void atari_hotlist_keypress(struct core_window *cw, uint32_t ucs4)
{
//GUIWIN *gemtk_win;
//GRECT area;
- LOG("ucs4: %"PRIu32 , ucs4);
+ NSLOG(netsurf, INFO, "ucs4: %"PRIu32, ucs4);
hotlist_keypress(ucs4);
//gemtk_win = atari_treeview_get_gemtk_window(cw);
//atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
@@ -104,7 +104,7 @@ static void atari_hotlist_mouse_action(struct core_window *cw,
browser_mouse_state mouse,
int x, int y)
{
- LOG("x: %d, y: %d\n", x, y);
+ NSLOG(netsurf, INFO, "x: %d, y: %d\n", x, y);
hotlist_mouse_action(mouse, x, y);
}
@@ -123,7 +123,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
GRECT tb_area;
GUIWIN * gemtk_win;
- LOG("gw:%p", win);
+ NSLOG(netsurf, INFO, "gw:%p", win);
tv = (struct atari_treeview_window*) gemtk_wm_get_user_data(win);
cw = (struct core_window *)tv;
@@ -132,7 +132,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
switch (msg[0]) {
case WM_TOOLBAR:
- LOG("WM_TOOLBAR");
+ NSLOG(netsurf, INFO, "WM_TOOLBAR");
toolbar = gemtk_obj_get_tree(TOOLBAR_HOTLIST);
@@ -198,8 +198,8 @@ void atari_hotlist_init(void)
strncpy( (char*)&hl.path, nsoption_charp(hotlist_file), PATH_MAX-1 );
}
- LOG("Hotlist: %s", (char *)&hl.path);
- hotlist_init(hl.path);
+ NSLOG(netsurf, INFO, "Hotlist: %s", (char *)&hl.path);
+ hotlist_init(hl.path, hl.path);
if( hl.window == NULL ){
int flags = ATARI_TREEVIEW_WIDGETS;
@@ -224,7 +224,8 @@ void atari_hotlist_init(void)
if (hl.tv == NULL) {
/* handle it properly, clean up previous allocs */
- LOG("Failed to allocate treeview");
+ NSLOG(netsurf, INFO,
+ "Failed to allocate treeview");
return;
}
@@ -276,7 +277,7 @@ void atari_hotlist_destroy(void)
atari_treeview_delete(hl.tv);
hl.init = false;
}
- LOG("done");
+ NSLOG(netsurf, INFO, "done");
}
void atari_hotlist_redraw(void)
@@ -299,7 +300,7 @@ void atari_hotlist_add_page( const char * url, const char * title )
return;
if (hotlist_has_url(nsurl)) {
- LOG("URL already added as Bookmark");
+ NSLOG(netsurf, INFO, "URL already added as Bookmark");
nsurl_unref(nsurl);
return;
}
diff --git a/frontends/atari/misc.h b/frontends/atari/misc.h
index e581c23b2..05fd1aeef 100644
--- a/frontends/atari/misc.h
+++ b/frontends/atari/misc.h
@@ -31,10 +31,12 @@
lbuf[7] = (long)sbuf[7];
#define RECT_TO_GRECT(r,g) \
- (g)->g_x = (r->x0 < r->x1) ? r->x0 : r->x1 ; \
- (g)->g_y = (r->y0 < r->y1) ? r->y0 : r->y1 ; \
- (g)->g_w = (r->x0 < r->x1) ? r->x1 - r->x0 : r->x0 - r->x1 ; \
- (g)->g_h = (r->y0 < r->y1) ? r->y1 - r->y0 : r->y0 - r->y1 ;
+ do { \
+ (g)->g_x = (r->x0 < r->x1) ? r->x0 : r->x1 ; \
+ (g)->g_y = (r->y0 < r->y1) ? r->y0 : r->y1 ; \
+ (g)->g_w = (r->x0 < r->x1) ? r->x1 - r->x0 : r->x0 - r->x1 ; \
+ (g)->g_h = (r->y0 < r->y1) ? r->y1 - r->y0 : r->y0 - r->y1 ; \
+ } while(0)
diff --git a/frontends/atari/osspec.c b/frontends/atari/osspec.c
index f64402e8d..ca042f164 100644
--- a/frontends/atari/osspec.c
+++ b/frontends/atari/osspec.c
@@ -119,14 +119,14 @@ char *gemdos_realpath(const char * path, char * rpath)
return(rpath);
}
- LOG("realpath in: %s\n", path);
+ NSLOG(netsurf, INFO, "realpath in: %s\n", path);
r = realpath(path, work);
if (r != NULL) {
unx2dos((const char *)r, rpath);
- LOG("realpath out: %s\n", rpath);
+ NSLOG(netsurf, INFO, "realpath out: %s\n", rpath);
return(rpath);
} else {
- LOG("realpath out: NULL!\n");
+ NSLOG(netsurf, INFO, "realpath out: NULL!\n");
}
return (NULL);
}
diff --git a/frontends/atari/plot/font_freetype.c b/frontends/atari/plot/font_freetype.c
index 17d3c3bfd..f8109f6f2 100644
--- a/frontends/atari/plot/font_freetype.c
+++ b/frontends/atari/plot/font_freetype.c
@@ -154,11 +154,12 @@ static FT_Error ft_face_requester(FTC_FaceID face_id, FT_Library library, FT_Po
error = FT_New_Face(library, ft_face->fontfile, ft_face->index, face);
if (error) {
- LOG("Could not find font (code %d)\n", error);
+ NSLOG(netsurf, INFO, "Could not find font (code %d)\n", error);
} else {
error = FT_Select_Charmap(*face, FT_ENCODING_UNICODE);
if (error) {
- LOG("Could not select charmap (code %d)\n", error);
+ NSLOG(netsurf, INFO,
+ "Could not select charmap (code %d)\n", error);
} else {
for (cidx = 0; cidx < (*face)->num_charmaps; cidx++) {
if ((*face)->charmap == (*face)->charmaps[cidx]) {
@@ -168,7 +169,7 @@ static FT_Error ft_face_requester(FTC_FaceID face_id, FT_Library library, FT_Po
}
}
}
- LOG("Loaded face from %s\n", ft_face->fontfile);
+ NSLOG(netsurf, INFO, "Loaded face from %s\n", ft_face->fontfile);
return error;
}
@@ -190,7 +191,9 @@ ft_new_face(const char *option, const char *resname, const char *fontfile)
}
error = FTC_Manager_LookupFace(ft_cmanager, (FTC_FaceID)newf, &aface);
if (error) {
- LOG("Could not find font face %s (code %d)\n", fontfile, error);
+ NSLOG(netsurf, INFO,
+ "Could not find font face %s (code %d)\n", fontfile,
+ error);
free(newf);
newf = font_faces[FONT_FACE_DEFAULT]; /* use default */
}
@@ -247,7 +250,7 @@ static void ft_fill_scalar(const plot_font_style_t *fstyle, FTC_Scaler srec)
srec->face_id = (FTC_FaceID)font_faces[selected_face];
- srec->width = srec->height = (fstyle->size * 64) / FONT_SIZE_SCALE;
+ srec->width = srec->height = (fstyle->size * 64) / PLOT_STYLE_SCALE;
srec->pixel = 0;
/* calculate x/y resolution, when browser_get_dpi() isn't available */
@@ -292,7 +295,8 @@ static bool ft_font_init(void)
/* freetype library initialise */
error = FT_Init_FreeType( &library );
if (error) {
- LOG("Freetype could not initialised (code %d)\n", error);
+ NSLOG(netsurf, INFO,
+ "Freetype could not initialised (code %d)\n", error);
return false;
}
@@ -311,7 +315,9 @@ static bool ft_font_init(void)
NULL,
&ft_cmanager);
if (error) {
- LOG("Freetype could not initialise cache manager (code %d)\n", error);
+ NSLOG(netsurf, INFO,
+ "Freetype could not initialise cache manager (code %d)\n",
+ error);
FT_Done_FreeType(library);
return false;
}
@@ -330,7 +336,8 @@ static bool ft_font_init(void)
FONT_PKG_PATH FONT_FILE_SANS
);
if (font_faces[FONT_FACE_SANS_SERIF] == NULL) {
- LOG("Could not find default font (code %d)\n", error);
+ NSLOG(netsurf, INFO,
+ "Could not find default font (code %d)\n", error);
FTC_Manager_Done(ft_cmanager);
FT_Done_FreeType(library);
return false;
@@ -688,7 +695,7 @@ int ctor_font_plotter_freetype( FONT_PLOTTER self )
self->draw_glyph = draw_glyph8;
}
- LOG("%s: %s\n", (char *)__FILE__, __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s: %s\n", (char *)__FILE__, __FUNCTION__);
if( !init ) {
ft_font_init();
fontbmp = atari_bitmap_create(48, 48, 0);
diff --git a/frontends/atari/plot/font_internal.c b/frontends/atari/plot/font_internal.c
index 3575bc3e1..709697f74 100644
--- a/frontends/atari/plot/font_internal.c
+++ b/frontends/atari/plot/font_internal.c
@@ -96,7 +96,7 @@ int ctor_font_plotter_internal( FONT_PLOTTER self )
self->str_split = str_split;
self->pixel_pos = pixel_pos;
self->text = text;
- LOG("%s: %s\n", (char *)__FILE__, __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s: %s\n", (char *)__FILE__, __FUNCTION__);
if( !init ) {
vdih = self->vdi_handle;
fontbmp = atari_bitmap_create(48, 48, 0);
diff --git a/frontends/atari/plot/font_vdi.c b/frontends/atari/plot/font_vdi.c
index ef5499207..556c08e82 100644
--- a/frontends/atari/plot/font_vdi.c
+++ b/frontends/atari/plot/font_vdi.c
@@ -70,7 +70,7 @@ int ctor_font_plotter_vdi( FONT_PLOTTER self )
self->str_split = str_split;
self->pixel_pos = pixel_pos;
self->text = text;
- LOG("%s: %s\n", (char *)__FILE__, __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s: %s\n", (char *)__FILE__, __FUNCTION__);
if( !init ) {
vdih = self->vdi_handle;
}
@@ -106,9 +106,9 @@ static int str_width( FONT_PLOTTER self,const plot_font_style_t *fstyle, const c
fx |= 1;
vst_effects( self->vdi_handle, fx );
/* TODO: replace 90 with global dpi setting */
- //pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 / 72 );
+ //pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 / 72 );
//vst_height( self->vdi_handle, pxsize ,&cw, &ch, &cellw, &cellh);
- pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 );
+ pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 );
vst_point( self->vdi_handle, pxsize, &cw, &ch, &cellw, &cellh);
/*
if(slen != utf8_bounded_length(str, length)){
@@ -148,10 +148,10 @@ static int str_split( FONT_PLOTTER self, const plot_font_style_t * fstyle, const
if( fstyle->weight > 450 )
fx |= 1;
vst_effects( self->vdi_handle, fx );
- //pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 / 72 );
+ //pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 / 72 );
//vst_height( self->vdi_handle, pxsize ,&cw, &ch, &cellw, &cellh);
- pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 );
+ pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 );
vst_point( self->vdi_handle, pxsize, &cw, &ch, &cellw, &cellh);
*actual_x = 0;
//*char_offset = 0;
@@ -216,7 +216,7 @@ static int pixel_pos( FONT_PLOTTER self, const plot_font_style_t * fstyle,const
if( fstyle->weight > 450 )
fx |= 1;
vst_effects(self->vdi_handle, fx);
- pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 / 72 );
+ pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 / 72 );
vst_height( self->vdi_handle, pxsize ,&cw, &ch, &cellw, &cellh);
*actual_x = 0;
*char_offset = 0;
@@ -283,8 +283,8 @@ static int text( FONT_PLOTTER self, int x, int y, const char *text, size_t leng
/* TODO: netsurf uses 90 as default dpi ( somewhere defined in libcss),
use that value or pass it as arg, to reduce netsurf dependency */
- //pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 / 72 );
- pxsize = ceil( (fstyle->size/FONT_SIZE_SCALE) * 90 / 72 );
+ //pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 / 72 );
+ pxsize = ceil( (fstyle->size/PLOT_STYLE_SCALE) * 90 / 72 );
plot_get_dimensions(&canvas);
x += canvas.g_x;
diff --git a/frontends/atari/plot/plot.c b/frontends/atari/plot/plot.c
index 0a0d7a494..4935b1776 100644
--- a/frontends/atari/plot/plot.c
+++ b/frontends/atari/plot/plot.c
@@ -45,38 +45,31 @@
void vq_scrninfo(VdiHdl handle, short *work_out);
struct s_view {
- short x; /* drawing (screen) offset x */
- short y; /* drawing (screen) offset y */
- short w; /* width of buffer, not in sync with vis_w */
- short h; /* height of buffer, not in sync with vis_w */
- short vis_x; /* visible rectangle of the screen buffer */
- short vis_y; /* coords are relative to plot location */
- short vis_w; /* clipped to screen dimensions */
- short vis_h; /* visible width */
- struct rect abs_clipping; /* The toplevel clipping rectangle */
- struct rect clipping; /* actual clipping rectangle */
+ short x; /**< drawing (screen) offset x */
+ short y; /**< drawing (screen) offset y */
+ short w; /**< width of buffer, not in sync with vis_w */
+ short h; /**< height of buffer, not in sync with vis_w */
+ short vis_x; /**< visible rectangle of the screen buffer */
+ short vis_y; /**< coords are relative to plot location */
+ short vis_w; /**< clipped to screen dimensions */
+ short vis_h; /**< visible width */
+ struct rect abs_clipping; /**< The toplevel clipping rectangle */
+ struct rect clipping; /**< actual clipping rectangle */
float scale;
};
-/*
- * Capture the screen at x,y location
- * param self instance
- * param x absolute screen coords
- * param y absolute screen coords
- * param w width
- * param h height
- *
- * This creates an snapshot in RGBA format (NetSurf's native format)
+/**
+ * Garbage collection of the snapshot routine
*
+ * this should be called after you are done with the data returned by
+ * snapshot_create don't access the screenshot after you called this
+ * function
*/
-static struct bitmap * snapshot_create(int x, int y, int w, int h);
-
-/* Garbage collection of the snapshot routine */
-/* this should be called after you are done with the data returned by snapshot_create */
-/* don't access the screenshot after you called this function */
static void snapshot_suspend(void);
-/* destroy memory used by screenshot */
+/**
+ * destroy memory used by screenshot
+ */
static void snapshot_destroy(void);
#ifdef WITH_8BPP_SUPPORT
@@ -86,42 +79,78 @@ static char rgb_lookup[256][4];
short web_std_colors[6] = {0, 51, 102, 153, 204, 255};
unsigned short vdi_web_pal[216][3] = {
- {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000}, {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000},
- {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000}, {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000},
- {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000}, {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000},
- {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000}, {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000},
- {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000}, {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000},
- {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000}, {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000},
- {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8}, {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8},
- {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8}, {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8},
- {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8}, {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8},
- {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8}, {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8},
- {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8}, {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8},
- {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8}, {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8},
- {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190}, {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190},
- {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190}, {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190},
- {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190}, {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190},
- {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190}, {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190},
- {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190}, {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190},
- {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190}, {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190},
- {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258}, {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258},
- {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258}, {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258},
- {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258}, {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258},
- {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258}, {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258},
- {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258}, {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258},
- {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258}, {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258},
- {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320}, {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320},
- {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320}, {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320},
- {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320}, {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320},
- {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320}, {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320},
- {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320}, {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320},
- {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320}, {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320},
- {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8}, {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8},
- {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8}, {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8},
- {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8}, {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8},
- {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8}, {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8},
- {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8}, {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8},
- {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8}, {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8}
+ {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000},
+ {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000},
+ {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000},
+ {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000},
+ {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000},
+ {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000},
+ {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000},
+ {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000},
+ {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000},
+ {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000},
+ {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000},
+ {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000},
+ {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8},
+ {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8},
+ {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8},
+ {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8},
+ {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8},
+ {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8},
+ {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8},
+ {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8},
+ {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8},
+ {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8},
+ {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8},
+ {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8},
+ {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190},
+ {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190},
+ {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190},
+ {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190},
+ {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190},
+ {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190},
+ {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190},
+ {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190},
+ {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190},
+ {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190},
+ {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190},
+ {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190},
+ {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258},
+ {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258},
+ {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258},
+ {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258},
+ {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258},
+ {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258},
+ {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258},
+ {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258},
+ {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258},
+ {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258},
+ {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258},
+ {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258},
+ {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320},
+ {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320},
+ {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320},
+ {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320},
+ {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320},
+ {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320},
+ {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320},
+ {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320},
+ {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320},
+ {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320},
+ {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320},
+ {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320},
+ {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8},
+ {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8},
+ {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8},
+ {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8},
+ {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8},
+ {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8},
+ {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8},
+ {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8},
+ {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8},
+ {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8},
+ {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8},
+ {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8}
};
#endif
@@ -180,15 +209,16 @@ VdiHdl atari_plot_vdi_handle = -1;
unsigned long atari_plot_flags;
unsigned long atari_font_flags;
-typedef bool (*bitmap_convert_fnc)( struct bitmap * img, int x, int y,
- GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out );
+typedef bool (*bitmap_convert_fnc)(struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out );
static bitmap_convert_fnc bitmap_convert;
+/* exported interface documented in atari/plot.h */
const char* plot_err_str(int i)
{
- return(plot_error_codes[abs(i)]);
+ return (plot_error_codes[abs(i)]);
}
+
/**
* Set line drawing color by passing netsurf XBGR "colour" type.
*
@@ -200,21 +230,22 @@ inline static void vsl_rgbcolor(short vdih, colour cin)
#ifdef WITH_8BPP_SUPPORT
if( vdi_sysinfo.scr_bpp > 8 ) {
#endif
- RGB1000 c; /* a struct with three (RGB) shorts */
- rgb_to_vdi1000( (unsigned char*)&cin, &c);
- vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
- vsl_color(vdih, OFFSET_CUSTOM_COLOR);
+ RGB1000 c; /* a struct with three (RGB) shorts */
+ rgb_to_vdi1000( (unsigned char*)&cin, &c);
+ vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
+ vsl_color(vdih, OFFSET_CUSTOM_COLOR);
#ifdef WITH_8BPP_SUPPORT
} else {
- if( vdi_sysinfo.scr_bpp >= 4 ){
- vsl_color(vdih, RGB_TO_VDI(cin));
- }
- else
- vsl_color(vdih, BLACK);
+ if( vdi_sysinfo.scr_bpp >= 4 ){
+ vsl_color(vdih, RGB_TO_VDI(cin));
+ }
+ else
+ vsl_color(vdih, BLACK);
}
#endif
}
+
/**
* Set fill color by passing netsurf XBGR "colour" type.
*
@@ -226,23 +257,22 @@ inline static void vsf_rgbcolor(short vdih, colour cin)
#ifdef WITH_8BPP_SUPPORT
if( vdi_sysinfo.scr_bpp > 8 ) {
#endif
- RGB1000 c; /* a struct with three (RGB) shorts */
- rgb_to_vdi1000( (unsigned char*)&cin, &c);
- vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
- vsf_color( vdih, OFFSET_CUSTOM_COLOR );
+ RGB1000 c; /* a struct with three (RGB) shorts */
+ rgb_to_vdi1000( (unsigned char*)&cin, &c);
+ vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
+ vsf_color( vdih, OFFSET_CUSTOM_COLOR );
#ifdef WITH_8BPP_SUPPORT
} else {
- if( vdi_sysinfo.scr_bpp >= 4 ){
- vsf_color( vdih, RGB_TO_VDI(cin) );
- }
- else
- vsf_color( vdih, WHITE );
+ if( vdi_sysinfo.scr_bpp >= 4 ){
+ vsf_color( vdih, RGB_TO_VDI(cin) );
+ }
+ else
+ vsf_color( vdih, WHITE );
}
#endif
}
-
/**
* Get current visible coords
*/
@@ -255,7 +285,6 @@ inline static void plot_get_visible_grect(GRECT * out)
}
-
/* calculate visible area of framebuffer in coords relative to framebuffer */
/* position */
/* result: */
@@ -280,24 +309,29 @@ inline static void update_visible_rect(void)
common.g_h = frame.g_h = view.h;
if (rc_intersect(&screen, &common)) {
- view.vis_w = common.g_w;
- view.vis_h = common.g_h;
- if (view.x < screen.g_x)
- view.vis_x = frame.g_w - common.g_w;
- else
- view.vis_x = 0;
- if (view.y <screen.g_y)
- view.vis_y = frame.g_h - common.g_h;
- else
- view.vis_y = 0;
+ view.vis_w = common.g_w;
+ view.vis_h = common.g_h;
+ if (view.x < screen.g_x)
+ view.vis_x = frame.g_w - common.g_w;
+ else
+ view.vis_x = 0;
+ if (view.y <screen.g_y)
+ view.vis_y = frame.g_h - common.g_h;
+ else
+ view.vis_y = 0;
} else {
- view.vis_w = view.vis_h = 0;
- view.vis_x = view.vis_y = 0;
+ view.vis_w = view.vis_h = 0;
+ view.vis_x = view.vis_y = 0;
}
}
-/* Returns the visible parts of the box (relative coords within framebuffer),*/
-/* relative to screen coords (normally starting at 0,0 ) */
+
+/**
+ * Returns the visible parts of the box
+ *
+ * The returned values are relative coords within framebuffer,
+ * relative to screen coords (normally starting at 0,0 )
+ */
inline static bool fbrect_to_screen(GRECT box, GRECT * ret)
{
GRECT out, vis, screen;
@@ -314,14 +348,14 @@ inline static bool fbrect_to_screen(GRECT box, GRECT * ret)
vis.g_h = view.h;
if ( !rc_intersect( &screen, &vis ) ) {
- return( false );
+ return( false );
}
vis.g_x = view.w - vis.g_w;
vis.g_y = view.h - vis.g_h;
/* clip box to visible region: */
if( !rc_intersect(&vis, &box) ) {
- return( false );
+ return( false );
}
out.g_x = box.g_x + view.x;
out.g_y = box.g_y + view.y;
@@ -331,8 +365,12 @@ inline static bool fbrect_to_screen(GRECT box, GRECT * ret)
return ( true );
}
-/* copy an rectangle from the plot buffer to screen */
-/* because this is an on-screen plotter, this is an screen to screen copy. */
+
+/**
+ * copy an rectangle from the plot buffer to screen
+ *
+ * because this is an on-screen plotter, this is an screen to screen copy.
+ */
bool plot_copy_rect(GRECT src, GRECT dst)
{
MFDB devmf;
@@ -344,9 +382,9 @@ bool plot_copy_rect(GRECT src, GRECT dst)
plot_get_visible_grect(&vis );
if( !rc_intersect(&vis, &src) )
- return(true);
+ return(true);
if( !rc_intersect(&vis, &dst) )
- return(true);
+ return(true);
src.g_x = view.x + src.g_x;
src.g_y = view.y + src.g_y;
@@ -384,23 +422,25 @@ bool plot_copy_rect(GRECT src, GRECT dst)
return(true);
}
+
/**
* Fill the screen info structure.
*
* \param vdih The handle
* \param[out] info The infor structure to fill.
*/
-static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) {
-
- unsigned long cookie_EdDI=0; /** \todo this long is being cast to a pointer */
+static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info)
+{
+ /** \todo this long is being cast to a pointer */
+ unsigned long cookie_EdDI=0;
short out[300];
memset( info, 0, sizeof(struct s_vdi_sysinfo) );
info->vdi_handle = vdih;
if ( tos_getcookie(C_EdDI, (long *)&cookie_EdDI) == C_NOTFOUND ) {
- info->EdDiVersion = 0;
+ info->EdDiVersion = 0;
} else {
- info->EdDiVersion = EdDI_version( (void *)cookie_EdDI );
+ info->EdDiVersion = EdDI_version( (void *)cookie_EdDI );
}
memset( &out, 0, sizeof(short)*300 );
@@ -408,10 +448,10 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) {
info->scr_w = out[0]+1;
info->scr_h = out[1]+1;
if( out[39] == 2 ) {
- info->scr_bpp = 1;
- info->colors = out[39];
+ info->scr_bpp = 1;
+ info->colors = out[39];
} else {
- info->colors = out[39];
+ info->colors = out[39];
}
memset( &out, 0, sizeof(short)*300 );
@@ -420,31 +460,31 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) {
info->maxpolycoords = out[14];
info->maxintin = out[15];
if( out[30] & 1 ) {
- info->rasterscale = true;
+ info->rasterscale = true;
} else {
- info->rasterscale = false;
+ info->rasterscale = false;
}
switch( info->scr_bpp ) {
case 8:
- info->pixelsize=1;
- break;
+ info->pixelsize=1;
+ break;
case 15:
case 16:
- info->pixelsize=2;
- break;
+ info->pixelsize=2;
+ break;
case 24:
- info->pixelsize=3;
- break;
+ info->pixelsize=3;
+ break;
case 32:
- info->pixelsize=4;
- break;
+ info->pixelsize=4;
+ break;
case 64:
- info->pixelsize=8;
- break;
+ info->pixelsize=8;
+ break;
default:
- info->pixelsize=1;
- break;
+ info->pixelsize=1;
+ break;
}
info->pitch = info->scr_w * info->pixelsize;
@@ -452,75 +492,75 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) {
info->screensize = ( info->scr_w * info->pixelsize ) * info->scr_h;
if( info->EdDiVersion >= EDDI_10 ) {
- memset( &out, 0, sizeof(short)*300 );
- vq_scrninfo(vdih, (short*)&out);
- info->vdiformat = out[0];
- info->clut = out[1];
- info->scr_bpp = out[2];
- info->hicolors = *((unsigned long*) &out[3]);
- if( info->EdDiVersion >= EDDI_11 ) {
- info->pitch = out[5];
- info->screen = (void *) *((unsigned long *) &out[6]);
- }
-
- switch( info->clut ) {
-
- case VDI_CLUT_HARDWARE: {
-
- }
- break;
-
- case VDI_CLUT_SOFTWARE: {
- int component; /* red, green, blue, alpha, overlay */
- int num_bit;
- unsigned short *tmp_p;
-
- /* We can build masks with info here */
- tmp_p = (unsigned short *) &out[16];
- for (component=0; component<5; component++) {
- for (num_bit=0; num_bit<16; num_bit++) {
- unsigned short val;
-
- val = *tmp_p++;
-
- if (val == 0xffff) {
- continue;
- }
-
- switch(component) {
- case 0:
- info->mask_r |= 1<< val;
- break;
- case 1:
- info->mask_g |= 1<< val;
- break;
- case 2:
- info->mask_b |= 1<< val;
- break;
- case 3:
- info->mask_a |= 1<< val;
- break;
- }
- }
- }
- }
-
- /* Remove lower green bits for Intel endian screen */
- if ((info->mask_g == ((7<<13)|3)) || (info->mask_g == ((7<<13)|7))) {
- info->mask_g &= ~(7<<13);
- }
- break;
-
- case VDI_CLUT_NONE:
- break;
- }
+ memset( &out, 0, sizeof(short)*300 );
+ vq_scrninfo(vdih, (short*)&out);
+ info->vdiformat = out[0];
+ info->clut = out[1];
+ info->scr_bpp = out[2];
+ info->hicolors = *((unsigned long*) &out[3]);
+ if( info->EdDiVersion >= EDDI_11 ) {
+ info->pitch = out[5];
+ info->screen = (void *) *((unsigned long *) &out[6]);
+ }
+
+ switch( info->clut ) {
+
+ case VDI_CLUT_HARDWARE:
+ break;
+
+ case VDI_CLUT_SOFTWARE:
+ {
+ int component; /* red, green, blue, alpha, overlay */
+ int num_bit;
+ unsigned short *tmp_p;
+
+ /* We can build masks with info here */
+ tmp_p = (unsigned short *) &out[16];
+ for (component=0; component<5; component++) {
+ for (num_bit=0; num_bit<16; num_bit++) {
+ unsigned short val;
+
+ val = *tmp_p++;
+
+ if (val == 0xffff) {
+ continue;
+ }
+
+ switch(component) {
+ case 0:
+ info->mask_r |= 1<< val;
+ break;
+ case 1:
+ info->mask_g |= 1<< val;
+ break;
+ case 2:
+ info->mask_b |= 1<< val;
+ break;
+ case 3:
+ info->mask_a |= 1<< val;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove lower green bits for Intel endian screen */
+ if ((info->mask_g == ((7<<13)|3)) ||
+ (info->mask_g == ((7<<13)|7))) {
+ info->mask_g &= ~(7<<13);
+ }
+ break;
+
+ case VDI_CLUT_NONE:
+ break;
+ }
}
}
-/*
- Convert an RGB color to an VDI Color
-*/
+/**
+ * Convert an RGB color to an VDI Color
+ */
inline void rgb_to_vdi1000(unsigned char * in, RGB1000 *out)
{
double r = ((double)in[3]/255); /* prozentsatz red */
@@ -532,6 +572,7 @@ inline void rgb_to_vdi1000(unsigned char * in, RGB1000 *out)
return;
}
+
inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out)
{
double r = ((double)in[0]/1000); /* prozentsatz red */
@@ -548,7 +589,8 @@ inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out)
/**
* Set pixel within an 8 bit VDI standard bitmap.
*/
-inline static void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val )
+inline static void
+set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val )
{
short * buf;
short whichbit = (1<<(15-(x%16)));
@@ -580,6 +622,7 @@ inline static void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned
*buf = (val&(1<<7)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
}
+
/**
* Read pixel from an 8 bit VDI standard bitmap.
*/
@@ -593,42 +636,42 @@ inline static unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y)
buf += ((dst->fd_wdwidth*(y))+(x>>4));
if( *buf & whichbit )
- ret |= 1;
+ ret |= 1;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 2;
+ ret |= 2;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 4;
+ ret |= 4;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 8;
+ ret |= 8;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 16;
+ ret |= 16;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 32;
+ ret |= 32;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 64;
+ ret |= 64;
buf += wdplanesz;
if( *buf & whichbit )
- ret |= 128;
+ ret |= 128;
return( ret );
}
-/*
- Convert an RGB color into an index into the 216 colors web pallette
-*/
+/**
+ * Convert an RGB color into an index into the 216 colors web pallette
+ */
inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b)
{
short i;
@@ -640,24 +683,24 @@ inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b)
diff_b = abs(r-b);
diff_c = abs(r-b);
if( diff_a < 2 && diff_b < 2 && diff_c < 2 ) {
- if( (r!=0XFF) && (g!=0XFF) && (b!=0XFF) ) {
- if( ((r&0xF0)>>4) != 0 )
- //printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) );
- return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) );
- }
+ if( (r!=0XFF) && (g!=0XFF) && (b!=0XFF) ) {
+ if( ((r&0xF0)>>4) != 0 )
+ //printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) );
+ return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) );
+ }
}
/* convert each 8bit color to 6bit web color: */
for( i=0; i<3; i++) {
- if(0 == rgb[i] % web_std_colors[1] ) {
- tval[i] = rgb[i] / web_std_colors[1];
- } else {
- int pos = ((short)rgb[i] / web_std_colors[1]);
- if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) )
- tval[i] = pos+1;
- else
- tval[i] = pos;
- }
+ if(0 == rgb[i] % web_std_colors[1] ) {
+ tval[i] = rgb[i] / web_std_colors[1];
+ } else {
+ int pos = ((short)rgb[i] / web_std_colors[1]);
+ if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) )
+ tval[i] = pos+1;
+ else
+ tval[i] = pos;
+ }
}
return(tval[2]*36+tval[1]*6+tval[0]);
}
@@ -692,6 +735,7 @@ static void dump_vdi_info(short vdih)
printf("};\n");
}
+
/**
* Create an snapshot of the screen image in device format.
*/
@@ -702,29 +746,29 @@ static MFDB * snapshot_create_native_mfdb(int x, int y, int w, int h)
/* allocate memory for the snapshot */
{
- int scr_stride = MFDB_STRIDE( w );
- int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
- if(size_buf_scr == 0 ){
- /* init screen mfdb */
- buf_scr.fd_addr = malloc( scr_size );
- size_buf_scr = scr_size;
- } else {
- if( scr_size >size_buf_scr ) {
- buf_scr.fd_addr = realloc(
- buf_scr.fd_addr, scr_size
- );
- size_buf_scr = scr_size;
- }
- }
- if(buf_scr.fd_addr == NULL ) {
- size_buf_scr = 0;
- return( NULL );
- }
- buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp;
- buf_scr.fd_w = scr_stride;
- buf_scr.fd_h = h;
- buf_scr.fd_wdwidth = scr_stride >> 4;
- assert(buf_scr.fd_addr != NULL );
+ int scr_stride = MFDB_STRIDE( w );
+ int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
+ if(size_buf_scr == 0 ){
+ /* init screen mfdb */
+ buf_scr.fd_addr = malloc( scr_size );
+ size_buf_scr = scr_size;
+ } else {
+ if( scr_size >size_buf_scr ) {
+ buf_scr.fd_addr = realloc(
+ buf_scr.fd_addr, scr_size
+ );
+ size_buf_scr = scr_size;
+ }
+ }
+ if(buf_scr.fd_addr == NULL ) {
+ size_buf_scr = 0;
+ return( NULL );
+ }
+ buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp;
+ buf_scr.fd_w = scr_stride;
+ buf_scr.fd_h = h;
+ buf_scr.fd_wdwidth = scr_stride >> 4;
+ assert(buf_scr.fd_addr != NULL );
}
init_mfdb( 0, w, h, 0, &scr );
pxy[0] = x;
@@ -736,18 +780,27 @@ static MFDB * snapshot_create_native_mfdb(int x, int y, int w, int h)
pxy[6] = w-1;
pxy[7] = h-1;
vro_cpyfm(
- atari_plot_vdi_handle, S_ONLY, (short*)&pxy,
- &scr, &buf_scr
- );
+ atari_plot_vdi_handle, S_ONLY, (short*)&pxy,
+ &scr, &buf_scr
+ );
return( &buf_scr );
}
-/*
+/**
* Create an snapshot of the screen in netsurf ABGR format
+ *
+ * This creates an snapshot in RGBA format (NetSurf's native format)
+ *
+ * Capture the screen at x,y location
+ *
+ * \param x absolute screen coords
+ * \param y absolute screen coords
+ * \param w width
+ * \param h height
*/
-static struct bitmap * snapshot_create(int x, int y, int w, int h)
+static struct bitmap *snapshot_create(int x, int y, int w, int h)
{
int err;
MFDB * native;
@@ -764,37 +817,37 @@ static struct bitmap * snapshot_create(int x, int y, int w, int h)
native = snapshot_create_native_mfdb(x, y, w, h );
if(vfmt.bits == 32 )
- goto no_copy;
+ goto no_copy;
/* allocate buffer for result bitmap: */
if(buf_scr_compat == NULL ) {
- buf_scr_compat = atari_bitmap_create(w, h, 0);
+ buf_scr_compat = atari_bitmap_create(w, h, 0);
} else {
- buf_scr_compat = atari_bitmap_realloc( w, h,
- buf_scr_compat->bpp,
- w *buf_scr_compat->bpp,
- BITMAP_GROW,
- buf_scr_compat );
+ buf_scr_compat = atari_bitmap_realloc( w, h,
+ buf_scr_compat->bpp,
+ w *buf_scr_compat->bpp,
+ BITMAP_GROW,
+ buf_scr_compat );
}
/* convert screen buffer to ns format: */
err = Hermes_ConverterRequest( hermes_cnv_h,
- &vfmt,
- &nsfmt
- );
+ &vfmt,
+ &nsfmt
+ );
assert( err != 0 );
err = Hermes_ConverterCopy( hermes_cnv_h,
- native->fd_addr,
- 0, /* x src coord of top left in pixel coords */
- 0, /* y src coord of top left in pixel coords */
- w, h,
- native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */
- buf_scr_compat->pixdata,
- 0, /* x dst coord of top left in pixel coords */
- 0, /* y dst coord of top left in pixel coords */
- w, h,
- atari_bitmap_get_rowstride(buf_scr_compat) /* stride as bytes */
- );
+ native->fd_addr,
+ 0, /* x src coord of top left in pixel coords */
+ 0, /* y src coord of top left in pixel coords */
+ w, h,
+ native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */
+ buf_scr_compat->pixdata,
+ 0, /* x dst coord of top left in pixel coords */
+ 0, /* y dst coord of top left in pixel coords */
+ w, h,
+ atari_bitmap_get_rowstride(buf_scr_compat) /* stride as bytes */
+ );
assert( err != 0 );
return( (struct bitmap * )buf_scr_compat );
@@ -808,59 +861,61 @@ no_copy:
uint32_t row, col;
for (row = 0; row<(uint32_t)h; row++) {
- // fd_w matches stride!
- uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w)));
- for (col=0; col<(uint32_t)w; col++) {
- *(rowptr+col) = (*(rowptr+col)<<8);
- }
+ // fd_w matches stride!
+ uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w)));
+ for (col=0; col<(uint32_t)w; col++) {
+ *(rowptr+col) = (*(rowptr+col)<<8);
+ }
}
return( &snapshot );
}
+
/**
* Notify the snapshot interface that the last snapshot is no longer in use.
*/
static void snapshot_suspend(void)
{
if(size_buf_scr > CONV_KEEP_LIMIT ) {
- buf_scr.fd_addr = realloc(
- buf_scr.fd_addr, CONV_KEEP_LIMIT
- );
- if(buf_scr.fd_addr != NULL ) {
- size_buf_scr = CONV_KEEP_LIMIT;
- } else {
- size_buf_scr = 0;
- }
+ buf_scr.fd_addr = realloc(
+ buf_scr.fd_addr, CONV_KEEP_LIMIT
+ );
+ if(buf_scr.fd_addr != NULL ) {
+ size_buf_scr = CONV_KEEP_LIMIT;
+ } else {
+ size_buf_scr = 0;
+ }
}
#ifdef WITH_8BPP_SUPPORT
if(size_buf_std > CONV_KEEP_LIMIT ) {
- buf_std.fd_addr = realloc(
- buf_std.fd_addr, CONV_KEEP_LIMIT
- );
- if(buf_std.fd_addr != NULL ) {
- size_buf_std = CONV_KEEP_LIMIT;
- } else {
- size_buf_std = 0;
- }
+ buf_std.fd_addr = realloc(
+ buf_std.fd_addr, CONV_KEEP_LIMIT
+ );
+ if(buf_std.fd_addr != NULL ) {
+ size_buf_std = CONV_KEEP_LIMIT;
+ } else {
+ size_buf_std = 0;
+ }
}
#endif
if(buf_scr_compat != NULL ) {
- size_t bs = atari_bitmap_buffer_size(buf_scr_compat );
- if( bs > CONV_KEEP_LIMIT ) {
- int w = 0;
- int h = 1;
- w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp);
- assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp );
- buf_scr_compat = atari_bitmap_realloc( w, h,
- buf_scr_compat->bpp,
- CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat
- );
- }
+ size_t bs = atari_bitmap_buffer_size(buf_scr_compat );
+ if( bs > CONV_KEEP_LIMIT ) {
+ int w = 0;
+ int h = 1;
+ w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp);
+ assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp );
+ buf_scr_compat = atari_bitmap_realloc( w, h,
+ buf_scr_compat->bpp,
+ CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat
+ );
+ }
}
}
+
/**
* Shut down the snapshot interface.
*/
@@ -869,7 +924,7 @@ static void snapshot_destroy(void)
free(buf_scr.fd_addr);
if( buf_scr_compat != NULL) {
- atari_bitmap_destroy(buf_scr_compat);
+ atari_bitmap_destroy(buf_scr_compat);
}
buf_scr.fd_addr = NULL;
@@ -890,17 +945,19 @@ inline static uint32_t ablend(uint32_t pixel, uint32_t scrpixel)
pixel >>= 8;
scrpixel >>= 8;
rb = ((pixel & 0xFF00FF) * opacity +
- (scrpixel & 0xFF00FF) * transp) >> 8;
+ (scrpixel & 0xFF00FF) * transp) >> 8;
g = ((pixel & 0x00FF00) * opacity +
- (scrpixel & 0x00FF00) * transp) >> 8;
+ (scrpixel & 0x00FF00) * transp) >> 8;
return ((rb & 0xFF00FF) | (g & 0xFF00)) << 8;
}
-/*
- Alpha blends an image, using one pixel as the background.
- The bitmap receives the result.
-*/
+
+/**
+ * Alpha blends an image, using one pixel as the background.
+ *
+ * The bitmap receives the result.
+ */
inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip)
{
uint32_t * imgrow;
@@ -909,22 +966,25 @@ inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip)
img_stride= atari_bitmap_get_rowstride(img);
for( img_y = 0; img_y < clip->g_h; img_y++) {
- imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
- for( img_x = 0; img_x < clip->g_w; img_x++ ) {
- imgrow[img_x] = ablend( imgrow[img_x], bg );
- }
+ imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
+ for( img_x = 0; img_x < clip->g_w; img_x++ ) {
+ imgrow[img_x] = ablend( imgrow[img_x], bg );
+ }
}
return(true);
}
-/*
- Aplha blends the foreground image (img) onto the
- background images (bg). The background receives the blended
- image pixels.
-*/
-inline static bool ablend_bitmap( struct bitmap * img, struct bitmap * bg,
- GRECT * img_clip, GRECT * bg_clip )
+/**
+ * Aplha blends the foreground image onto thebackground images.
+ *
+ * The background receives the blended image pixels.
+ */
+inline static bool
+ablend_bitmap(struct bitmap *img,
+ struct bitmap *bg,
+ GRECT *img_clip,
+ GRECT * bg_clip )
{
uint32_t * imgrow;
uint32_t * screenrow;
@@ -935,29 +995,29 @@ inline static bool ablend_bitmap( struct bitmap * img, struct bitmap * bg,
bg_stride = atari_bitmap_get_rowstride(bg);
for( img_y = img_clip->g_y, bg_y = 0; bg_y < img_clip->g_h; bg_y++, img_y++) {
- imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
- screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y));
- for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) {
-
- // when the pixel isn't fully transparent,...:
- if( (imgrow[img_x] & 0x0FF) != 0 ){
- screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
- }
-
- // FIXME, maybe this loop would be faster??:
- // ---
- //if( (imgrow[img_x] & 0x0FF) != 0xFF ){
- // imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
- //}
-
- // or maybe even this???
- // ---
- //if( (imgrow[img_x] & 0x0FF) == 0xFF ){
- // screenrow[bg_x] = imgrow[img_x];
- //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) {
- // screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
- //}
- }
+ imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
+ screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y));
+ for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) {
+
+ // when the pixel isn't fully transparent,...:
+ if( (imgrow[img_x] & 0x0FF) != 0 ){
+ screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
+ }
+
+ // FIXME, maybe this loop would be faster??:
+ // ---
+ //if( (imgrow[img_x] & 0x0FF) != 0xFF ){
+ // imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
+ //}
+
+ // or maybe even this???
+ // ---
+ //if( (imgrow[img_x] & 0x0FF) == 0xFF ){
+ // screenrow[bg_x] = imgrow[img_x];
+ //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) {
+ // screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
+ //}
+ }
}
return(false);
}
@@ -972,30 +1032,30 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h)
{
/* allocate memory for the snapshot */
{
- int scr_stride = MFDB_STRIDE( w );
- int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
- if(size_buf_std == 0 ){
- /* init screen mfdb */
- buf_std.fd_addr = malloc( scr_size );
- size_buf_std = scr_size;
- } else {
- if( scr_size >size_buf_std ) {
- buf_std.fd_addr = realloc(
- buf_std.fd_addr, scr_size
- );
- size_buf_std = scr_size;
- }
- }
- if(buf_std.fd_addr == NULL ) {
- size_buf_std = 0;
- return( NULL );
- }
- buf_std.fd_nplanes = 8;
- buf_std.fd_w = scr_stride;
- buf_std.fd_h = h;
- buf_std.fd_stand = 1;
- buf_std.fd_wdwidth = scr_stride >> 4;
- assert(buf_std.fd_addr != NULL );
+ int scr_stride = MFDB_STRIDE( w );
+ int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
+ if(size_buf_std == 0 ){
+ /* init screen mfdb */
+ buf_std.fd_addr = malloc( scr_size );
+ size_buf_std = scr_size;
+ } else {
+ if( scr_size >size_buf_std ) {
+ buf_std.fd_addr = realloc(
+ buf_std.fd_addr, scr_size
+ );
+ size_buf_std = scr_size;
+ }
+ }
+ if(buf_std.fd_addr == NULL ) {
+ size_buf_std = 0;
+ return( NULL );
+ }
+ buf_std.fd_nplanes = 8;
+ buf_std.fd_w = scr_stride;
+ buf_std.fd_h = h;
+ buf_std.fd_stand = 1;
+ buf_std.fd_wdwidth = scr_stride >> 4;
+ assert(buf_std.fd_addr != NULL );
}
MFDB * native = snapshot_create_native_mfdb(x,y,w,h );
assert( native );
@@ -1004,6 +1064,7 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h)
return( &buf_std );
}
+
/**
* Convert an bitmap to an 8 bit device dependant MFDB
* \param img the bitmap (only tested with 32bit bitmaps)
@@ -1015,9 +1076,14 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h)
* \param out receives the converted bitmap (still owned by the plot API)
*
*/
-static bool bitmap_convert_8(struct bitmap * img, int x,
- int y, GRECT * clip, uint32_t bg, uint32_t flags,
- MFDB *out )
+static bool
+bitmap_convert_8(struct bitmap *img,
+ int x,
+ int y,
+ GRECT *clip,
+ uint32_t bg,
+ uint32_t flags,
+ MFDB *out)
{
MFDB native;
MFDB stdform;
@@ -1029,11 +1095,11 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
bool opaque = atari_bitmap_get_opaque( img );
if( opaque == false ){
- if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
- &&
- ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
- opaque = true;
- }
+ if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
+ &&
+ ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
+ opaque = true;
+ }
}
assert( clip->g_h > 0 );
@@ -1046,53 +1112,53 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
// the bitmap is fully opaque
if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){
- if( img->converted == true ){
- *out = img->native;
- return( 0 );
- }
- if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
- cache = true;
- }
+ if( img->converted == true ){
+ *out = img->native;
+ return( 0 );
+ }
+ if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
+ cache = true;
+ }
}
if( ( flags & BITMAPF_MONOGLYPH ) != 0 ){
- assert(cache == false);
+ assert(cache == false);
}
/* (re)allocate buffer for out image: */
/* altough the buffer is named "buf_packed" on 8bit systems */
/* it's not... */
if( cache == false ){
- // the size of the output will match the size of the clipping:
- dststride = MFDB_STRIDE( clip->g_w );
- dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt);
- if (dstsize > size_buf_packed) {
- int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
- void *buf;
- if (buf_packed == NULL) {
- buf = malloc( blocks * CONV_BLOCK_SIZE);
- } else {
- buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
- }
- if (buf == NULL) {
- return( 0-ERR_NO_MEM );
- }
- buf_packed = buf;
- size_buf_packed = blocks * CONV_BLOCK_SIZE;
- }
- native.fd_addr = buf_packed;
+ // the size of the output will match the size of the clipping:
+ dststride = MFDB_STRIDE( clip->g_w );
+ dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt);
+ if (dstsize > size_buf_packed) {
+ int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
+ void *buf;
+ if (buf_packed == NULL) {
+ buf = malloc( blocks * CONV_BLOCK_SIZE);
+ } else {
+ buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
+ }
+ if (buf == NULL) {
+ return( 0-ERR_NO_MEM );
+ }
+ buf_packed = buf;
+ size_buf_packed = blocks * CONV_BLOCK_SIZE;
+ }
+ native.fd_addr = buf_packed;
}
else {
- // the output image will be completly saved, so size of the output
- // image will match the input image size.
- dststride = MFDB_STRIDE( bw );
- dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt);
- assert( out->fd_addr == NULL );
- native.fd_addr = malloc( dstsize );
- if (native.fd_addr == NULL){
- if (scrbuf != NULL)
- atari_bitmap_destroy(scrbuf);
- return( 0-ERR_NO_MEM );
- }
+ // the output image will be completly saved, so size of the output
+ // image will match the input image size.
+ dststride = MFDB_STRIDE( bw );
+ dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt);
+ assert( out->fd_addr == NULL );
+ native.fd_addr = malloc( dstsize );
+ if (native.fd_addr == NULL){
+ if (scrbuf != NULL)
+ atari_bitmap_destroy(scrbuf);
+ return( 0-ERR_NO_MEM );
+ }
}
@@ -1103,29 +1169,29 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
*/
// realloc mem for stdform
if( opaque == false ){
- // point image to snapshot buffer, otherwise allocate mem
- MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h);
- stdform.fd_addr = bg->fd_addr;
- bh = clip->g_h;
+ // point image to snapshot buffer, otherwise allocate mem
+ MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h);
+ stdform.fd_addr = bg->fd_addr;
+ bh = clip->g_h;
} else {
- if (dstsize > size_buf_planar) {
- int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
- void *buf;
- if (buf_planar == NULL) {
- buf = malloc(blocks * CONV_BLOCK_SIZE);
- } else {
- buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE);
- }
- if (buf == NULL ) {
- if (cache) {
- free(native.fd_addr);
- }
- return( 0-ERR_NO_MEM );
- }
- buf_planar = buf;
- size_buf_planar = blocks * CONV_BLOCK_SIZE;
- }
- stdform.fd_addr = buf_planar;
+ if (dstsize > size_buf_planar) {
+ int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
+ void *buf;
+ if (buf_planar == NULL) {
+ buf = malloc(blocks * CONV_BLOCK_SIZE);
+ } else {
+ buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE);
+ }
+ if (buf == NULL ) {
+ if (cache) {
+ free(native.fd_addr);
+ }
+ return( 0-ERR_NO_MEM );
+ }
+ buf_planar = buf;
+ size_buf_planar = blocks * CONV_BLOCK_SIZE;
+ }
+ stdform.fd_addr = buf_planar;
}
stdform.fd_w = dststride;
stdform.fd_h = bh;
@@ -1143,67 +1209,67 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
int wdplanesize = stdform.fd_wdwidth*stdform.fd_h;
if( opaque == false ){
- // apply transparency and convert to vdi std format
- unsigned long bgcol = 0;
- unsigned char prev_col = 0;
- for( y=0; y<clip->g_h; y++ ){
- row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y)));
- for( x=0; x<clip->g_w; x++ ){
- pixel = row[x+clip->g_x];
- if( (pixel&0xFF) == 0 ){
- continue;
- }
- if( (pixel&0xFF) < 0xF0 ){
- col = get_stdpx( &stdform, wdplanesize,x,y );
- if( (col != prev_col) || (y == 0) )
- bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8);
- if( prev_col != col || prev_pixel != pixel ){
- prev_col = col;
- pixel = ablend( pixel, bgcol );
- prev_pixel = pixel;
- pixel = pixel >> 8;
- /* convert pixel value to vdi color index: */
- col = ( ((pixel&0xFF)<<16)
- | (pixel&0xFF00)
- | ((pixel&0xFF0000)>>16) );
- val = RGB_TO_VDI( col );
- }
- set_stdpx( &stdform, wdplanesize, x, y, val );
- } else {
- if( pixel != prev_pixel ){
- /* convert pixel value to vdi color index: */
- pixel = pixel >> 8;
- col = ( ((pixel&0xFF)<<16)
- | (pixel&0xFF00)
- | ((pixel&0xFF0000)>>16) );
- val = RGB_TO_VDI( col );
- prev_pixel = pixel;
- }
- set_stdpx( &stdform, wdplanesize, x, y, val );
- }
- }
- }
- // adjust output position:
- clip->g_x = 0;
- clip->g_y = 0;
+ // apply transparency and convert to vdi std format
+ unsigned long bgcol = 0;
+ unsigned char prev_col = 0;
+ for( y=0; y<clip->g_h; y++ ){
+ row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y)));
+ for( x=0; x<clip->g_w; x++ ){
+ pixel = row[x+clip->g_x];
+ if( (pixel&0xFF) == 0 ){
+ continue;
+ }
+ if( (pixel&0xFF) < 0xF0 ){
+ col = get_stdpx( &stdform, wdplanesize,x,y );
+ if( (col != prev_col) || (y == 0) )
+ bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8);
+ if( prev_col != col || prev_pixel != pixel ){
+ prev_col = col;
+ pixel = ablend( pixel, bgcol );
+ prev_pixel = pixel;
+ pixel = pixel >> 8;
+ /* convert pixel value to vdi color index: */
+ col = ( ((pixel&0xFF)<<16)
+ | (pixel&0xFF00)
+ | ((pixel&0xFF0000)>>16) );
+ val = RGB_TO_VDI( col );
+ }
+ set_stdpx( &stdform, wdplanesize, x, y, val );
+ } else {
+ if( pixel != prev_pixel ){
+ /* convert pixel value to vdi color index: */
+ pixel = pixel >> 8;
+ col = ( ((pixel&0xFF)<<16)
+ | (pixel&0xFF00)
+ | ((pixel&0xFF0000)>>16) );
+ val = RGB_TO_VDI( col );
+ prev_pixel = pixel;
+ }
+ set_stdpx( &stdform, wdplanesize, x, y, val );
+ }
+ }
+ }
+ // adjust output position:
+ clip->g_x = 0;
+ clip->g_y = 0;
} else {
- // convert the whole image data to vdi std format.
- for( y=0; y < bh; y++ ){
- row = (uint32_t *)(img->pixdata + (img_stride * y));
- for( x=0; x < bw; x++ ){
- pixel = row[x];
- if( pixel != prev_pixel ){
- /* convert pixel value to vdi color index: */
- pixel = pixel >> 8;
- col = ( ((pixel&0xFF)<<16)
- | (pixel&0xFF00)
- | ((pixel&0xFF0000)>>16) );
- val = RGB_TO_VDI( col );
- prev_pixel = pixel;
- }
- set_stdpx( &stdform, wdplanesize, x, y, val );
- }
- }
+ // convert the whole image data to vdi std format.
+ for( y=0; y < bh; y++ ){
+ row = (uint32_t *)(img->pixdata + (img_stride * y));
+ for( x=0; x < bw; x++ ){
+ pixel = row[x];
+ if( pixel != prev_pixel ){
+ /* convert pixel value to vdi color index: */
+ pixel = pixel >> 8;
+ col = ( ((pixel&0xFF)<<16)
+ | (pixel&0xFF00)
+ | ((pixel&0xFF0000)>>16) );
+ val = RGB_TO_VDI( col );
+ prev_pixel = pixel;
+ }
+ set_stdpx( &stdform, wdplanesize, x, y, val );
+ }
+ }
}
// convert into native format:
@@ -1216,8 +1282,8 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
vr_trnfm(atari_plot_vdi_handle, &stdform, &native );
*out = native;
if( cache == true ){
- img->native = native;
- img->converted = true;
+ img->native = native;
+ img->converted = true;
}
return(0);
@@ -1225,24 +1291,30 @@ static bool bitmap_convert_8(struct bitmap * img, int x,
#endif
-/*
- *
+/**
* Convert bitmap to the native screen format
- * img: the bitmap
- * x: coordinate where the bitmap REGION (described in clip)
+ *
+ * \param img the bitmap
+ * \param x coordinate where the bitmap REGION (described in clip)
* shall be drawn (screen coords)
- * y: coordinate where the bitmap REGION (described in clip)
+ * \param y coordinate where the bitmap REGION (described in clip)
* shall be drawn (screen coords)
- * clip: which area of the bitmap shall be drawn
- * bg: background color
- * flags: blit flags
- * out: the result MFDB
+ * \param clip which area of the bitmap shall be drawn
+ * \param bg background color
+ * \param flags blit flags
+ * \param out the result MFDB
*/
-static bool bitmap_convert_tc(struct bitmap * img, int x, int y,
- GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out )
+static bool
+bitmap_convert_tc(struct bitmap *img,
+ int x,
+ int y,
+ GRECT *clip,
+ uint32_t bg,
+ uint32_t flags,
+ MFDB *out)
{
- int dststride; /* stride of dest. image */
- int dstsize; /* size of dest. in byte */
+ int dststride; /* stride of dest. image */
+ int dstsize; /* size of dest. in byte */
int err;
int bw, bh;
struct bitmap * scrbuf = NULL;
@@ -1250,15 +1322,14 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y,
bool cache = ( flags & BITMAPF_BUFFER_NATIVE );
bool opaque = atari_bitmap_get_opaque( img );
- if( opaque == false ){
- if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
- &&
- ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
- opaque = true;
- }
+ if (opaque == false ) {
+ if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
+ &&
+ ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
+ opaque = true;
+ }
}
-
assert( clip->g_h > 0 );
assert( clip->g_w > 0 );
@@ -1277,80 +1348,80 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y,
// toolbar buttons right now.
if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){
- if( img->converted == true ){
- *out = img->native;
- return( 0 );
- }
- if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
- cache = true;
- }
+ if( img->converted == true ){
+ *out = img->native;
+ return( 0 );
+ }
+ if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
+ cache = true;
+ }
}
/* rem. if eddi xy is installed, we could directly access the screen! */
/* apply transparency to the image: */
if (( opaque == false )) {
- /* copy the screen to an temp buffer: */
- if ((flags & BITMAPF_BUFFER_NATIVE) == 0) {
- scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h);
- if( scrbuf != NULL ) {
-
- assert( clip->g_w <= bw );
- assert( clip->g_h <= bh );
-
- // copy blended pixels to the screen buffer:
- ablend_bitmap( img, scrbuf, clip, NULL );
- /* adjust size which gets converted: */
- bw = clip->g_w;
- bh = clip->g_h;
- /* adjust output position: */
- clip->g_x = 0;
- clip->g_y = 0;
- /* set the source of conversion: */
- source = scrbuf;
- }
- } else {
- /*
- The whole bitmap can be transformed to an mfdb
- (and get's cached)
- */
- GRECT region = { 0, 0, bw, bh };
- ablend_pixel( img, bg, &region );
- source = img;
- }
+ /* copy the screen to an temp buffer: */
+ if ((flags & BITMAPF_BUFFER_NATIVE) == 0) {
+ scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h);
+ if( scrbuf != NULL ) {
+
+ assert( clip->g_w <= bw );
+ assert( clip->g_h <= bh );
+
+ // copy blended pixels to the screen buffer:
+ ablend_bitmap( img, scrbuf, clip, NULL );
+ /* adjust size which gets converted: */
+ bw = clip->g_w;
+ bh = clip->g_h;
+ /* adjust output position: */
+ clip->g_x = 0;
+ clip->g_y = 0;
+ /* set the source of conversion: */
+ source = scrbuf;
+ }
+ } else {
+ /*
+ The whole bitmap can be transformed to an mfdb
+ (and get's cached)
+ */
+ GRECT region = { 0, 0, bw, bh };
+ ablend_pixel( img, bg, &region );
+ source = img;
+ }
} else {
- source = img;
+ source = img;
}
/* (re)allocate buffer for converted image: */
dststride = MFDB_STRIDE(bw);
dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt );
if (cache == false) {
- /* ensure cache buffer is large enough */
- if (dstsize > size_buf_packed) {
- int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
- void *buf;
- if (buf_packed == NULL) {
- buf = malloc(blocks * CONV_BLOCK_SIZE);
- } else {
- buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
- }
- if (buf == NULL ) {
- if (scrbuf != NULL) {
- atari_bitmap_destroy(scrbuf);
- }
- return( 0-ERR_NO_MEM );
- }
- buf_packed = buf;
- size_buf_packed = blocks * CONV_BLOCK_SIZE;
- }
- out->fd_addr = buf_packed;
+ /* ensure cache buffer is large enough */
+ if (dstsize > size_buf_packed) {
+ int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
+ void *buf;
+ if (buf_packed == NULL) {
+ buf = malloc(blocks * CONV_BLOCK_SIZE);
+ } else {
+ buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
+ }
+ if (buf == NULL ) {
+ if (scrbuf != NULL) {
+ atari_bitmap_destroy(scrbuf);
+ }
+ return( 0-ERR_NO_MEM );
+ }
+ buf_packed = buf;
+ size_buf_packed = blocks * CONV_BLOCK_SIZE;
+ }
+ out->fd_addr = buf_packed;
} else {
- assert( out->fd_addr == NULL );
- out->fd_addr = (void*)malloc( dstsize );
- if( out->fd_addr == NULL ){
- if( scrbuf != NULL )
- atari_bitmap_destroy( scrbuf );
- return( 0-ERR_NO_MEM );
- }
+ assert( out->fd_addr == NULL );
+ out->fd_addr = (void*)malloc( dstsize );
+ if( out->fd_addr == NULL ){
+ if( scrbuf != NULL )
+ atari_bitmap_destroy( scrbuf );
+ return( 0-ERR_NO_MEM );
+ }
}
out->fd_w = dststride;
@@ -1361,10 +1432,10 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y,
out->fd_r1 = out->fd_r2 = out->fd_r3 = 0;
err = Hermes_ConverterRequest(
- hermes_cnv_h,
- &nsfmt,
- &vfmt
- );
+ hermes_cnv_h,
+ &nsfmt,
+ &vfmt
+ );
assert( err != 0 );
// FIXME: here we can use the same optimization which is used for
@@ -1372,43 +1443,44 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y,
/* convert image to virtual format: */
err = Hermes_ConverterCopy( hermes_cnv_h,
- source->pixdata,
- 0, /* x src coord of top left in pixel coords */
- 0, /* y src coord of top left in pixel coords */
- bw, bh,
- source->rowstride, /* stride as bytes */
- out->fd_addr,
- 0, /* x dst coord of top left in pixel coords */
- 0, /* y dst coord of top left in pixel coords */
- bw, bh,
- (dststride >> 3) * atari_plot_bpp_virt /* stride as bytes */
- );
+ source->pixdata,
+ 0, /* x src coord of top left in pixel coords */
+ 0, /* y src coord of top left in pixel coords */
+ bw, bh,
+ source->rowstride, /* stride as bytes */
+ out->fd_addr,
+ 0, /* x dst coord of top left in pixel coords */
+ 0,/* y dst coord of top left in pixel coords */
+ bw, bh,
+ (dststride >> 3) * atari_plot_bpp_virt /* stride as bytes */
+ );
assert( err != 0 );
if( cache == true ){
- img->native = *out;
- img->converted = true;
+ img->native = *out;
+ img->converted = true;
}
return( 0 );
}
+
inline static void convert_bitmap_done(void)
{
if (size_buf_packed > CONV_KEEP_LIMIT) {
- void *buf;
- /* free the mem if it was an large allocation ... */
- buf = realloc(buf_packed, CONV_KEEP_LIMIT);
- if (buf != NULL) {
- buf_packed = buf;
- size_buf_packed = CONV_KEEP_LIMIT;
- }
+ void *buf;
+ /* free the mem if it was an large allocation ... */
+ buf = realloc(buf_packed, CONV_KEEP_LIMIT);
+ if (buf != NULL) {
+ buf_packed = buf;
+ size_buf_packed = CONV_KEEP_LIMIT;
+ }
}
}
bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
- unsigned long bg, unsigned long flags )
+ unsigned long bg, unsigned long flags )
{
MFDB src_mf;
MFDB scrmf;
@@ -1431,7 +1503,7 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
clip.g_h = view.clipping.y1 - view.clipping.y0;
if( !rc_intersect( &clip, &off) ) {
- return(true);
+ return(true);
}
// clip the visible rectangle of the plot area
@@ -1439,7 +1511,7 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
// screen region:
plot_get_visible_grect(&vis);
if( !rc_intersect( &vis, &off) ) {
- return(true);
+ return(true);
}
screen_x = view.x + off.g_x;
@@ -1453,8 +1525,8 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
/* Convert the Bitmap to native screen format - ready for output. */
/* This includes blending transparent pixels: */
if (bitmap_convert(bmp, screen_x, screen_y, &off, bg, flags, &src_mf)
- != 0 ) {
- return(true);
+ != 0 ) {
+ return(true);
}
// setup the src region:
@@ -1475,8 +1547,9 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
return(true);
}
+
bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor,
- uint32_t flags)
+ uint32_t flags)
{
MFDB screen;
// MFDB tran;
@@ -1487,7 +1560,7 @@ bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor,
plot_get_clip_grect(&off);
if( rc_intersect(loc, &off) == 0 ){
- return( 1 );
+ return( 1 );
}
init_mfdb( 0, loc->g_w, loc->g_h, 0, &screen );
@@ -1527,53 +1600,49 @@ bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor,
if( flags & PLOT_FLAG_TRANS && src->fd_nplanes == 1){
- vrt_cpyfm(atari_plot_vdi_handle, MD_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c);
+ vrt_cpyfm(atari_plot_vdi_handle, MD_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c);
} else {
- /* this method only plots transparent bitmaps, right now... */
+ /* this method only plots transparent bitmaps, right now... */
}
return( 1 );
}
-/*
- Init screen and font driver objects.
- Returns non-zero value > -1 when the objects could be succesfully created.
- Returns value < 0 to indicate an error
-*/
-int plot_init(char * fdrvrname)
+/* exported interface documented in atari/plot.h */
+int plot_init(const struct redraw_context *ctx, char *fdrvrname)
{
-
- GRECT loc_pos= {0,0,360,400};
+ GRECT loc_pos = { 0, 0, 360, 400 };
int err=0;
if( nsoption_int(atari_dither) == 1)
- atari_plot_flags |= PLOT_FLAG_DITHER;
+ atari_plot_flags |= PLOT_FLAG_DITHER;
if( nsoption_int(atari_transparency) == 1 )
- atari_plot_flags |= PLOT_FLAG_TRANS;
+ atari_plot_flags |= PLOT_FLAG_TRANS;
if( nsoption_int(atari_font_monochrom) == 1 )
- atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH;
+ atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH;
- if(atari_plot_vdi_handle == -1) {
+ if (atari_plot_vdi_handle == -1) {
- short dummy;
- short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1};
- short work_out[57];
- atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy);
- v_opnvwk(work_in, &atari_plot_vdi_handle, work_out);
- LOG("Plot VDI handle: %d", atari_plot_vdi_handle);
+ short dummy;
+ short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1};
+ short work_out[57];
+ atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy);
+ v_opnvwk(work_in, &atari_plot_vdi_handle, work_out);
+ NSLOG(netsurf, INFO, "Plot VDI handle: %d", atari_plot_vdi_handle);
}
read_vdi_sysinfo(atari_plot_vdi_handle, &vdi_sysinfo);
if(verbose_log) {
- dump_vdi_info(atari_plot_vdi_handle) ;
- dump_font_drivers();
+ dump_vdi_info(atari_plot_vdi_handle) ;
+ dump_font_drivers();
}
fplotter = new_font_plotter(atari_plot_vdi_handle, fdrvrname,
- atari_font_flags, &err);
- if(err) {
- const char * desc = plot_err_str(err);
- LOG("Unable to load font plotter %s -> %s", fdrvrname, desc );
- die("font plotter");
+ atari_font_flags, &err);
+ if (err) {
+ const char * desc = plot_err_str(err);
+ NSLOG(netsurf, INFO, "Unable to load font plotter %s -> %s",
+ fdrvrname, desc);
+ die("font plotter");
}
memset(&view, 0, sizeof(struct s_view));
@@ -1587,9 +1656,9 @@ int plot_init(char * fdrvrname)
buf_packed = NULL;
buf_planar = NULL;
if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK ) {
- atari_plot_bpp_virt = vdi_sysinfo.scr_bpp;
+ atari_plot_bpp_virt = vdi_sysinfo.scr_bpp;
} else {
- atari_plot_bpp_virt = 8;
+ atari_plot_bpp_virt = 8;
}
plot_set_scale(1.0);
@@ -1600,7 +1669,7 @@ int plot_init(char * fdrvrname)
clip.y0 = 0;
clip.x1 = view.w;
clip.y1 = view.h;
- plot_clip(&clip);
+ ctx->plot->clip(ctx, &clip);
assert(Hermes_Init());
@@ -1610,38 +1679,38 @@ int plot_init(char * fdrvrname)
/* Setup color lookup tables and palette */
unsigned char rgbcol[4];
if( vdi_sysinfo.scr_bpp <= 8 ){
- unsigned char graytone=0;
- int i;
- for( i=0; i<=255; i++ ) {
-
- // get the current color and save it for restore:
- vq_color(atari_plot_vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] );
- if( i<OFFSET_WEB_PAL ) {
- pal[i][0] = sys_pal[i][0];
- pal[i][1] = sys_pal[i][1];
- pal[i][2] = sys_pal[i][2];
- } else if( vdi_sysinfo.scr_bpp >= 8 ) {
- if ( i < OFFSET_CUST_PAL ){
- pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0];
- pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1];
- pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2];
- //set the new palette color to websafe value:
- vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
- }
- if( i >= OFFSET_CUST_PAL && i<OFFSET_CUST_PAL+16 ) {
- /* here we define 20 additional gray colors... */
- rgbcol[1] = rgbcol[2] = rgbcol[3] = ((graytone&0x0F) << 4);
- rgb_to_vdi1000( &rgbcol[0], &pal[i][0] );
- vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
- graytone++;
- }
-
- }
- vdi1000_to_rgb( &pal[i][0], &rgb_lookup[i][0] );
- }
+ unsigned char graytone=0;
+ int i;
+ for( i=0; i<=255; i++ ) {
+
+ // get the current color and save it for restore:
+ vq_color(atari_plot_vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] );
+ if( i<OFFSET_WEB_PAL ) {
+ pal[i][0] = sys_pal[i][0];
+ pal[i][1] = sys_pal[i][1];
+ pal[i][2] = sys_pal[i][2];
+ } else if( vdi_sysinfo.scr_bpp >= 8 ) {
+ if ( i < OFFSET_CUST_PAL ){
+ pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0];
+ pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1];
+ pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2];
+ //set the new palette color to websafe value:
+ vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
+ }
+ if( i >= OFFSET_CUST_PAL && i<OFFSET_CUST_PAL+16 ) {
+ /* here we define 20 additional gray colors... */
+ rgbcol[1] = rgbcol[2] = rgbcol[3] = ((graytone&0x0F) << 4);
+ rgb_to_vdi1000( &rgbcol[0], &pal[i][0] );
+ vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
+ graytone++;
+ }
+
+ }
+ vdi1000_to_rgb( &pal[i][0], &rgb_lookup[i][0] );
+ }
} else {
- /* no need to change the palette - its application specific */
+ /* no need to change the palette - its application specific */
}
#else
bitmap_convert = bitmap_convert_tc;
@@ -1675,6 +1744,7 @@ int plot_init(char * fdrvrname)
return( err );
}
+
int plot_finalise( void )
{
@@ -1682,10 +1752,10 @@ int plot_finalise( void )
#ifdef WITH_8BPP_SUPPORT
if (vfmt.indexed) {
- int i;
- for (i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++) {
- vs_color(atari_plot_vdi_handle, i, &sys_pal[i][0]);
- }
+ int i;
+ for (i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++) {
+ vs_color(atari_plot_vdi_handle, i, &sys_pal[i][0]);
+ }
}
#endif
@@ -1701,25 +1771,27 @@ int plot_finalise( void )
return 0;
}
+
bool plot_lock(void)
{
if ((atari_plot_flags & PLOT_FLAG_LOCKED) != 0)
- return(true);
+ return(true);
if( !wind_update(BEG_UPDATE|0x100) )
- return(false);
+ return(false);
if( !wind_update(BEG_MCTRL|0x100) ){
- wind_update(END_UPDATE);
- return(false);
+ wind_update(END_UPDATE);
+ return(false);
}
atari_plot_flags |= PLOT_FLAG_LOCKED;
graf_mouse(M_OFF, NULL);
return(true);
}
+
bool plot_unlock(void)
{
if( (atari_plot_flags & PLOT_FLAG_LOCKED) == 0 )
- return(true);
+ return(true);
wind_update(END_MCTRL);
wind_update(END_UPDATE);
graf_mouse(M_ON, NULL);
@@ -1728,214 +1800,40 @@ bool plot_unlock(void)
return(false);
}
-bool plot_rectangle(int x0, int y0, int x1, int y1,
- const plot_style_t *pstyle )
-{
- short pxy[4];
- GRECT r, rclip, sclip;
- int sw = pstyle->stroke_width;
- uint32_t lt;
-
- /* current canvas clip: */
- rclip.g_x = view.clipping.x0;
- rclip.g_y = view.clipping.y0;
- rclip.g_w = view.clipping.x1 - view.clipping.x0;
- rclip.g_h = view.clipping.y1 - view.clipping.y0;
-
- /* physical clipping: */
- sclip.g_x = rclip.g_x;
- sclip.g_y = rclip.g_y;
- sclip.g_w = view.vis_w;
- sclip.g_h = view.vis_h;
- rc_intersect(&sclip, &rclip);
- r.g_x = x0;
- r.g_y = y0;
- r.g_w = x1 - x0;
- r.g_h = y1 - y0;
-
- if (!rc_intersect( &rclip, &r )) {
- return(true);
- }
- if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
- /*
- manually draw the line, because we do not need vdi clipping
- for vertical / horizontal line draws.
- */
- if( sw == 0)
- sw = 1;
-
- NSLT2VDI(lt, pstyle);
- vsl_type(atari_plot_vdi_handle, (lt&0x0F));
- /*
- if the line style is not available within VDI system,
- define own style:
- */
- if( (lt&0x0F) == 7 ){
- vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
- }
- vsl_width(atari_plot_vdi_handle, (short)sw );
- vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
- /* top border: */
- if( r.g_y == y0){
- pxy[0] = view.x + r.g_x;
- pxy[1] = view.y + r.g_y ;
- pxy[2] = view.x + r.g_x + r.g_w;
- pxy[3] = view.y + r.g_y;
- v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
- }
-
- /* right border: */
- if( r.g_x + r.g_w == x1 ){
- pxy[0] = view.x + r.g_x + r.g_w;
- pxy[1] = view.y + r.g_y;
- pxy[2] = view.x + r.g_x + r.g_w;
- pxy[3] = view.y + r.g_y + r.g_h;
- v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
- }
-
- /* bottom border: */
- if( r.g_y+r.g_h == y1 ){
- pxy[0] = view.x + r.g_x;
- pxy[1] = view.y + r.g_y+r.g_h;
- pxy[2] = view.x + r.g_x+r.g_w;
- pxy[3] = view.y + r.g_y+r.g_h;
- v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
- }
-
- /* left border: */
- if( r.g_x == x0 ){
- pxy[0] = view.x + r.g_x;
- pxy[1] = view.y + r.g_y;
- pxy[2] = view.x + r.g_x;
- pxy[3] = view.y + r.g_y + r.g_h;
- v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
- }
- }
-
- if( pstyle->fill_type != PLOT_OP_TYPE_NONE ){
- short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ?
- pstyle->stroke_width : 0;
-
- vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
- vsf_perimeter(atari_plot_vdi_handle, 0);
- vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
-
-
- pxy[0] = view.x + r.g_x + stroke_width;
- pxy[1] = view.y + r.g_y + stroke_width;
- pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width;
- pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width;
-
- vsf_style(atari_plot_vdi_handle, 1);
- v_bar(atari_plot_vdi_handle, (short*)&pxy);
- }
- return (true);
-}
-
-bool plot_line(int x0, int y0, int x1, int y1,
- const plot_style_t *pstyle )
-{
- short pxy[4];
- uint32_t lt;
- int sw = pstyle->stroke_width;
-
- if((x0 < 0 && x1 < 0) || (y0 < 0 && y1 < 0)){
- return(true);
- }
-
- pxy[0] = view.x + MAX(0,x0);
- pxy[1] = view.y + MAX(0,y0);
- pxy[2] = view.x + MAX(0,x1);
- pxy[3] = view.y + MAX(0,y1);
-
- if((y0 > view.h-1) && (y1 > view.h-1))
- return(true);
-
- //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h);
- //printf("line: %d,%d,%d,%d\n", x0, y0, x1, y1);
-
-
- //plot_vdi_clip(true);
- if( sw == 0)
- sw = 1;
- NSLT2VDI(lt, pstyle)
- vsl_type(atari_plot_vdi_handle, (lt&0x0F));
- /* if the line style is not available within VDI system,define own style: */
- if( (lt&0x0F) == 7 ){
- vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
- }
- vsl_width(atari_plot_vdi_handle, (short)sw);
- vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
- v_pline(atari_plot_vdi_handle, 2, (short *)&pxy );
- //plot_vdi_clip(false);
- return (true);
-}
-
-static bool plot_polygon(const int *p, unsigned int n,
- const plot_style_t *pstyle)
-{
- short pxy[n*2];
- unsigned int i=0;
- if (vdi_sysinfo.maxpolycoords > 0)
- assert( (signed int)n < vdi_sysinfo.maxpolycoords);
-
- vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
- vsf_style(atari_plot_vdi_handle, 1);
- for (i = 0; i<n*2; i=i+2) {
- pxy[i] = (short)view.x+p[i];
- pxy[i+1] = (short)view.y+p[i+1];
- }
- if (pstyle->fill_type == PLOT_OP_TYPE_SOLID) {
- vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
- v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy);
- } else {
- pxy[n*2]=pxy[0];
- pxy[n*2+1]=pxy[1];
- vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
- v_pline(atari_plot_vdi_handle, n+1, (short *)&pxy);
- }
-
- return ( true );
-}
-
-/***
- * Set plot origin and canvas size
- * \param x the x origin
- * \param y the y origin
- * \param w the width of the plot area
- * \param h the height of the plot area
- */
-bool plot_set_dimensions(int x, int y, int w, int h)
+/* exported interface documented in atari/plot.h */
+bool
+plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h)
{
bool doupdate = false;
struct rect newclip = {0, 0, w, h};
GRECT absclip = {x, y, w, h};
if (!(w == view.w && h == view.h)) {
- view.w = (short)w;
- view.h = (short)h;
- doupdate = true;
+ view.w = (short)w;
+ view.h = (short)h;
+ doupdate = true;
}
if (!(x == view.x && y == view.y)) {
- view.x = (short)x;
- view.y = (short)y;
- doupdate = true;
+ view.x = (short)x;
+ view.y = (short)y;
+ doupdate = true;
}
if (doupdate==true)
- update_visible_rect();
+ update_visible_rect();
//dbg_rect("plot_set_dimensions", &newclip);
plot_set_abs_clipping(&absclip);
- plot_clip(&newclip);
+ ctx->plot->clip(ctx, &newclip);
return(true);
}
-/***
+
+/**
* Get current canvas size
- * \param dst the GRECT * which receives the canvas size
*
+ * \param dst the GRECT * which receives the canvas size
*/
bool plot_get_dimensions(GRECT *dst)
{
@@ -1946,6 +1844,7 @@ bool plot_get_dimensions(GRECT *dst)
return(true);
}
+
/**
* set scale of plotter.
* \param scale the new scale value
@@ -1961,6 +1860,7 @@ float plot_set_scale(float scale)
return(ret);
}
+
float plot_get_scale(void)
{
return(view.scale);
@@ -1968,10 +1868,9 @@ float plot_get_scale(void)
/**
- *
* Subsequent calls to plot_clip will be clipped by the absolute clip.
- * \param area the maximum clipping rectangle (absolute screen coords)
*
+ * \param area the maximum clipping rectangle (absolute screen coords)
*/
void plot_set_abs_clipping(const GRECT *area)
{
@@ -1980,21 +1879,20 @@ void plot_set_abs_clipping(const GRECT *area)
plot_get_dimensions(&canvas);
if(!rc_intersect(area, &canvas)){
- view.abs_clipping.x0 = 0;
- view.abs_clipping.x1 = 0;
- view.abs_clipping.y0 = 0;
- view.abs_clipping.y1 = 0;
- }
- else {
- view.abs_clipping.x0 = area->g_x;
- view.abs_clipping.x1 = area->g_x + area->g_w;
- view.abs_clipping.y0 = area->g_y;
- view.abs_clipping.y1 = area->g_y + area->g_h;
+ view.abs_clipping.x0 = 0;
+ view.abs_clipping.x1 = 0;
+ view.abs_clipping.y0 = 0;
+ view.abs_clipping.y1 = 0;
+ } else {
+ view.abs_clipping.x0 = area->g_x;
+ view.abs_clipping.x1 = area->g_x + area->g_w;
+ view.abs_clipping.y0 = area->g_y;
+ view.abs_clipping.y1 = area->g_y + area->g_h;
}
}
-/***
+/**
* Get the maximum clip extent, in absolute screen coords
* \param dst the structure that receives the absolute clipping
*/
@@ -2004,7 +1902,7 @@ void plot_get_abs_clipping(struct rect *dst)
}
-/***
+/**
* Get the maximum clip extent, in absolute screen coords
* \param dst the structure that receives the absolute clipping
*/
@@ -2016,7 +1914,64 @@ void plot_get_abs_clipping_grect(GRECT *dst)
dst->g_h = view.abs_clipping.y1 - view.abs_clipping.y0;
}
-bool plot_clip(const struct rect *clip)
+
+VdiHdl plot_get_vdi_handle(void)
+{
+ return(atari_plot_vdi_handle);
+}
+
+
+long plot_get_flags(void)
+{
+ return(atari_plot_flags);
+}
+
+
+bool plot_get_clip(struct rect * out)
+{
+ out->x0 = view.clipping.x0;
+ out->y0 = view.clipping.y0;
+ out->x1 = view.clipping.x1;
+ out->y1 = view.clipping.y1;
+ return( true );
+}
+
+
+void plot_get_clip_grect(GRECT * out)
+{
+ struct rect clip={0,0,0,0};
+
+ plot_get_clip(&clip);
+
+ out->g_x = clip.x0;
+ out->g_y = clip.y0;
+ out->g_w = clip.x1 - clip.x0;
+ out->g_h = clip.y1 - clip.y0;
+}
+
+
+FONT_PLOTTER plot_get_text_plotter()
+{
+ return(fplotter);
+}
+
+
+void plot_set_text_plotter(FONT_PLOTTER font_plotter)
+{
+ fplotter = font_plotter;
+}
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_clip(const struct redraw_context *ctx, const struct rect *clip)
{
GRECT canvas, screen, gclip, maxclip;
short pxy[4];
@@ -2041,14 +1996,14 @@ bool plot_clip(const struct rect *clip)
rc_intersect(&canvas, &gclip);
if(gclip.g_h < 0){
- gclip.g_h = 0;
+ gclip.g_h = 0;
}
if (!rc_intersect(&screen, &gclip)) {
- //dbg_rect("cliprect: ", &view.clipping);
- //dbg_grect("screen: ", &canvas);
- //dbg_grect("canvas clipped: ", &gclip);
- //assert(1 == 0);
+ //dbg_rect("cliprect: ", &view.clipping);
+ //dbg_grect("screen: ", &canvas);
+ //dbg_grect("canvas clipped: ", &gclip);
+ //assert(1 == 0);
}
// When setting VDI clipping, obey to maximum cliping rectangle:
@@ -2064,106 +2019,377 @@ bool plot_clip(const struct rect *clip)
vs_clip(atari_plot_vdi_handle, 1, (short*)&pxy);
- return ( true );
+ return NSERROR_OK;
}
-VdiHdl plot_get_vdi_handle(void)
-{
- return(atari_plot_vdi_handle);
-}
-long plot_get_flags(void)
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x, int y, int radius, int angle1, int angle2)
{
- return(atari_plot_flags);
+ vswr_mode(atari_plot_vdi_handle, MD_REPLACE);
+ if (pstyle->fill_type == PLOT_OP_TYPE_NONE) {
+ return NSERROR_OK;
+ }
+
+ if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
+ vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
+ vsf_perimeter(atari_plot_vdi_handle, 1);
+ vsf_interior(atari_plot_vdi_handle, 1 );
+ v_arc(atari_plot_vdi_handle,
+ view.x + x,
+ view.y + y,
+ radius,
+ angle1 * 10,
+ angle2 * 10);
+ } else {
+ vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
+ vsl_width(atari_plot_vdi_handle, 1);
+ vsf_perimeter(atari_plot_vdi_handle, 1);
+ v_arc(atari_plot_vdi_handle,
+ view.x + x,
+ view.y + y, radius,
+ angle1 * 10,
+ angle2 * 10);
+ }
+
+ return NSERROR_OK;
}
-bool plot_get_clip(struct rect * out)
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x, int y, int radius)
{
- out->x0 = view.clipping.x0;
- out->y0 = view.clipping.y0;
- out->x1 = view.clipping.x1;
- out->y1 = view.clipping.y1;
- return( true );
+ if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
+ vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
+ vsf_perimeter(atari_plot_vdi_handle, 1);
+ vsf_interior(atari_plot_vdi_handle, 0);
+ v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
+ } else {
+ vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
+ vsf_perimeter(atari_plot_vdi_handle, 0);
+ vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
+ v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
+ }
+ return NSERROR_OK;
}
-void plot_get_clip_grect(GRECT * out)
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_line(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *line)
{
- struct rect clip={0,0,0,0};
+ short pxy[4];
+ uint32_t lt;
+ int sw = plot_style_fixed_to_int(pstyle->stroke_width);
- plot_get_clip(&clip);
+ if (((line->x0 < 0) && (line->x1 < 0)) ||
+ ((line->y0 < 0) && (line->y1 < 0))) {
+ return NSERROR_OK;
+ }
- out->g_x = clip.x0;
- out->g_y = clip.y0;
- out->g_w = clip.x1 - clip.x0;
- out->g_h = clip.y1 - clip.y0;
-}
+ pxy[0] = view.x + MAX(0, line->x0);
+ pxy[1] = view.y + MAX(0, line->y0);
+ pxy[2] = view.x + MAX(0, line->x1);
+ pxy[3] = view.y + MAX(0, line->y1);
-FONT_PLOTTER plot_get_text_plotter()
-{
- return(fplotter);
-}
+ if ((line->y0 > view.h-1) && (line->y1 > view.h-1)) {
+ return NSERROR_OK;
+ }
-void plot_set_text_plotter(FONT_PLOTTER font_plotter)
-{
- fplotter = font_plotter;
-}
+ //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h);
+ //printf("line: %d,%d,%d,%d\n", x0, y0, x1, y1);
-static bool plot_text(int x, int y, const char *text, size_t length, const plot_font_style_t *fstyle )
-{
- if (view.scale != 1.0) {
- plot_font_style_t newstyle = *fstyle;
- newstyle.size = (int)((float)fstyle->size*view.scale);
- fplotter->text(fplotter, x, y, text, length, &newstyle);
- } else {
- fplotter->text(fplotter, x, y, text, length, fstyle);
+ //plot_vdi_clip(true);
+
+ if (sw == 0) {
+ sw = 1;
}
+ NSLT2VDI(lt, pstyle)
+ vsl_type(atari_plot_vdi_handle, (lt&0x0F));
+ /* if the line style is not available within VDI system,define own style: */
+ if ((lt&0x0F) == 7 ) {
+ vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
+ }
+ vsl_width(atari_plot_vdi_handle, (short)sw);
+ vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
+ v_pline(atari_plot_vdi_handle, 2, (short *)&pxy );
+ //plot_vdi_clip(false);
- return ( true );
+ return NSERROR_OK;
}
-static bool plot_disc(int x, int y, int radius, const plot_style_t *pstyle)
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *rect)
{
- if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
- vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
- vsf_perimeter(atari_plot_vdi_handle, 1);
- vsf_interior(atari_plot_vdi_handle, 0);
- v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
- } else {
- vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
- vsf_perimeter(atari_plot_vdi_handle, 0);
- vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
- v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
+ short pxy[4];
+ GRECT r, rclip, sclip;
+ int sw = plot_style_fixed_to_int(pstyle->stroke_width);
+ uint32_t lt;
+
+ /* current canvas clip: */
+ rclip.g_x = view.clipping.x0;
+ rclip.g_y = view.clipping.y0;
+ rclip.g_w = view.clipping.x1 - view.clipping.x0;
+ rclip.g_h = view.clipping.y1 - view.clipping.y0;
+
+ /* physical clipping: */
+ sclip.g_x = rclip.g_x;
+ sclip.g_y = rclip.g_y;
+ sclip.g_w = view.vis_w;
+ sclip.g_h = view.vis_h;
+
+ rc_intersect(&sclip, &rclip);
+ r.g_x = rect->x0;
+ r.g_y = rect->y0;
+ r.g_w = rect->x1 - rect->x0;
+ r.g_h = rect->y1 - rect->y0;
+
+ if (!rc_intersect(&rclip, &r)) {
+ return NSERROR_OK;
}
- return(true);
+ if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
+ /*
+ manually draw the line, because we do not need vdi clipping
+ for vertical / horizontal line draws.
+ */
+ if (sw == 0)
+ sw = 1;
+
+ NSLT2VDI(lt, pstyle);
+ vsl_type(atari_plot_vdi_handle, (lt&0x0F));
+ /*
+ if the line style is not available within VDI system,
+ define own style:
+ */
+ if ((lt&0x0F) == 7 ) {
+ vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
+ }
+ vsl_width(atari_plot_vdi_handle, (short)sw );
+ vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
+ /* top border: */
+ if (r.g_y == rect->y0) {
+ pxy[0] = view.x + r.g_x;
+ pxy[1] = view.y + r.g_y ;
+ pxy[2] = view.x + r.g_x + r.g_w;
+ pxy[3] = view.y + r.g_y;
+ v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
+ }
+
+ /* right border: */
+ if (r.g_x + r.g_w == rect->x1 ) {
+ pxy[0] = view.x + r.g_x + r.g_w;
+ pxy[1] = view.y + r.g_y;
+ pxy[2] = view.x + r.g_x + r.g_w;
+ pxy[3] = view.y + r.g_y + r.g_h;
+ v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
+ }
+
+ /* bottom border: */
+ if ( r.g_y+r.g_h == rect->y1 ) {
+ pxy[0] = view.x + r.g_x;
+ pxy[1] = view.y + r.g_y+r.g_h;
+ pxy[2] = view.x + r.g_x+r.g_w;
+ pxy[3] = view.y + r.g_y+r.g_h;
+ v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
+ }
+
+ /* left border: */
+ if ( r.g_x == rect->x0 ) {
+ pxy[0] = view.x + r.g_x;
+ pxy[1] = view.y + r.g_y;
+ pxy[2] = view.x + r.g_x;
+ pxy[3] = view.y + r.g_y + r.g_h;
+ v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
+ }
+ }
+
+ if (pstyle->fill_type != PLOT_OP_TYPE_NONE ) {
+ short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ?
+ plot_style_fixed_to_int(pstyle->stroke_width) : 0;
+
+ vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
+ vsf_perimeter(atari_plot_vdi_handle, 0);
+ vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
+
+
+ pxy[0] = view.x + r.g_x + stroke_width;
+ pxy[1] = view.y + r.g_y + stroke_width;
+ pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width;
+ pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width;
+
+ vsf_style(atari_plot_vdi_handle, 1);
+ v_bar(atari_plot_vdi_handle, (short*)&pxy);
+ }
+
+ return NSERROR_OK;
}
-static bool plot_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *pstyle)
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const int *p,
+ unsigned int n)
{
+ short pxy[n*2];
+ unsigned int i = 0;
- vswr_mode(atari_plot_vdi_handle, MD_REPLACE );
- if (pstyle->fill_type == PLOT_OP_TYPE_NONE)
- return(true);
- if ( pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
- vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
- vsf_perimeter(atari_plot_vdi_handle, 1);
- vsf_interior(atari_plot_vdi_handle, 1 );
- v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10);
+ if (vdi_sysinfo.maxpolycoords > 0)
+ assert( (signed int)n < vdi_sysinfo.maxpolycoords);
+
+ vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
+ vsf_style(atari_plot_vdi_handle, 1);
+ for (i = 0; i<n*2; i=i+2) {
+ pxy[i] = (short)view.x+p[i];
+ pxy[i+1] = (short)view.y+p[i+1];
+ }
+
+ if (pstyle->fill_type == PLOT_OP_TYPE_SOLID) {
+ vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
+ v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy);
} else {
- vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
- vsl_width(atari_plot_vdi_handle, 1 );
- vsf_perimeter(atari_plot_vdi_handle, 1);
- v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10);
+ pxy[n*2]=pxy[0];
+ pxy[n*2+1]=pxy[1];
+ vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
+ v_pline(atari_plot_vdi_handle, n+1, (short *)&pxy);
}
- return (true);
+ return NSERROR_OK;
}
-static bool plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
+{
+ /** \todo Implement atari path plot */
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
struct bitmap * bm = NULL;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
@@ -2175,78 +2401,109 @@ static bool plot_bitmap(int x, int y, int width, int height,
bmph = atari_bitmap_get_height(bitmap);
if(view.scale != 1.0){
- width = (int)(((float)width)*view.scale);
- height = (int)(((float)height)*view.scale);
+ width = (int)(((float)width)*view.scale);
+ height = (int)(((float)height)*view.scale);
}
if ( repeat_x || repeat_y ) {
- plot_get_clip(&clip);
- if( repeat_x && width == 1 && repeat_y && height == 1 ) {
- width = MAX( width, clip.x1 - x );
- height = MAX( height, clip.y1 - y );
- } else if( repeat_x && width == 1 ) {
- width = MAX( width, clip.x1 - x);
- } else if( repeat_y && height == 1) {
- height = MAX( height, clip.y1 - y );
- }
- }
-
- if( width != bmpw || height != bmph ) {
- atari_bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height );
- if( bitmap->resized )
- bm = bitmap->resized;
- else
- bm = bitmap;
+ plot_get_clip(&clip);
+ if (repeat_x && width == 1 && repeat_y && height == 1 ) {
+ width = MAX( width, clip.x1 - x );
+ height = MAX( height, clip.y1 - y );
+ } else if (repeat_x && width == 1 ) {
+ width = MAX( width, clip.x1 - x);
+ } else if (repeat_y && height == 1) {
+ height = MAX( height, clip.y1 - y );
+ }
+ }
+
+ if (width != bmpw || height != bmph) {
+ atari_bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height );
+ if (bitmap->resized) {
+ bm = bitmap->resized;
+ } else {
+ bm = bitmap;
+ }
} else {
- bm = bitmap;
+ bm = bitmap;
}
/* out of memory? */
- if( bm == NULL ) {
- printf("plot: out of memory! bmp: %p, bmpres: %p\n", bitmap, bitmap->resized );
- return( true );
+ if (bm == NULL) {
+ printf("plot: out of memory! bmp: %p, bmpres: %p\n",
+ bitmap, bitmap->resized );
+ return NSERROR_NOMEM;
}
if (!(repeat_x || repeat_y) ) {
- plot_blit_bitmap(bm, x, y, bg, flags );
+ plot_blit_bitmap(bm, x, y, bg, flags);
} else {
- int xf,yf;
- int xoff = x;
- int yoff = y;
-
- if (yoff > clip.y0 )
- yoff = (clip.y0 - height) + ((yoff - clip.y0) % height);
- if (xoff > clip.x0 )
- xoff = (clip.x0 - width) + ((xoff - clip.x0) % width);
- /* for now, repeating just works in the rigth / down direction */
- /*
- if( repeat_x == true )
- xoff = clip.x0;
- if(repeat_y == true )
- yoff = clip.y0;
- */
-
- for( xf = xoff; xf < clip.x1; xf += width ) {
- for( yf = yoff; yf < clip.y1; yf += height ) {
- plot_blit_bitmap(bm, xf, yf, bg, flags );
- if (!repeat_y)
- break;
- }
- if (!repeat_x)
- break;
- }
- }
- return ( true );
+ int xf,yf;
+ int xoff = x;
+ int yoff = y;
+
+ if (yoff > clip.y0) {
+ yoff = (clip.y0 - height) + ((yoff - clip.y0) % height);
+ }
+ if (xoff > clip.x0) {
+ xoff = (clip.x0 - width) + ((xoff - clip.x0) % width);
+ }
+ /* for now, repeating just works in the rigth / down direction */
+ /*
+ if( repeat_x == true )
+ xoff = clip.x0;
+ if(repeat_y == true )
+ yoff = clip.y0;
+ */
+
+ for (xf = xoff; xf < clip.x1; xf += width ) {
+ for (yf = yoff; yf < clip.y1; yf += height ) {
+ plot_blit_bitmap(bm, xf, yf, bg, flags );
+ if (!repeat_y) {
+ break;
+ }
+ }
+ if (!repeat_x) {
+ break;
+ }
+ }
+ }
+
+ return NSERROR_OK;
}
-static bool plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- return ( true );
-}
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
+{
+ if (view.scale != 1.0) {
+ plot_font_style_t newstyle = *fstyle;
+ newstyle.size = (int)((float)fstyle->size*view.scale);
+ fplotter->text(fplotter, x, y, text, length, &newstyle);
+ } else {
+ fplotter->text(fplotter, x, y, text, length, fstyle);
+ }
+ return NSERROR_OK;
+}
+/** atari plottr operation table */
const struct plotter_table atari_plotters = {
.rectangle = plot_rectangle,
.line = plot_line,
diff --git a/frontends/atari/plot/plot.h b/frontends/atari/plot/plot.h
index fd73a8c33..a827c008c 100644
--- a/frontends/atari/plot/plot.h
+++ b/frontends/atari/plot/plot.h
@@ -55,6 +55,7 @@
#define ERR_PLOTTER_NOT_AVAILABLE 3 /* invalid plotter driver name passed */
struct plot_style_s;
+struct redraw_context;
struct s_vdi_sysinfo {
short vdi_handle; /**< vdi handle */
@@ -83,7 +84,16 @@ struct rect;
extern const struct plotter_table atari_plotters;
-int plot_init(char *);
+/**
+ * Init screen and font driver objects.
+ *
+ * \param ctx The current redraw context.
+ * \param fdrvrname font driver name.
+ * \return value > 1 when the objects could be succesfully created or
+ * <= 0 to indicate an error.
+ */
+int plot_init(const struct redraw_context *ctx, char *fdrvrname);
+
int plot_finalise(void);
/**
@@ -93,7 +103,17 @@ const char* plot_err_str(int i) ;
bool plot_lock(void);
bool plot_unlock(void);
-bool plot_set_dimensions( int x, int y, int w, int h );
+
+/**
+ * Set plot origin and canvas size
+ *
+ * \param ctx The current redraw context.
+ * \param x the x origin
+ * \param y the y origin
+ * \param w the width of the plot area
+ * \param h the height of the plot area
+ */
+bool plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h );
bool plot_get_dimensions(GRECT *dst);
float plot_get_scale(void);
float plot_set_scale(float);
@@ -101,13 +121,10 @@ void plot_set_abs_clipping(const GRECT *area);
void plot_get_abs_clipping(struct rect *dst);
void plot_get_abs_clipping_grect(GRECT *dst);
bool plot_get_clip(struct rect * out);
-/* Get clipping for current framebuffer as GRECT */
+/** Get clipping for current framebuffer as GRECT */
void plot_get_clip_grect(GRECT * out);
-bool plot_clip(const struct rect *clip);
VdiHdl plot_get_vdi_handle(void);
long plot_get_flags(void);
-bool plot_rectangle( int x0, int y0, int x1, int y1,const struct plot_style_s *style );
-bool plot_line( int x0, int y0, int x1, int y1, const struct plot_style_s *style );
bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
unsigned long bg, unsigned long flags);
bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor, uint32_t flags);
diff --git a/frontends/atari/rootwin.c b/frontends/atari/rootwin.c
index aa8e08047..6576eac77 100644
--- a/frontends/atari/rootwin.c
+++ b/frontends/atari/rootwin.c
@@ -105,7 +105,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
switch (msg[0]) {
case WM_REDRAW:
- LOG("WM_REDRAW");
+ NSLOG(netsurf, INFO, "WM_REDRAW");
on_redraw(data->rootwin, msg);
break;
@@ -113,7 +113,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
case WM_SIZED:
case WM_MOVED:
case WM_FULLED:
- LOG("WM_SIZED");
+ NSLOG(netsurf, INFO, "WM_SIZED");
on_resized(data->rootwin);
break;
@@ -132,7 +132,7 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
case WM_TOPPED:
case WM_NEWTOP:
case WM_UNICONIFY:
- LOG("WM_TOPPED");
+ NSLOG(netsurf, INFO, "WM_TOPPED");
gui_set_input_gui_window(data->rootwin->active_gui_window);
//window_restore_active_gui_window(data->rootwin);
// TODO: use something like "restore_active_gui_window_state()"
@@ -143,7 +143,8 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
// TODO: this needs to iterate through all gui windows and
// check if the rootwin is this window...
if (data->rootwin->active_gui_window != NULL) {
- LOG("WM_CLOSED initiated destroy for bw %p", data->rootwin->active_gui_window->browser->bw);
+ NSLOG(netsurf, INFO, "WM_CLOSED initiated destroy for bw %p",
+ data->rootwin->active_gui_window->browser->bw);
browser_window_destroy(
data->rootwin->active_gui_window->browser->bw);
}
@@ -166,13 +167,16 @@ static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
// handle key
uint16_t nkc = gem_to_norm( (short)ev_out->emo_kmeta,
(short)ev_out->emo_kreturn);
- LOG("rootwin MU_KEYBD input, nkc: %x\n", nkc);
+ NSLOG(netsurf, INFO, "rootwin MU_KEYBD input, nkc: %x\n", nkc);
retval = on_window_key_input(data->rootwin, nkc);
// printf("on_window_key_input: %d\n", retval);
}
if ((ev_out->emo_events & MU_BUTTON) != 0) {
- LOG("rootwin MU_BUTTON input, x: %d, y: %d\n", ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_x);
+ NSLOG(netsurf, INFO,
+ "rootwin MU_BUTTON input, x: %d, y: %d\n",
+ ev_out->emo_mouse.p_x,
+ ev_out->emo_mouse.p_x);
window_get_grect(data->rootwin, BROWSER_AREA_CONTENT,
&area);
if (POINT_WITHIN(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y,
@@ -312,13 +316,13 @@ void window_unref_gui_window(ROOTWIN *rootwin, struct gui_window *gw)
struct gui_window *w;
input_window = NULL;
- LOG("window: %p, gui_window: %p", rootwin, gw);
+ NSLOG(netsurf, INFO, "window: %p, gui_window: %p", rootwin, gw);
w = window_list;
// find the next active tab:
while( w != NULL ) {
if(w->root == rootwin && w != gw) {
- LOG("activating next tab %p", w);
+ NSLOG(netsurf, INFO, "activating next tab %p", w);
gui_set_input_gui_window(w);
break;
}
@@ -338,7 +342,7 @@ int window_destroy(ROOTWIN *rootwin)
assert(rootwin != NULL);
- LOG("%p", rootwin);
+ NSLOG(netsurf, INFO, "%p", rootwin);
if (gemtk_wm_get_user_data(rootwin->win) != NULL) {
free(gemtk_wm_get_user_data(rootwin->win));
@@ -404,7 +408,7 @@ void window_restore_active_gui_window(ROOTWIN *rootwin)
GRECT tb_area;
struct gui_window *gw;
- LOG("rootwin %p", rootwin);
+ NSLOG(netsurf, INFO, "rootwin %p", rootwin);
assert(rootwin->active_gui_window);
@@ -499,7 +503,7 @@ void window_set_focus(struct s_gui_win_root *rootwin,
assert(rootwin != NULL);
if (rootwin->focus.type != type || rootwin->focus.element != element) {
- LOG("Set focus: %p (%d)\n", element, type);
+ NSLOG(netsurf, INFO, "Set focus: %p (%d)\n", element, type);
rootwin->focus.type = type;
rootwin->focus.element = element;
switch( type ) {
@@ -563,11 +567,11 @@ void window_set_active_gui_window(ROOTWIN *rootwin, struct gui_window *gw)
{
struct gui_window *old_gw = rootwin->active_gui_window;
- LOG("gw %p",gw);
+ NSLOG(netsurf, INFO, "gw %p", gw);
if (rootwin->active_gui_window != NULL) {
if(rootwin->active_gui_window == gw) {
- LOG("nothing to do...");
+ NSLOG(netsurf, INFO, "nothing to do...");
return;
}
}
@@ -576,7 +580,7 @@ void window_set_active_gui_window(ROOTWIN *rootwin, struct gui_window *gw)
rootwin->active_gui_window = gw;
if (old_gw != NULL) {
- LOG("restoring window...");
+ NSLOG(netsurf, INFO, "restoring window...");
window_restore_active_gui_window(rootwin);
}
}
@@ -651,7 +655,7 @@ void window_open_search(ROOTWIN *rootwin, bool reformat)
GRECT area;
OBJECT *obj;
- LOG("rootwin %p", rootwin);
+ NSLOG(netsurf, INFO, "rootwin %p", rootwin);
gw = rootwin->active_gui_window;
bw = gw->browser->bw;
@@ -758,8 +762,11 @@ void window_redraw_favicon(ROOTWIN *rootwin, GRECT *clip_ro)
xoff = ((work.g_w-work.g_h)/2);
work.g_w = work.g_h;
}
- plot_set_dimensions( work.g_x+xoff, work.g_y, work.g_w,
- work.g_h);
+ plot_set_dimensions(&rootwin_rdrw_ctx,
+ work.g_x+xoff,
+ work.g_y,
+ work.g_w,
+ work.g_h);
wind_get_grect(rootwin->aes_handle, WF_FIRSTXYWH, &visible);
while (visible.g_h > 0 && visible.g_w > 0) {
@@ -776,8 +783,14 @@ void window_redraw_favicon(ROOTWIN *rootwin, GRECT *clip_ro)
vs_clip(plot_vdi_handle, 1, (short*)&pxy);
//dbg_pxy("vdi clip", (short*)&pxy);
- atari_plotters.bitmap(0, 0, work.g_w, work.g_h,
- rootwin->icon, 0xffffff, 0);
+ rootwin_rdrw_ctx.plot->bitmap(&rootwin_rdrw_ctx,
+ rootwin->icon,
+ 0,
+ 0,
+ work.g_w,
+ work.g_h,
+ 0xffffff,
+ 0);
} else {
//dbg_grect("redraw vis area outside", &visible);
}
@@ -822,7 +835,8 @@ static void window_redraw_content(ROOTWIN *rootwin, GRECT *content_area,
//dbg_grect("browser redraw, content area", content_area);
//dbg_grect("browser redraw, content clip", clip);
- plot_set_dimensions(content_area->g_x, content_area->g_y,
+ plot_set_dimensions(&rootwin_rdrw_ctx,
+ content_area->g_x, content_area->g_y,
content_area->g_w, content_area->g_h);
oldscale = plot_set_scale(browser_window_get_scale(rootwin->active_gui_window->browser->bw));
@@ -849,7 +863,7 @@ static void window_redraw_content(ROOTWIN *rootwin, GRECT *content_area,
redraw_area.x1 = content_area_rel.g_x + content_area_rel.g_w;
redraw_area.y1 = content_area_rel.g_y + content_area_rel.g_h;
- plot_clip(&redraw_area);
+ rootwin_rdrw_ctx.plot->clip(&rootwin_rdrw_ctx, &redraw_area);
//dbg_rect("rdrw area", &redraw_area);
@@ -1468,7 +1482,13 @@ static void on_file_dropped(ROOTWIN *rootwin, short msg[8])
buff[size] = 0;
- LOG("file: %s, ext: %s, size: %ld dropped at: %d,%d\n", (char *)buff, (char *)&ext, size, mx, my);
+ NSLOG(netsurf, INFO,
+ "file: %s, ext: %s, size: %ld dropped at: %d,%d\n",
+ (char *)buff,
+ (char *)&ext,
+ size,
+ mx,
+ my);
gui_window_get_scroll(gw, &sx, &sy);
@@ -1490,7 +1510,8 @@ static void on_file_dropped(ROOTWIN *rootwin, short msg[8])
if (ret != NSERROR_OK) {
free(buff);
/* A bad encoding should never happen */
- LOG("utf8_from_local_encoding failed");
+ NSLOG(netsurf, INFO,
+ "utf8_from_local_encoding failed");
assert(ret != NSERROR_BAD_ENCODING);
/* no memory */
goto error;
diff --git a/frontends/atari/schedule.c b/frontends/atari/schedule.c
index 48980426d..9a7836b1f 100644
--- a/frontends/atari/schedule.c
+++ b/frontends/atari/schedule.c
@@ -23,15 +23,10 @@
#include "utils/sys_time.h"
#include "utils/errors.h"
+#include "utils/log.h"
#include "atari/schedule.h"
-#ifdef DEBUG_SCHEDULER
-#include "utils/log.h"
-#else
-#define LOG(x...)
-#endif
-
#define MS_NOW() ((clock() * 1000) / CLOCKS_PER_SEC)
/* linked list of scheduled callbacks */
@@ -71,7 +66,7 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
return NSERROR_OK;
}
- LOG("removing %p, %p", callback, p);
+ NSLOG(schedule, DEBUG, "removing %p, %p", callback, p);
cur_nscb = schedule_list;
prev_nscb = NULL;
@@ -80,7 +75,9 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
if ((cur_nscb->callback == callback) &&
(cur_nscb->p == p)) {
/* item to remove */
- LOG("callback entry %p removing %p(%p)", cur_nscb, cur_nscb->callback, cur_nscb->p);
+ NSLOG(schedule, DEBUG,
+ "callback entry %p removing %p(%p)", cur_nscb,
+ cur_nscb->callback, cur_nscb->p);
/* remove callback */
unlnk_nscb = cur_nscb;
@@ -118,7 +115,8 @@ nserror atari_schedule(int ival, void (*callback)(void *p), void *p)
nscb->timeout = MS_NOW() + ival;
- LOG("adding callback %p for %p(%p) at %d ms", nscb, callback, p, nscb->timeout);
+ NSLOG(schedule, DEBUG, "adding callback %p for %p(%p) at %d ms", nscb,
+ callback, p, nscb->timeout);
nscb->callback = callback;
nscb->p = p;
@@ -164,7 +162,9 @@ int schedule_run(void)
prev_nscb->next = unlnk_nscb->next;
}
- LOG("callback entry %p running %p(%p)", unlnk_nscb, unlnk_nscb->callback, unlnk_nscb->p);
+ NSLOG(schedule, DEBUG,
+ "callback entry %p running %p(%p)", unlnk_nscb,
+ unlnk_nscb->callback, unlnk_nscb->p);
/* call callback */
unlnk_nscb->callback(unlnk_nscb->p);
@@ -173,7 +173,7 @@ int schedule_run(void)
/* need to deal with callback modifying the list. */
if (schedule_list == NULL) {
- LOG("schedule_list == NULL");
+ NSLOG(schedule, DEBUG, "schedule_list == NULL");
return -1; /* no more callbacks scheduled */
}
@@ -198,7 +198,8 @@ int schedule_run(void)
/* make rettime relative to now and convert to ms */
nexttime = nexttime - now;
- LOG("returning time to next event as %ldms", nexttime);
+ NSLOG(schedule, DEBUG, "returning time to next event as %ldms",
+ nexttime);
/*return next event time in milliseconds (24days max wait) */
return nexttime;
@@ -210,14 +211,15 @@ void list_schedule(void)
{
struct nscallback *cur_nscb;
- LOG("schedule list at ms clock %ld", MS_NOW());
+ NSLOG(schedule, DEBUG, "schedule list at ms clock %ld", MS_NOW());
cur_nscb = schedule_list;
while (cur_nscb != NULL) {
- LOG("Schedule %p at %ld", cur_nscb, cur_nscb->timeout);
+ NSLOG(schedule, DEBUG, "Schedule %p at %ld", cur_nscb,
+ cur_nscb->timeout);
cur_nscb = cur_nscb->next;
}
- LOG("Maxmium callbacks scheduled: %d", max_scheduled);
+ NSLOG(schedule, DEBUG, "Maxmium callbacks scheduled: %d", max_scheduled);
}
diff --git a/frontends/atari/search.c b/frontends/atari/search.c
index 4da7f16a3..8df4ad676 100644
--- a/frontends/atari/search.c
+++ b/frontends/atari/search.c
@@ -67,7 +67,7 @@ struct gui_search_table *atari_search_table = &search_table;
*/
void nsatari_search_set_status(bool found, void *p)
{
- LOG("%p set status: %d\n", p, found);
+ NSLOG(netsurf, INFO, "%p set status: %d\n", p, found);
// TODO: maybe update GUI
}
@@ -80,7 +80,7 @@ void nsatari_search_set_status(bool found, void *p)
void nsatari_search_set_hourglass(bool active, void *p)
{
SEARCH_FORM_SESSION s = (SEARCH_FORM_SESSION)p;
- LOG("active: %d, session: %p", active, p);
+ NSLOG(netsurf, INFO, "active: %d, session: %p", active, p);
if (active) {
gui_window_set_pointer(s->g, GUI_POINTER_PROGRESS);
} else {
@@ -99,7 +99,7 @@ void nsatari_search_set_hourglass(bool active, void *p)
*/
void nsatari_search_add_recent(const char *string, void *p)
{
- LOG("%p add recent: %s\n", p, string);
+ NSLOG(netsurf, INFO, "%p add recent: %s\n", p, string);
}
@@ -115,7 +115,7 @@ void nsatari_search_set_forward_state(bool active, void *p)
GRECT area;
SEARCH_FORM_SESSION s = (SEARCH_FORM_SESSION)p;
/* deactivate back cb */
- LOG("%p: set forward state: %d\n", p, active);
+ NSLOG(netsurf, INFO, "%p: set forward state: %d\n", p, active);
gw = s->g;
@@ -142,7 +142,7 @@ void nsatari_search_set_back_state(bool active, void *p)
GRECT area;
SEARCH_FORM_SESSION s = (SEARCH_FORM_SESSION)p;
/* deactivate back cb */
- LOG("%p: set back state: %d\n", p, active);
+ NSLOG(netsurf, INFO, "%p: set back state: %d\n", p, active);
s->state.back_avail = active;
gw = s->g;
@@ -224,7 +224,7 @@ void nsatari_search_restore_form( struct s_search_form_session *s, OBJECT *obj)
void nsatari_search_session_destroy(struct s_search_form_session *s)
{
if (s != NULL) {
- LOG("session %p", s);
+ NSLOG(netsurf, INFO, "session %p", s);
browser_window_search_clear(s->g->browser->bw);
free(s);
}
diff --git a/frontends/atari/settings.c b/frontends/atari/settings.c
index ed1fb2e45..7084bacf7 100644
--- a/frontends/atari/settings.c
+++ b/frontends/atari/settings.c
@@ -172,7 +172,7 @@ static char **read_locales(void)
atari_warn_user("Failed to load locales: %s",buf);
return(NULL);
} else {
- LOG("Reading locales from: %s...", buf);
+ NSLOG(netsurf, INFO, "Reading locales from: %s...", buf);
}
/* Count items: */
@@ -257,15 +257,15 @@ static void display_settings(void)
/* "Cache" tab: */
tmp_option_memory_cache_size = nsoption_int(memory_cache_size) / (1024*1024);
- snprintf( spare, 255, "%d", tmp_option_memory_cache_size );
+ snprintf( spare, 255, "%u", tmp_option_memory_cache_size );
set_text( SETTINGS_STR_MAX_MEM_CACHE, spare, 4 );
tmp_option_disc_cache_size = nsoption_int(disc_cache_size) / (1024*1024);
- snprintf( spare, 255, "%d", tmp_option_disc_cache_size );
+ snprintf( spare, 255, "%u", tmp_option_disc_cache_size );
set_text( SETTINGS_STR_MAX_DISC_CACHE, spare, 4 );
tmp_option_disc_cache_age = nsoption_int(disc_cache_age);
- snprintf( spare, 255, "%02d", tmp_option_disc_cache_age );
+ snprintf( spare, 255, "%02u", tmp_option_disc_cache_age );
set_text( SETTINGS_EDIT_CACHE_AGE, spare, 3 );
/* "Paths" tab: */
@@ -303,7 +303,7 @@ static void display_settings(void)
// TODO: activate this option?
tmp_option_min_reflow_period = nsoption_int(min_reflow_period);
- snprintf( spare, 255, "%04d", tmp_option_min_reflow_period );
+ snprintf( spare, 255, "%04u", tmp_option_min_reflow_period );
set_text( SETTINGS_EDIT_MIN_REFLOW_PERIOD, spare,
INPUT_MIN_REFLOW_PERIOD_MAX_LEN );
@@ -597,7 +597,7 @@ static void form_event(int index, int external)
tmp_option_memory_cache_size = 1;
if( tmp_option_memory_cache_size > 999 )
tmp_option_memory_cache_size = 999;
- snprintf( spare, 255, "%02d", tmp_option_memory_cache_size );
+ snprintf( spare, 255, "%02u", tmp_option_memory_cache_size );
set_text( SETTINGS_STR_MAX_MEM_CACHE, spare, 5 );
is_button = true;
OBJ_REDRAW(SETTINGS_STR_MAX_MEM_CACHE);
@@ -614,7 +614,7 @@ static void form_event(int index, int external)
tmp_option_disc_cache_size = 1;
if( tmp_option_disc_cache_size > 9999 )
tmp_option_disc_cache_size = 9999;
- snprintf( spare, 255, "%02d", tmp_option_disc_cache_size );
+ snprintf( spare, 255, "%02u", tmp_option_disc_cache_size );
set_text( SETTINGS_STR_MAX_DISC_CACHE, spare, 5 );
is_button = true;
OBJ_REDRAW(SETTINGS_STR_MAX_DISC_CACHE);
@@ -630,7 +630,7 @@ static void form_event(int index, int external)
if( tmp_option_disc_cache_age > 99 )
tmp_option_disc_cache_age = 0;
- snprintf( spare, 255, "%02d", tmp_option_disc_cache_age );
+ snprintf( spare, 255, "%02u", tmp_option_disc_cache_age );
set_text( SETTINGS_EDIT_CACHE_AGE, spare, 2 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_CACHE_AGE);
@@ -645,7 +645,7 @@ static void form_event(int index, int external)
if( tmp_option_max_cached_fetch_handles > 31 )
tmp_option_max_cached_fetch_handles = 31;
- snprintf( spare, 255, "%02d", tmp_option_max_cached_fetch_handles );
+ snprintf( spare, 255, "%02u", tmp_option_max_cached_fetch_handles );
set_text( SETTINGS_EDIT_MAX_CACHED_CONNECTIONS, spare, 2 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_MAX_CACHED_CONNECTIONS);
@@ -660,7 +660,7 @@ static void form_event(int index, int external)
if( tmp_option_max_fetchers > 31 )
tmp_option_max_fetchers = 31;
- snprintf( spare, 255, "%02d", tmp_option_max_fetchers );
+ snprintf( spare, 255, "%02u", tmp_option_max_fetchers );
set_text( SETTINGS_EDIT_MAX_FETCHERS, spare, 2 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_MAX_FETCHERS);
@@ -675,7 +675,7 @@ static void form_event(int index, int external)
if( tmp_option_max_fetchers_per_host > 31 )
tmp_option_max_fetchers_per_host = 31;
- snprintf( spare, 255, "%02d", tmp_option_max_fetchers_per_host );
+ snprintf( spare, 255, "%02u", tmp_option_max_fetchers_per_host );
set_text( SETTINGS_EDIT_MAX_FETCHERS_PER_HOST, spare, 2 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_MAX_FETCHERS_PER_HOST);
@@ -691,7 +691,7 @@ static void form_event(int index, int external)
if( tmp_option_expire_url > 99 )
tmp_option_expire_url = 0;
- snprintf( spare, 255, "%02d", tmp_option_expire_url );
+ snprintf( spare, 255, "%02u", tmp_option_expire_url );
set_text( SETTINGS_EDIT_HISTORY_AGE, spare, 2 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_HISTORY_AGE);
@@ -726,7 +726,7 @@ static void form_event(int index, int external)
if( tmp_option_font_min_size < 10 )
tmp_option_font_min_size = 10;
- snprintf( spare, 255, "%03d", tmp_option_font_min_size );
+ snprintf( spare, 255, "%03u", tmp_option_font_min_size );
set_text( SETTINGS_EDIT_MIN_FONT_SIZE, spare, 3 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_MIN_FONT_SIZE);
@@ -744,7 +744,7 @@ static void form_event(int index, int external)
if( tmp_option_font_size < 50 )
tmp_option_font_size = 50;
- snprintf( spare, 255, "%03d", tmp_option_font_size );
+ snprintf( spare, 255, "%03u", tmp_option_font_size );
set_text( SETTINGS_EDIT_DEF_FONT_SIZE, spare, 3 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_DEF_FONT_SIZE);
@@ -760,7 +760,7 @@ static void form_event(int index, int external)
if( tmp_option_min_reflow_period > 9999 )
tmp_option_min_reflow_period = 10;
- snprintf( spare, 255, "%04d", tmp_option_min_reflow_period );
+ snprintf( spare, 255, "%04u", tmp_option_min_reflow_period );
set_text( SETTINGS_EDIT_MIN_REFLOW_PERIOD, spare, 4 );
is_button = true;
OBJ_REDRAW(SETTINGS_EDIT_MIN_REFLOW_PERIOD);
@@ -980,12 +980,12 @@ void open_settings(void)
void close_settings(void)
{
- LOG("closing");
+ NSLOG(netsurf, INFO, "closing");
gemtk_wm_remove(settings_guiwin);
settings_guiwin = NULL;
wind_close(h_aes_win);
wind_delete(h_aes_win);
h_aes_win = 0;
- LOG("Done");
+ NSLOG(netsurf, INFO, "Done");
}
diff --git a/frontends/atari/statusbar.c b/frontends/atari/statusbar.c
index 3a216f9a8..fe2008c82 100644
--- a/frontends/atari/statusbar.c
+++ b/frontends/atari/statusbar.c
@@ -166,7 +166,7 @@ CMP_STATUSBAR sb_create( struct gui_window * gw )
void sb_destroy( CMP_STATUSBAR s )
{
- LOG("%s\n", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s\n", __FUNCTION__);
if( s ) {
if( s->comp ){
mt_CompDelete( &app, s->comp );
@@ -206,7 +206,7 @@ CMP_STATUSBAR sb_create( struct gui_window * gw )
void sb_destroy( CMP_STATUSBAR s )
{
- LOG("%s\n", __FUNCTION__);
+ NSLOG(netsurf, INFO, "%s\n", __FUNCTION__);
if( s ) {
free( s );
}
diff --git a/frontends/atari/toolbar.c b/frontends/atari/toolbar.c
index 9ed87849c..b8f42267f 100644
--- a/frontends/atari/toolbar.c
+++ b/frontends/atari/toolbar.c
@@ -94,7 +94,7 @@ static float toolbar_url_scale = 1.0;
static plot_font_style_t font_style_url = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 14*FONT_SIZE_SCALE,
+ .size = 14*PLOT_STYLE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
@@ -269,7 +269,7 @@ struct s_toolbar *toolbar_create(struct s_gui_win_root *owner)
int i;
struct s_toolbar *t;
- LOG("owner %p", owner);
+ NSLOG(netsurf, INFO, "owner %p", owner);
assert(init == true);
@@ -302,7 +302,7 @@ struct s_toolbar *toolbar_create(struct s_gui_win_root *owner)
/* create the url widget: */
font_style_url.size =
- toolbar_styles[t->style].font_height_pt * FONT_SIZE_SCALE;
+ toolbar_styles[t->style].font_height_pt * PLOT_STYLE_SCALE;
textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
textarea_setup ta_setup;
@@ -327,8 +327,9 @@ struct s_toolbar *toolbar_create(struct s_gui_win_root *owner)
t->throbber.max_index = THROBBER_MAX_INDEX;
t->throbber.running = false;
- LOG("created toolbar: %p, root: %p, textarea: %p, throbber: %p",
- t, owner, t->url.textarea, &t->throbber);
+ NSLOG(netsurf, INFO,
+ "created toolbar: %p, root: %p, textarea: %p, throbber: %p", t,
+ owner, t->url.textarea, &t->throbber);
return( t );
}
@@ -435,7 +436,7 @@ void toolbar_redraw(struct s_toolbar *tb, GRECT *clip)
if (rc_intersect(clip, &area)) {
float old_scale;
- plot_set_dimensions(area_ro.g_x, area_ro.g_y, area_ro.g_w, area_ro.g_h);
+ plot_set_dimensions(&toolbar_rdrw_ctx, area_ro.g_x, area_ro.g_y, area_ro.g_w, area_ro.g_h);
struct rect r = {
.x0 = MAX(0,area.g_x - area_ro.g_x),
.y0 = MAX(0,area.g_y - area_ro.g_y),
@@ -458,7 +459,7 @@ toolbar_update_buttons(struct s_toolbar *tb,
struct browser_window *bw,
short button)
{
- LOG("tb %p", tb);
+ NSLOG(netsurf, INFO, "tb %p", tb);
struct s_tb_button * bt;
bool enable = false;
@@ -582,7 +583,7 @@ void toolbar_set_dimensions(struct s_toolbar *tb, GRECT *area)
void toolbar_set_url(struct s_toolbar *tb, const char *text)
{
- LOG("tb %p", tb);
+ NSLOG(netsurf, INFO, "tb %p", tb);
textarea_set_text(tb->url.textarea, text);
@@ -668,7 +669,7 @@ bool toolbar_text_input(struct s_toolbar *tb, char *text)
{
bool handled = true;
- LOG("tb %p", tb);
+ NSLOG(netsurf, INFO, "tb %p", tb);
return(handled);
}
@@ -757,7 +758,7 @@ void toolbar_mouse_input(struct s_toolbar *tb, short obj, short button)
short mx, my, mb, kstat;
struct gui_window * gw;
- LOG("tb %p", tb);
+ NSLOG(netsurf, INFO, "tb %p", tb);
if (obj==TOOLBAR_AREA_URL) {
diff --git a/frontends/atari/treeview.c b/frontends/atari/treeview.c
index 93aef6eb6..23db41309 100644
--- a/frontends/atari/treeview.c
+++ b/frontends/atari/treeview.c
@@ -16,21 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sys/types.h>
-#include <string.h>
-
#include "assert.h"
-#include "cflib.h"
-#include "netsurf/inttypes.h"
-#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
-#include "netsurf/plotters.h"
-#include "netsurf/mouse.h"
+#include "netsurf/inttypes.h"
#include "netsurf/core_window.h"
-#include "desktop/treeview.h"
+#include "netsurf/plotters.h"
#include "atari/gui.h"
#include "atari/plot/plot.h"
@@ -40,30 +32,6 @@
#include "atari/res/netsurf.rsh"
-/**
- * Declare Core Window Callbacks:
- */
-
-void atari_treeview_redraw_request(struct core_window *cw,
- const struct rect *r);
-void atari_treeview_update_size(struct core_window *cw, int width, int height);
-void atari_treeview_scroll_visible(struct core_window *cw,
- const struct rect *r);
-void atari_treeview_get_window_dimensions(struct core_window *cw,
- int *width, int *height);
- // TODO: implement drag status!
-void atari_treeview_drag_status(struct core_window *cw,
- core_window_drag_status ds);
-
-static struct core_window_callback_table cw_t = {
- .redraw_request = atari_treeview_redraw_request,
- .update_size = atari_treeview_update_size,
- .scroll_visible = atari_treeview_scroll_visible,
- .get_window_dimensions = atari_treeview_get_window_dimensions,
- .drag_status = atari_treeview_drag_status
-};
-
-
struct atari_treeview_window {
struct atari_treeview_window * prev_open;
struct atari_treeview_window * next_open;
@@ -81,23 +49,12 @@ struct atari_treeview_window {
static struct atari_treeview_window * treeviews_open;
-/* native GUI event handlers: */
-static void on_mbutton_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8]);
-static void on_keybd_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8]);
-static void on_redraw_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8]);
-
-/* static utils: */
-//static void atari_treeview_dump_info(struct atari_treeview_window *tv, char *s);
-
/**
* Schedule a redraw of the treeview content
*
*/
-static void atari_treeview_redraw_grect_request(struct core_window *cw,
- GRECT *area)
+static void
+atari_treeview_redraw_grect_request(struct core_window *cw, GRECT *area)
{
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
if (cw != NULL) {
@@ -115,260 +72,77 @@ static void atari_treeview_redraw_grect_request(struct core_window *cw,
int oldy1 = tv->rdw_area.g_y + tv->rdw_area.g_h;
tv->rdw_area.g_x = MIN(tv->rdw_area.g_x, area->g_x);
tv->rdw_area.g_y = MIN(tv->rdw_area.g_y, area->g_y);
- tv->rdw_area.g_w = ( oldx1 > newx1 ) ? oldx1 - tv->rdw_area.g_x : newx1 - tv->rdw_area.g_x;
- tv->rdw_area.g_h = ( oldy1 > newy1 ) ? oldy1 - tv->rdw_area.g_y : newy1 - tv->rdw_area.g_y;
- }
- //dbg_grect("atari_treeview_request_redraw_grect", &tv->rdw_area);
- }
-}
-
-
-void atari_treeview_get_grect(struct core_window *cw, enum treeview_area_e mode,
- GRECT *dest)
-{
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+ if ( oldx1 > newx1 ) {
+ tv->rdw_area.g_w = oldx1 - tv->rdw_area.g_x;
+ } else {
+ tv->rdw_area.g_w = newx1 - tv->rdw_area.g_x;
+ }
- if (mode == TREEVIEW_AREA_CONTENT) {
- gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, dest);
- }
- else if (mode == TREEVIEW_AREA_TOOLBAR) {
- gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_TOOLBAR, dest);
+ if ( oldy1 > newy1 ) {
+ tv->rdw_area.g_h = oldy1 - tv->rdw_area.g_y;
+ } else {
+ tv->rdw_area.g_h = newy1 - tv->rdw_area.g_y;
+ }
+ }
+ //dbg_grect("atari_treeview_request_redraw_grect", &tv->rdw_area);
}
}
-GUIWIN * atari_treeview_get_gemtk_window(struct core_window *cw)
-{
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
- return(tv->window);
-}
-/*
-static void atari_treeview_dump_info(struct atari_treeview_window *tv,
- char * title)
+#ifdef ATARI_TREEVIEW_DUMP
+static void
+atari_treeview_dump_info(struct atari_treeview_window *tv, char * title)
{
printf("Treeview Dump (%s)\n", title);
printf("=================================\n");
gemtk_wm_dump_window_info(atari_treeview_get_gemtk_window((struct core_window *)tv));
GEMTK_DBG_GRECT("Redraw Area: \n", &tv->rdw_area)
- dbg_grect("Redraw Area2: \n", &tv->rdw_area);
+ dbg_grect("Redraw Area2: \n", &tv->rdw_area);
printf("Extent: x: %d, y: %d\n", tv->extent.x, tv->extent.y);
}
-*/
+#endif
-static bool atari_treeview_is_iconified(struct core_window *cw){
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+static bool atari_treeview_is_iconified(struct core_window *cw)
+{
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
- return((gemtk_wm_get_state(tv->window)&GEMTK_WM_STATUS_ICONIFIED) != 0);
+ return((gemtk_wm_get_state(tv->window)&GEMTK_WM_STATUS_ICONIFIED) != 0);
}
-static void atari_treeview_redraw_icon(struct core_window *cw, GRECT *clip)
-{
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
- GRECT visible, work;
- OBJECT * tree = gemtk_obj_get_tree(ICONIFY);
- short aesh = gemtk_wm_get_handle(tv->window);
-
- gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_WORK, &work);
-
- tree->ob_x = work.g_x;
- tree->ob_y = work.g_y;
- tree->ob_width = work.g_w;
- tree->ob_height = work.g_h;
-
- wind_get_grect(aesh, WF_FIRSTXYWH, &visible);
- while (visible.g_h > 0 && visible.g_w > 0) {
-
- if (rc_intersect(&work, &visible)) {
- objc_draw(tree, 0, 8, visible.g_x, visible.g_y, visible.g_w,
- visible.g_h);
- } else {
- //dbg_grect("redraw vis area outside", &visible);
- }
-
- wind_get_grect(aesh, WF_NEXTXYWH, &visible);
- }
-}
-void atari_treeview_redraw(struct core_window *cw)
+static void atari_treeview_redraw_icon(struct core_window *cw, GRECT *clip)
{
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
- short pxy[4];
-
- if (tv != NULL && tv->is_open) {
- if( tv->redraw && ((plot_get_flags() & PLOT_FLAG_OFFSCREEN) == 0) ) {
+ GRECT visible, work;
+ OBJECT * tree = gemtk_obj_get_tree(ICONIFY);
+ short aesh = gemtk_wm_get_handle(tv->window);
- short todo[4];
- GRECT work;
- short handle = gemtk_wm_get_handle(tv->window);
- struct gemtk_wm_scroll_info_s *slid;
+ gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_WORK, &work);
- gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, &work);
- slid = gemtk_wm_get_scroll_info(tv->window);
+ tree->ob_x = work.g_x;
+ tree->ob_y = work.g_y;
+ tree->ob_width = work.g_w;
+ tree->ob_height = work.g_h;
-// // Debug code: this 3 lines help to inspect the redraw
-// // areas...
-// pxy[0] = work.g_x;
-// pxy[1] = work.g_y;
-// pxy[2] = pxy[0] + work.g_w-1;
-// pxy[3] = pxy[1] + work.g_h-1;
-//
-// vsf_color(plot_get_vdi_handle(), 0);
-// v_bar(plot_get_vdi_handle(), (short*)&pxy);
-// evnt_timer(500);
+ wind_get_grect(aesh, WF_FIRSTXYWH, &visible);
+ while (visible.g_h > 0 && visible.g_w > 0) {
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &atari_plotters
- };
- plot_set_dimensions(work.g_x, work.g_y, work.g_w, work.g_h);
- if (plot_lock() == false)
- return;
-
- if( wind_get(handle, WF_FIRSTXYWH,
- &todo[0], &todo[1], &todo[2], &todo[3] )!=0 ) {
- while (todo[2] && todo[3]) {
-
- if(!rc_intersect(&work, (GRECT*)&todo)){
- if (wind_get(handle, WF_NEXTXYWH,
- &todo[0], &todo[1], &todo[2], &todo[3])==0) {
- break;
- }
- continue;
- }
- pxy[0] = todo[0];
- pxy[1] = todo[1];
- pxy[2] = todo[0] + todo[2]-1;
- pxy[3] = todo[1] + todo[3]-1;
- vs_clip(plot_get_vdi_handle(), 1, (short*)&pxy);
-
- // Debug code: this 3 lines help to inspect the redraw
- // areas...
-
-// vsf_color(plot_get_vdi_handle(), 3);
-// v_bar(plot_get_vdi_handle(), (short*)&pxy);
-// evnt_timer(500);
-
-
- /* convert screen to treeview coords: */
- todo[0] = todo[0] - work.g_x ;//+ slid->x_pos*slid->x_unit_px;
- todo[1] = todo[1] - work.g_y ;//+ slid->y_pos*slid->y_unit_px;
- if( todo[0] < 0 ){
- todo[2] = todo[2] + todo[0];
- todo[0] = 0;
- }
- if( todo[1] < 0 ){
- todo[3] = todo[3] + todo[1];
- todo[1] = 0;
- }
-
- if (rc_intersect((GRECT *)&tv->rdw_area,(GRECT *)&todo)) {
- struct rect clip;
-
- clip.x0 = todo[0]+(slid->x_pos*slid->x_unit_px);
- clip.y0 = todo[1]+(slid->y_pos*slid->y_unit_px);
- clip.x1 = clip.x0 + todo[2]+(slid->x_pos*slid->x_unit_px);
- clip.y1 = clip.y0 + todo[3]+(slid->y_pos*slid->y_unit_px);
-
- tv->io->draw(cw, -(slid->x_pos*slid->x_unit_px),
- -(slid->y_pos*slid->y_unit_px),
- &clip, &ctx);
- }
- vs_clip(plot_get_vdi_handle(), 0, (short*)&pxy);
- if (wind_get(handle, WF_NEXTXYWH,
- &todo[0], &todo[1], &todo[2], &todo[3])==0) {
- break;
- }
- }
- } else {
- plot_unlock();
- return;
- }
- plot_unlock();
- tv->redraw = false;
- tv->rdw_area.g_x = 65000;
- tv->rdw_area.g_y = 65000;
- tv->rdw_area.g_w = -1;
- tv->rdw_area.g_h = -1;
+ if (rc_intersect(&work, &visible)) {
+ objc_draw(tree, 0, 8, visible.g_x, visible.g_y, visible.g_w,
+ visible.g_h);
} else {
- /* just copy stuff from the offscreen buffer */
+ //dbg_grect("redraw vis area outside", &visible);
}
- }
-}
-
-/**
- * GEMTK (netsurf's GEM toolkit) event sink
- *
-*/
-static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
-{
- short retval = 0;
- struct atari_treeview_window *tv = (struct atari_treeview_window *)
- gemtk_wm_get_user_data(win);
- struct core_window *cw = (struct core_window *)tv;
-
- if( (ev_out->emo_events & MU_MESAG) != 0 ) {
- // handle message
- switch (msg[0]) {
-
- case WM_REDRAW:
- on_redraw_event(cw, ev_out, msg);
- break;
-
- default:
- break;
- }
- }
- if( (ev_out->emo_events & MU_KEYBD) != 0 ) {
- on_keybd_event(cw, ev_out, msg);
- }
- if( (ev_out->emo_events & MU_BUTTON) != 0 ) {
- LOG("Treeview click at: %d,%d\n", ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
- on_mbutton_event(cw, ev_out, msg);
- }
-
- if(tv != NULL && tv->io->gemtk_user_func != NULL){
- tv->io->gemtk_user_func(win, ev_out, msg);
- }
-
- // TODO: evaluate return values of event handler functions and pass them on:
- return(retval);
-}
-
-
-static void __CDECL on_keybd_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8])
-{
- long kstate = 0;
- long kcode = 0;
- long ucs4;
- long ik;
- unsigned short nkc = 0;
- unsigned char ascii;
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
-
- kstate = ev_out->emo_kmeta;
- kcode = ev_out->emo_kreturn;
- nkc= gem_to_norm( (short)kstate, (short)kcode );
- ascii = (nkc & 0xFF);
- ik = nkc_to_input_key(nkc, &ucs4);
-
- if (ik == 0) {
- if (ascii >= 9) {
- tv->io->keypress(cw, ucs4);
- }
- } else {
- tv->io->keypress(cw, ik);
+ wind_get_grect(aesh, WF_NEXTXYWH, &visible);
}
}
-static void __CDECL on_redraw_event(struct core_window *cw,
- EVMULT_OUT *ev_out,
- short msg[8])
+static void __CDECL
+on_redraw_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
{
GRECT work, clip;
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
@@ -425,9 +199,9 @@ static void __CDECL on_redraw_event(struct core_window *cw,
}
}
-static void __CDECL on_mbutton_event(struct core_window *cw,
- EVMULT_OUT *ev_out,
- short msg[8])
+
+static void __CDECL
+on_mbutton_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
{
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
struct gemtk_wm_scroll_info_s *slid;
@@ -444,26 +218,26 @@ static void __CDECL on_mbutton_event(struct core_window *cw,
/* mouse click relative origin: */
- short origin_rel_x = (mx-work.g_x) +
- (slid->x_pos*slid->x_unit_px);
- short origin_rel_y = (my-work.g_y) +
- (slid->y_pos*slid->y_unit_px);
+ short origin_rel_x = (mx-work.g_x) + (slid->x_pos*slid->x_unit_px);
+ short origin_rel_y = (my-work.g_y) + (slid->y_pos*slid->y_unit_px);
/* Only pass on events in the content area: */
- if( origin_rel_x >= 0 && origin_rel_y >= 0
- && mx < work.g_x + work.g_w
- && my < work.g_y + work.g_h )
- {
+ if ((origin_rel_x >= 0) &&
+ (origin_rel_y >= 0) &&
+ (mx < work.g_x + work.g_w) &&
+ (my < work.g_y + work.g_h)) {
if (ev_out->emo_mclicks == 2) {
tv->io->mouse_action(cw,
- BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_DOUBLE_CLICK,
- origin_rel_x, origin_rel_y);
+ BROWSER_MOUSE_CLICK_1 |
+ BROWSER_MOUSE_DOUBLE_CLICK,
+ origin_rel_x,
+ origin_rel_y);
return;
}
graf_mkstate(&cur_rel_x, &cur_rel_y, &mbut, &dummy);
/* check for click or hold: */
- if( (mbut&1) == 0 ){
+ if ((mbut & 1) == 0 ) {
int bms;
bms = BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_PRESS_1;
if(ev_out->emo_mclicks == 2 ) {
@@ -483,43 +257,282 @@ static void __CDECL on_mbutton_event(struct core_window *cw,
tv->startdrag.x = origin_rel_x;
tv->startdrag.y = origin_rel_y;
/* First, report mouse press, to trigger entry selection */
- tv->io->mouse_action(cw, BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_PRESS_1, cur_rel_x,
- cur_rel_y);
+ tv->io->mouse_action(cw,
+ BROWSER_MOUSE_CLICK_1 |
+ BROWSER_MOUSE_PRESS_1,
+ cur_rel_x,
+ cur_rel_y);
atari_treeview_redraw(cw);
- tv->io->mouse_action(cw, BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_ON,
- cur_rel_x, cur_rel_y);
- do{
- if (abs(prev_x-cur_rel_x) > 5 || abs(prev_y-cur_rel_y) > 5) {
+ tv->io->mouse_action(cw,
+ BROWSER_MOUSE_DRAG_1 |
+ BROWSER_MOUSE_DRAG_ON,
+ cur_rel_x,
+ cur_rel_y);
+ do {
+ if (abs(prev_x-cur_rel_x) > 5 ||
+ abs(prev_y-cur_rel_y) > 5) {
tv->io->mouse_action(cw,
- BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_DRAG_ON,
- cur_rel_x, cur_rel_y);
+ BROWSER_MOUSE_HOLDING_1 |
+ BROWSER_MOUSE_DRAG_ON,
+ cur_rel_x,
+ cur_rel_y);
prev_x = cur_rel_x;
prev_y = cur_rel_y;
}
if (tv->redraw) {
// TODO: maybe GUI poll would fit better here?
- // ... is gui_poll re-entrance save?
+ // ... is gui_poll re-entrance save?
atari_treeview_redraw(cw);
}
/* sample mouse button state: */
- graf_mkstate(&cur_rel_x, &cur_rel_y, &mbut, &dummy);
- cur_rel_x = (cur_rel_x-work.g_x)+(slid->x_pos*slid->x_unit_px);
- cur_rel_y = (cur_rel_y-work.g_y)+(slid->y_pos*slid->y_unit_px);
- } while( mbut & 1 );
+ graf_mkstate(&cur_rel_x,
+ &cur_rel_y,
+ &mbut,
+ &dummy);
+ cur_rel_x = (cur_rel_x-work.g_x) +
+ (slid->x_pos*slid->x_unit_px);
+ cur_rel_y = (cur_rel_y-work.g_y) +
+ (slid->y_pos*slid->y_unit_px);
+ } while (mbut & 1);
/* End drag: */
- tv->io->mouse_action(cw, BROWSER_MOUSE_HOVER, cur_rel_x, cur_rel_y);
+ tv->io->mouse_action(cw,
+ BROWSER_MOUSE_HOVER,
+ cur_rel_x,
+ cur_rel_y);
gem_set_cursor(&gem_cursors.arrow);
}
}
}
+static void __CDECL
+on_keybd_event(struct core_window *cw, EVMULT_OUT *ev_out, short msg[8])
+{
+ long kstate = 0;
+ long kcode = 0;
+ long ucs4;
+ long ik;
+ unsigned short nkc = 0;
+ unsigned char ascii;
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+
+ kstate = ev_out->emo_kmeta;
+ kcode = ev_out->emo_kreturn;
+ nkc= gem_to_norm( (short)kstate, (short)kcode );
+ ascii = (nkc & 0xFF);
+ ik = nkc_to_input_key(nkc, &ucs4);
+
+ if (ik == 0) {
+ if (ascii >= 9) {
+ tv->io->keypress(cw, ucs4);
+ }
+ } else {
+ tv->io->keypress(cw, ik);
+ }
+}
+
+
+/**
+ * GEMTK (netsurf's GEM toolkit) event sink
+ *
+ */
+static short handle_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
+{
+ short retval = 0;
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)
+ gemtk_wm_get_user_data(win);
+ struct core_window *cw = (struct core_window *)tv;
+
+ if( (ev_out->emo_events & MU_MESAG) != 0 ) {
+ // handle message
+ switch (msg[0]) {
+
+ case WM_REDRAW:
+ on_redraw_event(cw, ev_out, msg);
+ break;
+
+ default:
+ break;
+ }
+ }
+ if ((ev_out->emo_events & MU_KEYBD) != 0 ) {
+ on_keybd_event(cw, ev_out, msg);
+ }
+ if ((ev_out->emo_events & MU_BUTTON) != 0 ) {
+ NSLOG(netsurf, INFO, "Treeview click at: %d,%d\n",
+ ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
+ on_mbutton_event(cw, ev_out, msg);
+ }
+
+ if (tv != NULL && tv->io->gemtk_user_func != NULL){
+ tv->io->gemtk_user_func(win, ev_out, msg);
+ }
+
+ // TODO: evaluate return values of event handler functions and pass them on:
+ return(retval);
+}
+
+
+/**
+ * callback from core to request an invalidation of a window area.
+ *
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] r area to redraw or NULL for the entire window area.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+atari_treeview_invalidate_area(struct core_window *cw,
+ const struct rect *r)
+{
+ GRECT area;
+ struct gemtk_wm_scroll_info_s * slid;
+ struct atari_treeview_window * tv = (struct atari_treeview_window *)cw;
+
+ assert(tv);
+
+ if (r != NULL) {
+ RECT_TO_GRECT(r, &area);
+
+ slid = gemtk_wm_get_scroll_info(tv->window);
+
+ //dbg_rect("redraw rect request", r);
+
+ // treeview redraw is always full window width:
+ area.g_x = 0;
+ area.g_w = 8000;
+ // but vertical redraw region is clipped:
+ area.g_y = r->y0 - (slid->y_pos*slid->y_unit_px);
+ area.g_h = r->y1 - r->y0;
+ } else {
+ atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
+ }
+ atari_treeview_redraw_grect_request(cw, &area);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Update the limits of the window
+ *
+ * \param cw the core window object
+ * \param width the width in px, or negative if don't care
+ * \param height the height in px, or negative if don't care
+ */
+static void
+atari_treeview_update_size(struct core_window *cw, int width, int height)
+{
+ GRECT area;
+ struct gemtk_wm_scroll_info_s *slid;
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+
+ if (tv != NULL) {
+
+ if (tv->disposing)
+ return;
+
+ /* Get acces to the gemtk window slider settings: */
+ slid = gemtk_wm_get_scroll_info(tv->window);
+
+ /* recalculate and refresh sliders: */
+ atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
+ if (width > -1) {
+ slid->x_units = (width/slid->x_unit_px);
+ } else {
+ slid->x_units = 1;
+ }
+
+ if (height > -1) {
+ slid->y_units = (height/slid->y_unit_px);
+ } else {
+ slid->y_units = 1;
+ }
+
+ tv->extent.x = width;
+ tv->extent.y = height;
+
+
+ /* printf("units content: %d, units viewport: %d\n",
+ (height/slid->y_unit_px),
+ (area.g_h/slid->y_unit_px));
+ */
+ gemtk_wm_update_slider(tv->window, GEMTK_WM_VH_SLIDER);
+ }
+}
+
+
+/**
+ * Scroll the window to make area visible
+ *
+ * \param cw the core window object
+ * \param r rectangle to make visible
+ */
+static void
+atari_treeview_scroll_visible(struct core_window *cw, const struct rect *r)
+{
+ /* atari frontend doesn't support dragging outside the treeview */
+ /* so there is no need to implement this? */
+}
+
+
+/**
+ * Get window viewport dimensions
+ *
+ * \param cw the core window object
+ * \param width to be set to viewport width in px, if non NULL
+ * \param height to be set to viewport height in px, if non NULL
+ */
+static void
+atari_treeview_get_window_dimensions(struct core_window *cw,
+ int *width,
+ int *height)
+{
+ if ((cw != NULL) &&
+ (width != NULL || height != NULL)) {
+ GRECT work;
+ atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &work);
+ *width = work.g_w;
+ *height = work.g_h;
+ }
+}
+
+
+/**
+ * Inform corewindow owner of drag status
+ *
+ * \param cw the core window object
+ * \param ds the current drag status
+ */
+static void
+atari_treeview_drag_status(struct core_window *cw, core_window_drag_status ds)
+{
+
+}
+
+
+/**
+ * Declare Core Window Callbacks:
+ */
+static struct core_window_callback_table cw_t = {
+ .invalidate = atari_treeview_invalidate_area,
+ .update_size = atari_treeview_update_size,
+ .scroll_visible = atari_treeview_scroll_visible,
+ .get_window_dimensions = atari_treeview_get_window_dimensions,
+ .drag_status = atari_treeview_drag_status
+};
+
+
+/* exported interface documented in atari/treeview.h */
struct core_window *
atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks,
- void * user_data, uint32_t flags)
+ void * user_data, uint32_t flags)
{
/* allocate the core_window struct: */
@@ -528,7 +541,7 @@ atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks,
tv = calloc(1, sizeof(struct atari_treeview_window));
if (tv == NULL) {
- LOG("calloc failed");
+ NSLOG(netsurf, INFO, "calloc failed");
atari_warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
return NULL;
}
@@ -555,12 +568,12 @@ atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks,
assert(tv->io);
assert(tv->io->init_phase2);
- /* Now that the window is configured for treeview content, */
- /* call init_phase2 which must create the treeview */
- /* descriptor, and at least setup the the default */
- /* event handlers of the treeview: */
- /* It would be more simple to not pass around the callbacks */
- /* but the treeview constructor requires them for initialization... */
+ /* Now that the window is configured for treeview content, */
+ /* call init_phase2 which must create the treeview */
+ /* descriptor, and at least setup the the default */
+ /* event handlers of the treeview: */
+ /* It would be more simple to not pass around the callbacks */
+ /* but the treeview constructor requires them for initialization... */
nserror err = tv->io->init_phase2((struct core_window *)tv, &cw_t);
if (err != NSERROR_OK) {
free(tv);
@@ -570,6 +583,147 @@ atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks,
return((struct core_window *)tv);
}
+
+/* exported interface documented in atari/treeview.h */
+void
+atari_treeview_get_grect(struct core_window *cw,
+ enum treeview_area_e mode,
+ GRECT *dest)
+{
+
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+
+ if (mode == TREEVIEW_AREA_CONTENT) {
+ gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, dest);
+ }
+ else if (mode == TREEVIEW_AREA_TOOLBAR) {
+ gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_TOOLBAR, dest);
+ }
+}
+
+
+/* exported interface documented in atari/treeview.h */
+GUIWIN * atari_treeview_get_gemtk_window(struct core_window *cw)
+{
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+ return(tv->window);
+}
+
+
+/* exported interface documented in atari/treeview.h */
+void atari_treeview_redraw(struct core_window *cw)
+{
+ struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
+ short pxy[4];
+
+ if (tv != NULL && tv->is_open) {
+ if( tv->redraw && ((plot_get_flags() & PLOT_FLAG_OFFSCREEN) == 0) ) {
+
+ short todo[4];
+ GRECT work;
+ short handle = gemtk_wm_get_handle(tv->window);
+ struct gemtk_wm_scroll_info_s *slid;
+
+ gemtk_wm_get_grect(tv->window, GEMTK_WM_AREA_CONTENT, &work);
+ slid = gemtk_wm_get_scroll_info(tv->window);
+
+// // Debug code: this 3 lines help to inspect the redraw
+// // areas...
+// pxy[0] = work.g_x;
+// pxy[1] = work.g_y;
+// pxy[2] = pxy[0] + work.g_w-1;
+// pxy[3] = pxy[1] + work.g_h-1;
+//
+// vsf_color(plot_get_vdi_handle(), 0);
+// v_bar(plot_get_vdi_handle(), (short*)&pxy);
+// evnt_timer(500);
+
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &atari_plotters
+ };
+ plot_set_dimensions(&ctx,
+ work.g_x,
+ work.g_y,
+ work.g_w,
+ work.g_h);
+ if (plot_lock() == false)
+ return;
+
+ if( wind_get(handle, WF_FIRSTXYWH,
+ &todo[0], &todo[1], &todo[2], &todo[3] )!=0 ) {
+ while (todo[2] && todo[3]) {
+
+ if(!rc_intersect(&work, (GRECT*)&todo)){
+ if (wind_get(handle, WF_NEXTXYWH,
+ &todo[0], &todo[1], &todo[2], &todo[3])==0) {
+ break;
+ }
+ continue;
+ }
+ pxy[0] = todo[0];
+ pxy[1] = todo[1];
+ pxy[2] = todo[0] + todo[2]-1;
+ pxy[3] = todo[1] + todo[3]-1;
+ vs_clip(plot_get_vdi_handle(), 1, (short*)&pxy);
+
+ // Debug code: this 3 lines help to inspect the redraw
+ // areas...
+
+// vsf_color(plot_get_vdi_handle(), 3);
+// v_bar(plot_get_vdi_handle(), (short*)&pxy);
+// evnt_timer(500);
+
+
+ /* convert screen to treeview coords: */
+ todo[0] = todo[0] - work.g_x ;//+ slid->x_pos*slid->x_unit_px;
+ todo[1] = todo[1] - work.g_y ;//+ slid->y_pos*slid->y_unit_px;
+ if( todo[0] < 0 ){
+ todo[2] = todo[2] + todo[0];
+ todo[0] = 0;
+ }
+ if( todo[1] < 0 ){
+ todo[3] = todo[3] + todo[1];
+ todo[1] = 0;
+ }
+
+ if (rc_intersect((GRECT *)&tv->rdw_area,(GRECT *)&todo)) {
+ struct rect clip;
+
+ clip.x0 = todo[0]+(slid->x_pos*slid->x_unit_px);
+ clip.y0 = todo[1]+(slid->y_pos*slid->y_unit_px);
+ clip.x1 = clip.x0 + todo[2]+(slid->x_pos*slid->x_unit_px);
+ clip.y1 = clip.y0 + todo[3]+(slid->y_pos*slid->y_unit_px);
+
+ tv->io->draw(cw, -(slid->x_pos*slid->x_unit_px),
+ -(slid->y_pos*slid->y_unit_px),
+ &clip, &ctx);
+ }
+ vs_clip(plot_get_vdi_handle(), 0, (short*)&pxy);
+ if (wind_get(handle, WF_NEXTXYWH,
+ &todo[0], &todo[1], &todo[2], &todo[3])==0) {
+ break;
+ }
+ }
+ } else {
+ plot_unlock();
+ return;
+ }
+ plot_unlock();
+ tv->redraw = false;
+ tv->rdw_area.g_x = 65000;
+ tv->rdw_area.g_y = 65000;
+ tv->rdw_area.g_w = -1;
+ tv->rdw_area.g_h = -1;
+ } else {
+ /* just copy stuff from the offscreen buffer */
+ }
+ }
+}
+
+
+/* exported interface documented in atari/treeview.h */
void atari_treeview_delete(struct core_window * cw)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
@@ -583,6 +737,7 @@ void atari_treeview_delete(struct core_window * cw)
}
+/* exported interface documented in atari/treeview.h */
void atari_treeview_open(struct core_window *cw, GRECT *pos)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
@@ -607,25 +762,32 @@ void atari_treeview_open(struct core_window *cw, GRECT *pos)
}
}
+
+/* exported interface documented in atari/treeview.h */
bool atari_treeview_is_open(struct core_window *cw)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
return(tv->is_open);
}
-void atari_treeview_set_user_data(struct core_window * cw,
- void *user_data_ptr)
+
+/* exported interface documented in atari/treeview.h */
+void atari_treeview_set_user_data(struct core_window *cw, void *user_data_ptr)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
tv->user_data = user_data_ptr;
}
+
+/* exported interface documented in atari/treeview.h */
void * atari_treeview_get_user_data(struct core_window * cw)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
return(tv->user_data);
}
+
+/* exported interface documented in atari/treeview.h */
void atari_treeview_close(struct core_window *cw)
{
struct atari_treeview_window *tv = (struct atari_treeview_window*)cw;
@@ -646,150 +808,24 @@ void atari_treeview_close(struct core_window *cw)
}
-/**
- * Core Window Callbacks:
- */
-
-/**
- * Request a redraw of the window
- *
- * \param cw the core window object
- * \param r rectangle to redraw
- */
-void atari_treeview_redraw_request(struct core_window *cw, const struct rect *r)
-{
- GRECT area;
- struct gemtk_wm_scroll_info_s * slid;
- struct atari_treeview_window * tv = (struct atari_treeview_window *)cw;
-
- RECT_TO_GRECT(r, &area)
-
- assert(tv);
-
- slid = gemtk_wm_get_scroll_info(tv->window);
-
- //dbg_rect("redraw rect request", r);
-
- // treeview redraw is always full window width:
- area.g_x = 0;
- area.g_w = 8000;
- // but vertical redraw region is clipped:
- area.g_y = r->y0 - (slid->y_pos*slid->y_unit_px);
- area.g_h = r->y1 - r->y0;
- atari_treeview_redraw_grect_request(cw, &area);
-}
-
-/**
- * Update the limits of the window
- *
- * \param cw the core window object
- * \param width the width in px, or negative if don't care
- * \param height the height in px, or negative if don't care
- */
-void atari_treeview_update_size(struct core_window *cw, int width, int height)
-{
- GRECT area;
- struct gemtk_wm_scroll_info_s *slid;
- struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
-
- if (tv != NULL) {
-
- if (tv->disposing)
- return;
-
- /* Get acces to the gemtk window slider settings: */
- slid = gemtk_wm_get_scroll_info(tv->window);
-
- /* recalculate and refresh sliders: */
- atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
- if (width > -1) {
- slid->x_units = (width/slid->x_unit_px);
- } else {
- slid->x_units = 1;
- }
-
- if (height > -1) {
- slid->y_units = (height/slid->y_unit_px);
- } else {
- slid->y_units = 1;
- }
-
- tv->extent.x = width;
- tv->extent.y = height;
-
-
- /*printf("units content: %d, units viewport: %d\n", (height/slid->y_unit_px),
- (area.g_h/slid->y_unit_px));*/
- gemtk_wm_update_slider(tv->window, GEMTK_WM_VH_SLIDER);
- }
-}
-
-
-/**
- * Scroll the window to make area visible
- *
- * \param cw the core window object
- * \param r rectangle to make visible
- */
-void atari_treeview_scroll_visible(struct core_window *cw, const struct rect *r)
-{
- /* atari frontend doesn't support dragging outside the treeview */
- /* so there is no need to implement this? */
-}
-
-
-/**
- * Get window viewport dimensions
- *
- * \param cw the core window object
- * \param width to be set to viewport width in px, if non NULL
- * \param height to be set to viewport height in px, if non NULL
- */
-void atari_treeview_get_window_dimensions(struct core_window *cw,
- int *width, int *height)
-{
- if (cw != NULL && (width != NULL || height != NULL)) {
- GRECT work;
- atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &work);
- *width = work.g_w;
- *height = work.g_h;
- }
-}
-
-
-/**
- * Inform corewindow owner of drag status
- *
- * \param cw the core window object
- * \param ds the current drag status
- */
-void atari_treeview_drag_status(struct core_window *cw,
- core_window_drag_status ds)
-{
-
-}
-
+/* exported interface documented in atari/treeview.h */
void atari_treeview_flush_redraws(void)
{
struct atari_treeview_window *tmp;
tmp = treeviews_open;
- if(tmp){
- while(tmp){
- assert(tmp->is_open);
- if(tmp->redraw){
- if (atari_treeview_is_iconified((struct core_window *)tmp)) {
- /* No content redraw for iconified windows */
- /* because otherwise the icon draw function would */
- /* have to deal with plot canvas coords */
- continue;
- }
-
- atari_treeview_redraw((struct core_window *)tmp);
- }
- tmp = tmp->next_open;
+ while (tmp != NULL) {
+ assert(tmp->is_open);
+ if (tmp->redraw &&
+ (!atari_treeview_is_iconified((struct core_window *)tmp))) {
+ /* Content redraw only for iconified windows
+ * because otherwise the icon draw function
+ * would have to deal with plot canvas coords
+ */
+ atari_treeview_redraw((struct core_window *)tmp);
}
+ tmp = tmp->next_open;
}
-}
+}
diff --git a/frontends/atari/treeview.h b/frontends/atari/treeview.h
index d10129eaa..fe267b122 100644
--- a/frontends/atari/treeview.h
+++ b/frontends/atari/treeview.h
@@ -68,7 +68,7 @@ struct atari_treeview_callbacks {
/**
* Initalize an window to be an treeview window.
*
-*/
+ */
struct core_window *atari_treeview_create(GUIWIN *win, struct atari_treeview_callbacks * callbacks, void * user_data, uint32_t flags);
/**
diff --git a/frontends/atari/verify_ssl.c b/frontends/atari/verify_ssl.c
index 055fd3057..b099fe488 100644
--- a/frontends/atari/verify_ssl.c
+++ b/frontends/atari/verify_ssl.c
@@ -80,7 +80,9 @@ static void __CDECL cert_info_draw( WINDOW * win, short buf[8], void * data)
if( line == NULL )
return;
- LOG("Cert info draw, win: %p, data: %p, scrollx: %d", win, data, dp->scrollx );
+ NSLOG(netsurf, INFO,
+ "Cert info draw, win: %p, data: %p, scrollx: %d", win, data,
+ dp->scrollx);
WindGet( win, WF_WORKXYWH, &x, &y, &w, &h );
/*using static values here, as RsrcUserDraw has mem leaks & a very small stack */
@@ -158,7 +160,7 @@ static void do_popup( WINDOW *win, int index, int mode, void *data)
char * items[dp->num_certs];
short x, y;
unsigned int i;
- LOG("do_popup: num certs: %d", dp->num_certs);
+ NSLOG(netsurf, INFO, "do_popup: num certs: %d", dp->num_certs);
for( i = 0; i<dp->num_certs; i++) {
items[i] = malloc( 48 );
strncpy(items[i], (char*)&dp->cert_infos_n[i].issuer, 46 );
@@ -182,8 +184,10 @@ static void do_popup( WINDOW *win, int index, int mode, void *data)
-bool verify_ssl_form_do( const char * url, const struct ssl_cert_info * cert_infos_n ,
- unsigned long num_certs )
+bool
+verify_ssl_form_do(const char * url,
+ const struct ssl_cert_info * cert_infos_n,
+ unsigned long num_certs)
{
OBJECT *tree;
WINDOW * form;
@@ -191,6 +195,13 @@ bool verify_ssl_form_do( const char * url, const struct ssl_cert_info * cert_inf
bool bres = false;
bool cont = true;
int res = 0;
+
+ RsrcGaddr (h_gem_rsrc , R_TREE, VERIFY, &tree);
+ ObjcString( tree, VERIFY_LBL_HOST, (char*)url );
+ ObjcChange( OC_OBJC, tree, VERIFY_BT_ACCEPT, 0, 0 );
+ ObjcChange( OC_OBJC, tree, VERIFY_BT_REJECT, 0, 0 );
+ form = FormWindBegin( tree, (char*)"SSL Verify failed" );
+
dp.cert_infos_n = (struct ssl_cert_info *)cert_infos_n;
dp.num_certs = num_certs;
dp.scrollx = 0;
@@ -199,12 +210,6 @@ bool verify_ssl_form_do( const char * url, const struct ssl_cert_info * cert_inf
dp.cols = cert_display_width( &dp.cert_infos_n[dp.current] );
dp.rows = 8;
dp.tree = tree;
-
- RsrcGaddr (h_gem_rsrc , R_TREE, VERIFY, &tree);
- ObjcString( tree, VERIFY_LBL_HOST, (char*)url );
- ObjcChange( OC_OBJC, tree, VERIFY_BT_ACCEPT, 0, 0 );
- ObjcChange( OC_OBJC, tree, VERIFY_BT_REJECT, 0, 0 );
- form = FormWindBegin( tree, (char*)"SSL Verify failed" );
EvntDataAdd( form, WM_REDRAW, cert_info_draw, (void*)&dp, EV_BOT );
/* this results in some extended objects which can not be freed: :( */
/* RsrcUserDraw( OC_FORM, tree, VERIFY_BOX_DETAILS, cert_info_draw,(void*)&dp ) ; */
@@ -243,7 +248,7 @@ bool verify_ssl_form_do( const char * url, const struct ssl_cert_info * cert_inf
break;
case VERIFY_BT_SCROLL_R:
- LOG("scroll r!");
+ NSLOG(netsurf, INFO, "scroll r!");
cont = true;
dp.scrollx += 1;
if( dp.scrollx > (dp.cols - (272 / 8 )) )
diff --git a/frontends/beos/bitmap.cpp b/frontends/beos/bitmap.cpp
index 68d8442ab..c4b008755 100644
--- a/frontends/beos/bitmap.cpp
+++ b/frontends/beos/bitmap.cpp
@@ -377,7 +377,7 @@ nsbeos_bitmap_get_pretile_x(struct bitmap* bitmap)
if (!bitmap->pretile_x) {
int width = bitmap->primary->Bounds().Width() + 1;
int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
- LOG("Pretiling %p for X*%d", bitmap, xmult);
+ NSLOG(netsurf, INFO, "Pretiling %p for X*%d", bitmap, xmult);
bitmap->pretile_x = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, 1);
}
return bitmap->pretile_x;
@@ -396,7 +396,7 @@ nsbeos_bitmap_get_pretile_y(struct bitmap* bitmap)
if (!bitmap->pretile_y) {
int height = bitmap->primary->Bounds().Height() + 1;
int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
- LOG("Pretiling %p for Y*%d", bitmap, ymult);
+ NSLOG(netsurf, INFO, "Pretiling %p for Y*%d", bitmap, ymult);
bitmap->pretile_y = nsbeos_bitmap_generate_pretile(bitmap->primary, 1, ymult);
}
return bitmap->pretile_y;
@@ -416,7 +416,8 @@ nsbeos_bitmap_get_pretile_xy(struct bitmap* bitmap)
int height = bitmap->primary->Bounds().Height() + 1;
int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
- LOG("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult);
+ NSLOG(netsurf, INFO, "Pretiling %p for X*%d Y*%d", bitmap,
+ xmult, ymult);
bitmap->pretile_xy = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, ymult);
}
return bitmap->pretile_xy;
diff --git a/frontends/beos/fetch_rsrc.cpp b/frontends/beos/fetch_rsrc.cpp
index e77f4c96e..ae3648354 100644
--- a/frontends/beos/fetch_rsrc.cpp
+++ b/frontends/beos/fetch_rsrc.cpp
@@ -71,13 +71,15 @@ BResources *gAppResources = NULL;
static bool fetch_rsrc_initialise(lwc_string *scheme)
{
- LOG("fetch_rsrc_initialise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "fetch_rsrc_initialise called for %s",
+ lwc_string_data(scheme));
return true;
}
static void fetch_rsrc_finalise(lwc_string *scheme)
{
- LOG("fetch_rsrc_finalise called for %s", lwc_string_data(scheme));
+ NSLOG(netsurf, INFO, "fetch_rsrc_finalise called for %s",
+ lwc_string_data(scheme));
}
static bool fetch_rsrc_can_fetch(const nsurl *url)
@@ -162,7 +164,7 @@ static bool fetch_rsrc_process(struct fetch_rsrc_context *c)
* rsrc://[TYPE][@NUM]/name[,mime]
*/
- LOG("*** Processing %s", c->url);
+ NSLOG(netsurf, INFO, "*** Processing %s", c->url);
if (strlen(c->url) < 7) {
/* 7 is the minimum possible length (rsrc://) */
@@ -199,11 +201,13 @@ static bool fetch_rsrc_process(struct fetch_rsrc_context *c)
uint8 c1, c2, c3, c4;
if (sscanf(params, "%c%c%c%c", &c1, &c2, &c3, &c4) > 3) {
type = c1 << 24 | c2 << 16 | c3 << 8 | c4;
- LOG("fetch_rsrc: type:%4.4s\n", (char *)&type);
+ NSLOG(netsurf, INFO, "fetch_rsrc: type:%4.4s\n",
+ (char *)&type);
}
}
- LOG("fetch_rsrc: 0x%08lx, %ld, '%s'\n", type, id, c->name);
+ NSLOG(netsurf, INFO, "fetch_rsrc: 0x%08lx, %ld, '%s'\n", type, id,
+ c->name);
bool found;
if (id)
@@ -278,7 +282,10 @@ static void fetch_rsrc_poll(lwc_string *scheme)
char header[64];
fetch_set_http_code(c->parent_fetch, 200);
- LOG("setting rsrc: MIME type to %s, length to %zd", c->mimetype, c->datalen);
+ NSLOG(netsurf, INFO,
+ "setting rsrc: MIME type to %s, length to %zd",
+ c->mimetype,
+ c->datalen);
/* Any callback can result in the fetch being aborted.
* Therefore, we _must_ check for this after _every_
* call to fetch_rsrc_send_callback().
@@ -308,7 +315,8 @@ static void fetch_rsrc_poll(lwc_string *scheme)
fetch_rsrc_send_callback(&msg, c);
}
} else {
- LOG("Processing of %s failed!", c->url);
+ NSLOG(netsurf, INFO, "Processing of %s failed!",
+ c->url);
/* Ensure that we're unlocked here. If we aren't,
* then fetch_rsrc_process() is broken.
diff --git a/frontends/beos/filetype.cpp b/frontends/beos/filetype.cpp
index 7a2ca97e5..bc988a8c7 100644
--- a/frontends/beos/filetype.cpp
+++ b/frontends/beos/filetype.cpp
@@ -18,6 +18,7 @@
#define __STDBOOL_H__ 1
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
diff --git a/frontends/beos/font.cpp b/frontends/beos/font.cpp
index 407918f0c..5e7e78228 100644
--- a/frontends/beos/font.cpp
+++ b/frontends/beos/font.cpp
@@ -130,7 +130,7 @@ void nsbeos_style_to_font(BFont &font, const struct plot_font_style *fstyle)
}
//fprintf(stderr, "nsbeos_style_to_font: value %f unit %d\n", style->font_size.value.length.value, style->font_size.value.length.unit);
- size = fstyle->size / FONT_SIZE_SCALE;
+ size = fstyle->size / PLOT_STYLE_SCALE;
//fprintf(stderr, "nsbeos_style_to_font: %f %d\n", size, style->font_size.value.length.unit);
@@ -204,8 +204,8 @@ static nserror beos_font_position(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- //LOG("(, '%s', %d, %d, , )", string, length, x);
- //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x);
+ NSLOG(netsurf, DEEPDEBUG, "(, '%s', %d, %d, , )", string, length, x);
+
int index;
BFont font;
@@ -261,8 +261,7 @@ static nserror beos_font_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x);
- //LOG("(, '%s', %d, %d, , )", string, length, x);
+ NSLOG(netsurf, DEEPDEBUG, "(, '%s', %d, %d, , )", string, length, x);
int index = 0;
BFont font;
diff --git a/frontends/beos/gui.cpp b/frontends/beos/gui.cpp
index d3321b58d..19f8eac49 100644
--- a/frontends/beos/gui.cpp
+++ b/frontends/beos/gui.cpp
@@ -112,7 +112,7 @@ static int sEventPipe[2];
/* exported function defined in beos/gui.h */
nserror beos_warn_user(const char *warning, const char *detail)
{
- LOG("warn_user: %s (%s)", warning, detail);
+ NSLOG(netsurf, INFO, "warn_user: %s (%s)", warning, detail);
BAlert *alert;
BString text(warning);
if (detail)
@@ -354,14 +354,15 @@ static void check_homedir(void)
if (err < B_OK) {
/* we really can't continue without a home directory. */
- LOG("Can't find user settings directory - nowhere to store state!");
+ NSLOG(netsurf, INFO,
+ "Can't find user settings directory - nowhere to store state!");
die("NetSurf needs to find the user settings directory in order to run.\n");
}
path.Append("NetSurf");
err = create_directory(path.Path(), 0644);
if (err < B_OK) {
- LOG("Unable to create %s", path.Path());
+ NSLOG(netsurf, INFO, "Unable to create %s", path.Path());
die("NetSurf could not create its settings directory.\n");
}
}
@@ -387,7 +388,7 @@ static nsurl *gui_get_resource_url(const char *path)
path = "favicon.png";
u << path;
- LOG("(%s) -> '%s'\n", path, u.String());
+ NSLOG(netsurf, INFO, "(%s) -> '%s'\n", path, u.String());
nsurl_create(u.String(), &url);
return url;
}
@@ -588,7 +589,7 @@ static void gui_init(int argc, char** argv)
die("Unable to load throbber image.\n");
find_resource(buf, "Choices", "%/Choices");
- LOG("Using '%s' as Preferences file", buf);
+ NSLOG(netsurf, INFO, "Using '%s' as Preferences file", buf);
options_file_location = strdup(buf);
nsoption_read(buf, NULL);
@@ -631,12 +632,12 @@ static void gui_init(int argc, char** argv)
if (nsoption_charp(cookie_file) == NULL) {
find_resource(buf, "Cookies", "%/Cookies");
- LOG("Using '%s' as Cookies file", buf);
+ NSLOG(netsurf, INFO, "Using '%s' as Cookies file", buf);
nsoption_set_charp(cookie_file, strdup(buf));
}
if (nsoption_charp(cookie_jar) == NULL) {
find_resource(buf, "Cookies", "%/Cookies");
- LOG("Using '%s' as Cookie Jar file", buf);
+ NSLOG(netsurf, INFO, "Using '%s' as Cookie Jar file", buf);
nsoption_set_charp(cookie_jar, strdup(buf));
}
if ((nsoption_charp(cookie_file) == NULL) ||
@@ -645,13 +646,13 @@ static void gui_init(int argc, char** argv)
if (nsoption_charp(url_file) == NULL) {
find_resource(buf, "URLs", "%/URLs");
- LOG("Using '%s' as URL file", buf);
+ NSLOG(netsurf, INFO, "Using '%s' as URL file", buf);
nsoption_set_charp(url_file, strdup(buf));
}
if (nsoption_charp(ca_path) == NULL) {
find_resource(buf, "certs", "/etc/ssl/certs");
- LOG("Using '%s' as certificate path", buf);
+ NSLOG(netsurf, INFO, "Using '%s' as certificate path", buf);
nsoption_set_charp(ca_path, strdup(buf));
}
@@ -763,17 +764,21 @@ void nsbeos_gui_poll(void)
timeout.tv_sec = (long)(next_schedule / 1000000LL);
timeout.tv_usec = (long)(next_schedule % 1000000LL);
- //LOG("gui_poll: select(%d, ..., %Ldus", max_fd, next_schedule);
+ NSLOG(netsurf, DEEPDEBUG,
+ "gui_poll: select(%d, ..., %Ldus",
+ max_fd, next_schedule);
fd_count = select(max_fd, &read_fd_set, &write_fd_set, &exc_fd_set,
&timeout);
- //LOG("select: %d\n", fd_count);
+ NSLOG(netsurf, DEEPDEBUG, "select: %d\n", fd_count);
if (fd_count > 0 && FD_ISSET(sEventPipe[0], &read_fd_set)) {
BMessage *message;
int len = read(sEventPipe[0], &message, sizeof(void *));
- //LOG("gui_poll: BMessage ? %d read", len);
+ NSLOG(netsurf, DEEPDEBUG, "gui_poll: BMessage ? %d read", len);
if (len == sizeof(void *)) {
- //LOG("gui_poll: BMessage.what %-4.4s\n", &(message->what));
+ NSLOG(netsurf, DEEPDEBUG,
+ "gui_poll: BMessage.what %-4.4s\n",
+ &(message->what));
nsbeos_dispatch_event(message);
}
}
@@ -1038,7 +1043,7 @@ int main(int argc, char** argv)
char path[12];
sprintf(path,"%.2s/Messages", getenv("LC_MESSAGES"));
- LOG("Loading messages from resource %s\n", path);
+ NSLOG(netsurf, INFO, "Loading messages from resource %s\n", path);
const uint8_t* res = (const uint8_t*)resources.LoadResource('data', path, &size);
if (size > 0 && res != NULL) {
@@ -1061,6 +1066,12 @@ int main(int argc, char** argv)
netsurf_exit();
+ /* finalise options */
+ nsoption_finalise(nsoptions, nsoptions_default);
+
+ /* finalise logging */
+ nslog_finalise();
+
return 0;
}
diff --git a/frontends/beos/plotters.cpp b/frontends/beos/plotters.cpp
index 5ba3fbbcb..2c50f9497 100644
--- a/frontends/beos/plotters.cpp
+++ b/frontends/beos/plotters.cpp
@@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Target independent plotting (BeOS/Haiku implementation).
+/**
+ * \file
+ * BeOS/Haiku implementation target independent plotting.
*/
#define __STDBOOL_H__ 1
@@ -31,11 +32,11 @@
#include <View.h>
#include <Shape.h>
extern "C" {
-#include "netsurf/plotters.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
#include "utils/nsurl.h"
+#include "netsurf/plotters.h"
}
#include "beos/font.h"
#include "beos/gui.h"
@@ -50,581 +51,751 @@ extern "C" {
* the right-bottom pixel is actually part of the BRect!
*/
-static bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
-static bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6]);
-static bool nsbeos_plot_clip(const struct rect *ns_clip);
-static bool nsbeos_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
-static bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style);
-static bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style);
-static bool nsbeos_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags);
-
-
#warning make patterns nicer
-static const pattern kDottedPattern = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
-static const pattern kDashedPattern = { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 };
-
-static const rgb_color kBlackColor = { 0, 0, 0, 255 };
-
-struct plotter_table plot;
+static const pattern kDottedPattern = {
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa
+};
+static const pattern kDashedPattern = {
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33
+};
-const struct plotter_table nsbeos_plotters = {
- nsbeos_plot_clip,
- nsbeos_plot_arc,
- nsbeos_plot_disc,
- nsbeos_plot_line,
- nsbeos_plot_rectangle,
- nsbeos_plot_polygon,
- nsbeos_plot_path,
- nsbeos_plot_bitmap,
- nsbeos_plot_text,
- NULL, // Group Start
- NULL, // Group End
- NULL, // Flush
- true // option_knockout
+static const rgb_color kBlackColor = {
+ 0, 0, 0, 255
};
+//struct plotter_table plot;
// #pragma mark - implementation
-
BView *nsbeos_current_gc(void)
{
- return current_view;
+ return current_view;
}
+
BView *nsbeos_current_gc_lock(void)
{
- BView *view = current_view;
- if (view && view->LockLooper())
- return view;
- return NULL;
+ BView *view = current_view;
+ if (view && view->LockLooper())
+ return view;
+ return NULL;
}
+
void nsbeos_current_gc_unlock(void)
{
- if (current_view)
- current_view->UnlockLooper();
+ if (current_view) {
+ current_view->UnlockLooper();
+ }
}
+
void nsbeos_current_gc_set(BView *view)
{
- // XXX: (un)lock previous ?
- current_view = view;
+ // XXX: (un)lock previous ?
+ current_view = view;
}
-bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+static nserror
+nsbeos_plot_bbitmap(int x, int y, int width, int height, BBitmap *b, colour bg)
{
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- BView *view;
+ /* XXX: This currently ignores the background colour supplied.
+ * Does this matter?
+ */
+
+ if (width == 0 || height == 0) {
+ return NSERROR_OK;
+ }
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
+
+ drawing_mode oldmode = view->DrawingMode();
+ source_alpha alpha;
+ alpha_function func;
+ view->GetBlendingMode(&alpha, &func);
+ //view->SetDrawingMode(B_OP_OVER);
+ view->SetDrawingMode(B_OP_ALPHA);
+ view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
+
+ // XXX DrawBitmap() resamples if rect doesn't match,
+ // but doesn't do any filtering
+ // XXX: use Zeta API if available ?
+
+ BRect rect(x, y, x + width - 1, y + height - 1);
+ /*
+ rgb_color old = view->LowColor();
+ if (bg != NS_TRANSPARENT) {
+ view->SetLowColor(nsbeos_rgb_colour(bg));
+ view->FillRect(rect, B_SOLID_LOW);
+ }
+ */
+ view->DrawBitmap(b, rect);
+ // maybe not needed?
+ //view->SetLowColor(old);
+ view->SetBlendingMode(alpha, func);
+ view->SetDrawingMode(oldmode);
+
+ //nsbeos_current_gc_unlock();
+
+ return NSERROR_OK;
+}
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
- nsbeos_set_colour(style->fill_colour);
+static BPoint transform_pt(float x, float y, const float transform[6])
+{
+#warning XXX: verify
+ //return BPoint(x, y);
+ BPoint pt;
+ pt.x = x * transform[0] + y * transform[1] + transform[4];
+ pt.y = x * transform[2] + y * transform[3] + transform[5];
+ /*
+ printf("TR: {%f, %f} { %f, %f, %f, %f, %f, %f} = { %f, %f }\n",
+ x, y,
+ transform[0], transform[1], transform[2],
+ transform[3], transform[4], transform[5],
+ pt.x, pt.y);
+ */
+ return pt;
+}
- BRect rect(x0, y0, x1 - 1, y1 - 1);
- view->FillRect(rect);
- //nsbeos_current_gc_unlock();
+rgb_color nsbeos_rgb_colour(colour c)
+{
+ rgb_color color;
+ if (c == NS_TRANSPARENT)
+ return B_TRANSPARENT_32_BIT;
+ color.red = c & 0x0000ff;
+ color.green = (c & 0x00ff00) >> 8;
+ color.blue = (c & 0xff0000) >> 16;
+ return color;
+}
- }
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- pattern pat;
- BView *view;
+void nsbeos_set_colour(colour c)
+{
+ rgb_color color = nsbeos_rgb_colour(c);
+ BView *view = nsbeos_current_gc();
+ view->SetHighColor(color);
+}
- switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
- default:
- pat = B_SOLID_HIGH;
- break;
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
- pat = kDottedPattern;
- break;
+/**
+ * Plot a caret.
+ *
+ * It is assumed that the plotters have been set up.
+ */
+void nsbeos_plot_caret(int x, int y, int h)
+{
+ BView *view;
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
- pat = kDashedPattern;
- break;
- }
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL)
+ /* TODO: report an error here */
+ return;
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
+ BPoint start(x, y);
+ BPoint end(x, y + h - 1);
+#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO)
+ view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
+#else
+ view->SetHighColor(kBlackColor);
+#endif
+ view->StrokeLine(start, end);
- nsbeos_set_colour(style->stroke_colour);
+ //nsbeos_current_gc_unlock();
+}
- float pensize = view->PenSize();
- view->SetPenSize(style->stroke_width);
- BRect rect(x0, y0, x1, y1);
- view->StrokeRect(rect, pat);
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param ns_clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_clip(const struct redraw_context *ctx, const struct rect *ns_clip)
+{
+ BView *view;
+ //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1);
- view->SetPenSize(pensize);
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
- //nsbeos_current_gc_unlock();
+ BRect rect(ns_clip->x0, ns_clip->y0, ns_clip->x1 - 1, ns_clip->y1 - 1);
+ BRegion clip(rect);
+ view->ConstrainClippingRegion(NULL);
+ if (view->Bounds() != rect) {
+ view->ConstrainClippingRegion(&clip);
+ }
- }
+ //nsbeos_current_gc_unlock();
- return true;
+ return NSERROR_OK;
}
-
-bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
- pattern pat;
- BView *view;
+ BView *view;
- switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
- default:
- pat = B_SOLID_HIGH;
- break;
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
- pat = kDottedPattern;
- break;
+ nsbeos_set_colour(style->fill_colour);
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
- pat = kDashedPattern;
- break;
- }
+ BPoint center(x, y);
+ float angle = angle1; // in degree
+ float span = angle2 - angle1; // in degree
+ view->StrokeArc(center, radius, radius, angle, span);
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
+ //nsbeos_current_gc_unlock();
- nsbeos_set_colour(style->stroke_colour);
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ BView *view;
- float pensize = view->PenSize();
- view->SetPenSize(style->stroke_width);
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
- BPoint start(x0, y0);
- BPoint end(x1, y1);
- view->StrokeLine(start, end, pat);
+ nsbeos_set_colour(style->fill_colour);
- view->SetPenSize(pensize);
+ BPoint center(x, y);
+ if (style->fill_type != PLOT_OP_TYPE_NONE)
+ view->FillEllipse(center, radius, radius);
+ else
+ view->StrokeEllipse(center, radius, radius);
- //nsbeos_current_gc_unlock();
+ //nsbeos_current_gc_unlock();
- return true;
+ return NSERROR_OK;
}
-bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
- unsigned int i;
- BView *view;
+ pattern pat;
+ BView *view;
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ pat = B_SOLID_HIGH;
+ break;
- nsbeos_set_colour(style->fill_colour);
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ pat = kDottedPattern;
+ break;
- BPoint points[n];
-
- for (i = 0; i < n; i++) {
- points[i] = BPoint(p[2 * i] - 0.5, p[2 * i + 1] - 0.5);
- }
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ pat = kDashedPattern;
+ break;
+ }
- if (style->fill_colour == NS_TRANSPARENT)
- view->StrokePolygon(points, (int32)n);
- else
- view->FillPolygon(points, (int32)n);
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_OK;
+ }
- return true;
-}
+ nsbeos_set_colour(style->stroke_colour);
+ float pensize = view->PenSize();
+ view->SetPenSize(plot_style_fixed_to_float(style->stroke_width));
+ BPoint start(line->x0, line->y0);
+ BPoint end(line->x1, line->y1);
+ view->StrokeLine(start, end, pat);
+ view->SetPenSize(pensize);
-bool nsbeos_plot_clip(const struct rect *ns_clip)
-{
- BView *view;
- //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1);
-
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
-
- BRect rect(ns_clip->x0, ns_clip->y0, ns_clip->x1 - 1,
- ns_clip->y1 - 1);
- BRegion clip(rect);
- view->ConstrainClippingRegion(NULL);
- if (view->Bounds() != rect)
- view->ConstrainClippingRegion(&clip);
-
-
- //nsbeos_current_gc_unlock();
-
- return true;
+ //nsbeos_current_gc_unlock();
+
+ return NSERROR_OK;
}
-bool nsbeos_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param nsrect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *nsrect)
{
- return nsfont_paint(fstyle, text, length, x, y);
-}
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ BView *view;
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
-bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style)
-{
- BView *view;
+ nsbeos_set_colour(style->fill_colour);
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
+ BRect rect(nsrect->x0, nsrect->y0, nsrect->x1 - 1, nsrect->y1 - 1);
+ view->FillRect(rect);
- nsbeos_set_colour(style->fill_colour);
+ //nsbeos_current_gc_unlock();
+ }
- BPoint center(x, y);
- if (style->fill_type != PLOT_OP_TYPE_NONE)
- view->FillEllipse(center, radius, radius);
- else
- view->StrokeEllipse(center, radius, radius);
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ pattern pat;
+ BView *view;
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ pat = B_SOLID_HIGH;
+ break;
- //nsbeos_current_gc_unlock();
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ pat = kDottedPattern;
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ pat = kDashedPattern;
+ break;
+ }
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
- return true;
+ nsbeos_set_colour(style->stroke_colour);
+
+ float pensize = view->PenSize();
+ view->SetPenSize(plot_style_fixed_to_float(style->stroke_width));
+
+ BRect rect(nsrect->x0, nsrect->y0, nsrect->x1, nsrect->y1);
+ view->StrokeRect(rect, pat);
+
+ view->SetPenSize(pensize);
+
+ //nsbeos_current_gc_unlock();
+ }
+
+ return NSERROR_OK;
}
-bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
- BView *view;
+ unsigned int i;
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
+ nsbeos_set_colour(style->fill_colour);
- nsbeos_set_colour(style->fill_colour);
+ BPoint points[n];
- BPoint center(x, y);
- float angle = angle1; // in degree
- float span = angle2 - angle1; // in degree
- view->StrokeArc(center, radius, radius, angle, span);
+ for (i = 0; i < n; i++) {
+ points[i] = BPoint(p[2 * i] - 0.5, p[2 * i + 1] - 0.5);
+ }
- //nsbeos_current_gc_unlock();
+ if (style->fill_colour == NS_TRANSPARENT) {
+ view->StrokePolygon(points, (int32)n);
+ } else {
+ view->FillPolygon(points, (int32)n);
+ }
- return true;
+ return NSERROR_OK;
}
-static bool nsbeos_plot_bbitmap(int x, int y, int width, int height,
- BBitmap *b, colour bg)
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
- /* XXX: This currently ignores the background colour supplied.
- * Does this matter?
- */
-
- if (width == 0 || height == 0)
- return true;
-
- BView *view;
-
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
-
- drawing_mode oldmode = view->DrawingMode();
- source_alpha alpha;
- alpha_function func;
- view->GetBlendingMode(&alpha, &func);
- //view->SetDrawingMode(B_OP_OVER);
- view->SetDrawingMode(B_OP_ALPHA);
- view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
-
- // XXX DrawBitmap() resamples if rect doesn't match,
- // but doesn't do any filtering
- // XXX: use Zeta API if available ?
-
- BRect rect(x, y, x + width - 1, y + height - 1);
- /*
- rgb_color old = view->LowColor();
- if (bg != NS_TRANSPARENT) {
- view->SetLowColor(nsbeos_rgb_colour(bg));
- view->FillRect(rect, B_SOLID_LOW);
- }
- */
- view->DrawBitmap(b, rect);
- // maybe not needed?
- //view->SetLowColor(old);
- view->SetBlendingMode(alpha, func);
- view->SetDrawingMode(oldmode);
-
- //nsbeos_current_gc_unlock();
-
- return true;
+ unsigned int i;
+ BShape shape;
+
+ if (n == 0) {
+ return NSERROR_OK;
+ }
+
+ if (p[0] != PLOTTER_PATH_MOVE) {
+ NSLOG(netsurf, INFO, "path doesn't start with a move");
+ return NSERROR_INVALID;
+ }
+
+ for (i = 0; i < n; ) {
+ if (p[i] == PLOTTER_PATH_MOVE) {
+ BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
+ shape.MoveTo(pt);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_CLOSE) {
+ shape.Close();
+ i++;
+ } else if (p[i] == PLOTTER_PATH_LINE) {
+ BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
+ shape.LineTo(pt);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_BEZIER) {
+ BPoint pt[3] = {
+ transform_pt(p[i + 1], p[i + 2], transform),
+ transform_pt(p[i + 3], p[i + 4], transform),
+ transform_pt(p[i + 5], p[i + 6], transform)
+ };
+ shape.BezierTo(pt);
+ i += 7;
+ } else {
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
+ return NSERROR_INVALID;
+ }
+ }
+ shape.Close();
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ rgb_color old_high = view->HighColor();
+ float old_pen = view->PenSize();
+ view->SetPenSize(plot_style_fixed_to_float(pstyle->stroke_width));
+ view->MovePenTo(0, 0);
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ view->SetHighColor(nsbeos_rgb_colour(pstyle->fill_colour));
+ view->FillShape(&shape);
+ }
+ if (pstyle->stroke_colour != NS_TRANSPARENT) {
+ view->SetHighColor(nsbeos_rgb_colour(pstyle->stroke_colour));
+ view->StrokeShape(&shape);
+ }
+ // restore
+ view->SetPenSize(old_pen);
+ view->SetHighColor(old_high);
+
+ //nsbeos_current_gc_unlock();
+
+ return NSERROR_OK;
}
-bool nsbeos_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
- int doneheight = 0, donewidth = 0;
- BBitmap *primary;
- BBitmap *pretiled;
+ int doneheight = 0, donewidth = 0;
+ BBitmap *primary;
+ BBitmap *pretiled;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
bool repeat_y = (flags & BITMAPF_REPEAT_Y);
- if (!(repeat_x || repeat_y)) {
- /* Not repeating at all, so just plot it */
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just plot it */
primary = nsbeos_bitmap_get_primary(bitmap);
return nsbeos_plot_bbitmap(x, y, width, height, primary, bg);
- }
-
- if (repeat_x && !repeat_y)
- pretiled = nsbeos_bitmap_get_pretile_x(bitmap);
- if (repeat_x && repeat_y)
- pretiled = nsbeos_bitmap_get_pretile_xy(bitmap);
- if (!repeat_x && repeat_y)
- pretiled = nsbeos_bitmap_get_pretile_y(bitmap);
- primary = nsbeos_bitmap_get_primary(bitmap);
-
- /* use the primary and pretiled widths to scale the w/h provided */
- width *= pretiled->Bounds().Width() + 1;
- width /= primary->Bounds().Width() + 1;
- height *= pretiled->Bounds().Height() + 1;
- height /= primary->Bounds().Height() + 1;
-
- BView *view;
-
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL) {
- beos_warn_user("No GC", 0);
- return false;
- }
-
- // XXX: do we really need to use clipping reg ?
- // I guess it's faster to not draw clipped out stuff...
-
- BRect cliprect;
- BRegion clipreg;
- view->GetClippingRegion(&clipreg);
- cliprect = clipreg.Frame();
-
- //XXX: FIXME
-
- if (y > cliprect.top)
- doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height);
- else
- doneheight = y;
-
- while (doneheight < ((int)cliprect.bottom)) {
- if (x > cliprect.left)
- donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width);
- else
- donewidth = x;
- while (donewidth < (cliprect.right)) {
- nsbeos_plot_bbitmap(donewidth, doneheight,
- width, height, pretiled, bg);
- donewidth += width;
- if (!repeat_x) break;
- }
- doneheight += height;
- if (!repeat_y) break;
- }
+ }
+
+ if (repeat_x && !repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_x(bitmap);
+ if (repeat_x && repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_xy(bitmap);
+ if (!repeat_x && repeat_y)
+ pretiled = nsbeos_bitmap_get_pretile_y(bitmap);
+ primary = nsbeos_bitmap_get_primary(bitmap);
+
+ /* use the primary and pretiled widths to scale the w/h provided */
+ width *= pretiled->Bounds().Width() + 1;
+ width /= primary->Bounds().Width() + 1;
+ height *= pretiled->Bounds().Height() + 1;
+ height /= primary->Bounds().Height() + 1;
+
+ BView *view;
+
+ view = nsbeos_current_gc/*_lock*/();
+ if (view == NULL) {
+ beos_warn_user("No GC", 0);
+ return NSERROR_INVALID;
+ }
+
+ // XXX: do we really need to use clipping reg ?
+ // I guess it's faster to not draw clipped out stuff...
+
+ BRect cliprect;
+ BRegion clipreg;
+ view->GetClippingRegion(&clipreg);
+ cliprect = clipreg.Frame();
+
+ //XXX: FIXME
+
+ if (y > cliprect.top) {
+ doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height);
+ } else {
+ doneheight = y;
+ }
+
+ while (doneheight < ((int)cliprect.bottom)) {
+ if (x > cliprect.left) {
+ donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width);
+ } else {
+ donewidth = x;
+ }
+
+ while (donewidth < (cliprect.right)) {
+ nsbeos_plot_bbitmap(donewidth, doneheight,
+ width, height, pretiled, bg);
+ donewidth += width;
+ if (!repeat_x) {
+ break;
+ }
+ }
+ doneheight += height;
+ if (!repeat_y) {
+ break;
+ }
+ }
#warning WRITEME
- return true;
-}
-static BPoint transform_pt(float x, float y, const float transform[6])
-{
-#warning XXX: verify
- //return BPoint(x, y);
- BPoint pt;
- pt.x = x * transform[0] + y * transform[1] + transform[4];
- pt.y = x * transform[2] + y * transform[3] + transform[5];
- /*
- printf("TR: {%f, %f} { %f, %f, %f, %f, %f, %f} = { %f, %f }\n",
- x, y,
- transform[0], transform[1], transform[2],
- transform[3], transform[4], transform[5],
- pt.x, pt.y);
- */
- return pt;
+ return NSERROR_OK;
}
-bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- unsigned int i;
-
- if (n == 0)
- return true;
-
- if (p[0] != PLOTTER_PATH_MOVE) {
- LOG("path doesn't start with a move");
- return false;
- }
-
- BShape shape;
-
- for (i = 0; i < n; ) {
- if (p[i] == PLOTTER_PATH_MOVE) {
- BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
- shape.MoveTo(pt);
- i += 3;
- } else if (p[i] == PLOTTER_PATH_CLOSE) {
- shape.Close();
- i++;
- } else if (p[i] == PLOTTER_PATH_LINE) {
- BPoint pt(transform_pt(p[i + 1], p[i + 2], transform));
- shape.LineTo(pt);
- i += 3;
- } else if (p[i] == PLOTTER_PATH_BEZIER) {
- BPoint pt[3] = {
- transform_pt(p[i + 1], p[i + 2], transform),
- transform_pt(p[i + 3], p[i + 4], transform),
- transform_pt(p[i + 5], p[i + 6], transform)
- };
- shape.BezierTo(pt);
- i += 7;
- } else {
- LOG("bad path command %f", p[i]);
- return false;
- }
- }
- shape.Close();
-
- BView *view;
-
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL)
- return false;
-
- rgb_color old_high = view->HighColor();
- float old_pen = view->PenSize();
- view->SetPenSize(width);
- view->MovePenTo(0, 0);
- if (fill != NS_TRANSPARENT) {
- view->SetHighColor(nsbeos_rgb_colour(fill));
- view->FillShape(&shape);
- }
- if (c != NS_TRANSPARENT) {
- view->SetHighColor(nsbeos_rgb_colour(c));
- view->StrokeShape(&shape);
- }
- // restore
- view->SetPenSize(old_pen);
- view->SetHighColor(old_high);
-
- //nsbeos_current_gc_unlock();
-
- return true;
-}
-rgb_color nsbeos_rgb_colour(colour c)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsbeos_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- rgb_color color;
- if (c == NS_TRANSPARENT)
- return B_TRANSPARENT_32_BIT;
- color.red = c & 0x0000ff;
- color.green = (c & 0x00ff00) >> 8;
- color.blue = (c & 0xff0000) >> 16;
- return color;
-}
+ if (!nsfont_paint(fstyle, text, length, x, y)) {
+ return NSERROR_INVALID;
+ }
-void nsbeos_set_colour(colour c)
-{
- rgb_color color = nsbeos_rgb_colour(c);
- BView *view = nsbeos_current_gc();
- view->SetHighColor(color);
+ return NSERROR_OK;
}
-/** Plot a caret. It is assumed that the plotters have been set up. */
-void nsbeos_plot_caret(int x, int y, int h)
-{
- BView *view;
-
- view = nsbeos_current_gc/*_lock*/();
- if (view == NULL)
- /* TODO: report an error here */
- return;
-
- BPoint start(x, y);
- BPoint end(x, y + h - 1);
-#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO)
- view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
-#else
- view->SetHighColor(kBlackColor);
-#endif
- view->StrokeLine(start, end);
- //nsbeos_current_gc_unlock();
+/**
+ * beos plotter operation table
+ */
+const struct plotter_table nsbeos_plotters = {
+ nsbeos_plot_clip,
+ nsbeos_plot_arc,
+ nsbeos_plot_disc,
+ nsbeos_plot_line,
+ nsbeos_plot_rectangle,
+ nsbeos_plot_polygon,
+ nsbeos_plot_path,
+ nsbeos_plot_bitmap,
+ nsbeos_plot_text,
+ NULL, // Group Start
+ NULL, // Group End
+ NULL, // Flush
+ true // option_knockout
+};
-}
#ifdef TEST_PLOTTERS
//
static void test_plotters(void)
{
- int x0, y0;
- int x1, y1;
- struct rect r;
-
- x0 = 5;
- y0 = 5;
- x1 = 35;
- y1 = 6;
-
- plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, false);
- y0+=2; y1+=2;
- plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, false);
- y0+=2; y1+=2;
- plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, true);
- y0+=2; y1+=2;
- plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, true);
- y0+=10; y1+=20;
-
- plot.fill(x0, y0, x1, y1, 0x00ff0000);
- plot.rectangle(x0+10, y0+10, x1-x0+1, y1-y0+1, 2, 0x00ffff00, true, false);
- y0+=30; y1+=30;
-
- r.x0 = x0 + 2;
- r.y0 = y0 + 2;
- r.x1 = x1 - 2;
- r.y1 = y1 - 2;
- plot.clip(&r);
-
- plot.fill(x0, y0, x1, y1, 0x00000000);
- plot.disc(x1, y1, 8, 0x000000ff, false);
-
- r.x0 = 0;
- r.y0 = 0;
- r.x1 = 300;
- r.y1 = 300;
- plot.clip(&r);
-
- y0+=30; y1+=30;
-
+ int x0, y0;
+ int x1, y1;
+ struct rect r;
+
+ x0 = 5;
+ y0 = 5;
+ x1 = 35;
+ y1 = 6;
+
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, false);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, false);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, true);
+ y0+=2; y1+=2;
+ plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, true);
+ y0+=10; y1+=20;
+
+ plot.fill(x0, y0, x1, y1, 0x00ff0000);
+ plot.rectangle(x0+10, y0+10, x1-x0+1, y1-y0+1, 2, 0x00ffff00, true, false);
+ y0+=30; y1+=30;
+
+ r.x0 = x0 + 2;
+ r.y0 = y0 + 2;
+ r.x1 = x1 - 2;
+ r.y1 = y1 - 2;
+ plot.clip(&r);
+
+ plot.fill(x0, y0, x1, y1, 0x00000000);
+ plot.disc(x1, y1, 8, 0x000000ff, false);
+
+ r.x0 = 0;
+ r.y0 = 0;
+ r.x1 = 300;
+ r.y1 = 300;
+ plot.clip(&r);
+
+ y0+=30; y1+=30;
+
}
#include <Application.h>
@@ -632,28 +803,27 @@ static void test_plotters(void)
#include <Window.h>
class PTView : public BView {
public:
- PTView(BRect frame) : BView(frame, "view", B_FOLLOW_NONE, B_WILL_DRAW) {};
- virtual ~PTView() {};
- virtual void Draw(BRect update)
- {
- test_plotters();
- };
+ PTView(BRect frame) : BView(frame, "view", B_FOLLOW_NONE, B_WILL_DRAW) {};
+ virtual ~PTView() {};
+ virtual void Draw(BRect update)
+ {
+ test_plotters();
+ };
};
extern "C" void test_plotters_main(void);
void test_plotters_main(void)
{
- BApplication app("application/x-vnd.NetSurf");
- memcpy(&plot, &nsbeos_plotters, sizeof(plot));
- BRect frame(0,0,300,300);
- PTView *view = new PTView(frame);
- frame.OffsetBySelf(100,100);
- BWindow *win = new BWindow(frame, "NetSurfPlotterTest", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE);
- win->AddChild(view);
- nsbeos_current_gc_set(view);
- win->Show();
- app.Run();
+ BApplication app("application/x-vnd.NetSurf");
+ memcpy(&plot, &nsbeos_plotters, sizeof(plot));
+ BRect frame(0,0,300,300);
+ PTView *view = new PTView(frame);
+ frame.OffsetBySelf(100,100);
+ BWindow *win = new BWindow(frame, "NetSurfPlotterTest", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE);
+ win->AddChild(view);
+ nsbeos_current_gc_set(view);
+ win->Show();
+ app.Run();
}
#endif /* TEST_PLOTTERS */
-
diff --git a/frontends/beos/res/adblock.css b/frontends/beos/res/adblock.css
index ff2485622..0d12aaa7c 120000
--- a/frontends/beos/res/adblock.css
+++ b/frontends/beos/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
+../../../resources/adblock.css \ No newline at end of file
diff --git a/frontends/beos/res/ca-bundle.txt b/frontends/beos/res/ca-bundle.txt
index 0b0e416ad..1187fa51a 120000
--- a/frontends/beos/res/ca-bundle.txt
+++ b/frontends/beos/res/ca-bundle.txt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
+../../../resources/ca-bundle \ No newline at end of file
diff --git a/frontends/beos/res/de/welcome.html b/frontends/beos/res/de/welcome.html
index 98a53b215..b77e23743 120000
--- a/frontends/beos/res/de/welcome.html
+++ b/frontends/beos/res/de/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/de/welcome.html,faf \ No newline at end of file
+../../../../resources/de/welcome.html \ No newline at end of file
diff --git a/frontends/beos/res/default.css b/frontends/beos/res/default.css
index a8579eb7c..fa3ae6c26 120000
--- a/frontends/beos/res/default.css
+++ b/frontends/beos/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
+../../../resources/default.css \ No newline at end of file
diff --git a/frontends/beos/res/en/credits.html b/frontends/beos/res/en/credits.html
index 252516fd7..f73ecd4aa 120000
--- a/frontends/beos/res/en/credits.html
+++ b/frontends/beos/res/en/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
+../../../../resources/en/credits.html \ No newline at end of file
diff --git a/frontends/beos/res/en/licence.html b/frontends/beos/res/en/licence.html
index 79f73669b..0c3b430b7 120000
--- a/frontends/beos/res/en/licence.html
+++ b/frontends/beos/res/en/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
+../../../../resources/en/licence.html \ No newline at end of file
diff --git a/frontends/beos/res/en/maps.html b/frontends/beos/res/en/maps.html
index bb3ffcbe7..507a4b248 120000
--- a/frontends/beos/res/en/maps.html
+++ b/frontends/beos/res/en/maps.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/maps.html,faf \ No newline at end of file
+../../../../resources/en/maps.html \ No newline at end of file
diff --git a/frontends/beos/res/en/welcome.html b/frontends/beos/res/en/welcome.html
index 601099223..543f31ddd 120000
--- a/frontends/beos/res/en/welcome.html
+++ b/frontends/beos/res/en/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
+../../../../resources/en/welcome.html \ No newline at end of file
diff --git a/frontends/beos/res/icons b/frontends/beos/res/icons
index c7f860352..94d2dc0df 120000
--- a/frontends/beos/res/icons
+++ b/frontends/beos/res/icons
@@ -1 +1 @@
-../../../!NetSurf/Resources/Icons \ No newline at end of file
+../../../resources/icons \ No newline at end of file
diff --git a/frontends/beos/res/internal.css b/frontends/beos/res/internal.css
index 17f9f1504..5583a9811 120000
--- a/frontends/beos/res/internal.css
+++ b/frontends/beos/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
+../../../resources/internal.css \ No newline at end of file
diff --git a/frontends/beos/res/it/credits.html b/frontends/beos/res/it/credits.html
index 64b78982e..2b7c99542 120000
--- a/frontends/beos/res/it/credits.html
+++ b/frontends/beos/res/it/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/credits.html,faf \ No newline at end of file
+../../../../resources/it/credits.html \ No newline at end of file
diff --git a/frontends/beos/res/it/licence.html b/frontends/beos/res/it/licence.html
index 4abc825d3..92afce85b 120000
--- a/frontends/beos/res/it/licence.html
+++ b/frontends/beos/res/it/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/licence.html,faf \ No newline at end of file
+../../../../resources/it/licence.html \ No newline at end of file
diff --git a/frontends/beos/res/it/welcome.html b/frontends/beos/res/it/welcome.html
index 59cef0551..2673ba948 120000
--- a/frontends/beos/res/it/welcome.html
+++ b/frontends/beos/res/it/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/welcome.html,faf \ No newline at end of file
+../../../../resources/it/welcome.html \ No newline at end of file
diff --git a/frontends/beos/res/ja/welcome.html b/frontends/beos/res/ja/welcome.html
index a2556ee4e..8b603f3df 120000
--- a/frontends/beos/res/ja/welcome.html
+++ b/frontends/beos/res/ja/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/ja/welcome.html,faf \ No newline at end of file
+../../../../resources/ja/welcome.html \ No newline at end of file
diff --git a/frontends/beos/res/netsurf.png b/frontends/beos/res/netsurf.png
index 905512c25..d0ab72a5e 120000
--- a/frontends/beos/res/netsurf.png
+++ b/frontends/beos/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
+../../../resources/netsurf.png \ No newline at end of file
diff --git a/frontends/beos/res/quirks.css b/frontends/beos/res/quirks.css
index 88aabe48c..1e752cb9e 120000
--- a/frontends/beos/res/quirks.css
+++ b/frontends/beos/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
+../../../resources/quirks.css \ No newline at end of file
diff --git a/frontends/beos/scaffolding.cpp b/frontends/beos/scaffolding.cpp
index 5e386bdaa..e6fb6e5a1 100644
--- a/frontends/beos/scaffolding.cpp
+++ b/frontends/beos/scaffolding.cpp
@@ -608,8 +608,10 @@ NSBaseView::Instantiate(BMessage *archive)
struct replicant_thread_info *info = new replicant_thread_info;
info->url = BString(url);
- if (nsbeos_find_app_path(info->app) < B_OK)
+ if (nsbeos_find_app_path(info->app) < B_OK) {
+ delete info;
return NULL;
+ }
info->args[0] = info->app;
info->args[1] = (char *)info->url.String();
info->args[2] = NULL;
@@ -794,7 +796,7 @@ int32 nsbeos_replicant_main_thread(void *_arg)
static void nsbeos_window_destroy_event(NSBrowserWindow *window, nsbeos_scaffolding *g, BMessage *event)
{
- LOG("Being Destroyed = %d", g->being_destroyed);
+ NSLOG(netsurf, INFO, "Being Destroyed = %d", g->being_destroyed);
if (--open_windows == 0)
nsbeos_done = true;
@@ -852,7 +854,9 @@ void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *m
bw = nsbeos_get_browser_for_gui(scaffold->top_level);
bool reloadAll = false;
- LOG("nsbeos_scaffolding_dispatch_event() what = 0x%08lx", message->what);
+ NSLOG(netsurf, INFO,
+ "nsbeos_scaffolding_dispatch_event() what = 0x%08lx",
+ message->what);
switch (message->what) {
case B_QUIT_REQUESTED:
nsbeos_scaffolding_destroy(scaffold);
@@ -995,7 +999,7 @@ void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *m
browser_window_key_press(bw, NS_KEY_PASTE);
break;
case B_SELECT_ALL:
- LOG("Selecting all text");
+ NSLOG(netsurf, INFO, "Selecting all text");
browser_window_key_press(bw, NS_KEY_SELECT_ALL);
break;
case B_NETPOSITIVE_BACK:
@@ -1357,7 +1361,8 @@ void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *m
void nsbeos_scaffolding_destroy(nsbeos_scaffolding *scaffold)
{
- LOG("Being Destroyed = %d", scaffold->being_destroyed);
+ NSLOG(netsurf, INFO, "Being Destroyed = %d",
+ scaffold->being_destroyed);
if (scaffold->being_destroyed) return;
scaffold->being_destroyed = 1;
nsbeos_window_destroy_event(scaffold->window, scaffold, NULL);
@@ -1442,7 +1447,7 @@ static void recursively_set_menu_items_target(BMenu *menu, BHandler *handler)
void nsbeos_attach_toplevel_view(nsbeos_scaffolding *g, BView *view)
{
- LOG("Attaching view to scaffolding %p", g);
+ NSLOG(netsurf, INFO, "Attaching view to scaffolding %p", g);
// this is a replicant,... and it went bad
if (!g->window) {
@@ -1720,7 +1725,8 @@ nsbeos_scaffolding *nsbeos_new_scaffolding(struct gui_window *toplevel)
{
struct beos_scaffolding *g = (struct beos_scaffolding *)malloc(sizeof(*g));
- LOG("Constructing a scaffold of %p for gui_window %p", g, toplevel);
+ NSLOG(netsurf, INFO,
+ "Constructing a scaffold of %p for gui_window %p", g, toplevel);
g->top_level = toplevel;
g->being_destroyed = 0;
diff --git a/frontends/beos/schedule.cpp b/frontends/beos/schedule.cpp
index e96e56d81..7877a838b 100644
--- a/frontends/beos/schedule.cpp
+++ b/frontends/beos/schedule.cpp
@@ -28,11 +28,7 @@ extern "C" {
#include "netsurf/content_type.h"
#include "netsurf/browser_window.h"
-#ifdef DEBUG_BEOS_SCHEDULE
#include "utils/log.h"
-#else
-#define LOG(x...)
-#endif
}
/** Killable callback closure embodiment. */
@@ -58,7 +54,10 @@ nsbeos_schedule_kill_callback(void *_target, void *_match)
_nsbeos_callback_t *match = (_nsbeos_callback_t *)_match;
if ((target->callback == match->callback) &&
(target->context == match->context)) {
- LOG("Found match for %p(%p), killing.", target->callback, target->context);
+ NSLOG(schedule, DEBUG,
+ "Found match for %p(%p), killing.",
+ target->callback,
+ target->context);
target->callback = NULL;
target->context = NULL;
target->callback_killed = true;
@@ -69,7 +68,9 @@ nsbeos_schedule_kill_callback(void *_target, void *_match)
static void
schedule_remove(void (*callback)(void *p), void *p)
{
- LOG("schedule_remove() for %p(%p)", cb->callback, cb->context);
+ NSLOG(schedule, DEBUG,
+ "schedule_remove() for %p(%p)",
+ callback, p);
if (callbacks == NULL)
return;
_nsbeos_callback_t cb_match;
@@ -81,7 +82,7 @@ schedule_remove(void (*callback)(void *p), void *p)
nserror beos_schedule(int t, void (*callback)(void *p), void *p)
{
- LOG("t:%d cb:%p p:%p", t, cb->callback, cb->context);
+ NSLOG(schedule, DEBUG, "t:%d cb:%p p:%p", t, callback, p);
if (callbacks == NULL) {
callbacks = new BList;
@@ -111,7 +112,7 @@ nserror beos_schedule(int t, void (*callback)(void *p), void *p)
bool
schedule_run(void)
{
- LOG("schedule_run()");
+ NSLOG(schedule, DEBUG, "schedule_run()");
earliest_callback_timeout = B_INFINITE_TIMEOUT;
if (callbacks == NULL)
@@ -120,7 +121,9 @@ schedule_run(void)
bigtime_t now = system_time();
int32 i;
- LOG("Checking %ld callbacks to for deadline.", this_run->CountItems());
+ NSLOG(schedule, DEBUG,
+ "Checking %ld callbacks to for deadline.",
+ callbacks->CountItems());
/* Run all the callbacks which made it this far. */
for (i = 0; i < callbacks->CountItems(); ) {
@@ -132,7 +135,11 @@ schedule_run(void)
i++;
continue;
}
- LOG("Running callbacks %p(%p).", cb->callback, cb->context);
+ NSLOG(schedule, DEBUG,
+ "Running callbacks %p(%p).",
+ cb->callback,
+ cb->context);
+
if (!cb->callback_killed)
cb->callback(cb->context);
callbacks->RemoveItem(cb);
diff --git a/frontends/beos/throbber.cpp b/frontends/beos/throbber.cpp
index fe40b3edc..315afef83 100644
--- a/frontends/beos/throbber.cpp
+++ b/frontends/beos/throbber.cpp
@@ -50,18 +50,21 @@ bool nsbeos_throbber_initialise_from_png(const int frames, ...)
if (frames < 2) {
/* we need at least two frames - one for idle, one for active */
- LOG("Insufficent number of frames in throbber animation!");
- LOG("(called with %d frames, where 2 is a minimum.)", frames);
+ NSLOG(netsurf, INFO,
+ "Insufficent number of frames in throbber animation!");
+ NSLOG(netsurf, INFO,
+ "(called with %d frames, where 2 is a minimum.)",
+ frames);
return false;
}
BResources *res = get_app_resources();
if (res == NULL) {
- LOG("Can't find resources for throbber!");
+ NSLOG(netsurf, INFO, "Can't find resources for throbber!");
return false;
}
- throb = (struct nsbeos_throbber *)malloc(sizeof(throb));
+ throb = (struct nsbeos_throbber *)malloc(sizeof(*throb));
throb->nframes = frames;
throb->framedata = (BBitmap **)malloc(sizeof(BBitmap *) * throb->nframes);
@@ -74,14 +77,17 @@ bool nsbeos_throbber_initialise_from_png(const int frames, ...)
data = res->LoadResource('data', fn, &size);
throb->framedata[i] = NULL;
if (!data) {
- LOG("Error when loading resource %s", fn);
+ NSLOG(netsurf, INFO, "Error when loading resource %s",
+ fn);
errors_when_loading = true;
continue;
}
BMemoryIO mem(data, size);
throb->framedata[i] = BTranslationUtils::GetBitmap(&mem);
if (throb->framedata[i] == NULL) {
- LOG("Error when loading %s: GetBitmap() returned NULL", fn);
+ NSLOG(netsurf, INFO,
+ "Error when loading %s: GetBitmap() returned NULL",
+ fn);
errors_when_loading = true;
}
}
diff --git a/frontends/beos/window.cpp b/frontends/beos/window.cpp
index fbf7b1652..f4229207b 100644
--- a/frontends/beos/window.cpp
+++ b/frontends/beos/window.cpp
@@ -354,7 +354,8 @@ static struct gui_window *gui_window_create(struct browser_window *bw,
return 0;
}
- LOG("Creating gui window %p for browser window %p", g, bw);
+ NSLOG(netsurf, INFO, "Creating gui window %p for browser window %p",
+ g, bw);
g->bw = bw;
g->mouse.state = 0;
@@ -436,25 +437,27 @@ void nsbeos_dispatch_event(BMessage *message)
continue;
if (gui && gui != z) {
- LOG("discarding event for destroyed gui_window");
+ NSLOG(netsurf, INFO,
+ "discarding event for destroyed gui_window");
delete message;
return;
}
if (scaffold && (!y || scaffold != y->scaffold)) {
- LOG("discarding event for destroyed scaffolding");
+ NSLOG(netsurf, INFO,
+ "discarding event for destroyed scaffolding");
delete message;
return;
}
// messages for top-level
if (scaffold) {
- LOG("dispatching to top-level");
+ NSLOG(netsurf, INFO, "dispatching to top-level");
nsbeos_scaffolding_dispatch_event(scaffold, message);
delete message;
return;
}
- //LOG("processing message");
+ NSLOG(netsurf, DEEPDEBUG, "processing message");
switch (message->what) {
case B_QUIT_REQUESTED:
// from the BApplication
@@ -763,7 +766,8 @@ void nsbeos_window_keypress_event(BView *view, gui_window *g, BMessage *event)
if (!numbytes)
numbytes = strlen(bytes);
- LOG("mods 0x%08lx key %ld raw %ld byte[0] %d", mods, key, raw_char, buff[0]);
+ NSLOG(netsurf, INFO, "mods 0x%08lx key %ld raw %ld byte[0] %d", mods,
+ key, raw_char, buff[0]);
char byte;
if (numbytes == 1) {
@@ -911,28 +915,6 @@ void nsbeos_reflow_all_windows(void)
}
-
-/**
- * callback from core to reformat a window.
- */
-static void beos_window_reformat(struct gui_window *g)
-{
- if (g == NULL) {
- return;
- }
-
- NSBrowserFrameView *view = g->view;
- if (view && view->LockLooper()) {
- BRect bounds = view->Bounds();
- view->UnlockLooper();
-#warning XXX why - 1 & - 2 !???
- browser_window_reformat(g->bw,
- false,
- bounds.Width() + 1 /* - 2*/,
- bounds.Height() + 1);
- }
-}
-
void nsbeos_window_destroy_browser(struct gui_window *g)
{
browser_window_destroy(g->bw);
@@ -952,10 +934,10 @@ static void gui_window_destroy(struct gui_window *g)
g->next->prev = g->prev;
- LOG("Destroying gui_window %p", g);
+ NSLOG(netsurf, INFO, "Destroying gui_window %p", g);
assert(g != NULL);
assert(g->bw != NULL);
- LOG(" Scaffolding: %p", g->scaffold);
+ NSLOG(netsurf, INFO, " Scaffolding: %p", g->scaffold);
if (g->view == NULL)
return;
@@ -1000,39 +982,39 @@ void nsbeos_redraw_caret(struct gui_window *g)
g->view->UnlockLooper();
}
-static void gui_window_redraw_window(struct gui_window *g)
-{
- if (g->view == NULL)
- return;
- if (!g->view->LockLooper())
- return;
-
- nsbeos_current_gc_set(g->view);
-
- g->view->Invalidate();
-
- nsbeos_current_gc_set(NULL);
- g->view->UnlockLooper();
-}
-
-static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
+/**
+ * Invalidate an area of a beos browser window
+ *
+ * \param g The netsurf window being invalidated.
+ * \param rect area to redraw or NULL for entrire window area.
+ * \return NSERROR_OK or appropriate error code.
+ */
+static nserror
+beos_window_invalidate_area(struct gui_window *g, const struct rect *rect)
{
- if (browser_window_has_content(g->bw) == false)
- return;
+ if (browser_window_has_content(g->bw) == false) {
+ return NSERROR_OK;
+ }
- if (g->view == NULL)
- return;
- if (!g->view->LockLooper())
- return;
+ if (g->view == NULL) {
+ return NSERROR_OK;
+ }
- nsbeos_current_gc_set(g->view);
+ if (!g->view->LockLooper()) {
+ return NSERROR_OK;
+ }
-//XXX +1 ??
- g->view->Invalidate(BRect(rect->x0, rect->y0,
- rect->x1 - 1, rect->y1 - 1));
+ if (rect != NULL) {
+ //XXX +1 ??
+ g->view->Invalidate(BRect(rect->x0, rect->y0,
+ rect->x1 - 1, rect->y1 - 1));
+ } else {
+ g->view->Invalidate();
+ }
- nsbeos_current_gc_set(NULL);
g->view->UnlockLooper();
+
+ return NSERROR_OK;
}
static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
@@ -1053,21 +1035,39 @@ static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
return true;
}
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+/**
+ * Set the scroll position of a beos browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The beos implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param g gui window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *g, const struct rect *rect)
{
//CALLED();
- if (g->view == NULL)
- return;
- if (!g->view->LockLooper())
- return;
+ if (g->view == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (!g->view->LockLooper()) {
+ return NSERROR_BAD_PARAMETER;
+ }
#warning XXX: report to view frame ?
- if (g->view->ScrollBar(B_HORIZONTAL))
- g->view->ScrollBar(B_HORIZONTAL)->SetValue(sx);
- if (g->view->ScrollBar(B_VERTICAL))
- g->view->ScrollBar(B_VERTICAL)->SetValue(sy);
+ if (g->view->ScrollBar(B_HORIZONTAL)) {
+ g->view->ScrollBar(B_HORIZONTAL)->SetValue(rect->x0);
+ }
+ if (g->view->ScrollBar(B_VERTICAL)) {
+ g->view->ScrollBar(B_VERTICAL)->SetValue(rect->y0);
+ }
g->view->UnlockLooper();
+
+ return NSERROR_OK;
}
@@ -1094,8 +1094,9 @@ static void gui_window_update_extent(struct gui_window *g)
x_max -= g->view->Bounds().Width() + 1;
y_max -= g->view->Bounds().Height() + 1;
- LOG("x_max = %d y_max = %d x_prop = %f y_prop = %f\n",
- x_max, y_max, x_prop, y_prop);
+ NSLOG(netsurf, INFO,
+ "x_max = %d y_max = %d x_prop = %f y_prop = %f\n", x_max,
+ y_max, x_prop, y_prop);
if (g->view->ScrollBar(B_HORIZONTAL)) {
g->view->ScrollBar(B_HORIZONTAL)->SetRange(0, x_max);
@@ -1331,31 +1332,42 @@ static struct gui_clipboard_table clipboard_table = {
struct gui_clipboard_table *beos_clipboard_table = &clipboard_table;
-static void gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
- bool scaled)
+/**
+ * Find the current dimensions of a beos browser window content area.
+ *
+ * \param g The gui window to measure content area of.
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated
+ * else error code.
+ */
+static nserror
+gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
+ bool scaled)
{
- if (g->view && g->view->LockLooper()) {
- *width = g->view->Bounds().Width() + 1;
- *height = g->view->Bounds().Height() + 1;
- g->view->UnlockLooper();
- }
-
- if (scaled) {
- *width /= g->scale;
- *height /= g->scale;
- }
+ if (g->view &&
+ g->view->LockLooper()) {
+ *width = g->view->Bounds().Width() + 1;
+ *height = g->view->Bounds().Height() + 1;
+ g->view->UnlockLooper();
+
+ if (scaled) {
+ *width /= g->scale;
+ *height /= g->scale;
+ }
+ }
+ return NSERROR_OK;
}
static struct gui_window_table window_table = {
gui_window_create,
gui_window_destroy,
- gui_window_redraw_window,
- gui_window_update_box,
+ beos_window_invalidate_area,
gui_window_get_scroll,
gui_window_set_scroll,
gui_window_get_dimensions,
gui_window_update_extent,
- beos_window_reformat,
/* from scaffold */
gui_window_set_title,
@@ -1369,7 +1381,6 @@ static struct gui_window_table window_table = {
gui_window_stop_throbber,
NULL, //drag_start
NULL, //save_link
- NULL, //scroll_visible
NULL, //scroll_start
gui_window_new_content,
NULL, //create_form_select_menu
diff --git a/frontends/cocoa/ArrowBox.h b/frontends/cocoa/ArrowBox.h
deleted file mode 100644
index c49fcb6e7..000000000
--- a/frontends/cocoa/ArrowBox.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (c) 1011 Sven Weidauer
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-
-
-#import <Cocoa/Cocoa.h>
-
-typedef enum {
- ArrowNone,
- ArrowTopEdge,
- ArrowBottomEdge,
- ArrowLeftEdge,
- ArrowRightEdge
-} ArrowEdge;
-
-
-@interface ArrowBox : NSView {
- CGFloat arrowPosition;
- CGFloat arrowSize;
- ArrowEdge arrowEdge;
- CGFloat cornerRadius;
- BOOL updateShadow;
-}
-
-@property (readwrite, assign, nonatomic) CGFloat arrowPosition;
-@property (readwrite, assign, nonatomic) CGFloat arrowSize;
-@property (readwrite, assign, nonatomic) ArrowEdge arrowEdge;
-@property (readwrite, assign, nonatomic) CGFloat cornerRadius;
-
-@end
diff --git a/frontends/cocoa/ArrowBox.m b/frontends/cocoa/ArrowBox.m
deleted file mode 100644
index 6605fcca9..000000000
--- a/frontends/cocoa/ArrowBox.m
+++ /dev/null
@@ -1,163 +0,0 @@
-/* Copyright 2011 Sven Weidauer
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#import "ArrowBox.h"
-
-@implementation ArrowBox
-
-@synthesize arrowPosition;
-@synthesize arrowSize;
-@synthesize arrowEdge;
-@synthesize cornerRadius;
-
-- (void) setArrowEdge: (ArrowEdge)newEdge
-{
- if (arrowEdge == newEdge) {
- return;
- }
-
- arrowEdge = newEdge;
-
- [self setNeedsDisplay: YES];
- updateShadow = YES;
-}
-
-
-- (void) setArrowSize: (CGFloat)newSize
-{
- arrowSize = newSize;
- [self setNeedsDisplay: YES];
- updateShadow = YES;
-}
-
-
-- (void) setCornerRadius: (CGFloat)newRadius
-{
- cornerRadius = newRadius;
- [self setNeedsDisplay: YES];
- updateShadow = YES;
-}
-
-- (void) setArrowPosition: (CGFloat)newPosition
-{
- arrowPosition = newPosition;
-
- [self setNeedsDisplay: YES];
- updateShadow = YES;
-}
-
-
-- (id)initWithFrame:(NSRect)frame
-{
- self = [super initWithFrame:frame];
- if (self) {
- arrowPosition = 50;
- cornerRadius = 10;
- arrowSize = 15;
- }
- return self;
-}
-
-- (void)drawRect:(NSRect)dirtyRect
-{
- [[NSColor clearColor] set];
- [NSBezierPath fillRect: dirtyRect];
-
- NSBezierPath *path = [NSBezierPath bezierPath];
-
- NSRect bounds = [self convertRectToBase: NSInsetRect( [self bounds], 2, 2 )];
- bounds.origin.x = floor( bounds.origin.x );
- bounds.origin.y = floor( bounds.origin.y );
- bounds.size.width = floor( bounds.size.width );
- bounds.size.height = floor( bounds.size.height );
- bounds = [self convertRectFromBase: bounds];
-
- const CGFloat right = bounds.size.width - arrowSize;
- const CGFloat top = bounds.size.height - arrowSize;
- const CGFloat left = arrowSize;
- const CGFloat bottom = arrowSize;
-
- [path setLineJoinStyle:NSRoundLineJoinStyle];
-
- [path moveToPoint: NSMakePoint( right - cornerRadius, top )];
-
- if (arrowEdge == ArrowTopEdge) {
- [path lineToPoint: NSMakePoint( arrowPosition + arrowSize, top )];
- [path lineToPoint: NSMakePoint( arrowPosition, top + arrowSize )];
- [path lineToPoint: NSMakePoint( arrowPosition - arrowSize, top )];
- }
-
- [path appendBezierPathWithArcFromPoint: NSMakePoint( left, top )
- toPoint: NSMakePoint( left, top - cornerRadius )
- radius: cornerRadius];
-
- if (arrowEdge == ArrowLeftEdge) {
- [path lineToPoint: NSMakePoint( left, bottom + arrowPosition + arrowSize )];
- [path lineToPoint: NSMakePoint( left - arrowSize, bottom + arrowPosition )];
- [path lineToPoint: NSMakePoint( left, bottom + arrowPosition - arrowSize )];
- }
-
- [path appendBezierPathWithArcFromPoint: NSMakePoint( left, bottom )
- toPoint: NSMakePoint( left + cornerRadius, bottom )
- radius: cornerRadius];
-
- if (arrowEdge == ArrowBottomEdge) {
- [path lineToPoint: NSMakePoint( arrowPosition - arrowSize, bottom )];
- [path lineToPoint: NSMakePoint( arrowPosition, bottom - arrowSize )];
- [path lineToPoint: NSMakePoint( arrowPosition + arrowSize, bottom )];
- }
-
- [path appendBezierPathWithArcFromPoint: NSMakePoint( right, bottom )
- toPoint: NSMakePoint( right, bottom + cornerRadius )
- radius: cornerRadius];
-
- if (arrowEdge == ArrowRightEdge) {
- [path lineToPoint: NSMakePoint( right, bottom + arrowPosition - arrowSize )];
- [path lineToPoint: NSMakePoint( right + arrowSize, bottom + arrowPosition )];
- [path lineToPoint: NSMakePoint( right, bottom + arrowPosition + arrowSize )];
- }
-
- [path appendBezierPathWithArcFromPoint: NSMakePoint( right, top )
- toPoint: NSMakePoint( right - cornerRadius, top )
- radius: cornerRadius];
- [path closePath];
-
- [[NSColor colorWithDeviceWhite: 1.0 alpha: 0.4] set];
- [[NSColor colorWithDeviceWhite: 0.0 alpha: 0.75] setFill];
-
- NSAffineTransform *transform = [NSAffineTransform transform];
- [transform translateXBy: bounds.origin.x yBy: bounds.origin.y];
- [transform concat];
-
- [path setLineWidth: 2.0];
- [path fill];
- [path stroke];
-
- if (updateShadow) {
- [[self window] invalidateShadow];
- [[self window] update];
- updateShadow = NO;
- }
-}
-
-@end
diff --git a/frontends/cocoa/ArrowWindow.h b/frontends/cocoa/ArrowWindow.h
deleted file mode 100644
index 79f422f3e..000000000
--- a/frontends/cocoa/ArrowWindow.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 1011 Sven Weidauer
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-
-
-#import <Cocoa/Cocoa.h>
-
-#import "ArrowBox.h"
-
-@interface ArrowWindow : NSWindow {
- ArrowBox *box;
- NSView *content;
- BOOL acceptsKey;
- NSWindow *attachedWindow;
-}
-
-@property (readwrite, assign, nonatomic) BOOL acceptsKey;
-
-@property (readwrite, assign, nonatomic) CGFloat arrowPosition;
-@property (readwrite, assign, nonatomic) CGFloat arrowSize;
-@property (readwrite, assign, nonatomic) ArrowEdge arrowEdge;
-@property (readwrite, assign, nonatomic) CGFloat cornerRadius;
-
-- (void) moveToPoint: (NSPoint) screenPoint;
-- (void) attachToView: (NSView *) view;
-- (void) detach;
-
-@end
diff --git a/frontends/cocoa/ArrowWindow.m b/frontends/cocoa/ArrowWindow.m
deleted file mode 100644
index 8edc32e9f..000000000
--- a/frontends/cocoa/ArrowWindow.m
+++ /dev/null
@@ -1,239 +0,0 @@
-/* Copyright 2011 Sven Weidauer
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#import "ArrowWindow.h"
-#import "ArrowBox.h"
-
-@implementation ArrowWindow
-
-@synthesize acceptsKey;
-
-- (id) initWithContentRect: (NSRect)contentRect styleMask: (NSUInteger)aStyle backing: (NSBackingStoreType)bufferingType defer: (BOOL)flag
-{
- if ((self = [super initWithContentRect: contentRect styleMask: NSBorderlessWindowMask backing: bufferingType defer: flag]) == nil) {
- return nil;
- }
-
- [self setBackgroundColor: [NSColor clearColor]];
- [self setOpaque: NO];
- [self setHasShadow: YES];
-
- return self;
-}
-
-- (void) setContentView: (NSView *)aView
-{
- if (aView == content) return;
-
- [content removeFromSuperview];
- content = aView;
-
- if (content == nil) return;
-
- if (box == nil) {
- box = [[ArrowBox alloc] initWithFrame: NSZeroRect];
- [box setArrowEdge: ArrowTopEdge];
- [super setContentView: box];
- [box release];
- }
-
- [box addSubview: content];
-
- NSRect frame = [self contentRectForFrameRect: [self frame]];
- frame.origin = [self convertScreenToBase: frame.origin];
- frame = [box convertRect: frame fromView: nil];
-
- [content setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
- [content setFrame: frame];
-}
-
-- (void) setContentSize: (NSSize)aSize
-{
- NSRect frame = [content frame];
- frame.size = aSize;
-
- frame = [box convertRect: frame toView: nil];
- frame.origin = [self convertBaseToScreen: frame.origin];
- frame = [self frameRectForContentRect: frame];
-
- [self setFrame: frame display: YES];
-}
-
-static const CGFloat padding = 0;
-
-- (NSRect) contentRectForFrameRect: (NSRect)frameRect
-{
- const CGFloat arrowSize = [box arrowSize];
- const CGFloat offset = 2 * (padding + arrowSize );
-
- return NSInsetRect( frameRect, offset, offset );
-}
-
-- (NSRect) frameRectForContentRect: (NSRect)contentRect
-{
- const CGFloat arrowSize = [box arrowSize];
- const CGFloat offset = -2 * (padding + arrowSize );
-
- return NSInsetRect( contentRect, offset, offset );
-}
-
-+ (NSRect) frameRectForContentRect: (NSRect)cRect styleMask: (NSUInteger)aStyle
-{
- const CGFloat DefaultArrowSize = 15;
- const CGFloat offset = -2 * (padding + DefaultArrowSize);
-
- return NSInsetRect( cRect, offset, offset );
-}
-
-- (BOOL) canBecomeKeyWindow
-{
- return acceptsKey;
-}
-
-- (void) moveToPoint: (NSPoint) screenPoint
-{
- switch ([box arrowEdge]) {
- case ArrowNone:
- screenPoint.x -= [box arrowSize];
- screenPoint.y += [box arrowSize];
- break;
-
- case ArrowTopEdge:
- screenPoint.x -= [box arrowPosition];
- break;
-
- case ArrowBottomEdge:
- screenPoint.x -= [box arrowPosition];
- screenPoint.y += NSHeight( [self frame] );
- break;
-
- case ArrowLeftEdge:
- screenPoint.y += NSHeight( [self frame] ) - [box arrowPosition] - [box arrowSize];
- break;
-
- case ArrowRightEdge:
- screenPoint.x -= NSWidth( [self frame] );
- screenPoint.y += NSHeight( [self frame] ) - [box arrowPosition] - [box arrowSize];
- break;
- }
-
- [self setFrameTopLeftPoint: screenPoint];
-}
-
-static NSRect ScreenRectForView( NSView *view )
-{
- NSRect viewRect = [view bounds]; // in View coordinate system
- viewRect = [view convertRect: viewRect toView: nil]; // translate to window coordinates
- viewRect.origin = [[view window] convertBaseToScreen: viewRect.origin]; // translate to screen coordinates
- return viewRect;
-}
-
-- (void) attachToView: (NSView *) view
-{
- if (nil != attachedWindow) [self detach];
-
- NSRect viewRect = ScreenRectForView( view );
- NSPoint arrowPoint;
-
- switch ([box arrowEdge]) {
- case ArrowLeftEdge:
- arrowPoint = NSMakePoint( NSMaxX( viewRect ),
- NSMidY( viewRect ) );
- break;
-
- case ArrowBottomEdge:
- arrowPoint = NSMakePoint( NSMidX( viewRect ),
- NSMaxY( viewRect ) );
- break;
-
- case ArrowRightEdge:
- arrowPoint = NSMakePoint( NSMinX( viewRect ),
- NSMidY( viewRect ) );
- break;
-
- case ArrowNone:
- case ArrowTopEdge:
- default:
- arrowPoint = NSMakePoint( NSMidX( viewRect ),
- NSMinY( viewRect ) );
- break;
-
- }
- attachedWindow = [view window];
- [self moveToPoint: arrowPoint];
- [attachedWindow addChildWindow: self ordered: NSWindowAbove];
-}
-
-- (void) detach
-{
- [attachedWindow removeChildWindow: self];
- [self close];
- attachedWindow = nil;
-}
-
-//MARK: -
-//MARK: Properties
-
-- (void) setArrowPosition: (CGFloat) newPosition
-{
- [box setArrowPosition: newPosition];
-}
-
-- (CGFloat) arrowPosition
-{
- return [box arrowPosition];
-}
-
-- (void) setArrowSize: (CGFloat)newSize
-{
- NSRect contentRect = [self contentRectForFrameRect: [self frame]];
- [box setArrowSize: newSize];
- [self setFrame: [self frameRectForContentRect: contentRect] display: [self isVisible]];
-}
-
-- (CGFloat) arrowSize
-{
- return [box arrowSize];
-}
-
-- (void) setArrowEdge: (ArrowEdge) newEdge
-{
- [box setArrowEdge: newEdge];
-}
-
-- (ArrowEdge) arrowEdge
-{
- return [box arrowEdge];
-}
-
-- (void) setCornerRadius: (CGFloat)newRadius
-{
- [box setCornerRadius: newRadius];
-}
-
-- (CGFloat) cornerRadius
-{
- return [box cornerRadius];
-}
-
-@end
diff --git a/frontends/cocoa/BlackScroller.h b/frontends/cocoa/BlackScroller.h
deleted file mode 100644
index 34110b035..000000000
--- a/frontends/cocoa/BlackScroller.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright (c) 1011 Sven Weidauer
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface BlackScroller : NSScroller {
- BOOL drawTrack;
- NSTrackingRectTag tag;
-}
-
-@property (readonly, getter=isHorizontal) BOOL horizontal;
-
-@end
diff --git a/frontends/cocoa/BlackScroller.m b/frontends/cocoa/BlackScroller.m
deleted file mode 100644
index 2ee739f3a..000000000
--- a/frontends/cocoa/BlackScroller.m
+++ /dev/null
@@ -1,154 +0,0 @@
-/* Copyright (c) 1011 Sven Weidauer
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#import "BlackScroller.h"
-
-@implementation BlackScroller
-
-- (void) setFrame: (NSRect)frameRect
-{
- [super setFrame: frameRect];
- if (tag != 0) [self removeTrackingRect: tag];
- tag = [self addTrackingRect: [self bounds] owner: self userData: NULL assumeInside: NO];
-}
-
-- (void) drawRect: (NSRect)dirtyRect
-{
- [[NSColor clearColor] set];
- [NSBezierPath fillRect: dirtyRect];
-
- if (drawTrack) [self drawKnobSlotInRect: [self rectForPart: NSScrollerKnobSlot]
- highlight: NO];
- [self drawKnob];
-}
-
-- (void) drawKnobSlotInRect: (NSRect)slotRect highlight: (BOOL)flag
-{
- slotRect = NSInsetRect( slotRect, 2, 2 );
- slotRect = [self convertRectToBase: slotRect];
- slotRect.origin.x = floor( slotRect.origin.x ) + 0.5;
- slotRect.origin.y = floor( slotRect.origin.y ) + 0.5;
- slotRect.size.width = floor( slotRect.size.width );
- slotRect.size.height = floor( slotRect.size.height );
- slotRect = [self convertRectFromBase: slotRect];
-
- NSGradient *gradient = [[[NSGradient alloc] initWithColorsAndLocations:
- [NSColor clearColor], 0.0,
- [NSColor clearColor], 0.4,
- [NSColor whiteColor], 1.0,
- nil] autorelease];
- [[NSColor whiteColor] set];
- const float radius = 0.5 * ([self isHorizontal] ? NSHeight( slotRect ) : NSWidth( slotRect ));
- NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect: slotRect
- xRadius: radius
- yRadius: radius];
- [gradient drawInBezierPath: path angle: [self isHorizontal] ? 90 : 0];
-
- [path stroke];
-}
-
-
-- (NSUsableScrollerParts) usableParts
-{
- return NSScrollerKnob | NSScrollerKnobSlot;
-}
-
-- (void) drawKnob
-{
- NSRect rect = NSInsetRect( [self rectForPart: NSScrollerKnob], 2, 2 );
-
- rect = [self convertRectToBase: rect];
- rect.origin.x = floor( rect.origin.x ) + 0.5;
- rect.origin.y = floor( rect.origin.y ) + 0.5;
- rect.size.width = floor( rect.size.width );
- rect.size.height = floor( rect.size.height );
- rect = [self convertRectFromBase: rect];
-
- [[NSColor colorWithDeviceWhite: 1.0 alpha: drawTrack ? 1.0 : 0.6] set];
-
- const float radius = 0.5 * ([self isHorizontal] ? NSHeight( rect ) : NSWidth( rect ));
- NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect: rect
- xRadius: radius
- yRadius: radius];
- [path fill];
- [path stroke];
-}
-
-- (NSRect) rectForPart: (NSScrollerPart)partCode
-{
- const bool horizontal = [self isHorizontal];
-
- NSRect rect = horizontal ? NSInsetRect( [self bounds], 4, 0 ) : NSInsetRect( [self bounds], 0, 4 );
-
- switch (partCode) {
- case NSScrollerKnobSlot:
- return rect;
-
- case NSScrollerKnob: {
- const CGFloat len = horizontal ? NSWidth( rect ) : NSHeight( rect );
- CGFloat knobLen = [self knobProportion] * len;
- const CGFloat minKnobLen = horizontal ? NSHeight( rect ) : NSWidth( rect );
- if (knobLen < minKnobLen) knobLen = minKnobLen;
-
- const CGFloat start = [self doubleValue] * (len - knobLen);
-
- if (horizontal) {
- rect.origin.x += start;
- rect.size.width = knobLen;
- } else {
- rect.origin.y += start;
- rect.size.height = knobLen;
- }
-
- return rect;
- }
-
- default:
- return [super rectForPart: partCode];
- }
-}
-
-- (BOOL) isOpaque
-{
- return NO;
-}
-
-- (BOOL) isHorizontal
-{
- NSRect bounds = [self bounds];
- return NSWidth( bounds ) > NSHeight( bounds );
-}
-
-- (void) mouseEntered: (NSEvent *)theEvent
-{
- drawTrack = YES;
- [self setNeedsDisplay: YES];
-}
-
-- (void) mouseExited: (NSEvent *)theEvent
-{
- drawTrack = NO;
- [self setNeedsDisplay: YES];
-}
-
-@end
diff --git a/frontends/cocoa/BookmarksController.h b/frontends/cocoa/BookmarksController.h
deleted file mode 100644
index aa71a1ac0..000000000
--- a/frontends/cocoa/BookmarksController.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class Tree;
-@class TreeView;
-
-@interface BookmarksController : NSWindowController {
- Tree *tree;
- TreeView *view;
- NSMapTable *nodeForMenu;
- NSMenu *defaultMenu;
-}
-
-@property (readwrite, assign, nonatomic) IBOutlet NSMenu *defaultMenu;
-@property (readwrite, assign, nonatomic) IBOutlet TreeView *view;
-
-- (IBAction) openBookmarkURL: (id) sender;
-- (IBAction) addBookmark: (id) sender;
-
-- (IBAction) editSelected: (id) sender;
-- (IBAction) deleteSelected: (id) sender;
-- (IBAction) addFolder: (id) sender;
-
-@end
diff --git a/frontends/cocoa/BookmarksController.m b/frontends/cocoa/BookmarksController.m
deleted file mode 100644
index d7918d9fc..000000000
--- a/frontends/cocoa/BookmarksController.m
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/messages.h"
-#import "utils/utils.h"
-#import "utils/nsurl.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/keypress.h"
-#import "desktop/hotlist.h"
-
-#import "cocoa/desktop-tree.h"
-#import "cocoa/BookmarksController.h"
-#import "cocoa/Tree.h"
-#import "cocoa/TreeView.h"
-#import "cocoa/NetsurfApp.h"
-#import "cocoa/BrowserViewController.h"
-#import "cocoa/gui.h"
-
-
-@interface BookmarksController ()
-- (void) noteAppWillTerminate: (NSNotification *) note;
-- (void) save;
-@end
-
-@implementation BookmarksController
-
-@synthesize defaultMenu;
-@synthesize view;
-
-static const char *cocoa_hotlist_path( void )
-{
- NSString *path = [[NSUserDefaults standardUserDefaults]
- stringForKey: kHotlistFileOption];
- return [path UTF8String];
-}
-
-- (id)init
-{
- if ((self = [super initWithWindowNibName: @"BookmarksWindow"]) == nil) {
- return nil;
- }
- tree_hotlist_path = cocoa_hotlist_path();
- tree = [[Tree alloc] initWithFlags: TREE_HOTLIST];
- nodeForMenu = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
- NSNonOwnedPointerMapValueCallBacks,
- 0);
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(noteAppWillTerminate:)
- name:NSApplicationWillTerminateNotification
- object:NSApp];
-
- return self;
-}
-
-- (void) noteAppWillTerminate: (NSNotification *)note
-{
- [self save];
-}
-
-- (void) save
-{
- hotlist_export( cocoa_hotlist_path(), NULL );
-}
-
-- (void) dealloc
-{
- [self setView: nil];
- NSFreeMapTable( nodeForMenu );
- [tree release];
-
- [[NSNotificationCenter defaultCenter] removeObserver: self];
-
- [super dealloc];
-}
-
-- (void) menuNeedsUpdate: (NSMenu *)menu
-{
-#if 0
- for (NSMenuItem *item in [menu itemArray]) {
- if ([item hasSubmenu]) NSMapRemove( nodeForMenu, [item submenu] );
- [menu removeItem: item];
- }
-
- bool hasSeparator = true;
- struct node *node = (struct node *)NSMapGet( nodeForMenu, menu );
- if (node == NULL) {
- for (NSMenuItem *item in [defaultMenu itemArray]) {
- [menu addItem: [[item copy] autorelease]];
- }
- hasSeparator = false;
- }
-
- for (struct node *child = tree_node_get_child( node );
- child != NULL;
- child = tree_node_get_next( child )) {
-
- if (tree_node_is_deleted( child )) continue;
-
- if (!hasSeparator) {
- [menu addItem: [NSMenuItem separatorItem]];
- hasSeparator = true;
- }
-
- NSString *title = [NSString stringWithUTF8String: tree_url_node_get_title( child )];
-
- NSMenuItem *item = [menu addItemWithTitle: title action: NULL keyEquivalent: @""];
- if (tree_node_is_folder( child )) {
- NSMenu *subMenu = [[[NSMenu alloc] initWithTitle: title] autorelease];
- NSMapInsert( nodeForMenu, subMenu, child );
- [subMenu setDelegate: self];
- [menu setSubmenu: subMenu forItem: item];
- } else {
- [item setRepresentedObject: [NSString stringWithUTF8String: tree_url_node_get_url( child )]];
- [item setTarget: self];
- [item setAction: @selector( openBookmarkURL: )];
- }
- }
-#endif
-}
-
-- (IBAction) openBookmarkURL: (id)sender
-{
- const char *urltxt = [[sender representedObject] UTF8String];
- NSParameterAssert( urltxt != NULL );
-
- nsurl *url;
- nserror error;
-
- error = nsurl_create(urltxt, &url);
- if (error == NSERROR_OK) {
- BrowserViewController *tab = [(NetSurfApp *)NSApp frontTab];
- if (tab != nil) {
- error = browser_window_navigate([tab browser],
- url,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- } else {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- }
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (IBAction) addBookmark: (id)sender
-{
- struct browser_window *bw = [[(NetSurfApp *)NSApp frontTab] browser];
- if (bw != NULL) {
- hotlist_add_url(browser_window_get_url(bw));
- }
-}
-
-- (BOOL) validateUserInterfaceItem: (id)item
-{
- SEL action = [item action];
-
- if (action == @selector( addBookmark: )) {
- return [(NetSurfApp *)NSApp frontTab] != nil;
- }
-
- return YES;
-}
-
-- (void) windowDidLoad
-{
- hotlist_expand(false);
- hotlist_contract(true);
-
- [view setTree: tree];
-}
-
-
-+ (void) initialize
-{
- [[NSUserDefaults standardUserDefaults]
- registerDefaults:
- [NSDictionary
- dictionaryWithObjectsAndKeys:cocoa_get_user_path( @"Bookmarks.html" ),
- kHotlistFileOption,
- nil]];
-}
-
-- (IBAction) editSelected: (id)sender
-{
- hotlist_edit_selection();
-}
-
-- (IBAction) deleteSelected: (id)sender
-{
- hotlist_keypress(NS_KEY_DELETE_LEFT);
-}
-
-- (IBAction) addFolder: (id)sender
-{
- hotlist_add_folder(NULL, false, 0);
-}
-
-@end
diff --git a/frontends/cocoa/BrowserView.h b/frontends/cocoa/BrowserView.h
deleted file mode 100644
index c626c8c5b..000000000
--- a/frontends/cocoa/BrowserView.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "cocoa/ScrollableView.h"
-
-@class LocalHistoryController;
-
-@interface BrowserView : ScrollableView <NSTextInput> {
- struct browser_window *browser;
-
- NSPoint caretPoint;
- CGFloat caretHeight;
- BOOL caretVisible;
- BOOL hasCaret;
- NSTimer *caretTimer;
-
- BOOL isDragging;
- NSPoint dragStart;
-
- BOOL historyVisible;
- LocalHistoryController *history;
-
- NSString *markedText;
-}
-
-@property (readwrite, assign, nonatomic) struct browser_window *browser;
-@property (readwrite, retain, nonatomic) NSTimer *caretTimer;
-@property (readwrite, assign, nonatomic, getter=isHistoryVisible) BOOL historyVisible;
-
-- (void) removeCaret;
-- (void) addCaretAt: (NSPoint) point height: (CGFloat) height;
-
-- (void) reformat;
-- (void) updateHistory;
-
-@end
diff --git a/frontends/cocoa/BrowserView.m b/frontends/cocoa/BrowserView.m
deleted file mode 100644
index f1259d835..000000000
--- a/frontends/cocoa/BrowserView.m
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/nsoption.h"
-#import "utils/messages.h"
-#import "utils/nsurl.h"
-#import "utils/utils.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/plotters.h"
-#import "netsurf/content.h"
-#import "netsurf/keypress.h"
-
-#import "cocoa/gui.h"
-#import "cocoa/BrowserView.h"
-#import "cocoa/HistoryView.h"
-#import "cocoa/font.h"
-#import "cocoa/coordinates.h"
-#import "cocoa/plotter.h"
-#import "cocoa/LocalHistoryController.h"
-#import "cocoa/BrowserWindowController.h"
-
-
-@interface BrowserView ()
-
-@property (readwrite, copy, nonatomic) NSString *markedText;
-
-- (void) scrollHorizontal: (CGFloat) amount;
-- (void) scrollVertical: (CGFloat) amount;
-- (CGFloat) pageScroll;
-
-- (void) reformat;
-
-- (void) popUpContextMenuForEvent: (NSEvent *) event;
-
-- (IBAction) cmOpenURLInTab: (id) sender;
-- (IBAction) cmOpenURLInWindow: (id) sender;
-- (IBAction) cmDownloadURL: (id) sender;
-
-- (IBAction) cmLinkCopy: (id) sender;
-- (IBAction) cmImageCopy: (id) sender;
-
-@end
-
-@implementation BrowserView
-
-@synthesize browser;
-@synthesize caretTimer;
-@synthesize markedText;
-
-static const CGFloat CaretWidth = 1.0;
-static const NSTimeInterval CaretBlinkTime = 0.8;
-
-- initWithFrame: (NSRect) frame
-{
- if ((self = [super initWithFrame: frame]) == nil) {
- return nil;
- }
-
- [self registerForDraggedTypes: [NSArray arrayWithObjects: NSURLPboardType, @"public.url", nil]];
-
- return self;
-}
-
-- (void) dealloc
-{
- [self setCaretTimer: nil];
- [self setMarkedText: nil];
- [history release];
-
- [super dealloc];
-}
-
-- (void) setCaretTimer: (NSTimer *)newTimer
-{
- if (newTimer != caretTimer) {
- [caretTimer invalidate];
- [caretTimer release];
- caretTimer = [newTimer retain];
- }
-}
-
-- (void) updateHistory
-{
- [history redraw];
-}
-
-static inline NSRect cocoa_get_caret_rect( BrowserView *view )
-{
- float bscale = browser_window_get_scale(view->browser);
-
- NSRect caretRect = {
- .origin = NSMakePoint( view->caretPoint.x * bscale, view->caretPoint.y * bscale ),
- .size = NSMakeSize( CaretWidth, view->caretHeight * bscale )
- };
-
- return caretRect;
-}
-
-- (void) removeCaret
-{
- hasCaret = NO;
- [self setNeedsDisplayInRect: cocoa_get_caret_rect( self )];
-
- [self setCaretTimer: nil];
-}
-
-- (void) addCaretAt: (NSPoint) point height: (CGFloat) height
-{
- if (hasCaret) {
- [self setNeedsDisplayInRect: cocoa_get_caret_rect( self )];
- }
-
- caretPoint = point;
- caretHeight = height;
- hasCaret = YES;
- caretVisible = YES;
-
- if (nil == caretTimer) {
- [self setCaretTimer: [NSTimer scheduledTimerWithTimeInterval: CaretBlinkTime target: self selector: @selector(caretBlink:) userInfo: nil repeats: YES]];
- } else {
- [caretTimer setFireDate: [NSDate dateWithTimeIntervalSinceNow: CaretBlinkTime]];
- }
-
- [self setNeedsDisplayInRect: cocoa_get_caret_rect( self )];
-}
-
-
-- (void) caretBlink: (NSTimer *)timer
-{
- if (hasCaret) {
- caretVisible = !caretVisible;
- [self setNeedsDisplayInRect: cocoa_get_caret_rect( self )];
- }
-}
-
-- (void)drawRect:(NSRect)dirtyRect
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &cocoa_plotters
- };
-
- const NSRect *rects = NULL;
- NSInteger count = 0;
- [self getRectsBeingDrawn: &rects count: &count];
-
- for (NSInteger i = 0; i < count; i++) {
- const struct rect clip = {
- .x0 = cocoa_pt_to_px( NSMinX( rects[i] ) ),
- .y0 = cocoa_pt_to_px( NSMinY( rects[i] ) ),
- .x1 = cocoa_pt_to_px( NSMaxX( rects[i] ) ),
- .y1 = cocoa_pt_to_px( NSMaxY( rects[i] ) )
- };
-
- browser_window_redraw(browser, 0, 0, &clip, &ctx);
- }
-
- NSRect caretRect = cocoa_get_caret_rect( self );
- if (hasCaret && caretVisible && [self needsToDrawRect: caretRect]) {
- [[NSColor blackColor] set];
- [NSBezierPath fillRect: caretRect];
- }
-
- [pool release];
-}
-
-- (BOOL) isFlipped
-{
- return YES;
-}
-
-- (void) viewDidMoveToWindow
-{
- NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect: [self visibleRect]
- options: NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect
- owner: self
- userInfo: nil];
- [self addTrackingArea: area];
- [area release];
-}
-
-static browser_mouse_state cocoa_mouse_flags_for_event( NSEvent *evt )
-{
- browser_mouse_state result = 0;
- NSUInteger flags = [evt modifierFlags];
-
- if (flags & NSShiftKeyMask) result |= BROWSER_MOUSE_MOD_1;
- if (flags & NSAlternateKeyMask) result |= BROWSER_MOUSE_MOD_2;
-
- return result;
-}
-
-- (NSPoint) convertMousePoint: (NSEvent *)event
-{
- NSPoint location = [self convertPoint: [event locationInWindow] fromView: nil];
- float bscale = browser_window_get_scale(browser);
-
- location.x /= bscale;
- location.y /= bscale;
-
- location.x = cocoa_pt_to_px( location.x );
- location.y = cocoa_pt_to_px( location.y );
- return location;
-}
-
-- (void) mouseDown: (NSEvent *)theEvent
-{
- if ([theEvent modifierFlags] & NSControlKeyMask) {
- [self popUpContextMenuForEvent: theEvent];
- return;
- }
-
- dragStart = [self convertMousePoint: theEvent];
-
- browser_window_mouse_click(browser,
- BROWSER_MOUSE_PRESS_1 | cocoa_mouse_flags_for_event( theEvent ),
- dragStart.x,
- dragStart.y );
-}
-
-- (void) rightMouseDown: (NSEvent *)theEvent
-{
- [self popUpContextMenuForEvent: theEvent];
-}
-
-- (void) mouseUp: (NSEvent *)theEvent
-{
- if (historyVisible) {
- [self setHistoryVisible: NO];
- return;
- }
-
- NSPoint location = [self convertMousePoint: theEvent];
-
- browser_mouse_state modifierFlags = cocoa_mouse_flags_for_event( theEvent );
-
- if (isDragging) {
- isDragging = NO;
- browser_window_mouse_track( browser, (browser_mouse_state)0, location.x, location.y );
- } else {
- modifierFlags |= BROWSER_MOUSE_CLICK_1;
- if ([theEvent clickCount] == 2) modifierFlags |= BROWSER_MOUSE_DOUBLE_CLICK;
- browser_window_mouse_click( browser, modifierFlags, location.x, location.y );
- }
-}
-
-#define squared(x) ((x)*(x))
-#define MinDragDistance (5.0)
-
-- (void) mouseDragged: (NSEvent *)theEvent
-{
- NSPoint location = [self convertMousePoint: theEvent];
- browser_mouse_state modifierFlags = cocoa_mouse_flags_for_event( theEvent );
-
- if (!isDragging) {
- const CGFloat distance = squared( dragStart.x - location.x ) + squared( dragStart.y - location.y );
-
- if (distance >= squared( MinDragDistance)) {
- isDragging = YES;
- browser_window_mouse_click(browser,
- BROWSER_MOUSE_DRAG_1 | modifierFlags,
- dragStart.x,
- dragStart.y);
- }
- }
-
- if (isDragging) {
- browser_window_mouse_track(browser,
- BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_DRAG_ON | modifierFlags,
- location.x,
- location.y );
- }
-}
-
-- (void) mouseMoved: (NSEvent *)theEvent
-{
- if (historyVisible) return;
-
- NSPoint location = [self convertMousePoint: theEvent];
-
- browser_window_mouse_track(browser,
- cocoa_mouse_flags_for_event(theEvent),
- location.x,
- location.y);
-}
-
-- (void) mouseExited: (NSEvent *) theEvent
-{
- [[NSCursor arrowCursor] set];
-}
-
-- (void) keyDown: (NSEvent *)theEvent
-{
- if (!historyVisible) {
- [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
- } else {
- [history keyDown: theEvent];
- }
-}
-
-- (void) insertText: (id)string
-{
- for (NSUInteger i = 0, length = [string length]; i < length; i++) {
- unichar ch = [string characterAtIndex: i];
- if (!browser_window_key_press( browser, ch )) {
- if (ch == ' ') [self scrollPageDown: self];
- break;
- }
- }
- [self setMarkedText: nil];
-}
-
-- (void) moveLeft: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_LEFT )) return;
- [self scrollHorizontal: -[[self enclosingScrollView] horizontalLineScroll]];
-}
-
-- (void) moveRight: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_RIGHT )) return;
- [self scrollHorizontal: [[self enclosingScrollView] horizontalLineScroll]];
-}
-
-- (void) moveUp: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_UP )) return;
- [self scrollVertical: -[[self enclosingScrollView] lineScroll]];
-}
-
-- (void) moveDown: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_DOWN )) return;
- [self scrollVertical: [[self enclosingScrollView] lineScroll]];
-}
-
-- (void) deleteBackward: (id)sender
-{
- if (!browser_window_key_press( browser, NS_KEY_DELETE_LEFT )) {
- [NSApp sendAction: @selector( goBack: ) to: nil from: self];
- }
-}
-
-- (void) deleteForward: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_DELETE_RIGHT );
-}
-
-- (void) cancelOperation: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_ESCAPE );
-}
-
-- (void) scrollPageUp: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_PAGE_UP )) {
- return;
- }
- [self scrollVertical: -[self pageScroll]];
-}
-
-- (void) scrollPageDown: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_PAGE_DOWN )) {
- return;
- }
- [self scrollVertical: [self pageScroll]];
-}
-
-- (void) insertTab: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_TAB );
-}
-
-- (void) insertBacktab: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_SHIFT_TAB );
-}
-
-- (void) moveToBeginningOfLine: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_LINE_START );
-}
-
-- (void) moveToEndOfLine: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_LINE_END );
-}
-
-- (void) moveToBeginningOfDocument: (id)sender
-{
- if (browser_window_key_press( browser, NS_KEY_TEXT_START )) return;
-}
-
-- (void) scrollToBeginningOfDocument: (id) sender
-{
- NSPoint origin = [self visibleRect].origin;
- origin.y = 0;
- [self scrollPoint: origin];
-}
-
-- (void) moveToEndOfDocument: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_TEXT_END );
-}
-
-- (void) scrollToEndOfDocument: (id) sender
-{
- NSPoint origin = [self visibleRect].origin;
- origin.y = NSHeight( [self frame] );
- [self scrollPoint: origin];
-}
-
-- (void) insertNewline: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_NL );
-}
-
-- (void) selectAll: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_SELECT_ALL );
-}
-
-- (void) copy: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_COPY_SELECTION );
-}
-
-- (void) cut: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_CUT_SELECTION );
-}
-
-- (void) paste: (id)sender
-{
- browser_window_key_press( browser, NS_KEY_PASTE );
-}
-
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-- (void) adjustFrame
-{
- browser_window_schedule_reformat(browser);
-
- [super adjustFrame];
-}
-
-- (BOOL) isHistoryVisible
-{
- return historyVisible;
-}
-
-- (void) setHistoryVisible: (BOOL)newVisible
-{
- if (newVisible == historyVisible) return;
- historyVisible = newVisible;
-
- if (historyVisible) {
- if (nil == history) {
- history = [[LocalHistoryController alloc] initWithBrowser: self];
- }
- [history attachToView: [(BrowserWindowController *)[[self window] windowController] historyButton]];
- } else {
- [history detach];
- }
-}
-
-- (void) scrollHorizontal: (CGFloat) amount
-{
- NSPoint currentPoint = [self visibleRect].origin;
- currentPoint.x += amount;
- [self scrollPoint: currentPoint];
-}
-
-- (void) scrollVertical: (CGFloat) amount
-{
- NSPoint currentPoint = [self visibleRect].origin;
- currentPoint.y += amount;
- [self scrollPoint: currentPoint];
-}
-
-- (CGFloat) pageScroll
-{
- return NSHeight( [[self superview] frame] ) - [[self enclosingScrollView] pageScroll];
-}
-
-- (void) reformat
-{
- NSRect size = [[self superview] frame];
- browser_window_reformat(browser,
- false,
- cocoa_pt_to_px( NSWidth( size ) ),
- cocoa_pt_to_px( NSHeight( size ) ) );
-}
-
-- (void) popUpContextMenuForEvent: (NSEvent *) event
-{
- NSMenu *popupMenu = [[NSMenu alloc] initWithTitle: @""];
- NSPoint point = [self convertMousePoint: event];
-
- struct browser_window_features cont;
-
- browser_window_get_features(browser, point.x, point.y, &cont);
-
- if (cont.object != NULL) {
- NSString *imageURL = [NSString stringWithUTF8String: nsurl_access(hlcache_handle_get_url( cont.object ))];
-
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Open image in new tab", @"Context menu" )
- action: @selector(cmOpenURLInTab:)
- keyEquivalent: @""] setRepresentedObject: imageURL];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Open image in new window", @"Context menu" )
- action: @selector(cmOpenURLInWindow:)
- keyEquivalent: @""] setRepresentedObject: imageURL];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Save image as", @"Context menu" )
- action: @selector(cmDownloadURL:)
- keyEquivalent: @""] setRepresentedObject: imageURL];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Copy image", @"Context menu" )
- action: @selector(cmImageCopy:)
- keyEquivalent: @""] setRepresentedObject: (id)content_get_bitmap( cont.object )];
-
- [popupMenu addItem: [NSMenuItem separatorItem]];
- }
-
- if (cont.link != NULL) {
- NSString *target = [NSString stringWithUTF8String: nsurl_access(cont.link)];
-
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Open link in new tab", @"Context menu" )
- action: @selector(cmOpenURLInTab:)
- keyEquivalent: @""] setRepresentedObject: target];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Open link in new window", @"Context menu" )
- action: @selector(cmOpenURLInWindow:)
- keyEquivalent: @""] setRepresentedObject: target];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Save link target", @"Context menu" )
- action: @selector(cmDownloadURL:)
- keyEquivalent: @""] setRepresentedObject: target];
- [[popupMenu addItemWithTitle: NSLocalizedString( @"Copy link", @"Context menu" )
- action: @selector(cmLinkCopy:)
- keyEquivalent: @""] setRepresentedObject: target];
-
- [popupMenu addItem: [NSMenuItem separatorItem]];
- }
-
- [popupMenu addItemWithTitle: NSLocalizedString( @"Back", @"Context menu" )
- action: @selector(goBack:) keyEquivalent: @""];
- [popupMenu addItemWithTitle: NSLocalizedString( @"Reload", @"Context menu" )
- action: @selector(reloadPage:) keyEquivalent: @""];
- [popupMenu addItemWithTitle: NSLocalizedString( @"Forward", @"Context menu" )
- action: @selector(goForward:) keyEquivalent: @""];
- [popupMenu addItemWithTitle: NSLocalizedString( @"View Source", @"Context menu" )
- action: @selector(viewSource:) keyEquivalent: @""];
-
- [NSMenu popUpContextMenu: popupMenu withEvent: event forView: self];
-
- [popupMenu release];
-}
-
-- (IBAction) cmOpenURLInTab: (id)sender
-{
- nsurl *url;
- nserror error;
-
- error = nsurl_create([[sender representedObject] UTF8String], &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY |
- BW_CREATE_TAB |
- BW_CREATE_CLONE,
- url,
- NULL,
- browser,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (IBAction) cmOpenURLInWindow: (id)sender
-{
- nsurl *url;
- nserror error;
-
- error = nsurl_create([[sender representedObject] UTF8String], &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY |
- BW_CREATE_CLONE,
- url,
- NULL,
- browser,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (IBAction) cmDownloadURL: (id)sender
-{
- nsurl *url;
-
- if (nsurl_create([[sender representedObject] UTF8String], &url) == NSERROR_OK) {
- browser_window_navigate(browser,
- url,
- NULL,
- BW_NAVIGATE_DOWNLOAD,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
-}
-
-- (IBAction) cmImageCopy: (id)sender
-{
- NSPasteboard *pb = [NSPasteboard generalPasteboard];
- [pb declareTypes: [NSArray arrayWithObject: NSTIFFPboardType] owner: nil];
- [pb setData: [[sender representedObject] TIFFRepresentation] forType: NSTIFFPboardType];
-}
-
-- (IBAction) cmLinkCopy: (id)sender
-{
- NSPasteboard *pb = [NSPasteboard generalPasteboard];
- [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: nil];
- [pb setString: [sender representedObject] forType: NSStringPboardType];
-}
-
-
-// MARK: -
-// MARK: Accepting dragged URLs
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- if ((NSDragOperationCopy | NSDragOperationGeneric) & [sender draggingSourceOperationMask]) {
- return NSDragOperationCopy;
- }
-
- return NSDragOperationNone;
-}
-
-- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
-{
- return YES;
-}
-
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- nsurl *url;
- nserror error;
-
- NSPasteboard *pb = [sender draggingPasteboard];
-
- NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObjects: @"public.url", NSURLPboardType, nil]];
-
- NSString *urlstr = nil;
-
- if ([type isEqualToString: NSURLPboardType]) {
- urlstr = [[NSURL URLFromPasteboard: pb] absoluteString];
- } else {
- urlstr = [pb stringForType: type];
- }
-
- error = nsurl_create([urlstr UTF8String], &url);
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- } else {
- browser_window_navigate(browser,
- url,
- NULL,
- BW_NAVIGATE_DOWNLOAD,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
-
- return YES;
-}
-
-// MARK: -
-// MARK: NSTextInput protocol implementation
-
-- (void) setMarkedText: (id) aString selectedRange: (NSRange) selRange
-{
- [markedText release];
- markedText = [aString isEqualToString: @""] ? nil : [aString copy];
-}
-
-- (void) unmarkText
-{
- [self setMarkedText: nil];
-}
-
-- (BOOL) hasMarkedText
-{
- return markedText != nil;
-}
-
-- (NSInteger) conversationIdentifier
-{
- return (NSInteger)self;
-}
-
-- (NSAttributedString *) attributedSubstringFromRange: (NSRange) theRange
-{
- return [[[NSAttributedString alloc] initWithString: @""] autorelease];
-}
-
-- (NSRange) markedRange
-{
- return NSMakeRange( NSNotFound, 0 );
-}
-
-- (NSRange) selectedRange
-{
- return NSMakeRange( NSNotFound, 0 );
-}
-
-- (NSRect) firstRectForCharacterRange: (NSRange) theRange
-{
- return NSZeroRect;
-}
-
-- (NSUInteger) characterIndexForPoint: (NSPoint) thePoint
-{
- return 0;
-}
-
-- (NSArray *) validAttributesForMarkedText
-{
- return [NSArray array];
-}
-
-- (void) doCommandBySelector: (SEL) sel;
-{
- [super doCommandBySelector: sel];
-}
-
-@end
diff --git a/frontends/cocoa/BrowserViewController.h b/frontends/cocoa/BrowserViewController.h
deleted file mode 100644
index 6b4c3e79c..000000000
--- a/frontends/cocoa/BrowserViewController.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#import <Cocoa/Cocoa.h>
-
-struct browser_window;
-@class BrowserView;
-@class BrowserWindowController;
-
-@interface BrowserViewController : NSViewController {
- struct browser_window *browser;
- NSString *url;
- BrowserView *browserView;
- BrowserWindowController *windowController;
- NSString *title;
- NSString *status;
- BOOL isProcessing;
- NSImage *favicon;
- BOOL canGoBack;
- BOOL canGoForward;
-}
-
-@property (readwrite, assign, nonatomic) struct browser_window *browser;
-@property (readwrite, copy, nonatomic) NSString *url;
-@property (readwrite, assign, nonatomic) IBOutlet BrowserView *browserView;
-@property (readwrite, retain, nonatomic) BrowserWindowController *windowController;
-@property (readwrite, copy, nonatomic) NSString *title;
-@property (readwrite, copy, nonatomic) NSString *status;
-@property (readwrite, assign, nonatomic) BOOL isProcessing;
-@property (readwrite, copy, nonatomic) NSImage *favicon;
-@property (readwrite, assign, nonatomic) BOOL canGoBack;
-@property (readwrite, assign, nonatomic) BOOL canGoForward;
-
-- (id) initWithBrowser: (struct browser_window *) bw;
-
-- (void) contentUpdated;
-- (void) updateBackForward;
-
-- (IBAction) navigate: (id) sender;
-
-- (IBAction) backForwardSelected: (id) sender;
-
-- (IBAction) goHome: (id) sender;
-
-- (IBAction) goBack: (id) sender;
-- (IBAction) goForward: (id) sender;
-- (IBAction) reloadPage: (id) sender;
-- (IBAction) stopLoading: (id) sender;
-
-- (IBAction) zoomIn: (id) sender;
-- (IBAction) zoomOut: (id) sender;
-- (IBAction) zoomOriginal: (id) sender;
-
-- (IBAction) viewSource: (id) sender;
-
-- (void) buildBackMenu: (NSMenu *)menu;
-- (void) buildForwardMenu: (NSMenu *)menu;
-
-@end
diff --git a/frontends/cocoa/BrowserViewController.m b/frontends/cocoa/BrowserViewController.m
deleted file mode 100644
index 4cac57ef3..000000000
--- a/frontends/cocoa/BrowserViewController.m
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/nsoption.h"
-#import "utils/corestrings.h"
-#import "utils/filename.h"
-#import "utils/file.h"
-#import "utils/messages.h"
-#import "utils/nsurl.h"
-#import "netsurf/content.h"
-#import "netsurf/browser_window.h"
-#import "desktop/browser_history.h"
-
-#import "cocoa/gui.h"
-#import "cocoa/BrowserViewController.h"
-#import "cocoa/BrowserView.h"
-#import "cocoa/BrowserWindowController.h"
-#import "cocoa/fetch.h"
-
-
-
-@implementation BrowserViewController
-
-@synthesize browser;
-@synthesize url;
-@synthesize browserView;
-@synthesize windowController;
-@synthesize title;
-@synthesize status;
-@synthesize isProcessing;
-@synthesize favicon;
-@synthesize canGoBack;
-@synthesize canGoForward;
-
-- (void) dealloc
-{
- [self setUrl: nil];
- [self setBrowserView: nil];
- [self setWindowController: nil];
- [self setTitle: nil];
- [self setStatus: nil];
- [self setFavicon: nil];
-
- [super dealloc];
-}
-
-- initWithBrowser: (struct browser_window *) bw
-{
- if ((self = [super initWithNibName: @"Browser" bundle: nil]) == nil) {
- return nil;
- }
-
- browser = bw;
-
- return self;
-}
-
-
-- (IBAction) navigate: (id) sender
-{
- nsurl *urlns;
- nserror error;
-
- error = nsurl_create([url UTF8String], &urlns);
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- } else {
- browser_window_navigate(browser,
- urlns,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- nsurl_unref(urlns);
- }
-}
-
-
-- (void) awakeFromNib
-{
- [browserView setBrowser: browser];
-}
-
-
-- (IBAction) zoomIn: (id) sender
-{
- browser_window_set_scale(browser,
- browser_window_get_scale(browser) * 1.1,
- true);
-}
-
-
-- (IBAction) zoomOut: (id) sender
-{
- browser_window_set_scale(browser,
- browser_window_get_scale(browser) * 0.9,
- true);
-}
-
-
-- (IBAction) zoomOriginal: (id) sender
-{
- browser_window_set_scale(browser,
- (float)nsoption_int(scale) / 100.0,
- true);
-}
-
-
-- (IBAction) backForwardSelected: (id) sender
-{
- if ([sender selectedSegment] == 0) {
- [self goBack: sender];
- } else {
- [self goForward: sender];
- }
-}
-
-
-- (IBAction) goBack: (id) sender
-{
- if (browser && browser_window_history_back_available( browser )) {
- browser_window_history_back(browser, false);
- [self updateBackForward];
- }
-}
-
-
-- (IBAction) goForward: (id) sender
-{
- if (browser && browser_window_history_forward_available( browser )) {
- browser_window_history_forward(browser, false);
- [self updateBackForward];
- }
-}
-
-
-- (IBAction) goHome: (id) sender
-{
- nsurl *urlns;
- nserror error;
-
- error = nsurl_create(nsoption_charp(homepage_url), &urlns);
- if (error == NSERROR_OK) {
- error = browser_window_navigate(browser,
- urlns,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- nsurl_unref(urlns);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-
-- (IBAction) reloadPage: (id) sender
-{
- browser_window_reload( browser, true );
-}
-
-
-- (IBAction) stopLoading: (id) sender
-{
- browser_window_stop( browser );
-}
-
-
-- (IBAction) viewSource: (id) sender
-{
- struct hlcache_handle *content;
- size_t size;
- const char *source;
- char *path = NULL;
-
- if (browser == NULL) {
- return;
- }
- content = browser_window_get_content(browser);
- if (content == NULL) {
- return;
- }
- source = content_get_source_data(content, &size);
- if (source == NULL) {
- return;
- }
-
- /* try to load local files directly. */
- netsurf_nsurl_to_path(hlcache_handle_get_url(content), &path);
-
- if (path == NULL) {
- /* We cannot release the requested filename until after it
- * has finished being used. As we can't easily find out when
- * this is, we simply don't bother releasing it and simply
- * allow it to be re-used next time NetSurf is started. The
- * memory overhead from doing this is under 1 byte per
- * filename. */
- const char *filename = filename_request();
- const char *extension = "txt";
- fprintf(stderr, "filename '%p'\n", filename);
- if (filename == NULL)
- return;
- lwc_string *str = content_get_mime_type(content);
- if (str) {
- NSString *mime = [NSString stringWithUTF8String:lwc_string_data(str)];
- NSString *uti = (NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mime, NULL);
- NSString *ext = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassFilenameExtension);
- extension = [ext UTF8String];
- lwc_string_unref(str);
- }
-
- NSURL *dataUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%s.%s", filename, extension]
- relativeToURL:[NSURL fileURLWithPath:@TEMP_FILENAME_PREFIX]];
-
-
- NSData *data = [NSData dataWithBytes:source length:size];
- [data writeToURL:dataUrl atomically:NO];
- path = [[dataUrl path] UTF8String];
- }
-
- if (path) {
- NSString * p = [NSString stringWithUTF8String: path];
- NSWorkspace * ws = [NSWorkspace sharedWorkspace];
- [ws openFile:p withApplication:@"Xcode"];
- }
-}
-
-
-static inline bool
-compare_float( float a, float b )
-{
- const float epsilon = 0.00001;
-
- if (a == b) {
- return true;
- }
-
- return fabs( (a - b) / b ) <= epsilon;
-}
-
-- (BOOL) validateUserInterfaceItem: (id) item
-{
- SEL action = [item action];
-
- if (action == @selector(copy:)) {
- return browser_window_get_editor_flags( browser ) & BW_EDITOR_CAN_COPY;
- }
-
- if (action == @selector(cut:)) {
- return browser_window_get_editor_flags( browser ) & BW_EDITOR_CAN_CUT;
- }
-
- if (action == @selector(paste:)) {
- return browser_window_get_editor_flags( browser ) & BW_EDITOR_CAN_PASTE;
- }
-
- if (action == @selector( stopLoading: )) {
- return browser_window_stop_available( browser );
- }
-
- if (action == @selector( zoomOriginal: )) {
- return !compare_float( browser_window_get_scale(browser), (float)nsoption_int(scale) / 100.0 );
- }
-
- if (action == @selector( goBack: )) {
- return canGoBack;
- }
-
- if (action == @selector( goForward: )) {
- return canGoForward;
- }
-
- return YES;
-}
-
-
-- (void) updateBackForward
-{
- [browserView updateHistory];
- [self setCanGoBack: browser != NULL && browser_window_history_back_available( browser )];
- [self setCanGoForward: browser != NULL && browser_window_history_forward_available( browser )];
-}
-
-- (void) contentUpdated
-{
- [browserView updateHistory];
-}
-
-struct history_add_menu_item_data {
- NSInteger index;
- NSMenu *menu;
- id target;
-};
-
-static bool
-history_add_menu_item_cb(const struct browser_window *bw,
- int x0, int y0, int x1, int y1,
- const struct history_entry *page,
- void *user_data )
-{
- struct history_add_menu_item_data *data = user_data;
-
- NSMenuItem *item = nil;
- if (data->index < [data->menu numberOfItems]) {
- item = [data->menu itemAtIndex: data->index];
- } else {
- item = [[NSMenuItem alloc] initWithTitle: @""
- action: @selector( historyItemSelected: )
- keyEquivalent: @""];
- [data->menu addItem: item];
- [item release];
- }
- ++data->index;
-
- [item setTarget: data->target];
- [item setTitle: [NSString stringWithUTF8String: browser_window_history_entry_get_title( page )]];
- [item setRepresentedObject: [NSValue valueWithPointer: page]];
-
- return true;
-}
-
-- (IBAction) historyItemSelected: (id) sender
-{
- struct history_entry *entry = [[sender representedObject] pointerValue];
- browser_window_history_go( browser, entry, false );
- [self updateBackForward];
-}
-
-- (void) buildBackMenu: (NSMenu *)menu
-{
- struct history_add_menu_item_data data = {
- .index = 0,
- .menu = menu,
- .target = self
- };
- browser_window_history_enumerate_back(browser,
- history_add_menu_item_cb,
- &data);
- while (data.index < [menu numberOfItems]) {
- [menu removeItemAtIndex: data.index];
- }
-}
-
-- (void) buildForwardMenu: (NSMenu *)menu
-{
- struct history_add_menu_item_data data = {
- .index = 0,
- .menu = menu,
- .target = self
- };
- browser_window_history_enumerate_forward(browser,
- history_add_menu_item_cb,
- &data);
- while (data.index < [menu numberOfItems]) {
- [menu removeItemAtIndex: data.index];
- }
-}
-
-@end
diff --git a/frontends/cocoa/BrowserWindow.h b/frontends/cocoa/BrowserWindow.h
deleted file mode 100644
index e0b83017f..000000000
--- a/frontends/cocoa/BrowserWindow.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface BrowserWindow : NSWindow {
-
-}
-
-@end
diff --git a/frontends/cocoa/BrowserWindow.m b/frontends/cocoa/BrowserWindow.m
deleted file mode 100644
index f01b17a25..000000000
--- a/frontends/cocoa/BrowserWindow.m
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/BrowserWindow.h"
-#import "cocoa/BrowserWindowController.h"
-
-@implementation BrowserWindow
-
-- (void) performClose: (id) sender
-{
- [[self windowController] closeCurrentTab: sender];
-}
-
-@end
diff --git a/frontends/cocoa/BrowserWindowController.h b/frontends/cocoa/BrowserWindowController.h
deleted file mode 100644
index 22e199509..000000000
--- a/frontends/cocoa/BrowserWindowController.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class PSMTabBarControl;
-@class BrowserViewController;
-@class URLFieldCell;
-
-@interface BrowserWindowController : NSWindowController {
- PSMTabBarControl *tabBar;
- NSTabView *tabView;
- URLFieldCell *urlField;
- NSObjectController *activeBrowserController;
- NSSegmentedControl *navigationControl;
- NSButton *historyButton;
- BrowserViewController *activeBrowser;
- NSMenu *historyBackMenu;
- NSMenu *historyForwardMenu;
-}
-
-@property (readwrite, assign, nonatomic) IBOutlet PSMTabBarControl *tabBar;
-@property (readwrite, assign, nonatomic) IBOutlet NSTabView *tabView;
-@property (readwrite, assign, nonatomic) IBOutlet URLFieldCell *urlField;
-@property (readwrite, assign, nonatomic) IBOutlet NSObjectController *activeBrowserController;
-@property (readwrite, assign, nonatomic) IBOutlet NSSegmentedControl *navigationControl;
-@property (readwrite, assign, nonatomic) IBOutlet NSButton *historyButton;
-@property (readwrite, assign, nonatomic) IBOutlet NSMenu *historyBackMenu;
-@property (readwrite, assign, nonatomic) IBOutlet NSMenu *historyForwardMenu;
-
-@property (readwrite, assign, nonatomic) BrowserViewController *activeBrowser;
-
-@property (readwrite, assign, nonatomic) BOOL canGoBack;
-@property (readwrite, assign, nonatomic) BOOL canGoForward;
-
-- (IBAction) newTab: (id) sender;
-- (IBAction) closeCurrentTab: (id) sender;
-
-- (void) addTab: (BrowserViewController *)browser;
-- (void) removeTab: (BrowserViewController *)browser;
-
-@end
diff --git a/frontends/cocoa/BrowserWindowController.m b/frontends/cocoa/BrowserWindowController.m
deleted file mode 100644
index aa7375a0e..000000000
--- a/frontends/cocoa/BrowserWindowController.m
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "netsurf/browser_window.h"
-#import "utils/nsoption.h"
-#import "utils/messages.h"
-#import "utils/utils.h"
-#import "utils/nsurl.h"
-
-#import "cocoa/BrowserWindowController.h"
-
-#import "cocoa/BrowserViewController.h"
-#import "cocoa/PSMTabBarControl/PSMTabBarControl.h"
-#import "cocoa/PSMTabBarControl/PSMRolloverButton.h"
-#import "cocoa/URLFieldCell.h"
-#import "cocoa/gui.h"
-#import "cocoa/NetsurfApp.h"
-
-
-@interface BrowserWindowController ()
-
-- (void) canCloseAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-
-@end
-
-
-@implementation BrowserWindowController
-
-@synthesize tabBar;
-@synthesize tabView;
-@synthesize urlField;
-@synthesize navigationControl;
-@synthesize historyButton;
-@synthesize historyBackMenu;
-@synthesize historyForwardMenu;
-
-@synthesize activeBrowser;
-@synthesize activeBrowserController;
-
-- (id) init;
-{
- if (nil == (self = [super initWithWindowNibName: @"BrowserWindow"])) return nil;
-
- return self;
-}
-
-- (void) dealloc;
-{
- [self setTabBar: nil];
- [self setTabView: nil];
- [self setUrlField: nil];
- [self setNavigationControl: nil];
-
- [super dealloc];
-}
-
-- (void) awakeFromNib;
-{
- [tabBar setShowAddTabButton: YES];
- [tabBar setTearOffStyle: PSMTabBarTearOffMiniwindow];
- [tabBar setCanCloseOnlyTab: YES];
- [tabBar setHideForSingleTab: YES];
-
- NSButton *b = [tabBar addTabButton];
- [b setTarget: self];
- [b setAction: @selector(newTab:)];
-
- [urlField setRefreshAction: @selector(reloadPage:)];
- [urlField bind: @"favicon" toObject: activeBrowserController withKeyPath: @"selection.favicon" options: nil];
-
- [self bind: @"canGoBack"
- toObject: activeBrowserController withKeyPath: @"selection.canGoBack"
- options: nil];
- [self bind: @"canGoForward"
- toObject: activeBrowserController withKeyPath: @"selection.canGoForward"
- options: nil];
-
- [navigationControl setMenu: historyBackMenu forSegment: 0];
- [navigationControl setMenu: historyForwardMenu forSegment: 1];
-}
-
-- (void) addTab: (BrowserViewController *)browser;
-{
- NSTabViewItem *item = [[[NSTabViewItem alloc] initWithIdentifier: browser] autorelease];
-
- [item setView: [browser view]];
- [item bind: @"label" toObject: browser withKeyPath: @"title" options: nil];
-
- [tabView addTabViewItem: item];
- [browser setWindowController: self];
-
- [tabView selectTabViewItem: item];
-}
-
-- (void) removeTab: (BrowserViewController *)browser;
-{
- NSUInteger itemIndex = [tabView indexOfTabViewItemWithIdentifier: browser];
- if (itemIndex != NSNotFound) {
- NSTabViewItem *item = [tabView tabViewItemAtIndex: itemIndex];
- [tabView removeTabViewItem: item];
- [browser setWindowController: nil];
- }
-}
-
-- (BOOL) windowShouldClose: (NSWindow *) window;
-{
- if ([tabView numberOfTabViewItems] <= 1) return YES;
- if ([[NSUserDefaults standardUserDefaults] boolForKey: kAlwaysCloseMultipleTabs]) return YES;
-
- NSAlert *ask = [NSAlert alertWithMessageText: NSLocalizedString( @"Do you really want to close this window?", nil )
- defaultButton: NSLocalizedString( @"Yes", @"'Yes' button" )
- alternateButton: NSLocalizedString( @"No" , @"'No' button" )
- otherButton:nil
- informativeTextWithFormat: NSLocalizedString( @"There are %d tabs open, do you want to close them all?", nil ),
- [tabView numberOfTabViewItems]];
- [ask setShowsSuppressionButton:YES];
-
- [ask beginSheetModalForWindow: window modalDelegate:self didEndSelector:@selector(canCloseAlertDidEnd:returnCode:contextInfo:)
- contextInfo: NULL];
-
- return NO;
-}
-
-- (void) canCloseAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-{
- if (returnCode == NSOKButton) {
- [[NSUserDefaults standardUserDefaults] setBool: [[alert suppressionButton] state] == NSOnState
- forKey: kAlwaysCloseMultipleTabs];
- [[self window] close];
- }
-}
-
-- (void) windowWillClose: (NSNotification *)notification;
-{
- for (NSTabViewItem *tab in [tabView tabViewItems]) {
- [tabView removeTabViewItem: tab];
- }
-}
-
-- (IBAction) newTab: (id) sender;
-{
- nsurl *url;
- nserror error;
-
- if (nsoption_charp(homepage_url) != NULL) {
- error = nsurl_create(nsoption_charp(homepage_url), &url);
- } else {
- error = nsurl_create(NETSURF_HOMEPAGE, &url);
- }
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY |
- BW_CREATE_TAB,
- url,
- NULL,
- [activeBrowser browser],
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (IBAction) closeCurrentTab: (id) sender;
-{
- [self removeTab: activeBrowser];
-}
-
-- (void) setActiveBrowser: (BrowserViewController *)newBrowser;
-{
- activeBrowser = newBrowser;
- [self setNextResponder: activeBrowser];
-}
-
-- (void) setCanGoBack: (BOOL)can;
-{
- [navigationControl setEnabled: can forSegment: 0];
-}
-
-- (BOOL) canGoBack;
-{
- return [navigationControl isEnabledForSegment: 0];
-}
-
-- (void) setCanGoForward: (BOOL)can;
-{
- [navigationControl setEnabled: can forSegment: 1];
-}
-
-- (BOOL) canGoForward;
-{
- return [navigationControl isEnabledForSegment: 1];
-}
-
-- (void)windowDidBecomeMain: (NSNotification *)note;
-{
- [(NetSurfApp *)NSApp setFrontTab: [[tabView selectedTabViewItem] identifier]];
-}
-
-- (void)menuNeedsUpdate:(NSMenu *)menu
-{
- if (menu == historyBackMenu) {
- [activeBrowser buildBackMenu: menu];
- } else if (menu == historyForwardMenu) {
- [activeBrowser buildForwardMenu: menu];
- }
-}
-
-#pragma mark -
-#pragma mark Tab bar delegate
-
-- (void) tabView: (NSTabView *)tabView didSelectTabViewItem: (NSTabViewItem *)tabViewItem;
-{
- [self setActiveBrowser: [tabViewItem identifier]];
- if ([[self window] isMainWindow]) {
- [(NetSurfApp *)NSApp setFrontTab: [tabViewItem identifier]];
- }
-}
-
-- (BOOL)tabView:(NSTabView*)aTabView shouldDragTabViewItem:(NSTabViewItem *)tabViewItem fromTabBar:(PSMTabBarControl *)tabBarControl
-{
- return [aTabView numberOfTabViewItems] > 1;
-}
-
-- (BOOL)tabView:(NSTabView*)aTabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl
-{
- [[tabViewItem identifier] setWindowController: self];
- return YES;
-}
-
-- (PSMTabBarControl *)tabView:(NSTabView *)aTabView newTabBarForDraggedTabViewItem:(NSTabViewItem *)tabViewItem atPoint:(NSPoint)point;
-{
- BrowserWindowController *newWindow = [[[BrowserWindowController alloc] init] autorelease];
- [[tabViewItem identifier] setWindowController: newWindow];
- [[newWindow window] setFrameOrigin: point];
- return newWindow->tabBar;
-}
-
-- (void) tabView: (NSTabView *)aTabView didCloseTabViewItem: (NSTabViewItem *)tabViewItem;
-{
- [tabViewItem unbind: @"label"];
-
- if (activeBrowser == [tabViewItem identifier]) {
- [self setActiveBrowser: nil];
- [(NetSurfApp *)NSApp setFrontTab: nil];
- }
-
- browser_window_destroy( [[tabViewItem identifier] browser] );
-}
-
-@end
diff --git a/frontends/cocoa/DownloadWindowController.h b/frontends/cocoa/DownloadWindowController.h
deleted file mode 100644
index 47a05be39..000000000
--- a/frontends/cocoa/DownloadWindowController.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-struct gui_download_table *cocoa_download_table;
-
-@interface DownloadWindowController : NSWindowController {
- struct download_context *context;
- unsigned long totalSize;
- unsigned long receivedSize;
-
- NSURL *url;
- NSString *mimeType;
- NSURL *saveURL;
- NSFileHandle *outputFile;
- NSMutableData *savedData;
- NSDate *startDate;
-
- BOOL canClose;
- BOOL shouldClose;
-}
-
-@property (readwrite, copy, nonatomic) NSURL *URL;
-@property (readwrite, copy, nonatomic) NSString *MIMEType;
-@property (readwrite, assign, nonatomic) unsigned long totalSize;
-@property (readwrite, copy, nonatomic) NSURL *saveURL;
-@property (readwrite, assign, nonatomic) unsigned long receivedSize;
-
-@property (readonly, nonatomic) NSString *fileName;
-@property (readonly, nonatomic) NSImage *icon;
-@property (readonly, nonatomic) NSString *statusText;
-
-- (id)initWithContext: (struct download_context *)ctx;
-
-- (void) abort;
-
-@end
diff --git a/frontends/cocoa/DownloadWindowController.m b/frontends/cocoa/DownloadWindowController.m
deleted file mode 100644
index b8cf09b18..000000000
--- a/frontends/cocoa/DownloadWindowController.m
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/log.h"
-#import "utils/nsurl.h"
-#import "desktop/download.h"
-#import "netsurf/download.h"
-
-#import "cocoa/DownloadWindowController.h"
-#import "cocoa/gui.h"
-
-@interface DownloadWindowController ()
-
-@property (readwrite, retain, nonatomic) NSFileHandle *outputFile;
-@property (readwrite, retain, nonatomic) NSMutableData *savedData;
-@property (readwrite, copy, nonatomic) NSDate *startDate;
-
-- (void)savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
-- (void)askCancelDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
-
-- (BOOL) receivedData: (NSData *)data;
-
-- (void) showError: (NSString *)error;
-- (void) downloadDone;
-- (void) removeIfPossible;
-
-@end
-
-static void cocoa_unregister_download( DownloadWindowController *download );
-static void cocoa_register_download( DownloadWindowController *download );
-
-
-@implementation DownloadWindowController
-
-- (id) initWithContext: (struct download_context *)ctx
-{
- if ((self = [super initWithWindowNibName: @"DownloadWindow"]) == nil) {
- return nil;
- }
-
- context = ctx;
- totalSize = download_context_get_total_length( context );
- [self setURL: [NSURL URLWithString: [NSString stringWithUTF8String: nsurl_access(download_context_get_url( context ))]]];
- [self setMIMEType: [NSString stringWithUTF8String: download_context_get_mime_type( context )]];
- [self setStartDate: [NSDate date]];
-
- return self;
-}
-
-- (void) dealloc
-{
- download_context_destroy( context );
-
- [self setURL: nil];
- [self setMIMEType: nil];
- [self setSaveURL: nil];
- [self setOutputFile: nil];
- [self setSavedData: nil];
- [self setStartDate: nil];
-
- [super dealloc];
-}
-
-- (void) abort
-{
- download_context_abort( context );
- [self removeIfPossible];
-}
-
-- (void) askForSave
-{
- canClose = NO;
- [[NSSavePanel savePanel]
- beginSheetForDirectory: nil
- file: [NSString stringWithUTF8String: download_context_get_filename( context )]
- modalForWindow: [self window]
- modalDelegate: self
- didEndSelector: @selector(savePanelDidEnd:returnCode:contextInfo:)
- contextInfo: NULL];
-}
-
-- (void) savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
- canClose = YES;
-
- if (returnCode == NSCancelButton) {
- [self abort];
- return;
- }
-
- NSURL *targetURL = [sheet URL];
- NSString *path = [targetURL path];
-
- [[NSFileManager defaultManager] createFileAtPath: path contents: nil attributes: nil];
-
- FSRef ref;
- if (CFURLGetFSRef( (CFURLRef)targetURL, &ref )) {
- NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- url, (NSString *)kLSQuarantineDataURLKey,
- (NSString *)kLSQuarantineTypeWebDownload, (NSString *)kLSQuarantineTypeKey,
- nil];
- LSSetItemAttribute( &ref, kLSRolesAll, kLSItemQuarantineProperties, (CFDictionaryRef)attributes );
- LOG("Set quarantine attributes on file %s", [path UTF8String]);
- }
-
- [self setOutputFile: [NSFileHandle fileHandleForWritingAtPath: path]];
- [self setSaveURL: targetURL];
-
- NSWindow *win = [self window];
- [win setRepresentedURL: targetURL];
- [win setTitle: [self fileName]];
-
- if (nil == outputFile) {
- [self performSelector: @selector(showError:) withObject: @"Cannot create file" afterDelay: 0];
- return;
- }
-
- if (nil != savedData) {
- [outputFile writeData: savedData];
- [self setSavedData: nil];
- }
-
- [self removeIfPossible];
-}
-
-- (BOOL) receivedData: (NSData *)data
-{
- if (outputFile) {
- [outputFile writeData: data];
- } else {
- if (nil == savedData) {
- [self setSavedData: [NSMutableData data]];
- }
- [savedData appendData: data];
- }
-
- [self setReceivedSize: receivedSize + [data length]];
-
- return YES;
-}
-
-- (void) showError: (NSString *)error
-{
- canClose = NO;
- NSAlert *alert = [NSAlert alertWithMessageText: NSLocalizedString( @"Error", @"show error" )
- defaultButton: NSLocalizedString( @"OK", @"'OK' button" )
- alternateButton: nil otherButton: nil
- informativeTextWithFormat: @"%@", error];
-
- [alert beginSheetModalForWindow: [self window] modalDelegate: self
- didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:)
- contextInfo: NULL];
-}
-
-- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
-{
- [self abort];
-}
-
-- (void) removeIfPossible
-{
- if (canClose && shouldClose) {
- cocoa_unregister_download( self );
- }
-}
-- (void) downloadDone
-{
- shouldClose = YES;
- [self removeIfPossible];
-}
-
-- (BOOL) windowShouldClose: (id)sender
-{
- if ([[NSUserDefaults standardUserDefaults] boolForKey: kAlwaysCancelDownload]) {
- return YES;
- }
-
- NSAlert *ask = [NSAlert alertWithMessageText: NSLocalizedString( @"Cancel download?", @"Download" )
- defaultButton: NSLocalizedString( @"Yes", @"" )
- alternateButton: NSLocalizedString( @"No", @"" )
- otherButton: nil
- informativeTextWithFormat: NSLocalizedString( @"Should the download of '%@' really be cancelled?", @"Download" ),
- [self fileName]];
- [ask setShowsSuppressionButton: YES];
- [ask beginSheetModalForWindow: [self window] modalDelegate: self
- didEndSelector: @selector(askCancelDidEnd:returnCode:contextInfo:) contextInfo: NULL];
- return NO;
-}
-
-- (void) windowWillClose: (NSNotification *)notification
-{
- [self abort];
-}
-
-- (void) askCancelDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
-{
- if (returnCode == NSOKButton) {
- [[NSUserDefaults standardUserDefaults]
- setBool: [[alert suppressionButton] state] == NSOnState
- forKey: kAlwaysCancelDownload];
- [self close];
- }
-}
-
-#pragma mark -
-#pragma mark Properties
-
-@synthesize URL = url;
-@synthesize MIMEType = mimeType;
-@synthesize totalSize;
-@synthesize saveURL;
-@synthesize outputFile;
-@synthesize savedData;
-@synthesize receivedSize;
-@synthesize startDate;
-
-+ (NSSet *) keyPathsForValuesAffectingStatusText
-{
- return [NSSet setWithObjects: @"totalSize", @"receivedSize", nil];
-}
-
-#ifndef NSAppKitVersionNumber10_5
-#define NSAppKitVersionNumber10_5 949
-#endif
-
-static NSString *cocoa_file_size_string( float size )
-{
- static unsigned factor = 0;
- if (factor == 0) {
- if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
- factor = 1000;
- } else {
- factor = 1024;
- }
- }
-
- if (size == 0) return @"nothing";
- if (size <= 1.0) return @"1 byte";
-
- if (size < factor - 1) return [NSString stringWithFormat:@"%1.0f bytes",size];
-
- size /= factor;
- if (size < factor - 1) return [NSString stringWithFormat:@"%1.1f KB", size];
-
- size /= factor;
- if (size < factor - 1) return [NSString stringWithFormat:@"%1.1f MB", size];
-
- size /= factor;
- if (size < factor - 1) return [NSString stringWithFormat:@"%1.1f GB", size];
-
- size /= factor;
- return [NSString stringWithFormat:@"%1.1f TB", size];
-}
-
-static NSString *cocoa_time_string( unsigned seconds )
-{
- if (seconds <= 10) {
- return NSLocalizedString(@"less than 10 seconds",
- @"time remaining" );
- }
-
- if (seconds < 60) {
- return [NSString stringWithFormat: NSLocalizedString( @"%u seconds",
- @"time remaining" ), seconds];
- }
-
- unsigned minutes = seconds / 60;
- seconds = seconds % 60;
-
- if (minutes < 60) {
- return [NSString stringWithFormat: NSLocalizedString( @"%u:%02u minutes",
- @"time remaining: minutes, seconds" ) , minutes, seconds];
- }
-
- unsigned hours = minutes / 60;
- minutes = minutes % 60;
-
- return [NSString stringWithFormat: NSLocalizedString( @"%2:%02u hours", @"time remaining: hours, minutes" ), hours, minutes];
-}
-
-- (NSString *) statusText
-{
- NSString *speedString = @"";
-
- float speed = 0.0;
- NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate: startDate];
- if (elapsedTime >= 0.1) {
- speed = (float)receivedSize / elapsedTime;
- speedString = [NSString stringWithFormat: @" (%@/s)", cocoa_file_size_string( speed )];
- }
-
- NSString *timeRemainingString = @"";
- NSString *totalSizeString = @"";
- if (totalSize != 0) {
- if (speed > 0.0) {
- float timeRemaining = (float)(totalSize - receivedSize) / speed;
- timeRemainingString = [NSString stringWithFormat: @": %@", cocoa_time_string( timeRemaining )];
- }
- totalSizeString = [NSString stringWithFormat: NSLocalizedString( @" of %@", @"... of (total size)" ), cocoa_file_size_string( totalSize )];
- }
-
- return [NSString stringWithFormat: @"%@%@%@%@", cocoa_file_size_string( receivedSize ),
- totalSizeString, speedString, timeRemainingString];
-}
-
-+ (NSSet *) keyPathsForValuesAffectingFileName
-{
- return [NSSet setWithObject: @"saveURL"];
-}
-
-- (NSString *) fileName
-{
- return [[saveURL path] lastPathComponent];
-}
-
-+ (NSSet *) keyPathsForValuesAffectingIcon
-{
- return [NSSet setWithObjects: @"mimeType", @"URL", nil];
-}
-
-- (NSImage *) icon;
-{
- NSString *type = [(NSString *)UTTypeCreatePreferredIdentifierForTag( kUTTagClassMIMEType, (CFStringRef)mimeType, NULL ) autorelease];
- if ([type hasPrefix: @"dyn."] || [type isEqualToString: (NSString *)kUTTypeData]) {
- NSString *pathExt = [[url path] pathExtension];
- type = [(NSString *)UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, (CFStringRef)pathExt, NULL ) autorelease];
- }
- return [[NSWorkspace sharedWorkspace] iconForFileType: type];
-}
-
-
-#pragma mark -
-#pragma mark NetSurf interface functions
-
-static struct gui_download_window *
-gui_download_window_create(download_context *ctx,
- struct gui_window *parent)
-{
- DownloadWindowController * const window = [[DownloadWindowController alloc] initWithContext: ctx];
- cocoa_register_download( window );
- [window askForSave];
- [window release];
-
- return (struct gui_download_window *)window;
-}
-
-static nserror
-gui_download_window_data(struct gui_download_window *dw,
- const char *data,
- unsigned int size)
-{
- DownloadWindowController * const window = (DownloadWindowController *)dw;
- return [window receivedData: [NSData dataWithBytes: data length: size]] ? NSERROR_OK : NSERROR_SAVE_FAILED;
-}
-
-static void
-gui_download_window_error(struct gui_download_window *dw,
- const char *error_msg)
-{
- DownloadWindowController * const window = (DownloadWindowController *)dw;
- [window showError: [NSString stringWithUTF8String: error_msg]];
-}
-
-static void
-gui_download_window_done(struct gui_download_window *dw)
-{
- DownloadWindowController * const window = (DownloadWindowController *)dw;
- [window downloadDone];
-}
-
-@end
-
-#pragma mark -
-static NSMutableSet *cocoa_all_downloads = nil;
-
-static void
-cocoa_register_download( DownloadWindowController *download )
-{
- if (cocoa_all_downloads == nil) {
- cocoa_all_downloads = [[NSMutableSet alloc] init];
- }
- [cocoa_all_downloads addObject: download];
-}
-
-static void
-cocoa_unregister_download( DownloadWindowController *download )
-{
- [cocoa_all_downloads removeObject: download];
-}
-
-
-static struct gui_download_table download_table = {
- .create = gui_download_window_create,
- .data = gui_download_window_data,
- .error = gui_download_window_error,
- .done = gui_download_window_done,
-};
-
-struct gui_download_table *cocoa_download_table = &download_table;
diff --git a/frontends/cocoa/FormSelectMenu.h b/frontends/cocoa/FormSelectMenu.h
deleted file mode 100644
index cec519296..000000000
--- a/frontends/cocoa/FormSelectMenu.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@interface FormSelectMenu : NSObject {
- NSMenu *menu;
- NSPopUpButtonCell *cell;
-
- struct browser_window *browser;
- struct form_control *control;
-}
-
-- (id)initWithControl: (struct form_control *) control forWindow: (struct browser_window *) window;
-- (void) runInView: (NSView *) view;
-
-@end
diff --git a/frontends/cocoa/FormSelectMenu.m b/frontends/cocoa/FormSelectMenu.m
deleted file mode 100644
index b7d168e0f..000000000
--- a/frontends/cocoa/FormSelectMenu.m
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/FormSelectMenu.h"
-#import "cocoa/coordinates.h"
-
-#import "netsurf/types.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/form.h"
-
-static inline NSRect cocoa_rect_for_control( struct browser_window *bw, struct form_control *control)
-{
- struct rect r;
- form_control_bounding_rect(control, &r);
- return cocoa_scaled_rect(browser_window_get_scale(bw),
- r.x0,
- r.y0,
- r.x1,
- r.y1);
-}
-
-@interface FormSelectMenu ()
-
-- (void) itemSelected: (id) sender;
-
-@end
-
-
-@implementation FormSelectMenu
-
-- (id) initWithControl: (struct form_control *) c forWindow: (struct browser_window *) w
-{
- if ((self = [super init]) == nil) return nil;
-
- control = c;
- browser = w;
-
- menu = [[NSMenu alloc] initWithTitle: @"Select"];
- if (menu == nil) {
- [self release];
- return nil;
- }
-
- [menu addItemWithTitle: @"" action: NULL keyEquivalent: @""];
-
- NSInteger currentItemIndex = 0;
- struct form_option *opt;
- for (opt = form_select_get_option(control, 0);
- opt != NULL;
- opt = opt->next) {
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle: [NSString stringWithUTF8String: opt->text]
- action: @selector( itemSelected: )
- keyEquivalent: @""];
- if (opt->selected) {
- [item setState: NSOnState];
- }
- [item setTarget: self];
- [item setTag: currentItemIndex++];
- [menu addItem: item];
- [item release];
- }
-
- [menu setDelegate: self];
-
- return self;
-}
-
-- (void) dealloc
-{
- [cell release];
- [menu release];
-
- [super dealloc];
-}
-
-- (void) runInView: (NSView *) view
-{
- [self retain];
-
- cell = [[NSPopUpButtonCell alloc] initTextCell: @"" pullsDown: YES];
- [cell setMenu: menu];
-
- const NSRect rect = cocoa_rect_for_control(browser, control);
-
- [cell attachPopUpWithFrame: rect inView: view];
- [cell performClickWithFrame: rect inView: view];
-}
-
-- (void) itemSelected: (id) sender
-{
- form_select_process_selection( control, [sender tag] );
-}
-
-- (void) menuDidClose: (NSMenu *) sender
-{
- [self release];
-}
-
-@end
diff --git a/frontends/cocoa/HistoryView.h b/frontends/cocoa/HistoryView.h
deleted file mode 100644
index 6ef061321..000000000
--- a/frontends/cocoa/HistoryView.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class HistoryView;
-@class BrowserView;
-
-@interface HistoryView : NSView {
- struct browser_window *browser;
- BrowserView *browserView;
- NSMutableArray *toolTips;
-}
-
-@property (readwrite, assign, nonatomic) BrowserView *browser;
-
-- (void) updateHistory;
-- (NSSize) size;
-
-@end
diff --git a/frontends/cocoa/HistoryView.m b/frontends/cocoa/HistoryView.m
deleted file mode 100644
index bead8dbed..000000000
--- a/frontends/cocoa/HistoryView.m
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/HistoryView.h"
-#import "cocoa/font.h"
-#import "cocoa/coordinates.h"
-#import "cocoa/plotter.h"
-#import "cocoa/LocalHistoryController.h"
-#import "cocoa/BrowserView.h"
-
-#import "desktop/browser_history.h"
-#import "netsurf/plotters.h"
-
-@implementation HistoryView
-
-@synthesize browser = browserView;
-
-- (void) setBrowser: (BrowserView *) bw;
-{
- browserView = bw;
- browser = [bw browser];
- [self updateHistory];
-}
-
-- (NSSize) size;
-{
- int width, height;
- browser_window_history_size( browser, &width, &height );
-
- return cocoa_size( width, height );
-}
-
-- (void) updateHistory;
-{
- [self setFrameSize: [self size]];
- [self setNeedsDisplay: YES];
-}
-
-- (void) drawRect: (NSRect)rect;
-{
- [[NSColor clearColor] set];
- [NSBezierPath fillRect: rect];
-
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &cocoa_plotters
- };
-
- cocoa_set_clip( rect );
-
- browser_window_history_redraw( browser, &ctx );
-}
-
-- (void) mouseUp: (NSEvent *)theEvent;
-{
- const NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
- const bool newWindow = [theEvent modifierFlags] & NSCommandKeyMask;
- if (browser_window_history_click( browser,
- cocoa_pt_to_px( location.x ), cocoa_pt_to_px( location.y ),
- newWindow )) {
- [browserView setHistoryVisible: NO];
- }
-}
-
-- (BOOL) isFlipped;
-{
- return YES;
-}
-
-- (void) mouseEntered: (NSEvent *) event;
-{
- [[NSCursor pointingHandCursor] set];
-}
-
-- (void) mouseExited: (NSEvent *) event;
-{
- [[NSCursor arrowCursor] set];
-}
-
-static bool cursor_rects_cb( const struct browser_window *bw, int x0, int y0, int x1, int y1,
- const struct history_entry *page, void *user_data )
-{
- HistoryView *view = user_data;
-
- NSRect rect = NSIntersectionRect( [view visibleRect], cocoa_rect( x0, y0, x1, y1 ) );
- if (!NSIsEmptyRect( rect )) {
-
- NSString *toolTip = [NSString stringWithFormat: @"%s\n%s", browser_window_history_entry_get_title(page),
- browser_window_history_entry_get_url( page )];
-
- [view addToolTipRect: rect owner: toolTip userData: nil];
- NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect: rect
- options: NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
- owner: view userInfo: nil];
- [view addTrackingArea: area];
- [area release];
- }
-
- return true;
-}
-
-- (NSToolTipTag)addToolTipRect: (NSRect) rect owner: (id) owner userData: (void *) userData;
-{
- if (toolTips == nil) toolTips = [[NSMutableArray alloc] init];
- [toolTips addObject: owner];
-
- return [super addToolTipRect: rect owner: owner userData: userData];
-}
-
-- (void) removeAllToolTips;
-{
- [super removeAllToolTips];
- [toolTips removeAllObjects];
-}
-
-- (void) updateTrackingAreas;
-{
- [self removeAllToolTips];
-
- for (NSTrackingArea *area in [self trackingAreas]) {
- [self removeTrackingArea: area];
- }
-
- browser_window_history_enumerate( browser, cursor_rects_cb, self );
-
- [super updateTrackingAreas];
-}
-
-- (void) dealloc;
-{
- [self removeAllToolTips];
- [super dealloc];
-}
-
-@end
diff --git a/frontends/cocoa/HistoryWindowController.h b/frontends/cocoa/HistoryWindowController.h
deleted file mode 100644
index 30ba8049a..000000000
--- a/frontends/cocoa/HistoryWindowController.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class Tree;
-@class TreeView;
-
-@interface HistoryWindowController : NSWindowController {
- Tree *tree;
- TreeView *view;
-}
-
-@property (readwrite, assign, nonatomic) IBOutlet TreeView *view;
-
-@end
diff --git a/frontends/cocoa/HistoryWindowController.m b/frontends/cocoa/HistoryWindowController.m
deleted file mode 100644
index cae679b9d..000000000
--- a/frontends/cocoa/HistoryWindowController.m
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/HistoryWindowController.h"
-#import "cocoa/Tree.h"
-#import "cocoa/TreeView.h"
-
-#import "desktop/global_history.h"
-
-@implementation HistoryWindowController
-
-@synthesize view;
-
-- init;
-{
- if ((self = [super initWithWindowNibName: @"HistoryWindow"]) == nil) return nil;
-
- tree = [[Tree alloc] initWithFlags: TREE_HISTORY];
-
- return self;
-}
-
-- (void) dealloc;
-{
- [tree release];
- [self setView: nil];
-
- [super dealloc];
-}
-
-- (void)awakeFromNib;
-{
- [view setTree: tree];
- [[self window] setExcludedFromWindowsMenu: YES];
-}
-
-@end
diff --git a/frontends/cocoa/LocalHistoryController.h b/frontends/cocoa/LocalHistoryController.h
deleted file mode 100644
index 3e6d1775e..000000000
--- a/frontends/cocoa/LocalHistoryController.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class HistoryView;
-@class BrowserView;
-
-@interface LocalHistoryController : NSWindowController {
- HistoryView *history;
- BrowserView *browser;
-}
-
-@property (readwrite, assign, nonatomic) BrowserView *browser;
-@property (readwrite, assign, nonatomic) IBOutlet HistoryView *history;
-
-- (id)initWithBrowser: (BrowserView *) bw;
-
-- (void) attachToView: (NSView *) view;
-- (void) detach;
-- (void) redraw;
-
-- (void) keyDown: (NSEvent *)theEvent;
-
-@end
diff --git a/frontends/cocoa/LocalHistoryController.m b/frontends/cocoa/LocalHistoryController.m
deleted file mode 100644
index b3992b614..000000000
--- a/frontends/cocoa/LocalHistoryController.m
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/LocalHistoryController.h"
-
-#import "cocoa/BrowserView.h"
-#import "cocoa/HistoryView.h"
-#import "cocoa/ArrowWindow.h"
-
-@implementation LocalHistoryController
-
-@synthesize browser;
-@synthesize history;
-
-- initWithBrowser: (BrowserView *) bw;
-{
- if ((self = [super initWithWindowNibName: @"LocalHistoryPanel"]) == nil) return nil;
-
- browser = bw;
-
- return self;
-}
-
-- (void) attachToView: (NSView *) view;
-{
- NSDisableScreenUpdates();
-
- ArrowWindow *box = (ArrowWindow *)[self window];
-
- [box setContentSize: [history size]];
- [box setArrowPosition: 50];
- [history updateHistory];
- [box attachToView: view];
-
- NSRect frame = [box frame];
- NSRect screenFrame = [[box screen] visibleFrame];
-
- const CGFloat arrowSize = [box arrowSize];
- frame.origin.x += arrowSize;
- frame.origin.y += arrowSize;
- frame.size.width -= 2 * arrowSize;
- frame.size.height -= 2 * arrowSize;
-
- if (NSMinY( frame ) < NSMinY( screenFrame )) {
- const CGFloat delta = NSMinY( screenFrame ) - NSMinY( frame );
- frame.size.height -= delta;
- frame.origin.y += delta;
- }
-
- CGFloat arrowPositionChange = 50;
- if (NSMaxX( frame ) > NSMaxX( screenFrame )) {
- const CGFloat delta = NSMaxX( frame ) - NSMaxX( screenFrame );
- arrowPositionChange += delta;
- frame.origin.x -= delta;
- }
-
- if (NSMinX( frame ) < NSMinX( screenFrame )) {
- const CGFloat delta = NSMinX( screenFrame ) - NSMinX( frame );
- arrowPositionChange -= delta;
- frame.origin.x += delta;
- frame.size.width -= delta;
- }
-
- frame.origin.x -= arrowSize;
- frame.origin.y -= arrowSize;
- frame.size.width += 2 * arrowSize;
- frame.size.height += 2 * arrowSize;
-
- [box setArrowPosition: arrowPositionChange];
- [box setFrame: frame display: YES];
-
- NSEnableScreenUpdates();
-}
-
-- (void) detach;
-{
- [(ArrowWindow *)[self window] detach];
-}
-
-- (void) windowDidLoad;
-{
- [history setBrowser: browser];
-}
-
-- (void) redraw;
-{
- [history setNeedsDisplay: YES];
-}
-
-- (void) keyDown: (NSEvent *)theEvent;
-{
- unichar key = [[theEvent characters] characterAtIndex: 0];
- switch (key) {
- case 27:
- [browser setHistoryVisible: NO];
- break;
-
- default:
- NSBeep();
- break;
- };
-}
-
-@end
diff --git a/frontends/cocoa/Makefile b/frontends/cocoa/Makefile
deleted file mode 100644
index a0ebfbb43..000000000
--- a/frontends/cocoa/Makefile
+++ /dev/null
@@ -1,250 +0,0 @@
-# ----------------------------------------------------------------------------
-# Mac OS X target setup
-# ----------------------------------------------------------------------------
-
-POSTEXES += NetSurf.app
-
-# shut up zconf.h and zlib.h
-#CFLAGS += -D_LARGEFILE64_SOURCE=1
-
-# add Mac Ports include and library paths for openssl
-ifneq ($(shell test -d /opt/local && echo 'yes'),)
- LDFLAGS += -L/opt/local/lib
- CFLAGS += -I/opt/local/include
-endif
-
-ifeq ($(SDK_VERSION),)
- # if no SDK_VERSION has been specified select one from those available
- SDK_PARAM := $(shell xcodebuild -showsdks | awk '/^$$/{p=0};p; /OS X SDKs:/{p=1}' | tail -1 | cut -f3)
- SDK_VERSION := $(MACOSX_VERSION)
-else
- SDK_PARAM := -sdk macosx$(SDK_VERSION)
-endif
-
-SDK_PATH ?= $(shell xcodebuild -version $(SDK_PARAM) Path)
-SDK_FLAGS := -isysroot $(SDK_PATH) -mmacosx-version-min=$(SDK_VERSION)
-CFLAGS := $(SDK_FLAGS) $(CFLAGS)
-LDFLAGS := $(SDK_FLAGS) -Wl,-syslibroot,$(SDK_PATH) $(LDFLAGS)
-CXXFLAGS := $(SDK_FLAGS) $(CXXFLAGS)
-
-# for timerisset()
-CFLAGS += -D_DARWIN_C_SOURCE
-
-LDFLAGS += -L/usr/lib
-LDFLAGS += -L/usr/X11/lib
-LDFLAGS += -lm -lcurl
-LDFLAGS += -lssl -lcrypto
-
-CFLAGS += -Dnscocoa -D_BSD_SOURCE -D_POSIX_C_SOURCE -std=c99 -g -Os
-
-CFLAGS += -I/usr/X11/include
-CFLAGS += -include cocoa/Prefix.pch
-
-VERSION_FULL := $(shell sed -n '/_version.*=.*"/{s/.*"\(.*\)".*/\1/;p;}' desktop/version.c)
-VERSION_MAJ := $(shell sed -n '/_major/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
-VERSION_MIN := $(shell sed -n '/_minor/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
-
-LDFLAGS += -Wl,-framework,Cocoa -Wl,-framework,Carbon $(NETLDFLAGS)
-
-$(eval $(call feature_enabled,IMAGEIO,-DWITH_APPLE_IMAGE,,Apple ImageIO ))
-
-ifneq ($(UNIVERSAL),)
- UNIVERSAL_FLAGS := $(foreach arch,$(UNIVERSAL),-arch $(arch) )
- CFLAGS += $(UNIVERSAL_FLAGS)
- LDFLAGS += $(UNIVERSAL_FLAGS)
- CXXFLAGS += $(UNIVERSAL_FLAGS)
-endif
-
-# ----------------------------------------------------------------------------
-# Source file setup
-# ----------------------------------------------------------------------------
-
-# sources purely for the Mac OS X build
-S_FRONTEND := \
- BookmarksController.m \
- BrowserView.m \
- BrowserViewController.m \
- BrowserWindowController.m \
- BrowserWindow.m \
- DownloadWindowController.m \
- NetSurfAppDelegate.m \
- NetsurfApp.m \
- PreferencesWindowController.m \
- ScrollableView.m \
- SearchWindowController.m \
- URLFieldCell.m \
- Tree.m \
- desktop-tree.m \
- TreeView.m \
- HistoryView.m \
- HistoryWindowController.m \
- FormSelectMenu.m \
- bitmap.m \
- fetch.m \
- font.m \
- gui.m \
- plotter.m \
- schedule.m \
- selection.m \
- ArrowBox.m \
- ArrowWindow.m \
- BlackScroller.m \
- LocalHistoryController.m \
- apple_image.m
-
-S_TABBAR := \
- NSBezierPath_AMShading.m \
- NSString_AITruncation.m \
- PSMOverflowPopUpButton.m \
- PSMProgressIndicator.m \
- PSMRolloverButton.m \
- PSMTabBarCell.m \
- PSMTabBarControl.m \
- PSMTabBarController.m \
- PSMTabDragAssistant.m \
- PSMTabDragView.m \
- PSMTabDragWindow.m \
- PSMTabDragWindowController.m \
- PSMUnifiedTabStyle.m
-
-S_FRONTEND += $(addprefix PSMTabBarControl/,$(S_TABBAR))
-
-# This is the final source build list
-# Note this is deliberately *not* expanded here as common and image
-# are not yet available
-SOURCES = $(addprefix $(shell pwd)/,$(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND))
-
-# Since we prefix the sources with the pwd, also create a special
-# prefixed rule so that the testament is run
-$(shell pwd)/content/fetchers/about.c: testament
-
-EXETARGET := NetSurf
-
-S_XIBS := \
- MainMenu.xib \
- Browser.xib \
- BrowserWindow.xib \
- DownloadWindow.xib \
- SearchWindow.xib \
- PreferencesWindow.xib \
- HistoryWindow.xib \
- BookmarksWindow.xib \
- LocalHistoryPanel.xib
-
-R_RESOURCES := \
- default.css \
- adblock.css \
- internal.css \
- quirks.css \
- NetSurf.icns \
- HomeTemplate.pdf \
- Icons \
- ca-bundle \
- netsurf.png
-
-
-TABBAR_RESOURCES := \
- AquaTabClose_Front_Pressed.png \
- AquaTabClose_Front_Rollover.png \
- AquaTabClose_Front.png \
- AquaTabCloseDirty_Front_Pressed.png \
- AquaTabCloseDirty_Front_Rollover.png \
- AquaTabCloseDirty_Front.png \
- AquaTabNew.png \
- AquaTabNewPressed.png \
- AquaTabNewRollover.png \
- overflowImage.png \
- overflowImagePressed.png \
- pi.png
-
-R_RESOURCES := $(addprefix $(FRONTEND_RESOURCES_DIR)/,$(R_RESOURCES))
-
-R_RESOURCES += $(addprefix $(FRONTEND_SOURCE_DIR)/PSMTabBarControl/Images/,$(TABBAR_RESOURCES))
-
-LANGUAGES := de en fr it nl
-LOCALIZED_RESOURCES := Localizable.strings
-
-#languiage project macro
-# $1 is language name
-# $2 is list of resources per language
-define make_lproj
-R_RESOURCES += $$(OBJROOT)/$(1).lproj
-$$(OBJROOT)/$(1).lproj: $(2)
- $(VQ)echo Bundling language $(1)
- $(Q)$(MKDIR) -p $$@
- $(Q)cp -pLR $(2) $$@
- $(Q)$(SPLIT_MESSAGES) -l $(1) -p cocoa -f messages resources/FatMessages > $$@/Messages
-endef
-
-# compile_xib (xib) (lang)
-define compile_xib
-$$(OBJROOT)/$(2).lproj: $$(OBJROOT)/$(2).lproj/$(1:.xib=.nib)
-
-$$(OBJROOT)/$(2).lproj/$(1:.xib=.nib): $(FRONTEND_RESOURCES_DIR)/$(1) $$(OBJROOT)/created
- $(VQ)echo Compiling XIB $(1) for language $(2)
- $(Q)$(MKDIR) -p $$(OBJROOT)/$(2).lproj
- $(Q)$(FRONTEND_SOURCE_DIR)/compile-xib.sh $(FRONTEND_RESOURCES_DIR)/$(1) $(2) $$@
-
-ifeq ($(wildcard $(FRONTEND_RESOURCES_DIR)/$(2).lproj/$(1).strings),$(FRONTEND_RESOURCES_DIR)/$(2).lproj/$(1).strings)
-$$(OBJROOT)/$(2).lproj/$(1:.xib=.nib): $(FRONTEND_RESOURCES_DIR)/$(2).lproj/$(1).strings
-endif
-
-endef
-
-$(foreach lang,$(LANGUAGES),$(eval $(call make_lproj,$(lang),$(addprefix $(FRONTEND_RESOURCES_DIR)/$(lang).lproj/,$(LOCALIZED_RESOURCES)))))
-$(foreach lang,$(LANGUAGES),$(foreach xib,$(S_XIBS),$(eval $(call compile_xib,$(xib),$(lang)))))
-
-# ----------------------------------------------------------------------------
-# Install target
-# ----------------------------------------------------------------------------
-
-install-cocoa: NetSurf.app
-
-NetSurf.app: NetSurf $(FRONTEND_SOURCE_DIR)/Makefile $(R_RESOURCES) NetSurf.app/Contents/Info.plist
- $(VQ)echo Assembling NetSurf.app bundle
- $(Q)$(MKDIR) -p NetSurf.app/Contents/MacOS
- $(Q)cp NetSurf NetSurf.app/Contents/MacOS
- $(Q)rm -rf NetSurf.app/Contents/Resources
- $(Q)$(MKDIR) -p NetSurf.app/Contents/Resources
- $(Q)cp -pLR $(R_RESOURCES) NetSurf.app/Contents/Resources
- $(Q)echo 'APPL????' > NetSurf.app/Contents/PkgInfo
-
-NetSurf.app/Contents/Info.plist: $(FRONTEND_RESOURCES_DIR)/NetSurf-Info.plist $(FRONTEND_SOURCE_DIR)/Makefile
- $(VQ)echo Generating Info.plist
- $(Q)$(MKDIR) -p NetSurf.app/Contents
- $(Q)sed -e 's/$${EXECUTABLE_NAME}/$(EXETARGET)/' \
- -e 's/$${PRODUCT_NAME.*}/$(EXETARGET)/' \
- -e 's/$${MACOSX_DEPLOYMENT_TARGET}/$(MACOSX_VERSION)/' \
- -e 's/$${NETSURF_VERSION}/$(VERSION_FULL)/' \
- -e 's/$${NETSURF_SHORT_VERSION}/$(VERSION_MAJ).$(VERSION_MIN)/' \
- < $(FRONTEND_RESOURCES_DIR)/NetSurf-Info.plist > NetSurf.app/Contents/Info.plist
-
-# ----------------------------------------------------------------------------
-# Package target
-# ----------------------------------------------------------------------------
-
-package-cocoa: NetSurf.dmg
-
-.INTERMEDIATE: NetSurf.tmp.dmg
-
-NetSurf.tmp.dmg: NetSurf.app
- hdiutil create -size 8m -fs HFS+ -volname "NetSurf" $@
- sleep 2
- hdiutil attach $@
- sleep 2
- cp -pPR $^ /Volumes/NetSurf/
- hdiutil detach $$(echo $$(hdiutil attach $@ | cut -f 1) | cut -f 1 -d ' ')
- sleep 2
-
-NetSurf.dmg: NetSurf.tmp.dmg
- hdiutil convert $^ -format UDZO -o $@
-
-CLEANS += clean-package-cocoa
-
-clean-package-cocoa:
- $(VQ)echo " CLEAN: NetSurf.tmp.dmg"
- $(Q)$(RM) NetSurf.tmp.dmg
- $(VQ)echo " CLEAN: NetSurf.dmg"
- $(Q)$(RM) NetSurf.dmg
- $(VQ)echo " CLEAN: NetSurf.app"
- $(Q)$(RM) -r NetSurf.app
diff --git a/frontends/cocoa/Makefile.defaults b/frontends/cocoa/Makefile.defaults
deleted file mode 100644
index 8f5792b0a..000000000
--- a/frontends/cocoa/Makefile.defaults
+++ /dev/null
@@ -1,30 +0,0 @@
-# ----------------------------------------------------------------------------
-# Cocoa-specific options
-# ----------------------------------------------------------------------------
-
-# Force using glibc internal iconv implementation instead of external libiconv
-# Valid options: YES, NO
-NETSURF_USE_LIBICONV_PLUG := NO
-
-# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
-# Valid options: YES, NO, AUTO
-NETSURF_USE_ROSPRITE := NO
-
-# Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
-# Valid options: YES, NO, AUTO
-NETSURF_USE_RSVG := AUTO
-
-# Enable NetSurf's use of libsvgtiny for displaying SVGs
-# Valid options: YES, NO, AUTO
-NETSURF_USE_NSSVG := AUTO
-
-NETSURF_USE_BMP := NO
-NETSURF_USE_GIF := NO
-NETSURF_USE_PNG := NO
-NETSURF_USE_JPEG := NO
-NETSURF_USE_IMAGEIO := YES
-
-MACOSX_VERSION := $(shell sw_vers -productVersion | awk -F '.' '{print $$1 "." $$2}')
-
-# Optimisation levels
-CFLAGS += -O2
diff --git a/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj b/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj
deleted file mode 100644
index ef25d2f1a..000000000
--- a/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,1023 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 45;
- objects = {
-
-/* Begin PBXFileReference section */
- 260F1F6312D620E800D9B07F /* content.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = content.c; sourceTree = "<group>"; };
- 260F1F6412D620E800D9B07F /* content.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = content.h; sourceTree = "<group>"; };
- 260F1F6512D620E800D9B07F /* content_protected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = content_protected.h; sourceTree = "<group>"; };
- 260F1F6612D620E800D9B07F /* content_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = content_type.h; sourceTree = "<group>"; };
- 260F1F6712D620E800D9B07F /* dirlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dirlist.c; sourceTree = "<group>"; };
- 260F1F6812D620E800D9B07F /* dirlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirlist.h; sourceTree = "<group>"; };
- 260F1F6912D620E800D9B07F /* fetch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fetch.c; sourceTree = "<group>"; };
- 260F1F6A12D620E800D9B07F /* fetch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fetch.h; sourceTree = "<group>"; };
- 260F1F6C12D620E800D9B07F /* curl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = curl.c; sourceTree = "<group>"; };
- 260F1F6D12D620E800D9B07F /* curl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = curl.h; sourceTree = "<group>"; };
- 260F1F6E12D620E800D9B07F /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = "<group>"; };
- 260F1F6F12D620E800D9B07F /* data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = data.h; sourceTree = "<group>"; };
- 260F1F7012D620E800D9B07F /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = file.c; sourceTree = "<group>"; };
- 260F1F7112D620E800D9B07F /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = "<group>"; };
- 260F1F7212D620E800D9B07F /* hlcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hlcache.c; sourceTree = "<group>"; };
- 260F1F7312D620E800D9B07F /* hlcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hlcache.h; sourceTree = "<group>"; };
- 260F1F7412D620E800D9B07F /* llcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = llcache.c; sourceTree = "<group>"; };
- 260F1F7512D620E800D9B07F /* llcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = llcache.h; sourceTree = "<group>"; };
- 260F1F7612D620E800D9B07F /* urldb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = urldb.c; sourceTree = "<group>"; };
- 260F1F7712D620E800D9B07F /* urldb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = urldb.h; sourceTree = "<group>"; };
- 260F1F7912D620E800D9B07F /* css.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = css.c; sourceTree = "<group>"; };
- 260F1F7A12D620E800D9B07F /* css.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = css.h; sourceTree = "<group>"; };
- 260F1F7B12D620E800D9B07F /* dump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dump.c; sourceTree = "<group>"; };
- 260F1F7C12D620E800D9B07F /* dump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dump.h; sourceTree = "<group>"; };
- 260F1F7D12D620E800D9B07F /* internal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = internal.c; sourceTree = "<group>"; };
- 260F1F7E12D620E800D9B07F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
- 260F1F7F12D620E800D9B07F /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = select.c; sourceTree = "<group>"; };
- 260F1F8012D620E800D9B07F /* select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = select.h; sourceTree = "<group>"; };
- 260F1F8112D620E800D9B07F /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = "<group>"; };
- 260F1F8212D620E800D9B07F /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
- 260F1F8412D620E800D9B07F /* 401login.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 401login.h; sourceTree = "<group>"; };
- 260F1F8512D620E800D9B07F /* browser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = browser.c; sourceTree = "<group>"; };
- 260F1F8612D620E800D9B07F /* browser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = browser.h; sourceTree = "<group>"; };
- 260F1F8712D620E800D9B07F /* cookies.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cookies.c; sourceTree = "<group>"; };
- 260F1F8812D620E800D9B07F /* cookies_old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cookies_old.h; sourceTree = "<group>"; };
- 260F1F8912D620E800D9B07F /* download.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = download.c; sourceTree = "<group>"; };
- 260F1F8A12D620E800D9B07F /* download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = download.h; sourceTree = "<group>"; };
- 260F1F8B12D620E800D9B07F /* frames.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frames.c; sourceTree = "<group>"; };
- 260F1F8C12D620E800D9B07F /* frames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frames.h; sourceTree = "<group>"; };
- 260F1F8D12D620E800D9B07F /* gui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gui.h; sourceTree = "<group>"; };
- 260F1F8E12D620E800D9B07F /* local_history.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = local_history.c; sourceTree = "<group>"; };
- 260F1F8F12D620E800D9B07F /* local_history.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_history.h; sourceTree = "<group>"; };
- 260F1F9012D620E800D9B07F /* history_global_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = history_global_core.c; sourceTree = "<group>"; };
- 260F1F9112D620E800D9B07F /* history_global_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = history_global_core.h; sourceTree = "<group>"; };
- 260F1F9212D620E800D9B07F /* hotlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hotlist.c; sourceTree = "<group>"; };
- 260F1F9312D620E800D9B07F /* hotlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hotlist.h; sourceTree = "<group>"; };
- 260F1F9412D620E800D9B07F /* knockout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = knockout.c; sourceTree = "<group>"; };
- 260F1F9512D620E800D9B07F /* knockout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = knockout.h; sourceTree = "<group>"; };
- 260F1F9612D620E800D9B07F /* mouse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mouse.c; sourceTree = "<group>"; };
- 260F1F9712D620E800D9B07F /* mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mouse.h; sourceTree = "<group>"; };
- 260F1F9812D620E800D9B07F /* netsurf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = netsurf.c; sourceTree = "<group>"; };
- 260F1F9912D620E800D9B07F /* netsurf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = netsurf.h; sourceTree = "<group>"; };
- 260F1F9A12D620E800D9B07F /* options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = options.c; sourceTree = "<group>"; };
- 260F1F9B12D620E800D9B07F /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = options.h; sourceTree = "<group>"; };
- 260F1F9C12D620E800D9B07F /* plot_style.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plot_style.c; sourceTree = "<group>"; };
- 260F1F9D12D620E800D9B07F /* plot_style.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plot_style.h; sourceTree = "<group>"; };
- 260F1F9E12D620E800D9B07F /* plotters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plotters.h; sourceTree = "<group>"; };
- 260F1F9F12D620E800D9B07F /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
- 260F1FA012D620E800D9B07F /* print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = print.h; sourceTree = "<group>"; };
- 260F1FA112D620E800D9B07F /* printer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = printer.h; sourceTree = "<group>"; };
- 260F1FA212D620E800D9B07F /* save_complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = save_complete.c; sourceTree = "<group>"; };
- 260F1FA312D620E800D9B07F /* save_complete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = save_complete.h; sourceTree = "<group>"; };
- 260F1FA512D620E800D9B07F /* font_haru.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = font_haru.c; sourceTree = "<group>"; };
- 260F1FA612D620E800D9B07F /* font_haru.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font_haru.h; sourceTree = "<group>"; };
- 260F1FA712D620E800D9B07F /* pdf_plotters.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pdf_plotters.c; sourceTree = "<group>"; };
- 260F1FA812D620E800D9B07F /* pdf_plotters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pdf_plotters.h; sourceTree = "<group>"; };
- 260F1FAA12D620E800D9B07F /* save_text.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = save_text.c; sourceTree = "<group>"; };
- 260F1FAB12D620E800D9B07F /* save_text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = save_text.h; sourceTree = "<group>"; };
- 260F1FAC12D620E800D9B07F /* scroll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scroll.c; sourceTree = "<group>"; };
- 260F1FAD12D620E800D9B07F /* scroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scroll.h; sourceTree = "<group>"; };
- 260F1FAE12D620E800D9B07F /* search.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = search.c; sourceTree = "<group>"; };
- 260F1FAF12D620E800D9B07F /* search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = search.h; sourceTree = "<group>"; };
- 260F1FB012D620E800D9B07F /* searchweb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = searchweb.c; sourceTree = "<group>"; };
- 260F1FB112D620E800D9B07F /* searchweb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = searchweb.h; sourceTree = "<group>"; };
- 260F1FB212D620E800D9B07F /* selection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = selection.c; sourceTree = "<group>"; };
- 260F1FB312D620E800D9B07F /* selection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = selection.h; sourceTree = "<group>"; };
- 260F1FB412D620E800D9B07F /* sslcert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sslcert.c; sourceTree = "<group>"; };
- 260F1FB512D620E800D9B07F /* sslcert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslcert.h; sourceTree = "<group>"; };
- 260F1FB612D620E800D9B07F /* textarea.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = textarea.c; sourceTree = "<group>"; };
- 260F1FB712D620E800D9B07F /* textarea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = textarea.h; sourceTree = "<group>"; };
- 260F1FB812D620E800D9B07F /* textinput.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = textinput.c; sourceTree = "<group>"; };
- 260F1FB912D620E800D9B07F /* textinput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = textinput.h; sourceTree = "<group>"; };
- 260F1FBA12D620E800D9B07F /* tree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tree.c; sourceTree = "<group>"; };
- 260F1FBB12D620E800D9B07F /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = "<group>"; };
- 260F1FBC12D620E800D9B07F /* tree_url_node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tree_url_node.c; sourceTree = "<group>"; };
- 260F1FBD12D620E800D9B07F /* tree_url_node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tree_url_node.h; sourceTree = "<group>"; };
- 260F1FBE12D620E800D9B07F /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = "<group>"; };
- 260F1FC712D620E800D9B07F /* box.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = box.c; sourceTree = "<group>"; };
- 260F1FC812D620E800D9B07F /* box.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = box.h; sourceTree = "<group>"; };
- 260F1FC912D620E800D9B07F /* box_construct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = box_construct.c; sourceTree = "<group>"; };
- 260F1FCA12D620E800D9B07F /* box_normalise.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = box_normalise.c; sourceTree = "<group>"; };
- 260F1FCB12D620E800D9B07F /* favicon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = favicon.c; sourceTree = "<group>"; };
- 260F1FCC12D620E800D9B07F /* favicon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = favicon.h; sourceTree = "<group>"; };
- 260F1FCD12D620E800D9B07F /* font.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = font.c; sourceTree = "<group>"; };
- 260F1FCE12D620E800D9B07F /* font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font.h; sourceTree = "<group>"; };
- 260F1FCF12D620E800D9B07F /* form.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = form.c; sourceTree = "<group>"; };
- 260F1FD012D620E800D9B07F /* form.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = form.h; sourceTree = "<group>"; };
- 260F1FD112D620E800D9B07F /* html.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = html.c; sourceTree = "<group>"; };
- 260F1FD212D620E800D9B07F /* html.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = html.h; sourceTree = "<group>"; };
- 260F1FD312D620E800D9B07F /* html_interaction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = html_interaction.c; sourceTree = "<group>"; };
- 260F1FD412D620E800D9B07F /* html_redraw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = html_redraw.c; sourceTree = "<group>"; };
- 260F1FD512D620E800D9B07F /* hubbub_binding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hubbub_binding.c; sourceTree = "<group>"; };
- 260F1FD612D620E800D9B07F /* imagemap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = imagemap.c; sourceTree = "<group>"; };
- 260F1FD712D620E800D9B07F /* imagemap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imagemap.h; sourceTree = "<group>"; };
- 260F1FD812D620E800D9B07F /* layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = layout.c; sourceTree = "<group>"; };
- 260F1FD912D620E800D9B07F /* layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout.h; sourceTree = "<group>"; };
- 260F1FDA12D620E800D9B07F /* list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = list.c; sourceTree = "<group>"; };
- 260F1FDB12D620E800D9B07F /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = "<group>"; };
- 260F1FDC12D620E800D9B07F /* parser_binding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser_binding.h; sourceTree = "<group>"; };
- 260F1FDD12D620E800D9B07F /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = "<group>"; };
- 260F1FDE12D620E800D9B07F /* table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = table.h; sourceTree = "<group>"; };
- 260F1FE012D620E800D9B07F /* textplain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = textplain.c; sourceTree = "<group>"; };
- 260F1FE112D620E800D9B07F /* textplain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = textplain.h; sourceTree = "<group>"; };
- 260F1FE312D620E800D9B07F /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
- 260F1FE412D620E800D9B07F /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = "<group>"; };
- 260F1FE512D620E800D9B07F /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
- 260F1FE612D620E800D9B07F /* container.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = container.c; sourceTree = "<group>"; };
- 260F1FE712D620E800D9B07F /* container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = container.h; sourceTree = "<group>"; };
- 260F1FE812D620E800D9B07F /* errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errors.h; sourceTree = "<group>"; };
- 260F1FE912D620E800D9B07F /* filename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filename.c; sourceTree = "<group>"; };
- 260F1FEA12D620E800D9B07F /* filename.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filename.h; sourceTree = "<group>"; };
- 260F1FEB12D620E800D9B07F /* resource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resource.c; sourceTree = "<group>"; };
- 260F1FEC12D620E800D9B07F /* resource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resource.h; sourceTree = "<group>"; };
- 260F1FED12D620E800D9B07F /* hashtable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hashtable.c; sourceTree = "<group>"; };
- 260F1FEE12D620E800D9B07F /* hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashtable.h; sourceTree = "<group>"; };
- 260F1FEF12D620E800D9B07F /* http.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = http.c; sourceTree = "<group>"; };
- 260F1FF012D620E800D9B07F /* http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http.h; sourceTree = "<group>"; };
- 260F1FF112D620E800D9B07F /* locale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locale.c; sourceTree = "<group>"; };
- 260F1FF212D620E800D9B07F /* locale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locale.h; sourceTree = "<group>"; };
- 260F1FF312D620E800D9B07F /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = "<group>"; };
- 260F1FF412D620E800D9B07F /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
- 260F1FF612D620E800D9B07F /* memdebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memdebug.c; sourceTree = "<group>"; };
- 260F1FF712D620E800D9B07F /* memdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memdebug.h; sourceTree = "<group>"; };
- 260F1FF812D620E800D9B07F /* messages.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = messages.c; sourceTree = "<group>"; };
- 260F1FF912D620E800D9B07F /* messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = messages.h; sourceTree = "<group>"; };
- 260F1FFA12D620E800D9B07F /* ring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ring.h; sourceTree = "<group>"; };
- 260F1FFB12D620E800D9B07F /* talloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = talloc.c; sourceTree = "<group>"; };
- 260F1FFC12D620E800D9B07F /* talloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = talloc.h; sourceTree = "<group>"; };
- 260F1FFF12D620E800D9B07F /* url.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = url.c; sourceTree = "<group>"; };
- 260F200012D620E800D9B07F /* url.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url.h; sourceTree = "<group>"; };
- 260F200112D620E800D9B07F /* useragent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = useragent.c; sourceTree = "<group>"; };
- 260F200212D620E800D9B07F /* useragent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = useragent.h; sourceTree = "<group>"; };
- 260F200312D620E800D9B07F /* utf8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utf8.c; sourceTree = "<group>"; };
- 260F200412D620E800D9B07F /* utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf8.h; sourceTree = "<group>"; };
- 260F200512D620E800D9B07F /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = "<group>"; };
- 260F200612D620E800D9B07F /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
- 260F200712D620E800D9B07F /* utsname.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utsname.h; sourceTree = "<group>"; };
- 260FC03112D85ACE00079C00 /* bitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap.h; sourceTree = "<group>"; };
- 26121DA812D700B800E10F91 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
- 26121EAB12D70E0A00E10F91 /* Browser.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Browser.xib; sourceTree = "<group>"; };
- 26121EFB12D7132100E10F91 /* BrowserView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserView.h; sourceTree = "<group>"; };
- 26121EFC12D7132100E10F91 /* BrowserView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BrowserView.m; sourceTree = "<group>"; };
- 261223B712D77F9C00E10F91 /* font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font.h; sourceTree = "<group>"; };
- 261223CB12D7805300E10F91 /* plotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plotter.h; sourceTree = "<group>"; };
- 2612265712D7ACB500E10F91 /* default.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = default.css; sourceTree = "<group>"; };
- 2612265912D7ACB500E10F91 /* quirks.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = quirks.css; sourceTree = "<group>"; };
- 2612265D12D7AD6800E10F91 /* adblock.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = adblock.css; sourceTree = "<group>"; };
- 2612269012D7AE4100E10F91 /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = de; path = de.lproj/Messages; sourceTree = "<group>"; };
- 2612269312D7AE9B00E10F91 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text; name = nl; path = nl.lproj/Messages; sourceTree = "<group>"; };
- 2612269412D7AEA800E10F91 /* en */ = {isa = PBXFileReference; lastKnownFileType = text; name = en; path = en.lproj/Messages; sourceTree = "<group>"; };
- 2612269512D7AEB500E10F91 /* it */ = {isa = PBXFileReference; lastKnownFileType = text; name = it; path = it.lproj/Messages; sourceTree = "<group>"; };
- 2612269612D7AEBE00E10F91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text; name = fr; path = fr.lproj/Messages; sourceTree = "<group>"; };
- 261DB22213180AFF00C59F12 /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
- 261DB22613180B4F00C59F12 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
- 261DB23313180CD600C59F12 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
- 261DB23413180CE000C59F12 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
- 261DB23513180CEE00C59F12 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
- 261DB24F1318444F00C59F12 /* compile-xib.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "compile-xib.sh"; sourceTree = "<group>"; };
- 261DB2501318444F00C59F12 /* extract-strings.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "extract-strings.sh"; sourceTree = "<group>"; };
- 261DB29013185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/BookmarksWindow.xib.strings; sourceTree = "<group>"; };
- 261DB29413185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/BrowserWindow.xib.strings; sourceTree = "<group>"; };
- 261DB29613185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/DownloadWindow.xib.strings; sourceTree = "<group>"; };
- 261DB29813185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/HistoryWindow.xib.strings; sourceTree = "<group>"; };
- 261DB29C13185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MainMenu.xib.strings; sourceTree = "<group>"; };
- 261DB29E13185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/PreferencesWindow.xib.strings; sourceTree = "<group>"; };
- 261DB2A013185C0A00C59F12 /* de */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SearchWindow.xib.strings; sourceTree = "<group>"; };
- 2622F1D512DCD84600CD5A62 /* TreeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeView.h; sourceTree = "<group>"; };
- 2622F1D612DCD84600CD5A62 /* TreeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TreeView.m; sourceTree = "<group>"; };
- 2625095012F72A8F0090D236 /* PreferencesWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferencesWindow.xib; sourceTree = "<group>"; };
- 2625095112F72AA70090D236 /* PreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindowController.h; sourceTree = "<group>"; };
- 2625095212F72AA70090D236 /* PreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindowController.m; sourceTree = "<group>"; };
- 2636299412F699250048542C /* NetSurf.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; name = NetSurf.app; path = ../NetSurf.app; sourceTree = SOURCE_ROOT; };
- 263629B312F69A290048542C /* Makefile.config */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.config; path = ../Makefile.config; sourceTree = SOURCE_ROOT; };
- 263629B412F69A290048542C /* Makefile.defaults */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.defaults; path = ../Makefile.defaults; sourceTree = SOURCE_ROOT; };
- 263629B512F69A290048542C /* Makefile.resources */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.resources; path = ../Makefile.resources; sourceTree = SOURCE_ROOT; };
- 263629B612F69A290048542C /* Makefile.sources */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.sources; path = ../Makefile.sources; sourceTree = SOURCE_ROOT; };
- 263629B712F69A3C0048542C /* Makefile.target */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.target; sourceTree = "<group>"; };
- 263629BC12F69A760048542C /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../Makefile; sourceTree = SOURCE_ROOT; };
- 263629C812F69B120048542C /* NetsurfApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetsurfApp.h; sourceTree = "<group>"; };
- 263629C912F69B120048542C /* NetsurfApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetsurfApp.m; sourceTree = "<group>"; };
- 263629CA12F69B120048542C /* system_colour.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = system_colour.m; sourceTree = "<group>"; };
- 263769A912F7EBE2000F45FE /* Tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tree.h; sourceTree = "<group>"; };
- 263769AA12F7EBE2000F45FE /* Tree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Tree.m; sourceTree = "<group>"; };
- 26376A4112F7FA67000F45FE /* HistoryWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HistoryWindow.xib; sourceTree = "<group>"; };
- 26376A4312F7FA86000F45FE /* HistoryWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryWindowController.h; sourceTree = "<group>"; };
- 26376A4412F7FA86000F45FE /* HistoryWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryWindowController.m; sourceTree = "<group>"; };
- 26376A8A12F7FF57000F45FE /* BookmarksController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BookmarksController.h; sourceTree = "<group>"; };
- 26376A8B12F7FF57000F45FE /* BookmarksController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BookmarksController.m; sourceTree = "<group>"; };
- 26376BAC12F820D7000F45FE /* BookmarksWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BookmarksWindow.xib; sourceTree = "<group>"; };
- 2639E20512F2ADEE00699678 /* coordinates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coordinates.h; sourceTree = "<group>"; };
- 264C344112F0987E00D11246 /* gui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gui.h; sourceTree = "<group>"; };
- 265F30A712D6637E0048B600 /* NetSurf-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "NetSurf-Info.plist"; sourceTree = "<group>"; };
- 265F30AB12D6637E0048B600 /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
- 265F311912D663F50048B600 /* gui.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = gui.m; sourceTree = "<group>"; };
- 265F314712D666660048B600 /* plotter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = plotter.m; sourceTree = "<group>"; };
- 265F316112D667E10048B600 /* schedule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = schedule.m; sourceTree = "<group>"; };
- 265F316612D668130048B600 /* thumbnail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = thumbnail.m; sourceTree = "<group>"; };
- 265F316F12D668790048B600 /* fetch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fetch.m; sourceTree = "<group>"; };
- 265F319012D668DB0048B600 /* url.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = url.m; sourceTree = "<group>"; };
- 265F31C412D66A0D0048B600 /* save.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = save.m; sourceTree = "<group>"; };
- 265F31CA12D66A890048B600 /* bitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap.h; sourceTree = "<group>"; };
- 265F31CB12D66A890048B600 /* bmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bmp.c; sourceTree = "<group>"; };
- 265F31CC12D66A890048B600 /* bmp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bmp.h; sourceTree = "<group>"; };
- 265F31CD12D66A890048B600 /* gif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gif.c; sourceTree = "<group>"; };
- 265F31CE12D66A890048B600 /* gif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gif.h; sourceTree = "<group>"; };
- 265F31CF12D66A890048B600 /* ico.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ico.c; sourceTree = "<group>"; };
- 265F31D012D66A890048B600 /* ico.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ico.h; sourceTree = "<group>"; };
- 265F31D112D66A890048B600 /* jpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jpeg.c; sourceTree = "<group>"; };
- 265F31D212D66A890048B600 /* jpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jpeg.h; sourceTree = "<group>"; };
- 265F31D312D66A890048B600 /* mng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mng.c; sourceTree = "<group>"; };
- 265F31D412D66A890048B600 /* mng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mng.h; sourceTree = "<group>"; };
- 265F31D512D66A890048B600 /* nssprite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nssprite.c; sourceTree = "<group>"; };
- 265F31D612D66A890048B600 /* nssprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nssprite.h; sourceTree = "<group>"; };
- 265F31D712D66A890048B600 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = png.c; sourceTree = "<group>"; };
- 265F31D812D66A890048B600 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = png.h; sourceTree = "<group>"; };
- 265F31D912D66A890048B600 /* rsvg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rsvg.c; sourceTree = "<group>"; };
- 265F31DA12D66A890048B600 /* rsvg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsvg.h; sourceTree = "<group>"; };
- 265F31DB12D66A890048B600 /* svg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svg.c; sourceTree = "<group>"; };
- 265F31DC12D66A890048B600 /* svg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svg.h; sourceTree = "<group>"; };
- 265F31DD12D66A890048B600 /* webp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = webp.c; sourceTree = "<group>"; };
- 265F31DE12D66A890048B600 /* webp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = webp.h; sourceTree = "<group>"; };
- 265F31EB12D66B190048B600 /* bitmap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bitmap.m; sourceTree = "<group>"; };
- 265F320512D66C200048B600 /* utf8.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utf8.m; sourceTree = "<group>"; };
- 265F321312D66CD90048B600 /* utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utils.m; sourceTree = "<group>"; };
- 265F321E12D66D510048B600 /* font.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = font.m; sourceTree = "<group>"; };
- 2666DC5B12F6D1770045E8B6 /* SearchWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchWindow.xib; sourceTree = "<group>"; };
- 2666DC5D12F6D2E70045E8B6 /* SearchWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchWindowController.h; sourceTree = "<group>"; };
- 2666DC5E12F6D2E70045E8B6 /* SearchWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchWindowController.m; sourceTree = "<group>"; };
- 2666DD5012F706BC0045E8B6 /* BrowserWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserWindow.h; sourceTree = "<group>"; };
- 2666DD5112F706BC0045E8B6 /* BrowserWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BrowserWindow.m; sourceTree = "<group>"; };
- 2684028E1301848100850DA2 /* HomeTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = HomeTemplate.pdf; sourceTree = "<group>"; };
- 26ABD61C12F02EB900407161 /* overflowImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = overflowImage.png; sourceTree = "<group>"; };
- 26ABD61D12F02EB900407161 /* overflowImagePressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = overflowImagePressed.png; sourceTree = "<group>"; };
- 26ABD61E12F02EB900407161 /* pi.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pi.png; sourceTree = "<group>"; };
- 26AFE63E12DDEB0A005AD082 /* NetSurf.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = NetSurf.icns; sourceTree = "<group>"; };
- 26AFE8E212DF4200005AD082 /* ScrollableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollableView.h; sourceTree = "<group>"; };
- 26AFE8E312DF4200005AD082 /* ScrollableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScrollableView.m; sourceTree = "<group>"; };
- 26AFE97A12DF514C005AD082 /* NetSurfAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetSurfAppDelegate.h; sourceTree = "<group>"; };
- 26AFE97B12DF514C005AD082 /* NetSurfAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetSurfAppDelegate.m; sourceTree = "<group>"; };
- 26AFEAE912E04253005AD082 /* DownloadWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DownloadWindowController.h; sourceTree = "<group>"; };
- 26AFEAEA12E04253005AD082 /* DownloadWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DownloadWindowController.m; sourceTree = "<group>"; };
- 26AFEAF012E042F9005AD082 /* DownloadWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DownloadWindow.xib; sourceTree = "<group>"; };
- 26AFED0312E09916005AD082 /* selection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = selection.m; sourceTree = "<group>"; };
- 26B4E91A130D351F0003B527 /* ArrowBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrowBox.h; sourceTree = "<group>"; };
- 26B4E91B130D351F0003B527 /* ArrowBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArrowBox.m; sourceTree = "<group>"; };
- 26B4E91C130D351F0003B527 /* ArrowWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrowWindow.h; sourceTree = "<group>"; };
- 26B4E91D130D351F0003B527 /* ArrowWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArrowWindow.m; sourceTree = "<group>"; };
- 26B4E91E130D351F0003B527 /* BlackScroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlackScroller.h; sourceTree = "<group>"; };
- 26B4E91F130D351F0003B527 /* BlackScroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlackScroller.m; sourceTree = "<group>"; };
- 26B4E926130D36A90003B527 /* LocalHistoryPanel.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LocalHistoryPanel.xib; sourceTree = "<group>"; };
- 26B4E928130D37E50003B527 /* LocalHistoryController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalHistoryController.h; sourceTree = "<group>"; };
- 26B4E929130D37E50003B527 /* LocalHistoryController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalHistoryController.m; sourceTree = "<group>"; };
- 26BA25AB1321653200AEC1DA /* apple_image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = apple_image.m; sourceTree = "<group>"; };
- 26BA25AC1321653200AEC1DA /* apple_image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apple_image.h; sourceTree = "<group>"; };
- 26CDCEB312E702D8004FC66B /* NSBezierPath_AMShading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBezierPath_AMShading.h; sourceTree = "<group>"; };
- 26CDCEB412E702D8004FC66B /* NSBezierPath_AMShading.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBezierPath_AMShading.m; sourceTree = "<group>"; };
- 26CDCEB512E702D8004FC66B /* NSString_AITruncation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSString_AITruncation.h; sourceTree = "<group>"; };
- 26CDCEB612E702D8004FC66B /* NSString_AITruncation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSString_AITruncation.m; sourceTree = "<group>"; };
- 26CDCEBD12E702D8004FC66B /* PSMOverflowPopUpButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMOverflowPopUpButton.h; sourceTree = "<group>"; };
- 26CDCEBE12E702D8004FC66B /* PSMOverflowPopUpButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMOverflowPopUpButton.m; sourceTree = "<group>"; };
- 26CDCEBF12E702D8004FC66B /* PSMProgressIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMProgressIndicator.h; sourceTree = "<group>"; };
- 26CDCEC012E702D8004FC66B /* PSMProgressIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMProgressIndicator.m; sourceTree = "<group>"; };
- 26CDCEC112E702D8004FC66B /* PSMRolloverButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMRolloverButton.h; sourceTree = "<group>"; };
- 26CDCEC212E702D8004FC66B /* PSMRolloverButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMRolloverButton.m; sourceTree = "<group>"; };
- 26CDCEC312E702D8004FC66B /* PSMTabBarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabBarCell.h; sourceTree = "<group>"; };
- 26CDCEC412E702D8004FC66B /* PSMTabBarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabBarCell.m; sourceTree = "<group>"; };
- 26CDCEC512E702D8004FC66B /* PSMTabBarControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabBarControl.h; sourceTree = "<group>"; };
- 26CDCEC612E702D8004FC66B /* PSMTabBarControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabBarControl.m; sourceTree = "<group>"; };
- 26CDCEC712E702D8004FC66B /* PSMTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabBarController.h; sourceTree = "<group>"; };
- 26CDCEC812E702D8004FC66B /* PSMTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabBarController.m; sourceTree = "<group>"; };
- 26CDCEC912E702D8004FC66B /* PSMTabDragAssistant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabDragAssistant.h; sourceTree = "<group>"; };
- 26CDCECA12E702D8004FC66B /* PSMTabDragAssistant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabDragAssistant.m; sourceTree = "<group>"; };
- 26CDCECB12E702D8004FC66B /* PSMTabDragView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabDragView.h; sourceTree = "<group>"; };
- 26CDCECC12E702D8004FC66B /* PSMTabDragView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabDragView.m; sourceTree = "<group>"; };
- 26CDCECD12E702D8004FC66B /* PSMTabDragWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabDragWindow.h; sourceTree = "<group>"; };
- 26CDCECE12E702D8004FC66B /* PSMTabDragWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabDragWindow.m; sourceTree = "<group>"; };
- 26CDCECF12E702D8004FC66B /* PSMTabDragWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabDragWindowController.h; sourceTree = "<group>"; };
- 26CDCED012E702D8004FC66B /* PSMTabDragWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMTabDragWindowController.m; sourceTree = "<group>"; };
- 26CDCED112E702D8004FC66B /* PSMTabStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMTabStyle.h; sourceTree = "<group>"; };
- 26CDCED212E702D8004FC66B /* PSMUnifiedTabStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSMUnifiedTabStyle.h; sourceTree = "<group>"; };
- 26CDCED312E702D8004FC66B /* PSMUnifiedTabStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSMUnifiedTabStyle.m; sourceTree = "<group>"; };
- 26CDCFDC12E706FE004FC66B /* AquaTabClose_Front.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabClose_Front.png; sourceTree = "<group>"; };
- 26CDCFDD12E706FF004FC66B /* AquaTabClose_Front_Pressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabClose_Front_Pressed.png; sourceTree = "<group>"; };
- 26CDCFDE12E706FF004FC66B /* AquaTabClose_Front_Rollover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabClose_Front_Rollover.png; sourceTree = "<group>"; };
- 26CDCFDF12E706FF004FC66B /* AquaTabCloseDirty_Front.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabCloseDirty_Front.png; sourceTree = "<group>"; };
- 26CDCFE012E706FF004FC66B /* AquaTabCloseDirty_Front_Pressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabCloseDirty_Front_Pressed.png; sourceTree = "<group>"; };
- 26CDCFE112E706FF004FC66B /* AquaTabCloseDirty_Front_Rollover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabCloseDirty_Front_Rollover.png; sourceTree = "<group>"; };
- 26CDCFE212E706FF004FC66B /* AquaTabNew.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabNew.png; sourceTree = "<group>"; };
- 26CDCFE312E706FF004FC66B /* AquaTabNewPressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabNewPressed.png; sourceTree = "<group>"; };
- 26CDCFE412E706FF004FC66B /* AquaTabNewRollover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AquaTabNewRollover.png; sourceTree = "<group>"; };
- 26CDCFF212E70AD1004FC66B /* BrowserWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BrowserWindow.xib; sourceTree = "<group>"; };
- 26CDD00112E70F56004FC66B /* BrowserWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserWindowController.h; sourceTree = "<group>"; };
- 26CDD00212E70F56004FC66B /* BrowserWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BrowserWindowController.m; sourceTree = "<group>"; };
- 26CDD0F412E726E0004FC66B /* BrowserViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserViewController.h; sourceTree = "<group>"; };
- 26CDD0F512E726E0004FC66B /* BrowserViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BrowserViewController.m; sourceTree = "<group>"; };
- 26E7A22B131FEBA8005B5B6A /* about.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = about.c; sourceTree = "<group>"; };
- 26E7A22C131FEBA8005B5B6A /* about.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = about.h; sourceTree = "<group>"; };
- 26E7A22D131FEBA8005B5B6A /* resource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resource.c; sourceTree = "<group>"; };
- 26E7A22E131FEBA8005B5B6A /* resource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resource.h; sourceTree = "<group>"; };
- 26EC3B6812ED62C0000A960C /* URLFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URLFieldCell.h; sourceTree = "<group>"; };
- 26EC3B6912ED62C0000A960C /* URLFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URLFieldCell.m; sourceTree = "<group>"; };
- 26EC3C4212ED8202000A960C /* HistoryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryView.h; sourceTree = "<group>"; };
- 26EC3C4312ED8202000A960C /* HistoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryView.m; sourceTree = "<group>"; };
- 26EC3F1612EF0CBD000A960C /* FormSelectMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormSelectMenu.h; sourceTree = "<group>"; };
- 26EC3F1712EF0CBD000A960C /* FormSelectMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FormSelectMenu.m; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXGroup section */
- 19C28FACFE9D520D11CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 2636299412F699250048542C /* NetSurf.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 260F1F6212D620E800D9B07F /* content */ = {
- isa = PBXGroup;
- children = (
- 260F1F6312D620E800D9B07F /* content.c */,
- 260F1F6412D620E800D9B07F /* content.h */,
- 260F1F6512D620E800D9B07F /* content_protected.h */,
- 260F1F6612D620E800D9B07F /* content_type.h */,
- 260F1F6712D620E800D9B07F /* dirlist.c */,
- 260F1F6812D620E800D9B07F /* dirlist.h */,
- 260F1F6912D620E800D9B07F /* fetch.c */,
- 260F1F6A12D620E800D9B07F /* fetch.h */,
- 260F1F6B12D620E800D9B07F /* fetchers */,
- 260F1F7212D620E800D9B07F /* hlcache.c */,
- 260F1F7312D620E800D9B07F /* hlcache.h */,
- 260F1F7412D620E800D9B07F /* llcache.c */,
- 260F1F7512D620E800D9B07F /* llcache.h */,
- 260F1F7612D620E800D9B07F /* urldb.c */,
- 260F1F7712D620E800D9B07F /* urldb.h */,
- );
- name = content;
- path = ../content;
- sourceTree = SOURCE_ROOT;
- };
- 260F1F6B12D620E800D9B07F /* fetchers */ = {
- isa = PBXGroup;
- children = (
- 26E7A22B131FEBA8005B5B6A /* about.c */,
- 26E7A22C131FEBA8005B5B6A /* about.h */,
- 26E7A22D131FEBA8005B5B6A /* resource.c */,
- 26E7A22E131FEBA8005B5B6A /* resource.h */,
- 260F1F6C12D620E800D9B07F /* curl.c */,
- 260F1F6D12D620E800D9B07F /* curl.h */,
- 260F1F6E12D620E800D9B07F /* data.c */,
- 260F1F6F12D620E800D9B07F /* data.h */,
- 260F1F7012D620E800D9B07F /* file.c */,
- 260F1F7112D620E800D9B07F /* file.h */,
- );
- path = fetchers;
- sourceTree = "<group>";
- };
- 260F1F7812D620E800D9B07F /* css */ = {
- isa = PBXGroup;
- children = (
- 260F1F7912D620E800D9B07F /* css.c */,
- 260F1F7A12D620E800D9B07F /* css.h */,
- 260F1F7B12D620E800D9B07F /* dump.c */,
- 260F1F7C12D620E800D9B07F /* dump.h */,
- 260F1F7D12D620E800D9B07F /* internal.c */,
- 260F1F7E12D620E800D9B07F /* internal.h */,
- 260F1F7F12D620E800D9B07F /* select.c */,
- 260F1F8012D620E800D9B07F /* select.h */,
- 260F1F8112D620E800D9B07F /* utils.c */,
- 260F1F8212D620E800D9B07F /* utils.h */,
- );
- name = css;
- path = ../css;
- sourceTree = SOURCE_ROOT;
- };
- 260F1F8312D620E800D9B07F /* desktop */ = {
- isa = PBXGroup;
- children = (
- 260F1F8412D620E800D9B07F /* 401login.h */,
- 260F1F8512D620E800D9B07F /* browser.c */,
- 260F1F8612D620E800D9B07F /* browser.h */,
- 260F1F8712D620E800D9B07F /* cookies.c */,
- 260F1F8812D620E800D9B07F /* cookies_old.h */,
- 260F1F8912D620E800D9B07F /* download.c */,
- 260F1F8A12D620E800D9B07F /* download.h */,
- 260F1F8B12D620E800D9B07F /* frames.c */,
- 260F1F8C12D620E800D9B07F /* frames.h */,
- 260F1F8D12D620E800D9B07F /* gui.h */,
- 260F1F8E12D620E800D9B07F /* local_history.c */,
- 260F1F8F12D620E800D9B07F /* local_history.h */,
- 260F1F9012D620E800D9B07F /* history_global_core.c */,
- 260F1F9112D620E800D9B07F /* history_global_core.h */,
- 260F1F9212D620E800D9B07F /* hotlist.c */,
- 260F1F9312D620E800D9B07F /* hotlist.h */,
- 260F1F9412D620E800D9B07F /* knockout.c */,
- 260F1F9512D620E800D9B07F /* knockout.h */,
- 260F1F9612D620E800D9B07F /* mouse.c */,
- 260F1F9712D620E800D9B07F /* mouse.h */,
- 260F1F9812D620E800D9B07F /* netsurf.c */,
- 260F1F9912D620E800D9B07F /* netsurf.h */,
- 260F1F9A12D620E800D9B07F /* options.c */,
- 260F1F9B12D620E800D9B07F /* options.h */,
- 260F1F9C12D620E800D9B07F /* plot_style.c */,
- 260F1F9D12D620E800D9B07F /* plot_style.h */,
- 260F1F9E12D620E800D9B07F /* plotters.h */,
- 260F1F9F12D620E800D9B07F /* print.c */,
- 260F1FA012D620E800D9B07F /* print.h */,
- 260F1FA112D620E800D9B07F /* printer.h */,
- 260F1FA212D620E800D9B07F /* save_complete.c */,
- 260F1FA312D620E800D9B07F /* save_complete.h */,
- 260F1FA412D620E800D9B07F /* save_pdf */,
- 260F1FAA12D620E800D9B07F /* save_text.c */,
- 260F1FAB12D620E800D9B07F /* save_text.h */,
- 260F1FAC12D620E800D9B07F /* scroll.c */,
- 260F1FAD12D620E800D9B07F /* scroll.h */,
- 260F1FAE12D620E800D9B07F /* search.c */,
- 260F1FAF12D620E800D9B07F /* search.h */,
- 260F1FB012D620E800D9B07F /* searchweb.c */,
- 260F1FB112D620E800D9B07F /* searchweb.h */,
- 260F1FB212D620E800D9B07F /* selection.c */,
- 260F1FB312D620E800D9B07F /* selection.h */,
- 260F1FB412D620E800D9B07F /* sslcert.c */,
- 260F1FB512D620E800D9B07F /* sslcert.h */,
- 260F1FB612D620E800D9B07F /* textarea.c */,
- 260F1FB712D620E800D9B07F /* textarea.h */,
- 260F1FB812D620E800D9B07F /* textinput.c */,
- 260F1FB912D620E800D9B07F /* textinput.h */,
- 260F1FBA12D620E800D9B07F /* tree.c */,
- 260F1FBB12D620E800D9B07F /* tree.h */,
- 260F1FBC12D620E800D9B07F /* tree_url_node.c */,
- 260F1FBD12D620E800D9B07F /* tree_url_node.h */,
- 260F1FBE12D620E800D9B07F /* version.c */,
- );
- name = desktop;
- path = ../desktop;
- sourceTree = SOURCE_ROOT;
- };
- 260F1FA412D620E800D9B07F /* save_pdf */ = {
- isa = PBXGroup;
- children = (
- 260F1FA512D620E800D9B07F /* font_haru.c */,
- 260F1FA612D620E800D9B07F /* font_haru.h */,
- 260F1FA712D620E800D9B07F /* pdf_plotters.c */,
- 260F1FA812D620E800D9B07F /* pdf_plotters.h */,
- );
- path = save_pdf;
- sourceTree = "<group>";
- };
- 260F1FC612D620E800D9B07F /* render */ = {
- isa = PBXGroup;
- children = (
- 260F1FC712D620E800D9B07F /* box.c */,
- 260F1FC812D620E800D9B07F /* box.h */,
- 260F1FC912D620E800D9B07F /* box_construct.c */,
- 260F1FCA12D620E800D9B07F /* box_normalise.c */,
- 260F1FCB12D620E800D9B07F /* favicon.c */,
- 260F1FCC12D620E800D9B07F /* favicon.h */,
- 260F1FCD12D620E800D9B07F /* font.c */,
- 260F1FCE12D620E800D9B07F /* font.h */,
- 260F1FCF12D620E800D9B07F /* form.c */,
- 260F1FD012D620E800D9B07F /* form.h */,
- 260F1FD112D620E800D9B07F /* html.c */,
- 260F1FD212D620E800D9B07F /* html.h */,
- 260F1FD312D620E800D9B07F /* html_interaction.c */,
- 260F1FD412D620E800D9B07F /* html_redraw.c */,
- 260F1FD512D620E800D9B07F /* hubbub_binding.c */,
- 260F1FD612D620E800D9B07F /* imagemap.c */,
- 260F1FD712D620E800D9B07F /* imagemap.h */,
- 260F1FD812D620E800D9B07F /* layout.c */,
- 260F1FD912D620E800D9B07F /* layout.h */,
- 260F1FDA12D620E800D9B07F /* list.c */,
- 260F1FDB12D620E800D9B07F /* list.h */,
- 260F1FDC12D620E800D9B07F /* parser_binding.h */,
- 260F1FDD12D620E800D9B07F /* table.c */,
- 260F1FDE12D620E800D9B07F /* table.h */,
- 260F1FE012D620E800D9B07F /* textplain.c */,
- 260F1FE112D620E800D9B07F /* textplain.h */,
- );
- name = render;
- path = ../render;
- sourceTree = SOURCE_ROOT;
- };
- 260F1FE212D620E800D9B07F /* utils */ = {
- isa = PBXGroup;
- children = (
- 260F1FE312D620E800D9B07F /* base64.c */,
- 260F1FE412D620E800D9B07F /* base64.h */,
- 260F1FE512D620E800D9B07F /* config.h */,
- 260F1FE612D620E800D9B07F /* container.c */,
- 260F1FE712D620E800D9B07F /* container.h */,
- 260F1FE812D620E800D9B07F /* errors.h */,
- 260F1FE912D620E800D9B07F /* filename.c */,
- 260F1FEA12D620E800D9B07F /* filename.h */,
- 260F1FEB12D620E800D9B07F /* resource.c */,
- 260F1FEC12D620E800D9B07F /* resource.h */,
- 260F1FED12D620E800D9B07F /* hashtable.c */,
- 260F1FEE12D620E800D9B07F /* hashtable.h */,
- 260F1FEF12D620E800D9B07F /* http.c */,
- 260F1FF012D620E800D9B07F /* http.h */,
- 260F1FF112D620E800D9B07F /* locale.c */,
- 260F1FF212D620E800D9B07F /* locale.h */,
- 260F1FF312D620E800D9B07F /* log.c */,
- 260F1FF412D620E800D9B07F /* log.h */,
- 260F1FF612D620E800D9B07F /* memdebug.c */,
- 260F1FF712D620E800D9B07F /* memdebug.h */,
- 260F1FF812D620E800D9B07F /* messages.c */,
- 260F1FF912D620E800D9B07F /* messages.h */,
- 260F1FFA12D620E800D9B07F /* ring.h */,
- 260F1FFB12D620E800D9B07F /* talloc.c */,
- 260F1FFC12D620E800D9B07F /* talloc.h */,
- 260F1FFF12D620E800D9B07F /* url.c */,
- 260F200012D620E800D9B07F /* url.h */,
- 260F200112D620E800D9B07F /* useragent.c */,
- 260F200212D620E800D9B07F /* useragent.h */,
- 260F200312D620E800D9B07F /* utf8.c */,
- 260F200412D620E800D9B07F /* utf8.h */,
- 260F200512D620E800D9B07F /* utils.c */,
- 260F200612D620E800D9B07F /* utils.h */,
- 260F200712D620E800D9B07F /* utsname.h */,
- );
- name = utils;
- path = ../utils;
- sourceTree = SOURCE_ROOT;
- };
- 261DB24E1318443500C59F12 /* Tools */ = {
- isa = PBXGroup;
- children = (
- 261DB24F1318444F00C59F12 /* compile-xib.sh */,
- 261DB2501318444F00C59F12 /* extract-strings.sh */,
- );
- name = Tools;
- sourceTree = "<group>";
- };
- 263629B212F69A080048542C /* Makefiles */ = {
- isa = PBXGroup;
- children = (
- 263629BC12F69A760048542C /* Makefile */,
- 263629B712F69A3C0048542C /* Makefile.target */,
- 263629B312F69A290048542C /* Makefile.config */,
- 263629B412F69A290048542C /* Makefile.defaults */,
- 263629B512F69A290048542C /* Makefile.resources */,
- 263629B612F69A290048542C /* Makefile.sources */,
- );
- name = Makefiles;
- sourceTree = "<group>";
- };
- 263769A812F7EBC3000F45FE /* Tree View */ = {
- isa = PBXGroup;
- children = (
- 2622F1D512DCD84600CD5A62 /* TreeView.h */,
- 2622F1D612DCD84600CD5A62 /* TreeView.m */,
- 263769A912F7EBE2000F45FE /* Tree.h */,
- 263769AA12F7EBE2000F45FE /* Tree.m */,
- );
- name = "Tree View";
- sourceTree = "<group>";
- };
- 26376A8C12F7FF5A000F45FE /* Bookmarks */ = {
- isa = PBXGroup;
- children = (
- 26376A8A12F7FF57000F45FE /* BookmarksController.h */,
- 26376A8B12F7FF57000F45FE /* BookmarksController.m */,
- );
- name = Bookmarks;
- sourceTree = "<group>";
- };
- 265F303F12D6637E0048B600 /* Cocoa Frontend */ = {
- isa = PBXGroup;
- children = (
- 26BA25AB1321653200AEC1DA /* apple_image.m */,
- 26BA25AC1321653200AEC1DA /* apple_image.h */,
- 26CDD26512E74402004FC66B /* Browser */,
- 26CDD26712E74453004FC66B /* Download */,
- 26CDD26612E7441E004FC66B /* Views */,
- 263769A812F7EBC3000F45FE /* Tree View */,
- 26376A8C12F7FF5A000F45FE /* Bookmarks */,
- 26CDD26812E74461004FC66B /* NSApplication */,
- 26CDD26912E7446E004FC66B /* Platform Interface */,
- 265F310F12D663C20048B600 /* Resources */,
- 26CDCEB212E702D8004FC66B /* PSMTabBarControl */,
- 265F30AB12D6637E0048B600 /* Prefix.pch */,
- 2625095112F72AA70090D236 /* PreferencesWindowController.h */,
- 2625095212F72AA70090D236 /* PreferencesWindowController.m */,
- 26376A4312F7FA86000F45FE /* HistoryWindowController.h */,
- 26376A4412F7FA86000F45FE /* HistoryWindowController.m */,
- );
- name = "Cocoa Frontend";
- sourceTree = "<group>";
- };
- 265F310F12D663C20048B600 /* Resources */ = {
- isa = PBXGroup;
- children = (
- 261DB28F13185C0A00C59F12 /* BookmarksWindow.xib.strings */,
- 261DB29313185C0A00C59F12 /* BrowserWindow.xib.strings */,
- 261DB29513185C0A00C59F12 /* DownloadWindow.xib.strings */,
- 261DB29713185C0A00C59F12 /* HistoryWindow.xib.strings */,
- 261DB29B13185C0A00C59F12 /* MainMenu.xib.strings */,
- 261DB29D13185C0A00C59F12 /* PreferencesWindow.xib.strings */,
- 261DB29F13185C0A00C59F12 /* SearchWindow.xib.strings */,
- 261DB22113180AFF00C59F12 /* Localizable.strings */,
- 2684028E1301848100850DA2 /* HomeTemplate.pdf */,
- 26AFE63E12DDEB0A005AD082 /* NetSurf.icns */,
- 2612268F12D7AE4100E10F91 /* Messages */,
- 2612265D12D7AD6800E10F91 /* adblock.css */,
- 2612265712D7ACB500E10F91 /* default.css */,
- 2612265912D7ACB500E10F91 /* quirks.css */,
- 265F30A712D6637E0048B600 /* NetSurf-Info.plist */,
- 26121DA812D700B800E10F91 /* MainMenu.xib */,
- 26121EAB12D70E0A00E10F91 /* Browser.xib */,
- 26AFEAF012E042F9005AD082 /* DownloadWindow.xib */,
- 26CDCFF212E70AD1004FC66B /* BrowserWindow.xib */,
- 2666DC5B12F6D1770045E8B6 /* SearchWindow.xib */,
- 2625095012F72A8F0090D236 /* PreferencesWindow.xib */,
- 26376A4112F7FA67000F45FE /* HistoryWindow.xib */,
- 26376BAC12F820D7000F45FE /* BookmarksWindow.xib */,
- 26B4E926130D36A90003B527 /* LocalHistoryPanel.xib */,
- );
- name = Resources;
- path = res;
- sourceTree = "<group>";
- };
- 265F31C912D66A890048B600 /* image */ = {
- isa = PBXGroup;
- children = (
- 265F31CA12D66A890048B600 /* bitmap.h */,
- 265F31CB12D66A890048B600 /* bmp.c */,
- 265F31CC12D66A890048B600 /* bmp.h */,
- 265F31CD12D66A890048B600 /* gif.c */,
- 265F31CE12D66A890048B600 /* gif.h */,
- 265F31CF12D66A890048B600 /* ico.c */,
- 265F31D012D66A890048B600 /* ico.h */,
- 265F31D112D66A890048B600 /* jpeg.c */,
- 265F31D212D66A890048B600 /* jpeg.h */,
- 265F31D312D66A890048B600 /* mng.c */,
- 265F31D412D66A890048B600 /* mng.h */,
- 265F31D512D66A890048B600 /* nssprite.c */,
- 265F31D612D66A890048B600 /* nssprite.h */,
- 265F31D712D66A890048B600 /* png.c */,
- 265F31D812D66A890048B600 /* png.h */,
- 265F31D912D66A890048B600 /* rsvg.c */,
- 265F31DA12D66A890048B600 /* rsvg.h */,
- 265F31DB12D66A890048B600 /* svg.c */,
- 265F31DC12D66A890048B600 /* svg.h */,
- 265F31DD12D66A890048B600 /* webp.c */,
- 265F31DE12D66A890048B600 /* webp.h */,
- );
- name = image;
- path = ../image;
- sourceTree = SOURCE_ROOT;
- };
- 26CDCEB212E702D8004FC66B /* PSMTabBarControl */ = {
- isa = PBXGroup;
- children = (
- 26CDCFDB12E706FE004FC66B /* Images */,
- 26CDCEB312E702D8004FC66B /* NSBezierPath_AMShading.h */,
- 26CDCEB412E702D8004FC66B /* NSBezierPath_AMShading.m */,
- 26CDCEB512E702D8004FC66B /* NSString_AITruncation.h */,
- 26CDCEB612E702D8004FC66B /* NSString_AITruncation.m */,
- 26CDCEBD12E702D8004FC66B /* PSMOverflowPopUpButton.h */,
- 26CDCEBE12E702D8004FC66B /* PSMOverflowPopUpButton.m */,
- 26CDCEBF12E702D8004FC66B /* PSMProgressIndicator.h */,
- 26CDCEC012E702D8004FC66B /* PSMProgressIndicator.m */,
- 26CDCEC112E702D8004FC66B /* PSMRolloverButton.h */,
- 26CDCEC212E702D8004FC66B /* PSMRolloverButton.m */,
- 26CDCEC312E702D8004FC66B /* PSMTabBarCell.h */,
- 26CDCEC412E702D8004FC66B /* PSMTabBarCell.m */,
- 26CDCEC512E702D8004FC66B /* PSMTabBarControl.h */,
- 26CDCEC612E702D8004FC66B /* PSMTabBarControl.m */,
- 26CDCEC712E702D8004FC66B /* PSMTabBarController.h */,
- 26CDCEC812E702D8004FC66B /* PSMTabBarController.m */,
- 26CDCEC912E702D8004FC66B /* PSMTabDragAssistant.h */,
- 26CDCECA12E702D8004FC66B /* PSMTabDragAssistant.m */,
- 26CDCECB12E702D8004FC66B /* PSMTabDragView.h */,
- 26CDCECC12E702D8004FC66B /* PSMTabDragView.m */,
- 26CDCECD12E702D8004FC66B /* PSMTabDragWindow.h */,
- 26CDCECE12E702D8004FC66B /* PSMTabDragWindow.m */,
- 26CDCECF12E702D8004FC66B /* PSMTabDragWindowController.h */,
- 26CDCED012E702D8004FC66B /* PSMTabDragWindowController.m */,
- 26CDCED112E702D8004FC66B /* PSMTabStyle.h */,
- 26CDCED212E702D8004FC66B /* PSMUnifiedTabStyle.h */,
- 26CDCED312E702D8004FC66B /* PSMUnifiedTabStyle.m */,
- );
- path = PSMTabBarControl;
- sourceTree = "<group>";
- };
- 26CDCFDB12E706FE004FC66B /* Images */ = {
- isa = PBXGroup;
- children = (
- 26ABD61C12F02EB900407161 /* overflowImage.png */,
- 26ABD61D12F02EB900407161 /* overflowImagePressed.png */,
- 26ABD61E12F02EB900407161 /* pi.png */,
- 26CDCFDC12E706FE004FC66B /* AquaTabClose_Front.png */,
- 26CDCFDD12E706FF004FC66B /* AquaTabClose_Front_Pressed.png */,
- 26CDCFDE12E706FF004FC66B /* AquaTabClose_Front_Rollover.png */,
- 26CDCFDF12E706FF004FC66B /* AquaTabCloseDirty_Front.png */,
- 26CDCFE012E706FF004FC66B /* AquaTabCloseDirty_Front_Pressed.png */,
- 26CDCFE112E706FF004FC66B /* AquaTabCloseDirty_Front_Rollover.png */,
- 26CDCFE212E706FF004FC66B /* AquaTabNew.png */,
- 26CDCFE312E706FF004FC66B /* AquaTabNewPressed.png */,
- 26CDCFE412E706FF004FC66B /* AquaTabNewRollover.png */,
- );
- path = Images;
- sourceTree = "<group>";
- };
- 26CDD23E12E743A3004FC66B /* NetSurf */ = {
- isa = PBXGroup;
- children = (
- 260F1F6212D620E800D9B07F /* content */,
- 260F1F7812D620E800D9B07F /* css */,
- 260F1F8312D620E800D9B07F /* desktop */,
- 260F1FC612D620E800D9B07F /* render */,
- 265F31C912D66A890048B600 /* image */,
- 260F1FE212D620E800D9B07F /* utils */,
- );
- name = NetSurf;
- sourceTree = "<group>";
- };
- 26CDD26512E74402004FC66B /* Browser */ = {
- isa = PBXGroup;
- children = (
- 26121EFB12D7132100E10F91 /* BrowserView.h */,
- 26121EFC12D7132100E10F91 /* BrowserView.m */,
- 26CDD00112E70F56004FC66B /* BrowserWindowController.h */,
- 26CDD00212E70F56004FC66B /* BrowserWindowController.m */,
- 26CDD0F412E726E0004FC66B /* BrowserViewController.h */,
- 26CDD0F512E726E0004FC66B /* BrowserViewController.m */,
- 2666DC5D12F6D2E70045E8B6 /* SearchWindowController.h */,
- 2666DC5E12F6D2E70045E8B6 /* SearchWindowController.m */,
- 2666DD5012F706BC0045E8B6 /* BrowserWindow.h */,
- 2666DD5112F706BC0045E8B6 /* BrowserWindow.m */,
- 26B4E928130D37E50003B527 /* LocalHistoryController.h */,
- 26B4E929130D37E50003B527 /* LocalHistoryController.m */,
- );
- name = Browser;
- sourceTree = "<group>";
- };
- 26CDD26612E7441E004FC66B /* Views */ = {
- isa = PBXGroup;
- children = (
- 26B4E91A130D351F0003B527 /* ArrowBox.h */,
- 26B4E91B130D351F0003B527 /* ArrowBox.m */,
- 26B4E91C130D351F0003B527 /* ArrowWindow.h */,
- 26B4E91D130D351F0003B527 /* ArrowWindow.m */,
- 26B4E91E130D351F0003B527 /* BlackScroller.h */,
- 26B4E91F130D351F0003B527 /* BlackScroller.m */,
- 26AFE8E212DF4200005AD082 /* ScrollableView.h */,
- 26AFE8E312DF4200005AD082 /* ScrollableView.m */,
- 26EC3B6812ED62C0000A960C /* URLFieldCell.h */,
- 26EC3B6912ED62C0000A960C /* URLFieldCell.m */,
- 26EC3C4212ED8202000A960C /* HistoryView.h */,
- 26EC3C4312ED8202000A960C /* HistoryView.m */,
- 26EC3F1612EF0CBD000A960C /* FormSelectMenu.h */,
- 26EC3F1712EF0CBD000A960C /* FormSelectMenu.m */,
- );
- name = Views;
- sourceTree = "<group>";
- };
- 26CDD26712E74453004FC66B /* Download */ = {
- isa = PBXGroup;
- children = (
- 26AFEAE912E04253005AD082 /* DownloadWindowController.h */,
- 26AFEAEA12E04253005AD082 /* DownloadWindowController.m */,
- );
- name = Download;
- sourceTree = "<group>";
- };
- 26CDD26812E74461004FC66B /* NSApplication */ = {
- isa = PBXGroup;
- children = (
- 263629C812F69B120048542C /* NetsurfApp.h */,
- 263629C912F69B120048542C /* NetsurfApp.m */,
- 26AFE97A12DF514C005AD082 /* NetSurfAppDelegate.h */,
- 26AFE97B12DF514C005AD082 /* NetSurfAppDelegate.m */,
- );
- name = NSApplication;
- sourceTree = "<group>";
- };
- 26CDD26912E7446E004FC66B /* Platform Interface */ = {
- isa = PBXGroup;
- children = (
- 263629CA12F69B120048542C /* system_colour.m */,
- 264C344112F0987E00D11246 /* gui.h */,
- 265F311912D663F50048B600 /* gui.m */,
- 261223CB12D7805300E10F91 /* plotter.h */,
- 265F314712D666660048B600 /* plotter.m */,
- 265F316112D667E10048B600 /* schedule.m */,
- 265F316612D668130048B600 /* thumbnail.m */,
- 265F316F12D668790048B600 /* fetch.m */,
- 265F319012D668DB0048B600 /* url.m */,
- 265F31C412D66A0D0048B600 /* save.m */,
- 260FC03112D85ACE00079C00 /* bitmap.h */,
- 265F31EB12D66B190048B600 /* bitmap.m */,
- 265F320512D66C200048B600 /* utf8.m */,
- 265F321312D66CD90048B600 /* utils.m */,
- 261223B712D77F9C00E10F91 /* font.h */,
- 265F321E12D66D510048B600 /* font.m */,
- 26AFED0312E09916005AD082 /* selection.m */,
- 2639E20512F2ADEE00699678 /* coordinates.h */,
- );
- name = "Platform Interface";
- sourceTree = "<group>";
- };
- 29B97314FDCFA39411CA2CEA /* Untitled */ = {
- isa = PBXGroup;
- children = (
- 265F303F12D6637E0048B600 /* Cocoa Frontend */,
- 26CDD23E12E743A3004FC66B /* NetSurf */,
- 263629B212F69A080048542C /* Makefiles */,
- 261DB24E1318443500C59F12 /* Tools */,
- 19C28FACFE9D520D11CA2CBB /* Products */,
- );
- name = Untitled;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXLegacyTarget section */
- 2636298F12F698E00048542C /* NetSurf */ = {
- isa = PBXLegacyTarget;
- buildArgumentsString = "$(ACTION) MKDIR=\"mkdir -p\"";
- buildConfigurationList = 2636299512F699250048542C /* Build configuration list for PBXLegacyTarget "NetSurf" */;
- buildPhases = (
- );
- buildToolPath = /usr/bin/make;
- buildWorkingDirectory = "$(SRCROOT)/..";
- dependencies = (
- );
- name = NetSurf;
- passBuildSettingsInEnvironment = 1;
- productName = NetSurf;
- };
-/* End PBXLegacyTarget section */
-
-/* Begin PBXProject section */
- 29B97313FDCFA39411CA2CEA /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = YES;
- };
- buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NetSurf" */;
- compatibilityVersion = "Xcode 3.1";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- de,
- en,
- fr,
- it,
- nl,
- );
- mainGroup = 29B97314FDCFA39411CA2CEA /* Untitled */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 2636298F12F698E00048542C /* NetSurf */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXVariantGroup section */
- 2612268F12D7AE4100E10F91 /* Messages */ = {
- isa = PBXVariantGroup;
- children = (
- 2612269012D7AE4100E10F91 /* de */,
- 2612269312D7AE9B00E10F91 /* nl */,
- 2612269412D7AEA800E10F91 /* en */,
- 2612269512D7AEB500E10F91 /* it */,
- 2612269612D7AEBE00E10F91 /* fr */,
- );
- name = Messages;
- sourceTree = "<group>";
- };
- 261DB22113180AFF00C59F12 /* Localizable.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB22213180AFF00C59F12 /* en */,
- 261DB22613180B4F00C59F12 /* de */,
- 261DB23313180CD600C59F12 /* fr */,
- 261DB23413180CE000C59F12 /* it */,
- 261DB23513180CEE00C59F12 /* nl */,
- );
- name = Localizable.strings;
- sourceTree = "<group>";
- };
- 261DB28F13185C0A00C59F12 /* BookmarksWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29013185C0A00C59F12 /* de */,
- );
- name = BookmarksWindow.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29313185C0A00C59F12 /* BrowserWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29413185C0A00C59F12 /* de */,
- );
- name = BrowserWindow.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29513185C0A00C59F12 /* DownloadWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29613185C0A00C59F12 /* de */,
- );
- name = DownloadWindow.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29713185C0A00C59F12 /* HistoryWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29813185C0A00C59F12 /* de */,
- );
- name = HistoryWindow.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29B13185C0A00C59F12 /* MainMenu.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29C13185C0A00C59F12 /* de */,
- );
- name = MainMenu.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29D13185C0A00C59F12 /* PreferencesWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB29E13185C0A00C59F12 /* de */,
- );
- name = PreferencesWindow.xib.strings;
- sourceTree = "<group>";
- };
- 261DB29F13185C0A00C59F12 /* SearchWindow.xib.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 261DB2A013185C0A00C59F12 /* de */,
- );
- name = SearchWindow.xib.strings;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 2636299012F698E10048542C /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = NetSurf;
- };
- name = Debug;
- };
- 2636299112F698E10048542C /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- MKDIR = "mkdir -p";
- PRODUCT_NAME = NetSurf;
- };
- name = Release;
- };
- C01FCF4F08A954540054247B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = macosx10.5;
- };
- name = Debug;
- };
- C01FCF5008A954540054247B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- ONLY_ACTIVE_ARCH = NO;
- SDKROOT = macosx10.5;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 2636299512F699250048542C /* Build configuration list for PBXLegacyTarget "NetSurf" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2636299012F698E10048542C /* Debug */,
- 2636299112F698E10048542C /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NetSurf" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C01FCF4F08A954540054247B /* Debug */,
- C01FCF5008A954540054247B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
-}
diff --git a/frontends/cocoa/NetSurfAppDelegate.h b/frontends/cocoa/NetSurfAppDelegate.h
deleted file mode 100644
index a22c4ceee..000000000
--- a/frontends/cocoa/NetSurfAppDelegate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class SearchWindowController;
-@class PreferencesWindowController;
-@class HistoryWindowController;
-
-@interface NetSurfAppDelegate : NSObject {
- SearchWindowController *search;
- PreferencesWindowController *preferences;
- HistoryWindowController *history;
-}
-
-@property (readwrite, retain, nonatomic) SearchWindowController *search;
-@property (readwrite, retain, nonatomic) PreferencesWindowController *preferences;
-@property (readwrite, retain, nonatomic) HistoryWindowController *history;
-
-- (IBAction) showSearchWindow: (id) sender;
-- (IBAction) searchForward: (id) sender;
-- (IBAction) searchBackward: (id) sender;
-
-- (IBAction) showPreferences: (id) sender;
-- (IBAction) showGlobalHistory: (id) sender;
-
-@end
diff --git a/frontends/cocoa/NetSurfAppDelegate.m b/frontends/cocoa/NetSurfAppDelegate.m
deleted file mode 100644
index 0939a1149..000000000
--- a/frontends/cocoa/NetSurfAppDelegate.m
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/nsoption.h"
-#import "utils/messages.h"
-#import "utils/utils.h"
-#import "utils/nsurl.h"
-#import "netsurf/browser_window.h"
-
-#import "cocoa/gui.h"
-#import "cocoa/NetSurfAppDelegate.h"
-#import "cocoa/SearchWindowController.h"
-#import "cocoa/PreferencesWindowController.h"
-#import "cocoa/HistoryWindowController.h"
-
-
-@interface NetSurfAppDelegate ()
-
-- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-
-@end
-
-
-@implementation NetSurfAppDelegate
-
-@synthesize history;
-@synthesize search;
-@synthesize preferences;
-
-- (void) newDocument: (id) sender;
-{
- nsurl *url;
- nserror error;
-
- if (nsoption_charp(homepage_url) != NULL) {
- error = nsurl_create(nsoption_charp(homepage_url), &url);
- } else {
- error = nsurl_create(NETSURF_HOMEPAGE, &url);
- }
-
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (void) openDocument: (id) sender;
-{
- nsurl *u;
- nserror error;
-
- NSOpenPanel *openPanel = [NSOpenPanel openPanel];
- [openPanel setAllowsMultipleSelection: YES];
- if ([openPanel runModalForTypes: nil] == NSOKButton) {
- for (NSURL *url in [openPanel URLs]) {
- error = nsurl_create([[url absoluteString] UTF8String], &u);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- u,
- NULL,
- NULL,
- NULL);
- nsurl_unref(u);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
- }
- }
-}
-
-- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
-{
- nsurl *url;
- nserror error;
- NSString *urlAsString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
-
- error = nsurl_create([urlAsString UTF8String], &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-}
-
-- (IBAction) showSearchWindow: (id) sender;
-{
- if (search == nil) {
- [self setSearch: [[[SearchWindowController alloc] init] autorelease]];
- }
- [[search window] makeKeyAndOrderFront: self];
-}
-
-- (IBAction) searchForward: (id) sender;
-{
- [search search: SearchForward];
-}
-
-- (IBAction) searchBackward: (id) sender;
-{
- [search search: SearchBackward];
-}
-
-- (BOOL) validateMenuItem: (id) item;
-{
- SEL action = [item action];
-
- if (action == @selector( searchForward: )) {
- return [search canGoForward];
- } else if (action == @selector( searchBackward: )) {
- return [search canGoBack];
- }
-
- return YES;
-}
-
-- (IBAction) showPreferences: (id) sender;
-{
- if (preferences == nil) {
- [self setPreferences: [[[PreferencesWindowController alloc] init] autorelease]];
- }
- [preferences showWindow: sender];
-}
-
-- (IBAction) showGlobalHistory: (id) sender;
-{
- if (history == nil) {
- [self setHistory: [[[HistoryWindowController alloc] init] autorelease]];
- }
- [history showWindow: sender];
-}
-
-// Application delegate methods
-
-- (BOOL) applicationOpenUntitledFile: (NSApplication *)sender;
-{
- [self newDocument: self];
- return YES;
-}
-
--(void)applicationWillFinishLaunching:(NSNotification *)aNotification
-{
- NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
- [appleEventManager setEventHandler:self
- andSelector:@selector(handleGetURLEvent:withReplyEvent:)
- forEventClass:kInternetEventClass andEventID:kAEGetURL];
-}
-
-- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
-{
- nsurl *url;
- nserror error;
- NSURL *urltxt = [NSURL fileURLWithPath: filename];
-
- error = nsurl_create([[urltxt absoluteString] UTF8String], &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
-
- return YES;
-}
-
-
-@end
diff --git a/frontends/cocoa/NetsurfApp.h b/frontends/cocoa/NetsurfApp.h
deleted file mode 100644
index 330f33826..000000000
--- a/frontends/cocoa/NetsurfApp.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-@class BrowserViewController;
-
-@interface NetSurfApp : NSApplication {
- BrowserViewController *frontTab;
-}
-
-@property (readwrite, assign, nonatomic) BrowserViewController *frontTab;
-
-@end
-
-NSString *cocoa_get_user_path( NSString *fileName );
diff --git a/frontends/cocoa/NetsurfApp.m b/frontends/cocoa/NetsurfApp.m
deleted file mode 100644
index 7d49e0b51..000000000
--- a/frontends/cocoa/NetsurfApp.m
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/apple_image.h"
-#import "cocoa/NetsurfApp.h"
-#import "cocoa/gui.h"
-#import "cocoa/plotter.h"
-#import "cocoa/DownloadWindowController.h"
-#import "cocoa/SearchWindowController.h"
-#import "cocoa/selection.h"
-#import "cocoa/fetch.h"
-#import "cocoa/bitmap.h"
-#import "cocoa/font.h"
-
-#import "utils/filename.h"
-#import "utils/log.h"
-#import "utils/messages.h"
-#import "utils/utils.h"
-#import "utils/nsoption.h"
-#import "utils/nsurl.h"
-#import "netsurf/plotters.h"
-#import "netsurf/mouse.h"
-#import "netsurf/netsurf.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/cookie_db.h"
-#import "netsurf/url_db.h"
-#import "desktop/save_complete.h"
-#import "cocoa/desktop-tree.h"
-
-#ifndef NETSURF_HOMEPAGE
-#define NETSURF_HOMEPAGE "http://www.netsurf-browser.org/welcome/"
-#endif
-
-@implementation NetSurfApp
-
-@synthesize frontTab;
-
-static bool cocoa_done = false;
-
-/**
- * Cause an abnormal program termination.
- *
- * \note This never returns and is intended to terminate without any cleanup.
- *
- * \param error The message to display to the user.
- */
-static void die(const char * const error)
-{
- [NSException raise: @"NetsurfDie" format: @"Error: %s", error];
-}
-
-- (void) loadOptions
-{
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- [defaults registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys:
- cocoa_get_user_path( @"Cookies" ),
- kCookiesFileOption,
- cocoa_get_user_path( @"URLs" ),
- kURLsFileOption,
- [NSString stringWithUTF8String: NETSURF_HOMEPAGE],
- kHomepageURLOption,
- nil]];
-
-
- nsoption_setnull_charp(cookie_file, strdup( [[defaults objectForKey: kCookiesFileOption] UTF8String] ));
-
- nsoption_setnull_charp(cookie_jar, strdup( nsoption_charp(cookie_file) ));
-
- nsoption_setnull_charp(homepage_url, strdup( [[defaults objectForKey: kHomepageURLOption] UTF8String] ));
-
- urldb_load( [[defaults objectForKey: kURLsFileOption] UTF8String] );
- urldb_load_cookies( nsoption_charp(cookie_file) );
-
- cocoa_update_scale_factor();
- LOG("done setup");
-}
-
-- (void) saveOptions
-{
- urldb_save_cookies( nsoption_charp(cookie_file) );
- urldb_save( [[[NSUserDefaults standardUserDefaults] objectForKey: kURLsFileOption] UTF8String] );
-}
-
-- (void) run
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- [self finishLaunching];
-
- [self loadOptions];
-
- while (!cocoa_done) {
- [pool release];
- pool = [[NSAutoreleasePool alloc] init];
-
- NSEvent *event =
- [self nextEventMatchingMask: NSAnyEventMask
- untilDate: [NSDate distantFuture]
- inMode: NSDefaultRunLoopMode
- dequeue: YES];
- if (nil != event) {
- [self sendEvent: event];
- [self updateWindows];
- }
-
- }
-
- [self saveOptions];
-
- [pool release];
-}
-
--(void) terminate: (id)sender
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification object:self];
-
- cocoa_done = true;
- [self postEvent: [NSEvent otherEventWithType: NSApplicationDefined
- location: NSZeroPoint
- modifierFlags: 0
- timestamp: 0
- windowNumber: 0
- context: NULL
- subtype: 0
- data1: 0
- data2: 0]
- atStart: YES];
-}
-
-@end
-
-#pragma mark -
-
-static NSString *cocoa_get_preferences_path( void )
-{
- NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
- NSCAssert( [paths count] >= 1, @"Where is the application support directory?" );
-
- NSString *netsurfPath = [[paths objectAtIndex: 0] stringByAppendingPathComponent: @"NetSurf"];
-
- NSFileManager *fm = [NSFileManager defaultManager];
- BOOL isDirectory = NO;
- BOOL exists = [fm fileExistsAtPath: netsurfPath isDirectory: &isDirectory];
-
- if (!exists) {
- exists = [fm createDirectoryAtPath: netsurfPath withIntermediateDirectories: YES attributes: nil error: NULL];
- isDirectory = YES;
- }
- if (!(exists && isDirectory)) {
- die( "Cannot create netsurf preferences directory" );
- }
-
- return netsurfPath;
-}
-
-NSString *cocoa_get_user_path( NSString *fileName )
-{
- return [cocoa_get_preferences_path() stringByAppendingPathComponent: fileName];
-}
-
-static const char *cocoa_get_options_file( void )
-{
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- [defaults registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys:
- cocoa_get_user_path( @"Options" ), kOptionsFileOption,
- nil]];
-
- return [[defaults objectForKey: kOptionsFileOption] UTF8String];
-}
-
-static NSApplication *cocoa_prepare_app( void )
-{
- /* if application instance has already been created return it */
- if (NSApp != nil) {
- return NSApp;
- }
-
- NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
-
- /* Obtain principle class of bundle which must implement sharedApplication API */
- Class principalClass = NSClassFromString([infoDictionary objectForKey:@"NSPrincipalClass"]);
- NSCAssert([principalClass respondsToSelector:@selector(sharedApplication)],
- @"Principal class must implement sharedApplication.");
-
- /* create application instance */
- [principalClass sharedApplication];
-
- /* load interface nib */
- NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
- NSNib *mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:[NSBundle mainBundle]];
- [mainNib instantiateNibWithOwner:NSApp topLevelObjects:nil];
- [mainNib release];
-
- return NSApp;
-}
-
-/**
- * Set option defaults for cocoa frontend
- *
- * @param defaults The option table to update.
- * @return error status.
- */
-static nserror set_defaults(struct nsoption_s *defaults)
-{
- /* Set defaults for absent option strings */
- const char * const ca_bundle = [[[NSBundle mainBundle] pathForResource: @"ca-bundle" ofType: @""] UTF8String];
-
- nsoption_setnull_charp(ca_bundle, strdup(ca_bundle));
-
- return NSERROR_OK;
-}
-
-int main( int argc, char **argv )
-{
- nsurl *url;
- nserror error;
- struct netsurf_table cocoa_table = {
- .misc = cocoa_misc_table,
- .window = cocoa_window_table,
- .clipboard = cocoa_clipboard_table,
- .download = cocoa_download_table,
- .fetch = cocoa_fetch_table,
- .search = cocoa_search_table,
- .bitmap = cocoa_bitmap_table,
- .layout = cocoa_layout_table,
- };
-
- error = netsurf_register(&cocoa_table);
- if (error != NSERROR_OK) {
- die("NetSurf operation table failed registration");
- }
-
- const char * const messages = [[[NSBundle mainBundle] pathForResource: @"Messages" ofType: @""] UTF8String];
- const char * const options = cocoa_get_options_file();
-
- /* initialise logging. Not fatal if it fails but not much we
- * can do about it either.
- */
- nslog_init(NULL, &argc, argv);
-
- /* user options setup */
- error = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
- if (error != NSERROR_OK) {
- die("Options failed to initialise");
- }
- nsoption_read(options, NULL);
- nsoption_commandline(&argc, argv, NULL);
-
- error = messages_add_from_file(messages);
-
- /* common initialisation */
- error = netsurf_init(NULL);
- if (error != NSERROR_OK) {
- die("NetSurf failed to initialise");
- }
-
- /* Initialise filename allocator */
- filename_initialise();
-
- (void)apple_image_init();
-
- NSApplication *app = cocoa_prepare_app();
-
- for (int i = 1; i < argc; i++) {
- /* skip -psn_* and other possible options */
- if (argv[i][0] == '-')
- continue;
-
- error = nsurl_create(argv[i], &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- cocoa_warning(messages_get_errorcode(error), 0);
- }
- }
-
- [app run];
-
- netsurf_exit();
-
- return 0;
-}
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front.png
deleted file mode 100644
index 77d220505..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Pressed.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Pressed.png
deleted file mode 100644
index 197ea95c2..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Pressed.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Rollover.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Rollover.png
deleted file mode 100644
index 2dfe5777e..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabCloseDirty_Front_Rollover.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front.png
deleted file mode 100644
index 02b72d39e..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Pressed.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Pressed.png
deleted file mode 100644
index f81125a01..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Pressed.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Rollover.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Rollover.png
deleted file mode 100644
index 4f6b865f7..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabClose_Front_Rollover.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNew.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabNew.png
deleted file mode 100644
index 10a83705d..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNew.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewPressed.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewPressed.png
deleted file mode 100644
index cb4dd10f2..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewPressed.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewRollover.png b/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewRollover.png
deleted file mode 100644
index 4d469f8a6..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/AquaTabNewRollover.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/overflowImage.png b/frontends/cocoa/PSMTabBarControl/Images/overflowImage.png
deleted file mode 100644
index 2b762555d..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/overflowImage.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/overflowImagePressed.png b/frontends/cocoa/PSMTabBarControl/Images/overflowImagePressed.png
deleted file mode 100644
index b3918b344..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/overflowImagePressed.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/Images/pi.png b/frontends/cocoa/PSMTabBarControl/Images/pi.png
deleted file mode 100644
index 4d598dc73..000000000
--- a/frontends/cocoa/PSMTabBarControl/Images/pi.png
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.h b/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.h
deleted file mode 100644
index fd2c2dde4..000000000
--- a/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// NSBezierPath_AMShading.h
-// ------------------------
-//
-// Created by Andreas on 2005-06-01.
-// Copyright 2005 Andreas Mayer. All rights reserved.
-//
-// based on http://www.cocoadev.com/index.pl?GradientFill
-
-
-#import <Cocoa/Cocoa.h>
-
-@interface NSBezierPath (AMShading)
-
-- (void)customHorizontalFillWithCallbacks:(CGFunctionCallbacks) functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor;
-- (void)customVerticalFillWithCallbacks:(CGFunctionCallbacks) functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor;
-
-- (void)linearGradientFillWithStartColor:(NSColor *)startColor endColor:(NSColor *)endColor;
-- (void)linearVerticalGradientFillWithStartColor:(NSColor *)startColor endColor:(NSColor *)endColor;
-
-- (void)bilinearGradientFillWithOuterColor:(NSColor *)outerColor innerColor:(NSColor *)innerColor;
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.m b/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.m
deleted file mode 100644
index 30ee24096..000000000
--- a/frontends/cocoa/PSMTabBarControl/NSBezierPath_AMShading.m
+++ /dev/null
@@ -1,119 +0,0 @@
-//
-// NSBezierPath_AMShading.m
-// ------------------------
-//
-// Created by Andreas on 2005-06-01.
-// Copyright 2005 Andreas Mayer. All rights reserved.
-//
-
-#import "NSBezierPath_AMShading.h"
-
-
-@implementation NSBezierPath (AMShading)
-
-static void linearShadedColor(void *info, const CGFloat *in, CGFloat *out){
- CGFloat *colors = (CGFloat *)info;
- *out++ = colors[0] + *in * colors[8];
- *out++ = colors[1] + *in * colors[9];
- *out++ = colors[2] + *in * colors[10];
- *out++ = colors[3] + *in * colors[11];
-}
-
-static void bilinearShadedColor(void *info, const CGFloat *in, CGFloat *out){
- CGFloat *colors = (CGFloat *)info;
- CGFloat factor = (*in) * 2.0;
- if(*in > 0.5) {
- factor = 2 - factor;
- }
- *out++ = colors[0] + factor * colors[8];
- *out++ = colors[1] + factor * colors[9];
- *out++ = colors[2] + factor * colors[10];
- *out++ = colors[3] + factor * colors[11];
-}
-
-- (void)linearGradientFillWithStartColor:(NSColor *)startColor endColor:(NSColor *)endColor {
- static const CGFunctionCallbacks callbacks = {0, &linearShadedColor, NULL};
-
- [self customHorizontalFillWithCallbacks:callbacks firstColor:startColor secondColor:endColor];
-}
-
-- (void)linearVerticalGradientFillWithStartColor:(NSColor *)startColor endColor:(NSColor *)endColor {
- static const CGFunctionCallbacks callbacks = {0, &linearShadedColor, NULL};
-
- [self customVerticalFillWithCallbacks:callbacks firstColor:startColor secondColor:endColor];
-}
-
-- (void)bilinearGradientFillWithOuterColor:(NSColor *)outerColor innerColor:(NSColor *)innerColor {
- static const CGFunctionCallbacks callbacks = {0, &bilinearShadedColor, NULL};
-
- [self customHorizontalFillWithCallbacks:callbacks firstColor:innerColor secondColor:outerColor];
-}
-
-- (void)customFillWithCallbacks:(CGFunctionCallbacks)functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
- CGColorSpaceRef colorspace;
- CGShadingRef shading;
- CGFunctionRef function;
- CGFloat colors[12]; // pointer to color values
-
- // get my context
- CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
-
- NSColor *deviceDependentFirstColor = [firstColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- NSColor *deviceDependentSecondColor = [secondColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
-
- // set up colors for gradient
- colors[0] = [deviceDependentFirstColor redComponent];
- colors[1] = [deviceDependentFirstColor greenComponent];
- colors[2] = [deviceDependentFirstColor blueComponent];
- colors[3] = [deviceDependentFirstColor alphaComponent];
-
- colors[4] = [deviceDependentSecondColor redComponent];
- colors[5] = [deviceDependentSecondColor greenComponent];
- colors[6] = [deviceDependentSecondColor blueComponent];
- colors[7] = [deviceDependentSecondColor alphaComponent];
-
- // difference between start and end color for each color components
- colors[8] = (colors[4] - colors[0]);
- colors[9] = (colors[5] - colors[1]);
- colors[10] = (colors[6] - colors[2]);
- colors[11] = (colors[7] - colors[3]);
-
- // draw gradient
- colorspace = CGColorSpaceCreateDeviceRGB();
- size_t components = 1 + CGColorSpaceGetNumberOfComponents(colorspace);
- static const CGFloat domain[2] = {0.0, 1.0};
- static const CGFloat range[10] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
- //static const CGFunctionCallbacks callbacks = {0, &bilinearShadedColor, NULL};
-
- // Create a CGFunctionRef that describes a function taking 1 input and kChannelsPerColor outputs.
- function = CGFunctionCreate(colors, 1, domain, components, range, &functionCallbacks);
-
- shading = CGShadingCreateAxial(colorspace, startPoint, endPoint, function, NO, NO);
-
- CGContextSaveGState(currentContext);
- [self addClip];
- CGContextDrawShading(currentContext, shading);
- CGContextRestoreGState(currentContext);
-
- CGShadingRelease(shading);
- CGFunctionRelease(function);
- CGColorSpaceRelease(colorspace);
-}
-
-- (void)customHorizontalFillWithCallbacks:(CGFunctionCallbacks)functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor {
- [self customFillWithCallbacks:functionCallbacks
- firstColor:firstColor
- secondColor:secondColor
- startPoint:CGPointMake(0, NSMinY([self bounds]))
- endPoint:CGPointMake(0, NSMaxY([self bounds]))];
-}
-
-- (void)customVerticalFillWithCallbacks:(CGFunctionCallbacks)functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor {
- [self customFillWithCallbacks:functionCallbacks
- firstColor:firstColor
- secondColor:secondColor
- startPoint:CGPointMake(NSMinX([self bounds]), 0)
- endPoint:CGPointMake(NSMaxX([self bounds]), 0)];
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.h b/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.h
deleted file mode 100644
index cbcbf2c7f..000000000
--- a/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.h
+++ /dev/null
@@ -1,12 +0,0 @@
-//
-// NSString_AITruncation.h
-// PSMTabBarControl
-//
-// Created by Evan Schoenberg on 7/14/07.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@interface NSString (AITruncation)
-- (NSString *)stringWithEllipsisByTruncatingToLength:(NSUInteger)length;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.m b/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.m
deleted file mode 100644
index 1a54502e5..000000000
--- a/frontends/cocoa/PSMTabBarControl/NSString_AITruncation.m
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// NSString_AITruncation.m
-// PSMTabBarControl
-//
-// Created by Evan Schoenberg on 7/14/07.
-// From Adium, which is licensed under the GPL. Used in PSMTabBarControl with permission.
-// The contents of this remain licensed under the GPL.
-//
-
-#import "NSString_AITruncation.h"
-
-@implementation NSString (AITruncation)
-
-+ (id)ellipsis {
- return [NSString stringWithUTF8String:"\xE2\x80\xA6"];
-}
-
-- (NSString *)stringWithEllipsisByTruncatingToLength:(NSUInteger)length {
- NSString *returnString;
-
- if(length < [self length]) {
- //Truncate and append the ellipsis
- returnString = [[self substringToIndex:length - 1] stringByAppendingString:[NSString ellipsis]];
- } else {
- //We don't need to truncate, so don't append an ellipsis
- returnString = [[self copy] autorelease];
- }
-
- return returnString;
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.h b/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.h
deleted file mode 100644
index decda5be4..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// PSMOverflowPopUpButton.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 11/4/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface PSMOverflowPopUpButton : NSPopUpButton {
- NSImage *_PSMTabBarOverflowPopUpImage;
- NSImage *_PSMTabBarOverflowDownPopUpImage;
- BOOL _down;
- BOOL _animatingAlternateImage;
- NSTimer *_animationTimer;
- CGFloat _animationValue;
-}
-
-//alternate image display
-- (BOOL)animatingAlternateImage;
-- (void)setAnimatingAlternateImage:(BOOL)flag;
-
-// archiving
-- (void)encodeWithCoder:(NSCoder *)aCoder;
-- (id)initWithCoder:(NSCoder *)aDecoder;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.m b/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.m
deleted file mode 100644
index c316f6973..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMOverflowPopUpButton.m
+++ /dev/null
@@ -1,152 +0,0 @@
-//
-// PSMOverflowPopUpButton.m
-// PSMTabBarControl
-//
-// Created by John Pannell on 11/4/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-#import "PSMOverflowPopUpButton.h"
-#import "PSMTabBarControl.h"
-
-#define TIMER_INTERVAL 1.0 / 15.0
-#define ANIMATION_STEP 0.033f
-
-@implementation PSMOverflowPopUpButton
-
-- (id)initWithFrame:(NSRect)frameRect pullsDown:(BOOL)flag {
- if ((self = [super initWithFrame:frameRect pullsDown:YES]) != nil) {
- [self setBezelStyle:NSRegularSquareBezelStyle];
- [self setBordered:NO];
- [self setTitle:@""];
- [self setPreferredEdge:NSMaxXEdge];
- _PSMTabBarOverflowPopUpImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"overflowImage"]];
- _PSMTabBarOverflowDownPopUpImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"overflowImagePressed"]];
- _animatingAlternateImage = NO;
- }
- return self;
-}
-
-- (void)dealloc {
- [_PSMTabBarOverflowPopUpImage release];
- [_PSMTabBarOverflowDownPopUpImage release];
- [super dealloc];
-}
-
-- (void)drawRect:(NSRect)rect {
- if(_PSMTabBarOverflowPopUpImage == nil) {
- [super drawRect:rect];
- return;
- }
-
- NSImage *image = (_down) ? _PSMTabBarOverflowDownPopUpImage : _PSMTabBarOverflowPopUpImage;
- NSSize imageSize = [image size];
- NSRect bounds = [self bounds];
-
- NSPoint drawPoint = NSMakePoint(NSMidX(bounds) - (imageSize.width * 0.5f), NSMidY(bounds) - (imageSize.height * 0.5f));
-
- if([self isFlipped]) {
- drawPoint.y += imageSize.height;
- }
-
- [image compositeToPoint:drawPoint operation:NSCompositeSourceOver fraction:(_animatingAlternateImage ? 0.7f : 1.0f)];
-
- if(_animatingAlternateImage) {
- NSImage *alternateImage = [self alternateImage];
- NSSize altImageSize = [alternateImage size];
- drawPoint = NSMakePoint(NSMidX(bounds) - (altImageSize.width * 0.5f), NSMidY(bounds) - (altImageSize.height * 0.5f));
-
- if([self isFlipped]) {
- drawPoint.y += altImageSize.height;
- }
-
- [[self alternateImage] compositeToPoint:drawPoint operation:NSCompositeSourceOver fraction:sin(_animationValue * M_PI)];
- }
-}
-
-- (void)mouseDown:(NSEvent *)event {
- _down = YES;
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationReceived:) name:NSMenuDidEndTrackingNotification object:[self menu]];
- [self setNeedsDisplay:YES];
- [super mouseDown:event];
-}
-
-- (void)setHidden:(BOOL)value {
- if([self isHidden] != value) {
- if(value) {
- // Stop any animating alternate image if we hide
- [_animationTimer invalidate], _animationTimer = nil;
- } else if(_animatingAlternateImage) {
- // Restart any animating alternate image if we unhide
- _animationValue = ANIMATION_STEP;
- _animationTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(animateStep:) userInfo:nil repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode];
- }
- }
-
- [super setHidden:value];
-}
-
-- (void)notificationReceived:(NSNotification *)notification {
- _down = NO;
- [self setNeedsDisplay:YES];
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
-- (void)setAnimatingAlternateImage:(BOOL)flag {
- if(_animatingAlternateImage != flag) {
- _animatingAlternateImage = flag;
-
- if(![self isHidden]) {
- if(flag) {
- _animationValue = ANIMATION_STEP;
- _animationTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(animateStep:) userInfo:nil repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode];
- } else {
- [_animationTimer invalidate], _animationTimer = nil;
- }
-
- [self setNeedsDisplay:YES];
- }
- }
-}
-
-- (BOOL)animatingAlternateImage;
-{
- return _animatingAlternateImage;
-}
-
-- (void)animateStep:(NSTimer *)timer {
- _animationValue += ANIMATION_STEP;
-
- if(_animationValue >= 1) {
- _animationValue = ANIMATION_STEP;
- }
-
- [self setNeedsDisplay:YES];
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder {
- [super encodeWithCoder:aCoder];
- if([aCoder allowsKeyedCoding]) {
- [aCoder encodeObject:_PSMTabBarOverflowPopUpImage forKey:@"PSMTabBarOverflowPopUpImage"];
- [aCoder encodeObject:_PSMTabBarOverflowDownPopUpImage forKey:@"PSMTabBarOverflowDownPopUpImage"];
- [aCoder encodeBool:_animatingAlternateImage forKey:@"PSMTabBarOverflowAnimatingAlternateImage"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder {
- if((self = [super initWithCoder:aDecoder])) {
- if([aDecoder allowsKeyedCoding]) {
- _PSMTabBarOverflowPopUpImage = [[aDecoder decodeObjectForKey:@"PSMTabBarOverflowPopUpImage"] retain];
- _PSMTabBarOverflowDownPopUpImage = [[aDecoder decodeObjectForKey:@"PSMTabBarOverflowDownPopUpImage"] retain];
- [self setAnimatingAlternateImage:[aDecoder decodeBoolForKey:@"PSMTabBarOverflowAnimatingAlternateImage"]];
- }
- }
- return self;
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.h b/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.h
deleted file mode 100644
index ffce06926..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// PSMProgressIndicator.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 2/23/06.
-// Copyright 2006 Positive Spin Media. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface PSMProgressIndicator : NSProgressIndicator {
-}
-
-@end \ No newline at end of file
diff --git a/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.m b/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.m
deleted file mode 100644
index 983609bbc..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMProgressIndicator.m
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// PSMProgressIndicator.m
-// PSMTabBarControl
-//
-// Created by John Pannell on 2/23/06.
-// Copyright 2006 Positive Spin Media. All rights reserved.
-//
-
-#import "PSMProgressIndicator.h"
-#import "PSMTabBarControl.h"
-
-@interface PSMTabBarControl (PSMProgressIndicatorExtensions)
-
-- (void)update;
-
-@end
-
-@implementation PSMProgressIndicator
-
-- (id) initWithFrame: (NSRect)frameRect;
-{
- if ((self = [super initWithFrame: frameRect]) == nil) return nil;
- [self setControlSize: NSSmallControlSize];
- return self;
-}
-
-// overrides to make tab bar control re-layout things if status changes
-- (void)setHidden:(BOOL)flag {
- [super setHidden:flag];
- [(PSMTabBarControl *)[self superview] update];
-}
-
-- (void)stopAnimation:(id)sender {
- [NSObject cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(startAnimation:)
- object:nil];
- [super stopAnimation:sender];
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.h b/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.h
deleted file mode 100644
index 62fce23e0..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// PSMOverflowPopUpButton.h
-// NetScrape
-//
-// Created by John Pannell on 8/4/04.
-// Copyright 2004 Positive Spin Media. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@interface PSMRolloverButton : NSButton {
- NSImage *_rolloverImage;
- NSImage *_usualImage;
- NSTrackingRectTag _myTrackingRectTag;
-}
-
-// the regular image
-- (void)setUsualImage:(NSImage *)newImage;
-- (NSImage *)usualImage;
-
-// the rollover image
-- (void)setRolloverImage:(NSImage *)newImage;
-- (NSImage *)rolloverImage;
-
-// tracking rect for mouse events
-- (void)addTrackingRect;
-- (void)removeTrackingRect;
-@end \ No newline at end of file
diff --git a/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.m b/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.m
deleted file mode 100644
index 8886560c7..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMRolloverButton.m
+++ /dev/null
@@ -1,170 +0,0 @@
-//
-// PSMOverflowPopUpButton.m
-// NetScrape
-//
-// Created by John Pannell on 8/4/04.
-// Copyright 2004 Positive Spin Media. All rights reserved.
-//
-
-#import "PSMRolloverButton.h"
-
-@implementation PSMRolloverButton
-
-- (void)awakeFromNib {
- if([[self superclass] instancesRespondToSelector:@selector(awakeFromNib)]) {
- [super awakeFromNib];
- }
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(rolloverFrameDidChange:)
- name:NSViewFrameDidChangeNotification
- object:self];
- [self setPostsFrameChangedNotifications:YES];
- [self resetCursorRects];
-
- _myTrackingRectTag = -1;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [self removeTrackingRect];
-
- [super dealloc];
-}
-
-// the regular image
-- (void)setUsualImage:(NSImage *)newImage {
- [newImage retain];
- [_usualImage release];
- _usualImage = newImage;
-
- [self setImage:_usualImage];
-}
-
-- (NSImage *)usualImage {
- return _usualImage;
-}
-
-- (void)setRolloverImage:(NSImage *)newImage {
- [newImage retain];
- [_rolloverImage release];
- _rolloverImage = newImage;
-}
-
-- (NSImage *)rolloverImage {
- return _rolloverImage;
-}
-
-//Remove old tracking rects when we change superviews
-- (void)viewWillMoveToSuperview:(NSView *)newSuperview {
- [self removeTrackingRect];
-
- [super viewWillMoveToSuperview:newSuperview];
-}
-
-- (void)viewDidMoveToSuperview {
- [super viewDidMoveToSuperview];
-
- [self resetCursorRects];
-}
-
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
- [self removeTrackingRect];
-
- [super viewWillMoveToWindow:newWindow];
-}
-
-- (void)viewDidMoveToWindow {
- [super viewDidMoveToWindow];
-
- [self resetCursorRects];
-}
-
-- (void)rolloverFrameDidChange:(NSNotification *)inNotification {
- [self resetCursorRects];
-}
-
-- (void)addTrackingRect {
- // assign a tracking rect to watch for mouse enter/exit
- NSRect trackRect = [self bounds];
- NSPoint localPoint = [self convertPoint:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
- fromView:nil];
- BOOL mouseInside = NSPointInRect(localPoint, trackRect);
-
- _myTrackingRectTag = [self addTrackingRect:trackRect owner:self userData:nil assumeInside:mouseInside];
- if(mouseInside) {
- //[self mouseEntered:nil];
- [self setImage:_rolloverImage];
- } else{
- //[self mouseExited:nil];
- [self setImage:_usualImage];
- }
-}
-
-- (void)removeTrackingRect {
- if(_myTrackingRectTag != -1) {
- [self removeTrackingRect:_myTrackingRectTag];
- }
- _myTrackingRectTag = -1;
-}
-
-// override for rollover effect
-- (void)mouseEntered:(NSEvent *)theEvent;
-{
- // set rollover image
- [self setImage:_rolloverImage];
-
- [super mouseEntered:theEvent];
-}
-
-- (void)mouseExited:(NSEvent *)theEvent;
-{
- // restore usual image
- [self setImage:_usualImage];
-
- [super mouseExited:theEvent];
-}
-
-- (void)resetCursorRects {
- // called when the button rect has been changed
- [self removeTrackingRect];
- [self addTrackingRect];
-}
-
-- (void)setFrame:(NSRect)rect {
- [super setFrame:rect];
- [self resetCursorRects];
-}
-
-- (void)setBounds:(NSRect)rect {
- [super setBounds:rect];
- [self resetCursorRects];
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder {
- [super encodeWithCoder:aCoder];
- if([aCoder allowsKeyedCoding]) {
- [aCoder encodeObject:_rolloverImage forKey:@"rolloverImage"];
- [aCoder encodeObject:_usualImage forKey:@"usualImage"];
- [aCoder encodeInt64:_myTrackingRectTag forKey:@"myTrackingRectTag"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super initWithCoder:aDecoder];
- if(self) {
- if([aDecoder allowsKeyedCoding]) {
- _rolloverImage = [[aDecoder decodeObjectForKey:@"rolloverImage"] retain];
- _usualImage = [[aDecoder decodeObjectForKey:@"usualImage"] retain];
- _myTrackingRectTag = [aDecoder decodeInt64ForKey:@"myTrackingRectTag"];
- }
- }
- return self;
-}
-
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.h b/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.h
deleted file mode 100644
index c8f6cecdd..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.h
+++ /dev/null
@@ -1,116 +0,0 @@
-//
-// PSMTabBarCell.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 10/13/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-#import "PSMTabBarControl.h"
-#import "PSMProgressIndicator.h"
-
-
-@interface PSMTabBarCell : NSActionCell {
- // sizing
- NSRect _frame;
- NSSize _stringSize;
- NSInteger _currentStep;
- BOOL _isPlaceholder;
-
- // state
- NSInteger _tabState;
- NSTrackingRectTag _closeButtonTrackingTag; // left side tracking, if dragging
- NSTrackingRectTag _cellTrackingTag; // right side tracking, if dragging
- BOOL _closeButtonOver;
- BOOL _closeButtonPressed;
- PSMProgressIndicator *_indicator;
- BOOL _isInOverflowMenu;
- BOOL _hasCloseButton;
- BOOL _isCloseButtonSuppressed;
- BOOL _hasIcon;
- BOOL _hasLargeImage;
- NSInteger _count;
- NSColor *_countColor;
- BOOL _isEdited;
-}
-
-// creation/destruction
-- (id)initWithControlView:(PSMTabBarControl *)controlView;
-- (id)initPlaceholderWithFrame:(NSRect) frame expanded:(BOOL) value inControlView:(PSMTabBarControl *)controlView;
-- (void)dealloc;
-
-// accessors
-- (id)controlView;
-- (void)setControlView:(id)view;
-- (NSTrackingRectTag)closeButtonTrackingTag;
-- (void)setCloseButtonTrackingTag:(NSTrackingRectTag)tag;
-- (NSTrackingRectTag)cellTrackingTag;
-- (void)setCellTrackingTag:(NSTrackingRectTag)tag;
-- (CGFloat)width;
-- (NSRect)frame;
-- (void)setFrame:(NSRect)rect;
-- (void)setStringValue:(NSString *)aString;
-- (NSSize)stringSize;
-- (NSAttributedString *)attributedStringValue;
-- (NSInteger)tabState;
-- (void)setTabState:(NSInteger)state;
-- (NSProgressIndicator *)indicator;
-- (BOOL)isInOverflowMenu;
-- (void)setIsInOverflowMenu:(BOOL)value;
-- (BOOL)closeButtonPressed;
-- (void)setCloseButtonPressed:(BOOL)value;
-- (BOOL)closeButtonOver;
-- (void)setCloseButtonOver:(BOOL)value;
-- (BOOL)hasCloseButton;
-- (void)setHasCloseButton:(BOOL)set;
-- (void)setCloseButtonSuppressed:(BOOL)suppress;
-- (BOOL)isCloseButtonSuppressed;
-- (BOOL)hasIcon;
-- (void)setHasIcon:(BOOL)value;
-- (BOOL)hasLargeImage;
-- (void)setHasLargeImage:(BOOL)value;
-- (NSInteger)count;
-- (void)setCount:(NSInteger)value;
-- (NSColor *)countColor;
-- (void)setCountColor:(NSColor *)value;
-- (BOOL)isPlaceholder;
-- (void)setIsPlaceholder:(BOOL)value;
-- (NSInteger)currentStep;
-- (void)setCurrentStep:(NSInteger)value;
-- (BOOL)isEdited;
-- (void)setIsEdited:(BOOL)value;
-
-// component attributes
-- (NSRect)indicatorRectForFrame:(NSRect)cellFrame;
-- (NSRect)closeButtonRectForFrame:(NSRect)cellFrame;
-- (CGFloat)minimumWidthOfCell;
-- (CGFloat)desiredWidthOfCell;
-
-// drawing
-- (void)drawWithFrame:(NSRect) cellFrame inView:(NSView *)controlView;
-
-// tracking the mouse
-- (void)mouseEntered:(NSEvent *)theEvent;
-- (void)mouseExited:(NSEvent *)theEvent;
-
-// drag support
-- (NSImage *)dragImage;
-
-// archiving
-- (void)encodeWithCoder:(NSCoder *)aCoder;
-- (id)initWithCoder:(NSCoder *)aDecoder;
-
-@end
-
-@interface PSMTabBarControl (CellAccessors)
-
-- (id<PSMTabStyle>)style;
-
-@end
-
-@interface NSObject (IdentifierAccesors)
-
-- (NSImage *)largeImage;
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m b/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m
deleted file mode 100644
index f7a04f202..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m
+++ /dev/null
@@ -1,489 +0,0 @@
-//
-// PSMTabBarCell.m
-// PSMTabBarControl
-//
-// Created by John Pannell on 10/13/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-#import "PSMTabBarCell.h"
-#import "PSMTabBarControl.h"
-#import "PSMTabStyle.h"
-#import "PSMProgressIndicator.h"
-#import "PSMTabDragAssistant.h"
-
-@interface PSMTabBarControl (Private)
-- (void)update;
-@end
-
-@implementation PSMTabBarCell
-
-#pragma mark -
-#pragma mark Creation/Destruction
-- (id)initWithControlView:(PSMTabBarControl *)controlView {
- if((self = [super init])) {
- _controlView = controlView;
- _closeButtonTrackingTag = 0;
- _cellTrackingTag = 0;
- _closeButtonOver = NO;
- _closeButtonPressed = NO;
- _indicator = [[PSMProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth)];
- [_indicator setStyle:NSProgressIndicatorSpinningStyle];
- [_indicator setAutoresizingMask:NSViewMinYMargin];
- _hasCloseButton = YES;
- _isCloseButtonSuppressed = NO;
- _count = 0;
- _countColor = nil;
- _isEdited = NO;
- _isPlaceholder = NO;
- }
- return self;
-}
-
-- (id)initPlaceholderWithFrame:(NSRect)frame expanded:(BOOL)value inControlView:(PSMTabBarControl *)controlView {
- if((self = [super init])) {
- _controlView = controlView;
- _isPlaceholder = YES;
- if(!value) {
- if([controlView orientation] == PSMTabBarHorizontalOrientation) {
- frame.size.width = 0.0;
- } else {
- frame.size.height = 0.0;
- }
- }
- [self setFrame:frame];
- _closeButtonTrackingTag = 0;
- _cellTrackingTag = 0;
- _closeButtonOver = NO;
- _closeButtonPressed = NO;
- _indicator = nil;
- _hasCloseButton = YES;
- _isCloseButtonSuppressed = NO;
- _count = 0;
- _countColor = nil;
- _isEdited = NO;
-
- if(value) {
- [self setCurrentStep:(kPSMTabDragAnimationSteps - 1)];
- } else {
- [self setCurrentStep:0];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- [_countColor release];
-
- [_indicator removeFromSuperviewWithoutNeedingDisplay];
-
- [_indicator release];
- [super dealloc];
-}
-
-#pragma mark -
-#pragma mark Accessors
-
-- (id)controlView {
- return _controlView;
-}
-
-- (void)setControlView:(id)view {
- // no retain release pattern, as this simply switches a tab to another view.
- _controlView = view;
-}
-
-- (NSTrackingRectTag)closeButtonTrackingTag {
- return _closeButtonTrackingTag;
-}
-
-- (void)setCloseButtonTrackingTag:(NSTrackingRectTag)tag {
- _closeButtonTrackingTag = tag;
-}
-
-- (NSTrackingRectTag)cellTrackingTag {
- return _cellTrackingTag;
-}
-
-- (void)setCellTrackingTag:(NSTrackingRectTag)tag {
- _cellTrackingTag = tag;
-}
-
-- (CGFloat)width {
- return _frame.size.width;
-}
-
-- (NSRect)frame {
- return _frame;
-}
-
-- (void)setFrame:(NSRect)rect {
- _frame = rect;
-
- //move the status indicator along with the rest of the cell
- if(![[self indicator] isHidden] && ![_controlView isTabBarHidden]) {
- [[self indicator] setFrame:[self indicatorRectForFrame:rect]];
- }
-}
-
-- (void)setStringValue:(NSString *)aString {
- [super setStringValue:aString];
- _stringSize = [[self attributedStringValue] size];
- // need to redisplay now - binding observation was too quick.
- [_controlView update];
-}
-
-- (NSSize)stringSize {
- return _stringSize;
-}
-
-- (NSAttributedString *)attributedStringValue {
- return [(id < PSMTabStyle >)[_controlView style] attributedStringValueForTabCell:self];
-}
-
-- (NSInteger)tabState {
- return _tabState;
-}
-
-- (void)setTabState:(NSInteger)state {
- _tabState = state;
-}
-
-- (NSProgressIndicator *)indicator {
- return _indicator;
-}
-
-- (BOOL)isInOverflowMenu {
- return _isInOverflowMenu;
-}
-
-- (void)setIsInOverflowMenu:(BOOL)value {
- if(_isInOverflowMenu != value) {
- _isInOverflowMenu = value;
- if([[[self controlView] delegate] respondsToSelector:@selector(tabView:tabViewItem:isInOverflowMenu:)]) {
- [[[self controlView] delegate] tabView:[self controlView] tabViewItem:[self representedObject] isInOverflowMenu:_isInOverflowMenu];
- }
- }
-}
-
-- (BOOL)closeButtonPressed {
- return _closeButtonPressed;
-}
-
-- (void)setCloseButtonPressed:(BOOL)value {
- _closeButtonPressed = value;
-}
-
-- (BOOL)closeButtonOver {
- return(_closeButtonOver && ([_controlView allowsBackgroundTabClosing] || ([self tabState] & PSMTab_SelectedMask) || [[NSApp currentEvent] modifierFlags] & NSCommandKeyMask));
-}
-
-- (void)setCloseButtonOver:(BOOL)value {
- _closeButtonOver = value;
-}
-
-- (BOOL)hasCloseButton {
- return _hasCloseButton;
-}
-
-- (void)setHasCloseButton:(BOOL)set;
-{
- _hasCloseButton = set;
-}
-
-- (void)setCloseButtonSuppressed:(BOOL)suppress;
-{
- _isCloseButtonSuppressed = suppress;
-}
-
-- (BOOL)isCloseButtonSuppressed;
-{
- return _isCloseButtonSuppressed;
-}
-
-- (BOOL)hasIcon {
- return _hasIcon;
-}
-
-- (void)setHasIcon:(BOOL)value {
- _hasIcon = value;
- //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
-}
-
-- (BOOL)hasLargeImage {
- return _hasLargeImage;
-}
-
-- (void)setHasLargeImage:(BOOL)value {
- _hasLargeImage = value;
-}
-
-
-- (NSInteger)count {
- return _count;
-}
-
-- (void)setCount:(NSInteger)value {
- _count = value;
- //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
-}
-
-- (NSColor *)countColor {
- return _countColor;
-}
-
-- (void)setCountColor:(NSColor *)color {
- [_countColor release];
- _countColor = [color retain];
-}
-
-- (BOOL)isPlaceholder {
- return _isPlaceholder;
-}
-
-- (void)setIsPlaceholder:(BOOL)value;
-{
- _isPlaceholder = value;
-}
-
-- (NSInteger)currentStep {
- return _currentStep;
-}
-
-- (void)setCurrentStep:(NSInteger)value {
- if(value < 0) {
- value = 0;
- }
-
- if(value > (kPSMTabDragAnimationSteps - 1)) {
- value = (kPSMTabDragAnimationSteps - 1);
- }
-
- _currentStep = value;
-}
-
-- (BOOL)isEdited {
- return _isEdited;
-}
-
-- (void)setIsEdited:(BOOL)value {
- _isEdited = value;
- //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
-}
-
-#pragma mark -
-#pragma mark Bindings
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- // the progress indicator, label, icon, or count has changed - redraw the control view
- //[_controlView update];
- //I seem to have run into some odd issue with update not being called at the right time. This seems to avoid the problem.
- [_controlView performSelector:@selector(update) withObject:nil afterDelay:0.0];
-}
-
-#pragma mark -
-#pragma mark Component Attributes
-
-- (NSRect)indicatorRectForFrame:(NSRect)cellFrame {
- return [(id < PSMTabStyle >)[_controlView style] indicatorRectForTabCell:self];
-}
-
-- (NSRect)closeButtonRectForFrame:(NSRect)cellFrame {
- return [(id < PSMTabStyle >)[_controlView style] closeButtonRectForTabCell:self withFrame:cellFrame];
-}
-
-- (CGFloat)minimumWidthOfCell {
- return [(id < PSMTabStyle >)[_controlView style] minimumWidthOfTabCell:self];
-}
-
-- (CGFloat)desiredWidthOfCell {
- return [(id < PSMTabStyle >)[_controlView style] desiredWidthOfTabCell:self];
-}
-
-#pragma mark -
-#pragma mark Drawing
-
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
- if(_isPlaceholder) {
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
- NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
- return;
- }
-
- [(id < PSMTabStyle >)[_controlView style] drawTabCell:self];
-}
-
-#pragma mark -
-#pragma mark Tracking
-
-- (void)mouseEntered:(NSEvent *)theEvent {
- // check for which tag
- if([theEvent trackingNumber] == _closeButtonTrackingTag) {
- _closeButtonOver = YES;
- }
- if([theEvent trackingNumber] == _cellTrackingTag) {
- [self setHighlighted:YES];
- [_controlView setNeedsDisplay:NO];
- }
-
- // scrubtastic
- if([_controlView allowsScrubbing] && ([theEvent modifierFlags] & NSAlternateKeyMask)) {
- [_controlView performSelector:@selector(tabClick:) withObject:self];
- }
-
- // tell the control we only need to redraw the affected tab
- [_controlView setNeedsDisplayInRect:NSInsetRect([self frame], -2, -2)];
-}
-
-- (void)mouseExited:(NSEvent *)theEvent {
- // check for which tag
- if([theEvent trackingNumber] == _closeButtonTrackingTag) {
- _closeButtonOver = NO;
- }
-
- if([theEvent trackingNumber] == _cellTrackingTag) {
- [self setHighlighted:NO];
- [_controlView setNeedsDisplay:NO];
- }
-
- //tell the control we only need to redraw the affected tab
- [_controlView setNeedsDisplayInRect:NSInsetRect([self frame], -2, -2)];
-}
-
-#pragma mark -
-#pragma mark Drag Support
-
-- (NSImage *)dragImage {
- NSRect cellFrame = [(id < PSMTabStyle >)[(PSMTabBarControl *)_controlView style] dragRectForTabCell:self orientation:(PSMTabBarOrientation)[(PSMTabBarControl *)_controlView orientation]];
- //NSRect cellFrame = [self frame];
-
- [_controlView lockFocus];
- NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:cellFrame] autorelease];
- [_controlView unlockFocus];
- NSImage *image = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
- [image addRepresentation:rep];
- NSImage *returnImage = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
- [returnImage lockFocus];
- [image compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeSourceOver fraction:1.0];
- [returnImage unlockFocus];
- if(![[self indicator] isHidden]) {
- NSImage *pi = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"pi"]];
- [returnImage lockFocus];
- NSPoint indicatorPoint = NSMakePoint([self frame].size.width - MARGIN_X - kPSMTabBarIndicatorWidth, MARGIN_Y);
- [pi compositeToPoint:indicatorPoint operation:NSCompositeSourceOver fraction:1.0];
- [returnImage unlockFocus];
- [pi release];
- }
- return returnImage;
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder {
- [super encodeWithCoder:aCoder];
- if([aCoder allowsKeyedCoding]) {
- [aCoder encodeRect:_frame forKey:@"frame"];
- [aCoder encodeSize:_stringSize forKey:@"stringSize"];
- [aCoder encodeInteger:_currentStep forKey:@"currentStep"];
- [aCoder encodeBool:_isPlaceholder forKey:@"isPlaceholder"];
- [aCoder encodeInteger:_tabState forKey:@"tabState"];
- [aCoder encodeInteger:_closeButtonTrackingTag forKey:@"closeButtonTrackingTag"];
- [aCoder encodeInteger:_cellTrackingTag forKey:@"cellTrackingTag"];
- [aCoder encodeBool:_closeButtonOver forKey:@"closeButtonOver"];
- [aCoder encodeBool:_closeButtonPressed forKey:@"closeButtonPressed"];
- [aCoder encodeObject:_indicator forKey:@"indicator"];
- [aCoder encodeBool:_isInOverflowMenu forKey:@"isInOverflowMenu"];
- [aCoder encodeBool:_hasCloseButton forKey:@"hasCloseButton"];
- [aCoder encodeBool:_isCloseButtonSuppressed forKey:@"isCloseButtonSuppressed"];
- [aCoder encodeBool:_hasIcon forKey:@"hasIcon"];
- [aCoder encodeBool:_hasLargeImage forKey:@"hasLargeImage"];
- [aCoder encodeInteger:_count forKey:@"count"];
- [aCoder encodeBool:_isEdited forKey:@"isEdited"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super initWithCoder:aDecoder];
- if(self) {
- if([aDecoder allowsKeyedCoding]) {
- _frame = [aDecoder decodeRectForKey:@"frame"];
- _stringSize = [aDecoder decodeSizeForKey:@"stringSize"];
- _currentStep = [aDecoder decodeIntegerForKey:@"currentStep"];
- _isPlaceholder = [aDecoder decodeBoolForKey:@"isPlaceholder"];
- _tabState = [aDecoder decodeIntegerForKey:@"tabState"];
- _closeButtonTrackingTag = [aDecoder decodeIntegerForKey:@"closeButtonTrackingTag"];
- _cellTrackingTag = [aDecoder decodeIntegerForKey:@"cellTrackingTag"];
- _closeButtonOver = [aDecoder decodeBoolForKey:@"closeButtonOver"];
- _closeButtonPressed = [aDecoder decodeBoolForKey:@"closeButtonPressed"];
- _indicator = [[aDecoder decodeObjectForKey:@"indicator"] retain];
- _isInOverflowMenu = [aDecoder decodeBoolForKey:@"isInOverflowMenu"];
- _hasCloseButton = [aDecoder decodeBoolForKey:@"hasCloseButton"];
- _isCloseButtonSuppressed = [aDecoder decodeBoolForKey:@"isCloseButtonSuppressed"];
- _hasIcon = [aDecoder decodeBoolForKey:@"hasIcon"];
- _hasLargeImage = [aDecoder decodeBoolForKey:@"hasLargeImage"];
- _count = [aDecoder decodeIntegerForKey:@"count"];
- _isEdited = [aDecoder decodeBoolForKey:@"isEdited"];
- }
- }
- return self;
-}
-
-#pragma mark -
-#pragma mark Accessibility
-
--(BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString *)attribute {
- id attributeValue = nil;
-
- if([attribute isEqualToString: NSAccessibilityRoleAttribute]) {
- attributeValue = NSAccessibilityButtonRole;
- } else if([attribute isEqualToString: NSAccessibilityHelpAttribute]) {
- if([[[self controlView] delegate] respondsToSelector:@selector(accessibilityStringForTabView:objectCount:)]) {
- attributeValue = [NSString stringWithFormat:@"%@, %lu %@", [self stringValue],
- (unsigned long)[self count],
- [[[self controlView] delegate] accessibilityStringForTabView:[[self controlView] tabView] objectCount:[self count]]];
- } else {
- attributeValue = [self stringValue];
- }
- } else if([attribute isEqualToString: NSAccessibilityFocusedAttribute]) {
- attributeValue = [NSNumber numberWithBool:([self tabState] == 2)];
- } else {
- attributeValue = [super accessibilityAttributeValue:attribute];
- }
-
- return attributeValue;
-}
-
-- (NSArray *)accessibilityActionNames {
- static NSArray *actions;
-
- if(!actions) {
- actions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, nil];
- }
- return actions;
-}
-
-- (NSString *)accessibilityActionDescription:(NSString *)action {
- return NSAccessibilityActionDescription(action);
-}
-
-- (void)accessibilityPerformAction:(NSString *)action {
- if([action isEqualToString:NSAccessibilityPressAction]) {
- // this tab was selected
- [_controlView performSelector:@selector(tabClick:) withObject:self];
- }
-}
-
-- (id)accessibilityHitTest:(NSPoint)point {
- return NSAccessibilityUnignoredAncestor(self);
-}
-
-- (id)accessibilityFocusedUIElement:(NSPoint)point {
- return NSAccessibilityUnignoredAncestor(self);
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.h b/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.h
deleted file mode 100644
index 980c43d38..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.h
+++ /dev/null
@@ -1,241 +0,0 @@
-//
-// PSMTabBarControl.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 10/13/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-/*
- This view provides a control interface to manage a regular NSTabView. It looks and works like the tabbed browsing interface of many popular browsers.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#define PSMTabDragDidEndNotification @ "PSMTabDragDidEndNotification"
-#define PSMTabDragDidBeginNotification @ "PSMTabDragDidBeginNotification"
-
-#define kPSMTabBarControlHeight 22
-// internal cell border
-#define MARGIN_X 6
-#define MARGIN_Y 3
-// padding between objects
-#define kPSMTabBarCellPadding 4
-// fixed size objects
-#define kPSMMinimumTitleWidth 30
-#define kPSMTabBarIndicatorWidth 16.0
-#define kPSMTabBarIconWidth 16.0
-#define kPSMHideAnimationSteps 3.0
-
-// Value used in _currentStep to indicate that resizing operation is not in progress
-#define kPSMIsNotBeingResized -1
-
-// Value used in _currentStep when a resizing operation has just been started
-#define kPSMStartResizeAnimation 0
-
-@class PSMOverflowPopUpButton;
-@class PSMRolloverButton;
-@class PSMTabBarCell;
-@class PSMTabBarController;
-@protocol PSMTabStyle;
-
-typedef enum {
- PSMTabBarHorizontalOrientation,
- PSMTabBarVerticalOrientation
-} PSMTabBarOrientation;
-
-typedef enum {
- PSMTabBarTearOffAlphaWindow,
- PSMTabBarTearOffMiniwindow
-} PSMTabBarTearOffStyle;
-
-enum {
- PSMTab_SelectedMask = 1 << 1,
- PSMTab_LeftIsSelectedMask = 1 << 2,
- PSMTab_RightIsSelectedMask = 1 << 3,
- PSMTab_PositionLeftMask = 1 << 4,
- PSMTab_PositionMiddleMask = 1 << 5,
- PSMTab_PositionRightMask = 1 << 6,
- PSMTab_PositionSingleMask = 1 << 7,
-};
-
-@interface PSMTabBarControl : NSControl {
-
- // control basics
- NSMutableArray *_cells; // the cells that draw the tabs
- IBOutlet NSTabView *tabView; // the tab view being navigated
- PSMOverflowPopUpButton *_overflowPopUpButton; // for too many tabs
- PSMRolloverButton *_addTabButton;
- PSMTabBarController *_controller;
-
- // Spring-loading.
- NSTimer *_springTimer;
- NSTabViewItem *_tabViewItemWithSpring;
-
- // drawing style
- id<PSMTabStyle> style;
- BOOL _canCloseOnlyTab;
- BOOL _disableTabClose;
- BOOL _hideForSingleTab;
- BOOL _showAddTabButton;
- BOOL _sizeCellsToFit;
- BOOL _useOverflowMenu;
- BOOL _alwaysShowActiveTab;
- BOOL _allowsScrubbing;
- NSInteger _resizeAreaCompensation;
- PSMTabBarOrientation _orientation;
- BOOL _automaticallyAnimates;
- NSTimer *_animationTimer;
- PSMTabBarTearOffStyle _tearOffStyle;
-
- // behavior
- BOOL _allowsBackgroundTabClosing;
- BOOL _selectsTabsOnMouseDown;
-
- // vertical tab resizing
- BOOL _allowsResizing;
- BOOL _resizing;
-
- // cell width
- NSInteger _cellMinWidth;
- NSInteger _cellMaxWidth;
- NSInteger _cellOptimumWidth;
-
- // animation for hide/show
- NSInteger _currentStep;
- BOOL _isHidden;
- IBOutlet id partnerView; // gets resized when hide/show
- BOOL _awakenedFromNib;
- NSInteger _tabBarWidth;
- NSTimer *_showHideAnimationTimer;
-
- // drag and drop
- NSEvent *_lastMouseDownEvent; // keep this for dragging reference
- BOOL _didDrag;
- BOOL _closeClicked;
-
- // MVC help
- IBOutlet id delegate;
-}
-
-// control characteristics
-+ (NSBundle *)bundle;
-- (CGFloat)availableCellWidth;
-- (NSRect)genericCellRect;
-
-// control configuration
-- (PSMTabBarOrientation)orientation;
-- (void)setOrientation:(PSMTabBarOrientation)value;
-- (BOOL)canCloseOnlyTab;
-- (void)setCanCloseOnlyTab:(BOOL)value;
-- (BOOL)disableTabClose;
-- (void)setDisableTabClose:(BOOL)value;
-- (id<PSMTabStyle>)style;
-- (void)setStyle:(id <PSMTabStyle>)newStyle;
-- (NSString *)styleName;
-- (void)setStyleNamed:(NSString *)name;
-- (BOOL)hideForSingleTab;
-- (void)setHideForSingleTab:(BOOL)value;
-- (BOOL)showAddTabButton;
-- (void)setShowAddTabButton:(BOOL)value;
-- (NSInteger)cellMinWidth;
-- (void)setCellMinWidth:(NSInteger)value;
-- (NSInteger)cellMaxWidth;
-- (void)setCellMaxWidth:(NSInteger)value;
-- (NSInteger)cellOptimumWidth;
-- (void)setCellOptimumWidth:(NSInteger)value;
-- (BOOL)sizeCellsToFit;
-- (void)setSizeCellsToFit:(BOOL)value;
-- (BOOL)useOverflowMenu;
-- (void)setUseOverflowMenu:(BOOL)value;
-- (BOOL)allowsBackgroundTabClosing;
-- (void)setAllowsBackgroundTabClosing:(BOOL)value;
-- (BOOL)allowsResizing;
-- (void)setAllowsResizing:(BOOL)value;
-- (BOOL)selectsTabsOnMouseDown;
-- (void)setSelectsTabsOnMouseDown:(BOOL)value;
-- (BOOL)automaticallyAnimates;
-- (void)setAutomaticallyAnimates:(BOOL)value;
-- (BOOL)alwaysShowActiveTab;
-- (void)setAlwaysShowActiveTab:(BOOL)value;
-- (BOOL)allowsScrubbing;
-- (void)setAllowsScrubbing:(BOOL)value;
-- (PSMTabBarTearOffStyle)tearOffStyle;
-- (void)setTearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle;
-
-// Factory for default style
-+ (Class)defaultStyleClass;
-
-// accessors
-- (NSTabView *)tabView;
-- (void)setTabView:(NSTabView *)view;
-- (id)delegate;
-- (void)setDelegate:(id)object;
-- (id)partnerView;
-- (void)setPartnerView:(id)view;
-
-// the buttons
-- (PSMRolloverButton *)addTabButton;
-- (PSMOverflowPopUpButton *)overflowPopUpButton;
-
-// tab information
-- (NSMutableArray *)representedTabViewItems;
-- (NSInteger)numberOfVisibleTabs;
-- (PSMTabBarCell *)lastVisibleTab;
-
-// special effects
-- (void)hideTabBar:(BOOL) hide animate:(BOOL)animate;
-- (BOOL)isTabBarHidden;
-- (BOOL)isAnimating;
-
-// internal bindings methods also used by the tab drag assistant
-- (void)bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item;
-- (void)removeTabForCell:(PSMTabBarCell *)cell;
-
-@end
-
-
-@interface NSObject (TabBarControlDelegateMethods)
-
-//Standard NSTabView methods
-- (BOOL)tabView:(NSTabView *)aTabView shouldCloseTabViewItem:(NSTabViewItem *)tabViewItem;
-- (void)tabView:(NSTabView *)aTabView didCloseTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//"Spring-loaded" tabs methods
-- (NSArray *)allowedDraggedTypesForTabView:(NSTabView *)aTabView;
-- (void)tabView:(NSTabView *)aTabView acceptedDraggingInfo:(id <NSDraggingInfo>) draggingInfo onTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//Contextual menu method
-- (NSMenu *)tabView:(NSTabView *)aTabView menuForTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//Drag and drop methods
-- (BOOL)tabView:(NSTabView *)aTabView shouldDragTabViewItem:(NSTabViewItem *)tabViewItem fromTabBar:(PSMTabBarControl *)tabBarControl;
-- (BOOL)tabView:(NSTabView *)aTabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl;
-- (BOOL)tabView:(NSTabView *)aTabView shouldAllowTabViewItem:(NSTabViewItem *)tabViewItem toLeaveTabBar:(PSMTabBarControl *)tabBarControl;
-- (void)tabView:(NSTabView*)aTabView didDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl;
-
-
-//Tear-off tabs methods
-- (NSImage *)tabView:(NSTabView *)aTabView imageForTabViewItem:(NSTabViewItem *)tabViewItem offset:(NSSize *)offset styleMask:(NSUInteger *)styleMask;
-- (PSMTabBarControl *)tabView:(NSTabView *)aTabView newTabBarForDraggedTabViewItem:(NSTabViewItem *)tabViewItem atPoint:(NSPoint)point;
-- (void)tabView:(NSTabView *)aTabView closeWindowForLastTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//Overflow menu validation
-- (BOOL)tabView:(NSTabView *)aTabView validateOverflowMenuItem:(NSMenuItem *)menuItem forTabViewItem:(NSTabViewItem *)tabViewItem;
-- (void)tabView:(NSTabView *)aTabView tabViewItem:(NSTabViewItem *)tabViewItem isInOverflowMenu:(BOOL)inOverflowMenu;
-
-//tab bar hiding methods
-- (void)tabView:(NSTabView *)aTabView tabBarDidHide:(PSMTabBarControl *)tabBarControl;
-- (void)tabView:(NSTabView *)aTabView tabBarDidUnhide:(PSMTabBarControl *)tabBarControl;
-- (CGFloat)desiredWidthForVerticalTabBar:(PSMTabBarControl *)tabBarControl;
-
-//closing
-- (BOOL)tabView:(NSTabView *)aTabView disableTabCloseForTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//tooltips
-- (NSString *)tabView:(NSTabView *)aTabView toolTipForTabViewItem:(NSTabViewItem *)tabViewItem;
-
-//accessibility
-- (NSString *)accessibilityStringForTabView:(NSTabView *)aTabView objectCount:(NSInteger)objectCount;
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m b/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m
deleted file mode 100644
index cb0e0342c..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m
+++ /dev/null
@@ -1,1995 +0,0 @@
-//
-// PSMTabBarControl.m
-// PSMTabBarControl
-//
-// Created by John Pannell on 10/13/05.
-// Copyright 2005 Positive Spin Media. All rights reserved.
-//
-
-#import <objc/runtime.h>
-
-#import "PSMTabBarControl.h"
-#import "PSMTabBarCell.h"
-#import "PSMOverflowPopUpButton.h"
-#import "PSMRolloverButton.h"
-#import "PSMTabStyle.h"
-#import "PSMUnifiedTabStyle.h"
-#import "PSMTabDragAssistant.h"
-#import "PSMTabBarController.h"
-
-@interface PSMTabBarControl (Private)
-
-// constructor/destructor
-- (void)initAddedProperties;
-
-// accessors
-- (NSEvent *)lastMouseDownEvent;
-- (void)setLastMouseDownEvent:(NSEvent *)event;
-
-// contents
-- (void)addTabViewItem:(NSTabViewItem *)item;
-- (void)removeTabForCell:(PSMTabBarCell *)cell;
-
-// draw
-- (void)update;
-- (void)update:(BOOL)animate;
-- (void)_setupTrackingRectsForCell:(PSMTabBarCell *)cell;
-- (void)_positionOverflowMenu;
-- (void)_checkWindowFrame;
-
-// actions
-- (void)overflowMenuAction:(id)sender;
-- (void)closeTabClick:(id)sender;
-- (void)tabClick:(id)sender;
-- (void)tabNothing:(id)sender;
-
-// notification handlers
-- (void)frameDidChange:(NSNotification *)notification;
-- (void)windowDidMove:(NSNotification *)aNotification;
-- (void)windowDidUpdate:(NSNotification *)notification;
-
-// NSTabView delegate
-- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
-- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem;
-- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem;
-- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)tabView;
-
-// archiving
-- (void)encodeWithCoder:(NSCoder *)aCoder;
-- (id)initWithCoder:(NSCoder *)aDecoder;
-
-// convenience
-- (void)_bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item;
-- (id)cellForPoint:(NSPoint)point cellFrame:(NSRectPointer)outFrame;
-
-- (void)_animateCells:(NSTimer *)timer;
-@end
-
-@implementation PSMTabBarControl
-
-#pragma mark -
-#pragma mark Characteristics
-
-+ (NSBundle *)bundle
-{
- static NSBundle *bundle = nil;
- if(!bundle) {
- bundle = [NSBundle bundleForClass:[PSMTabBarControl class]];
- }
- return bundle;
-}
-
-/*!
- @method availableCellWidth
- @abstract The number of pixels available for cells
- @discussion Calculates the number of pixels available for cells based on margins and the window resize badge.
- @returns Returns the amount of space for cells.
- */
-
-- (CGFloat)availableCellWidth {
- return [self frame].size.width - [style leftMarginForTabBarControl] - [style rightMarginForTabBarControl] - _resizeAreaCompensation;
-}
-
-/*!
- @method genericCellRect
- @abstract The basic rect for a tab cell.
- @discussion Creates a generic frame for a tab cell based on the current control state.
- @returns Returns a basic rect for a tab cell.
- */
-
-- (NSRect)genericCellRect {
- NSRect aRect = [self frame];
- aRect.origin.x = [style leftMarginForTabBarControl];
- aRect.origin.y = 0.0;
- aRect.size.width = [self availableCellWidth];
- aRect.size.height = [style tabCellHeight];
- return aRect;
-}
-
-#pragma mark -
-#pragma mark Constructor/destructor
-
-- (void)initAddedProperties {
- _cells = [[NSMutableArray alloc] initWithCapacity:10];
- _controller = [[PSMTabBarController alloc] initWithTabBarControl:self];
- _animationTimer = nil;
-
- // default config
- _currentStep = kPSMIsNotBeingResized;
- _orientation = PSMTabBarHorizontalOrientation;
- _canCloseOnlyTab = NO;
- _disableTabClose = NO;
- _showAddTabButton = NO;
- _hideForSingleTab = NO;
- _sizeCellsToFit = NO;
- _isHidden = NO;
- _awakenedFromNib = NO;
- _automaticallyAnimates = NO;
- _useOverflowMenu = YES;
- _allowsBackgroundTabClosing = YES;
- _allowsResizing = NO;
- _selectsTabsOnMouseDown = NO;
- _alwaysShowActiveTab = NO;
- _allowsScrubbing = NO;
- _cellMinWidth = 100;
- _cellMaxWidth = 280;
- _cellOptimumWidth = 130;
- _tearOffStyle = PSMTabBarTearOffAlphaWindow;
- style = [[[[self class] defaultStyleClass] alloc] init];
-
- // the overflow button/menu
- NSRect overflowButtonRect = NSMakeRect([self frame].size.width - [style rightMarginForTabBarControl] + 1, 0, [style rightMarginForTabBarControl] - 1, [self frame].size.height);
- _overflowPopUpButton = [[PSMOverflowPopUpButton alloc] initWithFrame:overflowButtonRect pullsDown:YES];
- [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin];
- [_overflowPopUpButton setHidden:YES];
- [self addSubview:_overflowPopUpButton];
- [self _positionOverflowMenu];
-
- // new tab button
- NSRect addTabButtonRect = NSMakeRect([self frame].size.width - [style rightMarginForTabBarControl] + 1, 3.0, 16.0, 16.0);
- _addTabButton = [[PSMRolloverButton alloc] initWithFrame:addTabButtonRect];
- if(_addTabButton) {
- NSImage *newButtonImage = [style addTabButtonImage];
- if(newButtonImage) {
- [_addTabButton setUsualImage:newButtonImage];
- }
- newButtonImage = [style addTabButtonPressedImage];
- if(newButtonImage) {
- [_addTabButton setAlternateImage:newButtonImage];
- }
- newButtonImage = [style addTabButtonRolloverImage];
- if(newButtonImage) {
- [_addTabButton setRolloverImage:newButtonImage];
- }
- [_addTabButton setTitle:@""];
- [_addTabButton setImagePosition:NSImageOnly];
- [_addTabButton setButtonType:NSMomentaryChangeButton];
- [_addTabButton setBordered:NO];
- [_addTabButton setBezelStyle:NSShadowlessSquareBezelStyle];
- [self addSubview:_addTabButton];
-
- if(_showAddTabButton) {
- [_addTabButton setHidden:NO];
- } else {
- [_addTabButton setHidden:YES];
- }
- [_addTabButton setNeedsDisplay:YES];
- }
-}
-
-+ (Class) defaultStyleClass
-{
- return [PSMUnifiedTabStyle class];
-}
-
-- (id)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if(self) {
- // Initialization
- [self initAddedProperties];
- [self registerForDraggedTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil]];
-
- // resize
- [self setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frameDidChange:) name:NSViewFrameDidChangeNotification object:self];
- }
- [self setTarget:self];
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- //stop any animations that may be running
- [_animationTimer invalidate];
- [_animationTimer release]; _animationTimer = nil;
-
- [_showHideAnimationTimer invalidate];
- [_showHideAnimationTimer release]; _showHideAnimationTimer = nil;
-
- //Also unwind the spring, if it's wound.
- [_springTimer invalidate];
- [_springTimer release]; _springTimer = nil;
-
- //unbind all the items to prevent crashing
- //not sure if this is necessary or not
- // http://code.google.com/p/maccode/issues/detail?id=35
- NSEnumerator *enumerator = [[[_cells copy] autorelease] objectEnumerator];
- PSMTabBarCell *nextCell;
- while((nextCell = [enumerator nextObject])) {
- [self removeTabForCell:nextCell];
- }
-
- [_overflowPopUpButton release];
- [_cells release];
- [_controller release];
- [tabView release];
- [_addTabButton release];
- [partnerView release];
- [_lastMouseDownEvent release];
- [style release];
-
- [self unregisterDraggedTypes];
-
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // build cells from existing tab view items
- NSArray *existingItems = [tabView tabViewItems];
- NSEnumerator *e = [existingItems objectEnumerator];
- NSTabViewItem *item;
- while((item = [e nextObject])) {
- if(![[self representedTabViewItems] containsObject:item]) {
- [self addTabViewItem:item];
- }
- }
-}
-
-- (void)viewWillMoveToWindow:(NSWindow *)aWindow {
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
- [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
- [center removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
- [center removeObserver:self name:NSWindowDidUpdateNotification object:nil];
- [center removeObserver:self name:NSWindowDidMoveNotification object:nil];
-
- if(_showHideAnimationTimer) {
- [_showHideAnimationTimer invalidate];
- [_showHideAnimationTimer release]; _showHideAnimationTimer = nil;
- }
-
- if(aWindow) {
- [center addObserver:self selector:@selector(windowStatusDidChange:) name:NSWindowDidBecomeKeyNotification object:aWindow];
- [center addObserver:self selector:@selector(windowStatusDidChange:) name:NSWindowDidResignKeyNotification object:aWindow];
- [center addObserver:self selector:@selector(windowDidUpdate:) name:NSWindowDidUpdateNotification object:aWindow];
- [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:aWindow];
- }
-}
-
-- (void)windowStatusDidChange:(NSNotification *)notification {
- [self setNeedsDisplay:YES];
-}
-
-#pragma mark -
-#pragma mark Accessors
-
-- (NSMutableArray *)cells {
- return _cells;
-}
-
-- (NSEvent *)lastMouseDownEvent {
- return _lastMouseDownEvent;
-}
-
-- (void)setLastMouseDownEvent:(NSEvent *)event {
- [event retain];
- [_lastMouseDownEvent release];
- _lastMouseDownEvent = event;
-}
-
-- (id)delegate {
- return delegate;
-}
-
-- (void)setDelegate:(id)object {
- delegate = object;
-
- NSMutableArray *types = [NSMutableArray arrayWithObject:@"PSMTabBarControlItemPBType"];
-
- //Update the allowed drag types
- if([self delegate] && [[self delegate] respondsToSelector:@selector(allowedDraggedTypesForTabView:)]) {
- [types addObjectsFromArray:[[self delegate] allowedDraggedTypesForTabView:tabView]];
- }
- [self unregisterDraggedTypes];
- [self registerForDraggedTypes:types];
-}
-
-- (NSTabView *)tabView {
- return tabView;
-}
-
-- (void)setTabView:(NSTabView *)view {
- [view retain];
- [tabView release];
- tabView = view;
-}
-
-- (id<PSMTabStyle>)style {
- return style;
-}
-
-- (NSString *)styleName {
- return [style name];
-}
-
-- (void)setStyle:(id <PSMTabStyle>)newStyle {
- if(style != newStyle) {
- [style autorelease];
- style = [newStyle retain];
-
- // restyle add tab button
- if(_addTabButton) {
- NSImage *newButtonImage = [style addTabButtonImage];
- if(newButtonImage) {
- [_addTabButton setUsualImage:newButtonImage];
- }
-
- newButtonImage = [style addTabButtonPressedImage];
- if(newButtonImage) {
- [_addTabButton setAlternateImage:newButtonImage];
- }
-
- newButtonImage = [style addTabButtonRolloverImage];
- if(newButtonImage) {
- [_addTabButton setRolloverImage:newButtonImage];
- }
- }
-
- [self update];
- }
-}
-
-- (void)setStyleNamed:(NSString *)name {
-
- Class styleClass = NSClassFromString( [NSString stringWithFormat: @"PSM%@TabStyle", [name capitalizedString]] );
- if (styleClass == Nil) {
- styleClass = object_getClass([PSMTabBarControl defaultStyleClass]);
- }
-
- id <PSMTabStyle> newStyle = [[styleClass alloc] init];
- [self setStyle:newStyle];
- [newStyle release];
-}
-
-- (PSMTabBarOrientation)orientation {
- return _orientation;
-}
-
-- (void)setOrientation:(PSMTabBarOrientation)value {
- PSMTabBarOrientation lastOrientation = _orientation;
- _orientation = value;
-
- if(_tabBarWidth < 10) {
- _tabBarWidth = 120;
- }
-
- if (lastOrientation != _orientation) {
- [[self style] setOrientation:_orientation];
-
- [self _positionOverflowMenu]; //move the overflow popup button to the right place
- [self update:NO];
- }
-}
-
-- (BOOL)canCloseOnlyTab {
- return _canCloseOnlyTab;
-}
-
-- (void)setCanCloseOnlyTab:(BOOL)value {
- _canCloseOnlyTab = value;
- if([_cells count] == 1) {
- [self update];
- }
-}
-
-- (BOOL)disableTabClose {
- return _disableTabClose;
-}
-
-- (void)setDisableTabClose:(BOOL)value {
- _disableTabClose = value;
- [self update];
-}
-
-- (BOOL)hideForSingleTab {
- return _hideForSingleTab;
-}
-
-- (void)setHideForSingleTab:(BOOL)value {
- _hideForSingleTab = value;
- [self update];
-}
-
-- (BOOL)showAddTabButton {
- return _showAddTabButton;
-}
-
-- (void)setShowAddTabButton:(BOOL)value {
- _showAddTabButton = value;
- if(!NSIsEmptyRect([_controller addButtonRect])) {
- [_addTabButton setFrame:[_controller addButtonRect]];
- }
-
- [_addTabButton setHidden:!_showAddTabButton];
- [_addTabButton setNeedsDisplay:YES];
-
- [self update];
-}
-
-- (NSInteger)cellMinWidth {
- return _cellMinWidth;
-}
-
-- (void)setCellMinWidth:(NSInteger)value {
- _cellMinWidth = value;
- [self update];
-}
-
-- (NSInteger)cellMaxWidth {
- return _cellMaxWidth;
-}
-
-- (void)setCellMaxWidth:(NSInteger)value {
- _cellMaxWidth = value;
- [self update];
-}
-
-- (NSInteger)cellOptimumWidth {
- return _cellOptimumWidth;
-}
-
-- (void)setCellOptimumWidth:(NSInteger)value {
- _cellOptimumWidth = value;
- [self update];
-}
-
-- (BOOL)sizeCellsToFit {
- return _sizeCellsToFit;
-}
-
-- (void)setSizeCellsToFit:(BOOL)value {
- _sizeCellsToFit = value;
- [self update];
-}
-
-- (BOOL)useOverflowMenu {
- return _useOverflowMenu;
-}
-
-- (void)setUseOverflowMenu:(BOOL)value {
- _useOverflowMenu = value;
- [self update];
-}
-
-- (PSMRolloverButton *)addTabButton {
- return _addTabButton;
-}
-
-- (PSMOverflowPopUpButton *)overflowPopUpButton {
- return _overflowPopUpButton;
-}
-
-- (BOOL)allowsBackgroundTabClosing {
- return _allowsBackgroundTabClosing;
-}
-
-- (void)setAllowsBackgroundTabClosing:(BOOL)value {
- _allowsBackgroundTabClosing = value;
-}
-
-- (BOOL)allowsResizing {
- return _allowsResizing;
-}
-
-- (void)setAllowsResizing:(BOOL)value {
- _allowsResizing = value;
-}
-
-- (BOOL)selectsTabsOnMouseDown {
- return _selectsTabsOnMouseDown;
-}
-
-- (void)setSelectsTabsOnMouseDown:(BOOL)value {
- _selectsTabsOnMouseDown = value;
-}
-
-- (BOOL)automaticallyAnimates {
- return _automaticallyAnimates;
-}
-
-- (void)setAutomaticallyAnimates:(BOOL)value {
- _automaticallyAnimates = value;
-}
-
-- (BOOL)alwaysShowActiveTab {
- return _alwaysShowActiveTab;
-}
-
-- (void)setAlwaysShowActiveTab:(BOOL)value {
- _alwaysShowActiveTab = value;
-}
-
-- (BOOL)allowsScrubbing {
- return _allowsScrubbing;
-}
-
-- (void)setAllowsScrubbing:(BOOL)value {
- _allowsScrubbing = value;
-}
-
-- (PSMTabBarTearOffStyle)tearOffStyle {
- return _tearOffStyle;
-}
-
-- (void)setTearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle {
- _tearOffStyle = tearOffStyle;
-}
-
-#pragma mark -
-#pragma mark Functionality
-
-- (void)addTabViewItem:(NSTabViewItem *)item {
- // create cell
- PSMTabBarCell *cell = [[PSMTabBarCell alloc] initWithControlView:self];
- NSRect cellRect, lastCellFrame;
- if([_cells lastObject] != nil) {
- cellRect = lastCellFrame = [[_cells lastObject] frame];
- } else {
- cellRect = lastCellFrame = NSZeroRect;
- }
-
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- cellRect = [self genericCellRect];
- cellRect.size.width = 30;
- cellRect.origin.x = lastCellFrame.origin.x + lastCellFrame.size.width;
- } else {
- cellRect = /*lastCellFrame*/ [self genericCellRect];
- cellRect.size.width = lastCellFrame.size.width;
- cellRect.size.height = 0;
- cellRect.origin.y = lastCellFrame.origin.y + lastCellFrame.size.height;
- }
-
- [cell setRepresentedObject:item];
- [cell setFrame:cellRect];
-
- // bind it up
- [self bindPropertiesForCell:cell andTabViewItem:item];
-
- // add to collection
- [_cells addObject:cell];
- [cell release];
- if([_cells count] == (NSUInteger)[tabView numberOfTabViewItems]) {
- [self update]; // don't update unless all are accounted for!
- }
-}
-
-- (void)removeTabForCell:(PSMTabBarCell *)cell {
- NSTabViewItem *item = [cell representedObject];
-
- // unbind
- [[cell indicator] unbind:@"animate"];
- [[cell indicator] unbind:@"hidden"];
- [cell unbind:@"hasIcon"];
- [cell unbind:@"hasLargeImage"];
- [cell unbind:@"title"];
- [cell unbind:@"count"];
- [cell unbind:@"countColor"];
- [cell unbind:@"isEdited"];
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(isProcessing)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"isProcessing"];
- }
- }
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(icon)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"icon"];
- }
- }
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(objectCount)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"objectCount"];
- }
- }
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(countColor)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"countColor"];
- }
- }
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(largeImage)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"largeImage"];
- }
- }
-
- if([item identifier] != nil) {
- if([[item identifier] respondsToSelector:@selector(isEdited)]) {
- [[item identifier] removeObserver:cell forKeyPath:@"isEdited"];
- }
- }
-
- // stop watching identifier
- [item removeObserver:self forKeyPath:@"identifier"];
-
- // remove indicator
- if([[self subviews] containsObject:[cell indicator]]) {
- [[cell indicator] removeFromSuperview];
- }
- // remove tracking
- [[NSNotificationCenter defaultCenter] removeObserver:cell];
-
- if([cell closeButtonTrackingTag] != 0) {
- [self removeTrackingRect:[cell closeButtonTrackingTag]];
- [cell setCloseButtonTrackingTag:0];
- }
- if([cell cellTrackingTag] != 0) {
- [self removeTrackingRect:[cell cellTrackingTag]];
- [cell setCellTrackingTag:0];
- }
-
- // pull from collection
- [_cells removeObject:cell];
-
- [self update];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- // did the tab's identifier change?
- if([keyPath isEqualToString:@"identifier"]) {
- NSEnumerator *e = [_cells objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- if([cell representedObject] == object) {
- [self _bindPropertiesForCell:cell andTabViewItem:object];
- }
- }
- }
-}
-
-#pragma mark -
-#pragma mark Hide/Show
-
-- (void)hideTabBar:(BOOL)hide animate:(BOOL)animate {
- if(!_awakenedFromNib || (_isHidden && hide) || (!_isHidden && !hide) || (_currentStep != kPSMIsNotBeingResized)) {
- return;
- }
-
- [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
-
- _isHidden = hide;
- _currentStep = 0;
- if(!animate) {
- _currentStep = (NSInteger)kPSMHideAnimationSteps;
- }
-
- if(hide) {
- [_overflowPopUpButton removeFromSuperview];
- [_addTabButton removeFromSuperview];
- } else if(!animate) {
- [self addSubview:_overflowPopUpButton];
- [self addSubview:_addTabButton];
- }
-
- CGFloat partnerOriginalSize, partnerOriginalOrigin, myOriginalSize, myOriginalOrigin, partnerTargetSize, partnerTargetOrigin, myTargetSize, myTargetOrigin;
-
- // target values for partner
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- // current (original) values
- myOriginalSize = [self frame].size.height;
- myOriginalOrigin = [self frame].origin.y;
- if(partnerView) {
- partnerOriginalSize = [partnerView frame].size.height;
- partnerOriginalOrigin = [partnerView frame].origin.y;
- } else {
- partnerOriginalSize = [[self window] frame].size.height;
- partnerOriginalOrigin = [[self window] frame].origin.y;
- }
-
- if(partnerView) {
- // above or below me?
- if((myOriginalOrigin - 22) > partnerOriginalOrigin) {
- // partner is below me
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin + 21;
- myTargetSize = myOriginalSize - 21;
- partnerTargetOrigin = partnerOriginalOrigin;
- partnerTargetSize = partnerOriginalSize + 21;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin - 21;
- myTargetSize = myOriginalSize + 21;
- partnerTargetOrigin = partnerOriginalOrigin;
- partnerTargetSize = partnerOriginalSize - 21;
- }
- } else {
- // partner is above me
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = myOriginalSize - 21;
- partnerTargetOrigin = partnerOriginalOrigin - 21;
- partnerTargetSize = partnerOriginalSize + 21;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = myOriginalSize + 21;
- partnerTargetOrigin = partnerOriginalOrigin + 21;
- partnerTargetSize = partnerOriginalSize - 21;
- }
- }
- } else {
- // for window movement
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = myOriginalSize - 21;
- partnerTargetOrigin = partnerOriginalOrigin + 21;
- partnerTargetSize = partnerOriginalSize - 21;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = myOriginalSize + 21;
- partnerTargetOrigin = partnerOriginalOrigin - 21;
- partnerTargetSize = partnerOriginalSize + 21;
- }
- }
- } else { /* vertical */
- // current (original) values
- myOriginalSize = [self frame].size.width;
- myOriginalOrigin = [self frame].origin.x;
- if(partnerView) {
- partnerOriginalSize = [partnerView frame].size.width;
- partnerOriginalOrigin = [partnerView frame].origin.x;
- } else {
- partnerOriginalSize = [[self window] frame].size.width;
- partnerOriginalOrigin = [[self window] frame].origin.x;
- }
-
- if(partnerView) {
- //to the left or right?
- if(myOriginalOrigin < partnerOriginalOrigin + partnerOriginalSize) {
- // partner is to the left
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = 1;
- partnerTargetOrigin = partnerOriginalOrigin - myOriginalSize + 1;
- partnerTargetSize = partnerOriginalSize + myOriginalSize - 1;
- _tabBarWidth = myOriginalSize;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = myOriginalSize + _tabBarWidth;
- partnerTargetOrigin = partnerOriginalOrigin + _tabBarWidth;
- partnerTargetSize = partnerOriginalSize - _tabBarWidth;
- }
- } else {
- // partner is to the right
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin + myOriginalSize;
- myTargetSize = 1;
- partnerTargetOrigin = partnerOriginalOrigin;
- partnerTargetSize = partnerOriginalSize + myOriginalSize;
- _tabBarWidth = myOriginalSize;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin - _tabBarWidth;
- myTargetSize = myOriginalSize + _tabBarWidth;
- partnerTargetOrigin = partnerOriginalOrigin;
- partnerTargetSize = partnerOriginalSize - _tabBarWidth;
- }
- }
- } else {
- // for window movement
- if(_isHidden) {
- // I'm shrinking
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = 1;
- partnerTargetOrigin = partnerOriginalOrigin + myOriginalSize - 1;
- partnerTargetSize = partnerOriginalSize - myOriginalSize + 1;
- _tabBarWidth = myOriginalSize;
- } else {
- // I'm growing
- myTargetOrigin = myOriginalOrigin;
- myTargetSize = _tabBarWidth;
- partnerTargetOrigin = partnerOriginalOrigin - _tabBarWidth + 1;
- partnerTargetSize = partnerOriginalSize + _tabBarWidth - 1;
- }
- }
-
- if(!_isHidden && [[self delegate] respondsToSelector:@selector(desiredWidthForVerticalTabBar:)]) {
- myTargetSize = [[self delegate] desiredWidthForVerticalTabBar:self];
- }
- }
-
- NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:myOriginalOrigin], @"myOriginalOrigin", [NSNumber numberWithDouble:partnerOriginalOrigin], @"partnerOriginalOrigin", [NSNumber numberWithDouble:myOriginalSize], @"myOriginalSize", [NSNumber numberWithDouble:partnerOriginalSize], @"partnerOriginalSize", [NSNumber numberWithDouble:myTargetOrigin], @"myTargetOrigin", [NSNumber numberWithDouble:partnerTargetOrigin], @"partnerTargetOrigin", [NSNumber numberWithDouble:myTargetSize], @"myTargetSize", [NSNumber numberWithDouble:partnerTargetSize], @"partnerTargetSize", nil];
- if(_showHideAnimationTimer) {
- [_showHideAnimationTimer invalidate];
- [_showHideAnimationTimer release];
- }
- _showHideAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(animateShowHide:) userInfo:userInfo repeats:YES] retain];
-}
-
-- (void)animateShowHide:(NSTimer *)timer {
- // moves the frame of the tab bar and window (or partner view) linearly to hide or show the tab bar
- NSRect myFrame = [self frame];
- NSDictionary *userInfo = [timer userInfo];
- CGFloat myCurrentOrigin = ([[userInfo objectForKey:@"myOriginalOrigin"] doubleValue] + (([[userInfo objectForKey:@"myTargetOrigin"] doubleValue] - [[userInfo objectForKey:@"myOriginalOrigin"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps)));
- CGFloat myCurrentSize = ([[userInfo objectForKey:@"myOriginalSize"] doubleValue] + (([[userInfo objectForKey:@"myTargetSize"] doubleValue] - [[userInfo objectForKey:@"myOriginalSize"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps)));
- CGFloat partnerCurrentOrigin = ([[userInfo objectForKey:@"partnerOriginalOrigin"] doubleValue] + (([[userInfo objectForKey:@"partnerTargetOrigin"] doubleValue] - [[userInfo objectForKey:@"partnerOriginalOrigin"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps)));
- CGFloat partnerCurrentSize = ([[userInfo objectForKey:@"partnerOriginalSize"] doubleValue] + (([[userInfo objectForKey:@"partnerTargetSize"] doubleValue] - [[userInfo objectForKey:@"partnerOriginalSize"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps)));
-
- NSRect myNewFrame;
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- myNewFrame = NSMakeRect(myFrame.origin.x, myCurrentOrigin, myFrame.size.width, myCurrentSize);
- } else {
- myNewFrame = NSMakeRect(myCurrentOrigin, myFrame.origin.y, myCurrentSize, myFrame.size.height);
- }
-
- if(partnerView) {
- // resize self and view
- NSRect resizeRect;
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- resizeRect = NSMakeRect([partnerView frame].origin.x, partnerCurrentOrigin, [partnerView frame].size.width, partnerCurrentSize);
- } else {
- resizeRect = NSMakeRect(partnerCurrentOrigin, [partnerView frame].origin.y, partnerCurrentSize, [partnerView frame].size.height);
- }
- [partnerView setFrame:resizeRect];
- [partnerView setNeedsDisplay:YES];
- [self setFrame:myNewFrame];
- } else {
- // resize self and window
- NSRect resizeRect;
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- resizeRect = NSMakeRect([[self window] frame].origin.x, partnerCurrentOrigin, [[self window] frame].size.width, partnerCurrentSize);
- } else {
- resizeRect = NSMakeRect(partnerCurrentOrigin, [[self window] frame].origin.y, partnerCurrentSize, [[self window] frame].size.height);
- }
- [[self window] setFrame:resizeRect display:YES];
- [self setFrame:myNewFrame];
- }
-
- // next
- _currentStep++;
- if(_currentStep == kPSMHideAnimationSteps + 1) {
- _currentStep = kPSMIsNotBeingResized;
- [self viewDidEndLiveResize];
- [self update:NO];
-
- //send the delegate messages
- if(_isHidden) {
- if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidHide:)]) {
- [[self delegate] tabView:[self tabView] tabBarDidHide:self];
- }
- } else {
- [self addSubview:_overflowPopUpButton];
- [self addSubview:_addTabButton];
-
- if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidUnhide:)]) {
- [[self delegate] tabView:[self tabView] tabBarDidUnhide:self];
- }
- }
-
- [_showHideAnimationTimer invalidate];
- [_showHideAnimationTimer release]; _showHideAnimationTimer = nil;
- }
- [[self window] display];
-}
-
-- (BOOL)isTabBarHidden {
- return _isHidden;
-}
-
-- (BOOL)isAnimating {
- return _animationTimer != nil;
-}
-
-- (id)partnerView {
- return partnerView;
-}
-
-- (void)setPartnerView:(id)view {
- [partnerView release];
- [view retain];
- partnerView = view;
-}
-
-#pragma mark -
-#pragma mark Drawing
-
-- (BOOL)isFlipped {
- return YES;
-}
-
-- (void)drawRect:(NSRect)rect {
- [style drawTabBar:self inRect:rect];
-}
-
-- (void)update {
- [self update:_automaticallyAnimates];
-}
-
-- (void)update:(BOOL)animate {
- // make sure all of our tabs are accounted for before updating
- if((NSUInteger)[[self tabView] numberOfTabViewItems] != [_cells count]) {
- return;
- }
-
- // hide/show? (these return if already in desired state)
- if((_hideForSingleTab) && ([_cells count] <= 1)) {
- [self hideTabBar:YES animate:YES];
- return;
- } else {
- [self hideTabBar:NO animate:YES];
- }
-
- [self removeAllToolTips];
- [_controller layoutCells]; //eventually we should only have to call this when we know something has changed
-
- PSMTabBarCell *currentCell;
-
- NSMenu *overflowMenu = [_controller overflowMenu];
- [_overflowPopUpButton setHidden:(overflowMenu == nil)];
- [_overflowPopUpButton setMenu:overflowMenu];
-
- if(_animationTimer) {
- [_animationTimer invalidate];
- [_animationTimer release]; _animationTimer = nil;
- }
-
- if(animate) {
- NSMutableArray *targetFrames = [NSMutableArray arrayWithCapacity:[_cells count]];
-
- for(NSUInteger i = 0; i < [_cells count]; i++) {
- currentCell = [_cells objectAtIndex:i];
-
- //we're going from NSRect -> NSValue -> NSRect -> NSValue here - oh well
- [targetFrames addObject:[NSValue valueWithRect:[_controller cellFrameAtIndex:i]]];
- }
-
- [_addTabButton setHidden:!_showAddTabButton];
-
- NSAnimation *animation = [[NSAnimation alloc] initWithDuration:0.50 animationCurve:NSAnimationEaseInOut];
- [animation setAnimationBlockingMode:NSAnimationNonblocking];
- [animation startAnimation];
- _animationTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0
- target:self
- selector:@selector(_animateCells:)
- userInfo:[NSArray arrayWithObjects:targetFrames, animation, nil]
- repeats:YES] retain];
- [animation release];
- [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode];
- [self _animateCells:_animationTimer];
- } else {
- for(NSUInteger i = 0; i < [_cells count]; i++) {
- currentCell = [_cells objectAtIndex:i];
- [currentCell setFrame:[_controller cellFrameAtIndex:i]];
-
- if(![currentCell isInOverflowMenu]) {
- [self _setupTrackingRectsForCell:currentCell];
- }
- }
-
- [_addTabButton setFrame:[_controller addButtonRect]];
- [_addTabButton setHidden:!_showAddTabButton];
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)_animateCells:(NSTimer *)timer {
- NSAnimation *animation = [[timer userInfo] objectAtIndex:1];
- NSArray *targetFrames = [[timer userInfo] objectAtIndex:0];
- PSMTabBarCell *currentCell;
- NSUInteger cellCount = [_cells count];
-
- if((cellCount > 0) && [animation isAnimating]) {
- //compare our target position with the current position and move towards the target
- for(NSUInteger i = 0; i < [targetFrames count] && i < cellCount; i++) {
- currentCell = [_cells objectAtIndex:i];
- NSRect cellFrame = [currentCell frame], targetFrame = [[targetFrames objectAtIndex:i] rectValue];
- CGFloat sizeChange;
- CGFloat originChange;
-
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- sizeChange = (targetFrame.size.width - cellFrame.size.width) * [animation currentProgress];
- originChange = (targetFrame.origin.x - cellFrame.origin.x) * [animation currentProgress];
- cellFrame.size.width += sizeChange;
- cellFrame.origin.x += originChange;
- } else {
- sizeChange = (targetFrame.size.height - cellFrame.size.height) * [animation currentProgress];
- originChange = (targetFrame.origin.y - cellFrame.origin.y) * [animation currentProgress];
- cellFrame.size.height += sizeChange;
- cellFrame.origin.y += originChange;
- }
-
- [currentCell setFrame:cellFrame];
-
- //highlight the cell if the mouse is over it
- NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil];
- NSRect closeRect = [currentCell closeButtonRectForFrame:cellFrame];
- [currentCell setHighlighted:NSMouseInRect(mousePoint, cellFrame, [self isFlipped])];
- [currentCell setCloseButtonOver:NSMouseInRect(mousePoint, closeRect, [self isFlipped])];
- }
-
- if(_showAddTabButton) {
- //animate the add tab button
- NSRect target = [_controller addButtonRect], frame = [_addTabButton frame];
- frame.origin.x += (target.origin.x - frame.origin.x) * [animation currentProgress];
- [_addTabButton setFrame:frame];
- }
- } else {
- //put all the cells where they should be in their final position
- if(cellCount > 0) {
- for(NSUInteger i = 0; i < [targetFrames count] && i < cellCount; i++) {
- PSMTabBarCell *currentCell = [_cells objectAtIndex:i];
- NSRect cellFrame = [currentCell frame], targetFrame = [[targetFrames objectAtIndex:i] rectValue];
-
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- cellFrame.size.width = targetFrame.size.width;
- cellFrame.origin.x = targetFrame.origin.x;
- } else {
- cellFrame.size.height = targetFrame.size.height;
- cellFrame.origin.y = targetFrame.origin.y;
- }
-
- [currentCell setFrame:cellFrame];
-
- //highlight the cell if the mouse is over it
- NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil];
- NSRect closeRect = [currentCell closeButtonRectForFrame:cellFrame];
- [currentCell setHighlighted:NSMouseInRect(mousePoint, cellFrame, [self isFlipped])];
- [currentCell setCloseButtonOver:NSMouseInRect(mousePoint, closeRect, [self isFlipped])];
- }
- }
-
- //set the frame for the add tab button
- if(_showAddTabButton) {
- NSRect frame = [_addTabButton frame];
- frame.origin.x = [_controller addButtonRect].origin.x;
- [_addTabButton setFrame:frame];
- }
-
- [_animationTimer invalidate];
- [_animationTimer release]; _animationTimer = nil;
-
- for(NSUInteger i = 0; i < cellCount; i++) {
- currentCell = [_cells objectAtIndex:i];
-
- //we've hit the cells that are in overflow, stop setting up tracking rects
- if([currentCell isInOverflowMenu]) {
- break;
- }
-
- [self _setupTrackingRectsForCell:currentCell];
- }
- }
-
- [self setNeedsDisplay:YES];
-}
-
-- (void)_setupTrackingRectsForCell:(PSMTabBarCell *)cell {
- NSInteger tag, index = [_cells indexOfObject:cell];
- NSRect cellTrackingRect = [_controller cellTrackingRectAtIndex:index];
- NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil];
- BOOL mouseInCell = NSMouseInRect(mousePoint, cellTrackingRect, [self isFlipped]);
-
- //set the cell tracking rect
- [self removeTrackingRect:[cell cellTrackingTag]];
- tag = [self addTrackingRect:cellTrackingRect owner:cell userData:nil assumeInside:mouseInCell];
- [cell setCellTrackingTag:tag];
- [cell setHighlighted:mouseInCell];
-
- if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
- NSRect closeRect = [_controller closeButtonTrackingRectAtIndex:index];
- BOOL mouseInCloseRect = NSMouseInRect(mousePoint, closeRect, [self isFlipped]);
-
- //set the close button tracking rect
- [self removeTrackingRect:[cell closeButtonTrackingTag]];
- tag = [self addTrackingRect:closeRect owner:cell userData:nil assumeInside:mouseInCloseRect];
- [cell setCloseButtonTrackingTag:tag];
-
- [cell setCloseButtonOver:mouseInCloseRect];
- }
-
- //set the tooltip tracking rect
- [self addToolTipRect:[cell frame] owner:self userData:nil];
-}
-
-- (void)_positionOverflowMenu {
- NSRect cellRect, frame = [self frame];
- cellRect.size.height = [style tabCellHeight];
- cellRect.size.width = [style rightMarginForTabBarControl];
-
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- cellRect.origin.y = 0;
- cellRect.origin.x = frame.size.width - [style rightMarginForTabBarControl] + (_resizeAreaCompensation ? -(_resizeAreaCompensation - 1) : 1);
- [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin];
- } else {
- cellRect.origin.x = 0;
- cellRect.origin.y = frame.size.height - [style tabCellHeight];
- cellRect.size.width = frame.size.width;
- [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin | NSViewMinYMargin];
- }
-
- [_overflowPopUpButton setFrame:cellRect];
-}
-
-- (void)_checkWindowFrame {
- //figure out if the new frame puts the control in the way of the resize widget
- NSWindow *window = [self window];
-
- if(window) {
- NSRect resizeWidgetFrame = [[window contentView] frame];
- resizeWidgetFrame.origin.x += resizeWidgetFrame.size.width - 22;
- resizeWidgetFrame.size.width = 22;
- resizeWidgetFrame.size.height = 22;
-
- if([window showsResizeIndicator] && NSIntersectsRect([self frame], resizeWidgetFrame)) {
- //the resize widgets are larger on metal windows
- _resizeAreaCompensation = [window styleMask] & NSTexturedBackgroundWindowMask ? 20 : 8;
- } else {
- _resizeAreaCompensation = 0;
- }
-
- [self _positionOverflowMenu];
- }
-}
-
-#pragma mark -
-#pragma mark Mouse Tracking
-
-- (BOOL)mouseDownCanMoveWindow {
- return NO;
-}
-
-- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
- return YES;
-}
-
-- (void)mouseDown:(NSEvent *)theEvent {
- _didDrag = NO;
-
- // keep for dragging
- [self setLastMouseDownEvent:theEvent];
- // what cell?
- NSPoint mousePt = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- NSRect frame = [self frame];
-
- if([self orientation] == PSMTabBarVerticalOrientation && [self allowsResizing] && partnerView && (mousePt.x > frame.size.width - 3)) {
- _resizing = YES;
- }
-
- NSRect cellFrame;
- PSMTabBarCell *cell = [self cellForPoint:mousePt cellFrame:&cellFrame];
- if(cell) {
- BOOL overClose = NSMouseInRect(mousePt, [cell closeButtonRectForFrame:cellFrame], [self isFlipped]);
- if(overClose &&
- ![self disableTabClose] &&
- ![cell isCloseButtonSuppressed] &&
- ([self allowsBackgroundTabClosing] || [[cell representedObject] isEqualTo:[tabView selectedTabViewItem]] || [theEvent modifierFlags] & NSCommandKeyMask)) {
- [cell setCloseButtonOver:NO];
- [cell setCloseButtonPressed:YES];
- _closeClicked = YES;
- } else {
- [cell setCloseButtonPressed:NO];
- if(_selectsTabsOnMouseDown) {
- [self performSelector:@selector(tabClick:) withObject:cell];
- }
- }
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent {
- if([self lastMouseDownEvent] == nil) {
- return;
- }
-
- NSPoint currentPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
-
- if(_resizing) {
- NSRect frame = [self frame];
- CGFloat resizeAmount = [theEvent deltaX];
- if((currentPoint.x > frame.size.width && resizeAmount > 0) || (currentPoint.x < frame.size.width && resizeAmount < 0)) {
- [[NSCursor resizeLeftRightCursor] push];
-
- NSRect partnerFrame = [partnerView frame];
-
- //do some bounds checking
- if((frame.size.width + resizeAmount > [self cellMinWidth]) && (frame.size.width + resizeAmount < [self cellMaxWidth])) {
- frame.size.width += resizeAmount;
- partnerFrame.size.width -= resizeAmount;
- partnerFrame.origin.x += resizeAmount;
-
- [self setFrame:frame];
- [partnerView setFrame:partnerFrame];
- [[self superview] setNeedsDisplay:YES];
- }
- }
- return;
- }
-
- NSRect cellFrame;
- NSPoint trackingStartPoint = [self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil];
- PSMTabBarCell *cell = [self cellForPoint:trackingStartPoint cellFrame:&cellFrame];
- if(cell) {
- //check to see if the close button was the target in the clicked cell
- //highlight/unhighlight the close button as necessary
- NSRect iconRect = [cell closeButtonRectForFrame:cellFrame];
-
- if(_closeClicked && NSMouseInRect(trackingStartPoint, iconRect, [self isFlipped]) &&
- ([self allowsBackgroundTabClosing] || [[cell representedObject] isEqualTo:[tabView selectedTabViewItem]])) {
- [cell setCloseButtonPressed:NSMouseInRect(currentPoint, iconRect, [self isFlipped])];
- [self setNeedsDisplay:YES];
- return;
- }
-
- CGFloat dx = fabs(currentPoint.x - trackingStartPoint.x);
- CGFloat dy = fabs(currentPoint.y - trackingStartPoint.y);
- CGFloat distance = sqrt(dx * dx + dy * dy);
-
- if(distance >= 10 && !_didDrag && ![[PSMTabDragAssistant sharedDragAssistant] isDragging] &&
- [self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDragTabViewItem:fromTabBar:)] &&
- [[self delegate] tabView:tabView shouldDragTabViewItem:[cell representedObject] fromTabBar:self]) {
- _didDrag = YES;
- [[PSMTabDragAssistant sharedDragAssistant] startDraggingCell:cell fromTabBar:self withMouseDownEvent:[self lastMouseDownEvent]];
- }
- }
-}
-
-- (void)mouseUp:(NSEvent *)theEvent {
- if(_resizing) {
- _resizing = NO;
- [[NSCursor arrowCursor] set];
- } else {
- // what cell?
- NSPoint mousePt = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- NSRect cellFrame, mouseDownCellFrame;
- PSMTabBarCell *cell = [self cellForPoint:mousePt cellFrame:&cellFrame];
- PSMTabBarCell *mouseDownCell = [self cellForPoint:[self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil] cellFrame:&mouseDownCellFrame];
- if(cell) {
- NSPoint trackingStartPoint = [self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil];
- NSRect iconRect = [mouseDownCell closeButtonRectForFrame:mouseDownCellFrame];
-
- if((NSMouseInRect(mousePt, iconRect, [self isFlipped])) && ![self disableTabClose] && ![cell isCloseButtonSuppressed] && [mouseDownCell closeButtonPressed]) {
- if(([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0) {
- //If the user is holding Option, close all other tabs
- NSEnumerator *enumerator = [[[[self cells] copy] autorelease] objectEnumerator];
- PSMTabBarCell *otherCell;
-
- while((otherCell = [enumerator nextObject])) {
- if(otherCell != cell) {
- [self performSelector:@selector(closeTabClick:) withObject:otherCell];
- }
- }
-
- //Fix the close button for the clicked tab not to be pressed
- [cell setCloseButtonPressed:NO];
- } else {
- //Otherwise, close this tab
- [self performSelector:@selector(closeTabClick:) withObject:cell];
- }
- } else if(NSMouseInRect(mousePt, mouseDownCellFrame, [self isFlipped]) &&
- (!NSMouseInRect(trackingStartPoint, [cell closeButtonRectForFrame:cellFrame], [self isFlipped]) || ![self allowsBackgroundTabClosing] || [self disableTabClose])) {
- [mouseDownCell setCloseButtonPressed:NO];
- // If -[self selectsTabsOnMouseDown] is TRUE, we already performed tabClick: on mouseDown.
- if(![self selectsTabsOnMouseDown]) {
- [self performSelector:@selector(tabClick:) withObject:cell];
- }
- } else {
- [mouseDownCell setCloseButtonPressed:NO];
- [self performSelector:@selector(tabNothing:) withObject:cell];
- }
- }
-
- _closeClicked = NO;
- }
-}
-
-- (NSMenu *)menuForEvent:(NSEvent *)event {
- NSMenu *menu = nil;
- NSTabViewItem *item = [[self cellForPoint:[self convertPoint:[event locationInWindow] fromView:nil] cellFrame:nil] representedObject];
-
- if(item && [[self delegate] respondsToSelector:@selector(tabView:menuForTabViewItem:)]) {
- menu = [[self delegate] tabView:tabView menuForTabViewItem:item];
- }
- return menu;
-}
-
-#pragma mark -
-#pragma mark Drag and Drop
-
-- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
- return YES;
-}
-
-// NSDraggingSource
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- return(isLocal ? NSDragOperationMove : NSDragOperationNone);
-}
-
-- (BOOL)ignoreModifierKeysWhileDragging {
- return YES;
-}
-
-- (void)draggedImage:(NSImage *)anImage beganAt:(NSPoint)screenPoint {
- [[PSMTabDragAssistant sharedDragAssistant] draggingBeganAt:screenPoint];
-}
-
-- (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint {
- [[PSMTabDragAssistant sharedDragAssistant] draggingMovedTo:screenPoint];
-}
-
-// NSDraggingDestination
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
- if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) {
- if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] &&
- ![[self delegate] tabView:[[sender draggingSource] tabView] shouldDropTabViewItem:[[[PSMTabDragAssistant sharedDragAssistant] draggedCell] representedObject] inTabBar:self]) {
- return NSDragOperationNone;
- }
-
- [[PSMTabDragAssistant sharedDragAssistant] draggingEnteredTabBar:self atPoint:[self convertPoint:[sender draggingLocation] fromView:nil]];
- return NSDragOperationMove;
- }
-
- return NSDragOperationNone;
-}
-
-- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender {
- PSMTabBarCell *cell = [self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil];
-
- if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) {
- if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] &&
- ![[self delegate] tabView:[[sender draggingSource] tabView] shouldDropTabViewItem:[[[PSMTabDragAssistant sharedDragAssistant] draggedCell] representedObject] inTabBar:self]) {
- return NSDragOperationNone;
- }
-
- [[PSMTabDragAssistant sharedDragAssistant] draggingUpdatedInTabBar:self atPoint:[self convertPoint:[sender draggingLocation] fromView:nil]];
- return NSDragOperationMove;
- } else if(cell) {
- //something that was accepted by the delegate was dragged on
-
- //Test for the space bar (the skip-the-delay key).
- /*enum { virtualKeycodeForSpace = 49 }; //Source: IM:Tx (Fig. C-2)
- union {
- KeyMap keymap;
- char bits[16];
- } keymap;
- GetKeys(keymap.keymap);
- if ((GetCurrentEventKeyModifiers() == 0) && bit_test(keymap.bits, virtualKeycodeForSpace)) {
- //The user pressed the space bar. This skips the delay; the user wants to pop the spring on this tab *now*.
-
- //For some reason, it crashes if I call -fire here. I don't know why. It doesn't crash if I simply set the fire date to now.
- [_springTimer setFireDate:[NSDate date]];
- } else {*/
- //Wind the spring for a spring-loaded drop.
- //The delay time comes from Finder's defaults, which specifies it in milliseconds.
- //If the delegate can't handle our spring-loaded drop, we'll abort it when the timer fires. See fireSpring:. This is simpler than constantly (checking for spring-loaded awareness and tearing down/rebuilding the timer) at every delegate change.
-
- //If the user has dragged to a different tab, reset the timer.
- if(_tabViewItemWithSpring != [cell representedObject]) {
- [_springTimer invalidate];
- [_springTimer release]; _springTimer = nil;
- _tabViewItemWithSpring = [cell representedObject];
- }
- if(!_springTimer) {
- //Finder's default delay time, as of Tiger, is 668 ms. If the user has never changed it, there's no setting in its defaults, so we default to that amount.
- NSNumber *delayNumber = [(NSNumber *)CFPreferencesCopyAppValue((CFStringRef)@"SpringingDelayMilliseconds", (CFStringRef)@"com.apple.finder") autorelease];
- NSTimeInterval delaySeconds = delayNumber ?[delayNumber doubleValue] / 1000.0 : 0.668;
- _springTimer = [[NSTimer scheduledTimerWithTimeInterval:delaySeconds
- target:self
- selector:@selector(fireSpring:)
- userInfo:sender
- repeats:NO] retain];
- }
- return NSDragOperationCopy;
- }
-
- return NSDragOperationNone;
-}
-
-- (void)draggingExited:(id <NSDraggingInfo>)sender {
- [_springTimer invalidate];
- [_springTimer release]; _springTimer = nil;
-
- [[PSMTabDragAssistant sharedDragAssistant] draggingExitedTabBar:self];
-}
-
-- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
- //validate the drag operation only if there's a valid tab bar to drop into
- return [[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] == NSNotFound ||
- [[PSMTabDragAssistant sharedDragAssistant] destinationTabBar] != nil;
-}
-
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
- if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) {
- [[PSMTabDragAssistant sharedDragAssistant] performDragOperation];
- } else if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:acceptedDraggingInfo:onTabViewItem:)]) {
- //forward the drop to the delegate
- [[self delegate] tabView:tabView acceptedDraggingInfo:sender onTabViewItem:[[self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil] representedObject]];
- }
- return YES;
-}
-
-- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation {
- [[PSMTabDragAssistant sharedDragAssistant] draggedImageEndedAt:aPoint operation:operation];
-}
-
-- (void)concludeDragOperation:(id <NSDraggingInfo>)sender {
-}
-
-#pragma mark -
-#pragma mark Spring-loading
-
-- (void)fireSpring:(NSTimer *)timer {
- NSAssert1(timer == _springTimer, @"Spring fired by unrecognized timer %@", timer);
-
- id <NSDraggingInfo> sender = [timer userInfo];
- PSMTabBarCell *cell = [self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil];
- [tabView selectTabViewItem:[cell representedObject]];
-
- _tabViewItemWithSpring = nil;
- [_springTimer invalidate];
- [_springTimer release]; _springTimer = nil;
-}
-
-#pragma mark -
-#pragma mark Actions
-
-- (void)overflowMenuAction:(id)sender {
- NSTabViewItem *tabViewItem = (NSTabViewItem *)[sender representedObject];
- [tabView selectTabViewItem:tabViewItem];
-}
-
-- (void)closeTabClick:(id)sender {
- NSTabViewItem *item = [sender representedObject];
- [sender retain];
- if(([_cells count] == 1) && (![self canCloseOnlyTab])) {
- return;
- }
-
- if([[self delegate] respondsToSelector:@selector(tabView:shouldCloseTabViewItem:)]) {
- if(![[self delegate] tabView:tabView shouldCloseTabViewItem:item]) {
- // fix mouse downed close button
- [sender setCloseButtonPressed:NO];
- return;
- }
- }
-
- [item retain];
-
- [tabView removeTabViewItem:item];
- [item release];
- [sender release];
-}
-
-- (void)tabClick:(id)sender {
- [tabView selectTabViewItem:[sender representedObject]];
-}
-
-- (void)tabNothing:(id)sender {
- //[self update]; // takes care of highlighting based on state
-}
-
-- (void)frameDidChange:(NSNotification *)notification {
- [self _checkWindowFrame];
-
- // trying to address the drawing artifacts for the progress indicators - hackery follows
- // this one fixes the "blanking" effect when the control hides and shows itself
- NSEnumerator *e = [_cells objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- [[cell indicator] stopAnimation:self];
-
- [[cell indicator] performSelector:@selector(startAnimation:)
- withObject:nil
- afterDelay:0];
- }
-
- [self update:NO];
-}
-
-- (void)viewDidMoveToWindow {
- [self _checkWindowFrame];
-}
-
-- (void)viewWillStartLiveResize {
- NSEnumerator *e = [_cells objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- [[cell indicator] stopAnimation:self];
- }
- [self setNeedsDisplay:YES];
-}
-
--(void)viewDidEndLiveResize {
- NSEnumerator *e = [_cells objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- [[cell indicator] startAnimation:self];
- }
-
- [self _checkWindowFrame];
- [self update:NO];
-}
-
-- (void)resetCursorRects {
- [super resetCursorRects];
- if([self orientation] == PSMTabBarVerticalOrientation) {
- NSRect frame = [self frame];
- [self addCursorRect:NSMakeRect(frame.size.width - 2, 0, 2, frame.size.height) cursor:[NSCursor resizeLeftRightCursor]];
- }
-}
-
-- (void)windowDidMove:(NSNotification *)aNotification {
- [self setNeedsDisplay:YES];
-}
-
-- (void)windowDidUpdate:(NSNotification *)notification {
- // hide? must readjust things if I'm not supposed to be showing
- // this block of code only runs when the app launches
- if([self hideForSingleTab] && ([_cells count] <= 1) && !_awakenedFromNib) {
- // must adjust frames now before display
- NSRect myFrame = [self frame];
- if([self orientation] == PSMTabBarHorizontalOrientation) {
- if(partnerView) {
- NSRect partnerFrame = [partnerView frame];
- // above or below me?
- if(myFrame.origin.y - 22 > [partnerView frame].origin.y) {
- // partner is below me
- [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y + 21, myFrame.size.width, myFrame.size.height - 21)];
- [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y, partnerFrame.size.width, partnerFrame.size.height + 21)];
- } else {
- // partner is above me
- [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, myFrame.size.width, myFrame.size.height - 21)];
- [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y - 21, partnerFrame.size.width, partnerFrame.size.height + 21)];
- }
- [partnerView setNeedsDisplay:YES];
- [self setNeedsDisplay:YES];
- } else {
- // for window movement
- NSRect windowFrame = [[self window] frame];
- [[self window] setFrame:NSMakeRect(windowFrame.origin.x, windowFrame.origin.y + 21, windowFrame.size.width, windowFrame.size.height - 21) display:YES];
- [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, myFrame.size.width, myFrame.size.height - 21)];
- }
- } else {
- if(partnerView) {
- NSRect partnerFrame = [partnerView frame];
- //to the left or right?
- if(myFrame.origin.x < [partnerView frame].origin.x) {
- // partner is to the left
- [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, 1, myFrame.size.height)];
- [partnerView setFrame:NSMakeRect(partnerFrame.origin.x - myFrame.size.width + 1, partnerFrame.origin.y, partnerFrame.size.width + myFrame.size.width - 1, partnerFrame.size.height)];
- } else {
- // partner to the right
- [self setFrame:NSMakeRect(myFrame.origin.x + myFrame.size.width, myFrame.origin.y, 1, myFrame.size.height)];
- [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y, partnerFrame.size.width + myFrame.size.width, partnerFrame.size.height)];
- }
- _tabBarWidth = myFrame.size.width;
- [partnerView setNeedsDisplay:YES];
- [self setNeedsDisplay:YES];
- } else {
- // for window movement
- NSRect windowFrame = [[self window] frame];
- [[self window] setFrame:NSMakeRect(windowFrame.origin.x + myFrame.size.width - 1, windowFrame.origin.y, windowFrame.size.width - myFrame.size.width + 1, windowFrame.size.height) display:YES];
- [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, 1, myFrame.size.height)];
- }
- }
-
- _isHidden = YES;
-
- if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidHide:)]) {
- [[self delegate] tabView:[self tabView] tabBarDidHide:self];
- }
- }
-
- _awakenedFromNib = YES;
- [self setNeedsDisplay:YES];
-
- //we only need to do this once
- [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidUpdateNotification object:nil];
-}
-
-#pragma mark -
-#pragma mark Menu Validation
-
-- (BOOL)validateMenuItem:(NSMenuItem *)sender {
- [sender setState:([[sender representedObject] isEqualTo:[tabView selectedTabViewItem]]) ? NSOnState : NSOffState];
-
- return [[self delegate] respondsToSelector:@selector(tabView:validateOverflowMenuItem:forTabViewItem:)] ?
- [[self delegate] tabView:[self tabView] validateOverflowMenuItem:sender forTabViewItem:[sender representedObject]] : YES;
-}
-
-#pragma mark -
-#pragma mark NSTabView Delegate
-
-- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem {
- // here's a weird one - this message is sent before the "tabViewDidChangeNumberOfTabViewItems"
- // message, thus I can end up updating when there are no cells, if no tabs were (yet) present
- NSUInteger tabIndex = [aTabView indexOfTabViewItem:tabViewItem];
-
- if([_cells count] > 0 && tabIndex < [_cells count]) {
- PSMTabBarCell *thisCell = [_cells objectAtIndex:tabIndex];
- if(_alwaysShowActiveTab && [thisCell isInOverflowMenu]) {
- //temporarily disable the delegate in order to move the tab to a different index
- id tempDelegate = [aTabView delegate];
- [aTabView setDelegate:nil];
-
- // move it all around first
- [tabViewItem retain];
- [thisCell retain];
- [aTabView removeTabViewItem:tabViewItem];
- [aTabView insertTabViewItem:tabViewItem atIndex:0];
- [_cells removeObjectAtIndex:tabIndex];
- [_cells insertObject:thisCell atIndex:0];
- [thisCell setIsInOverflowMenu:NO]; //very important else we get a fun recursive loop going
- [[_cells objectAtIndex:[_cells count] - 1] setIsInOverflowMenu:YES]; //these 2 lines are pretty uncool and this logic needs to be updated
- [thisCell release];
- [tabViewItem release];
-
- [aTabView setDelegate:tempDelegate];
-
- //reset the selection since removing it changed the selection
- [aTabView selectTabViewItem:tabViewItem];
-
- [self update];
- } else {
- [_controller setSelectedCell:thisCell];
- [self setNeedsDisplay:YES];
- }
- }
-
- if([[self delegate] respondsToSelector:@selector(tabView:didSelectTabViewItem:)]) {
- [[self delegate] performSelector:@selector(tabView:didSelectTabViewItem:) withObject:aTabView withObject:tabViewItem];
- }
-}
-
-- (BOOL)tabView:(NSTabView *)aTabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem {
- if([[self delegate] respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) {
- return [[self delegate] tabView:aTabView shouldSelectTabViewItem:tabViewItem];
- } else {
- return YES;
- }
-}
-- (void)tabView:(NSTabView *)aTabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem {
- if([[self delegate] respondsToSelector:@selector(tabView:willSelectTabViewItem:)]) {
- [[self delegate] performSelector:@selector(tabView:willSelectTabViewItem:) withObject:aTabView withObject:tabViewItem];
- }
-}
-
-- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView {
- NSArray *tabItems = [tabView tabViewItems];
- // go through cells, remove any whose representedObjects are not in [tabView tabViewItems]
- NSEnumerator *e = [[[_cells copy] autorelease] objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- //remove the observer binding
- if([cell representedObject] && ![tabItems containsObject:[cell representedObject]]) {
- if([[self delegate] respondsToSelector:@selector(tabView:didCloseTabViewItem:)]) {
- [[self delegate] tabView:aTabView didCloseTabViewItem:[cell representedObject]];
- }
-
- [self removeTabForCell:cell];
- }
- }
-
- // go through tab view items, add cell for any not present
- NSMutableArray *cellItems = [self representedTabViewItems];
- NSEnumerator *ex = [tabItems objectEnumerator];
- NSTabViewItem *item;
- while((item = [ex nextObject])) {
- if(![cellItems containsObject:item]) {
- [self addTabViewItem:item];
- }
- }
-
- // pass along for other delegate responses
- if([[self delegate] respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)]) {
- [[self delegate] performSelector:@selector(tabViewDidChangeNumberOfTabViewItems:) withObject:aTabView];
- }
-
- // reset cursor tracking for the add tab button if one exists
- if([self addTabButton]) {
- [[self addTabButton] resetCursorRects];
- }
-}
-
-#pragma mark -
-#pragma mark Tooltips
-
-- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData {
- if([[self delegate] respondsToSelector:@selector(tabView:toolTipForTabViewItem:)]) {
- return [[self delegate] tabView:[self tabView] toolTipForTabViewItem:[[self cellForPoint:point cellFrame:nil] representedObject]];
- }
- return nil;
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder
-{
- [super encodeWithCoder:aCoder];
- if ([aCoder allowsKeyedCoding]) {
- [aCoder encodeObject:_cells forKey:@"PSMcells"];
- [aCoder encodeObject:tabView forKey:@"PSMtabView"];
- [aCoder encodeObject:_overflowPopUpButton forKey:@"PSMoverflowPopUpButton"];
- [aCoder encodeObject:_addTabButton forKey:@"PSMaddTabButton"];
- [aCoder encodeObject:style forKey:@"PSMstyle"];
- [aCoder encodeInteger:_orientation forKey:@"PSMorientation"];
- [aCoder encodeBool:_canCloseOnlyTab forKey:@"PSMcanCloseOnlyTab"];
- [aCoder encodeBool:_disableTabClose forKey:@"PSMdisableTabClose"];
- [aCoder encodeBool:_hideForSingleTab forKey:@"PSMhideForSingleTab"];
- [aCoder encodeBool:_allowsBackgroundTabClosing forKey:@"PSMallowsBackgroundTabClosing"];
- [aCoder encodeBool:_allowsResizing forKey:@"PSMallowsResizing"];
- [aCoder encodeBool:_selectsTabsOnMouseDown forKey:@"PSMselectsTabsOnMouseDown"];
- [aCoder encodeBool:_showAddTabButton forKey:@"PSMshowAddTabButton"];
- [aCoder encodeBool:_sizeCellsToFit forKey:@"PSMsizeCellsToFit"];
- [aCoder encodeInteger:_cellMinWidth forKey:@"PSMcellMinWidth"];
- [aCoder encodeInteger:_cellMaxWidth forKey:@"PSMcellMaxWidth"];
- [aCoder encodeInteger:_cellOptimumWidth forKey:@"PSMcellOptimumWidth"];
- [aCoder encodeInteger:_currentStep forKey:@"PSMcurrentStep"];
- [aCoder encodeBool:_isHidden forKey:@"PSMisHidden"];
- [aCoder encodeObject:partnerView forKey:@"PSMpartnerView"];
- [aCoder encodeBool:_awakenedFromNib forKey:@"PSMawakenedFromNib"];
- [aCoder encodeObject:_lastMouseDownEvent forKey:@"PSMlastMouseDownEvent"];
- [aCoder encodeObject:delegate forKey:@"PSMdelegate"];
- [aCoder encodeBool:_useOverflowMenu forKey:@"PSMuseOverflowMenu"];
- [aCoder encodeBool:_automaticallyAnimates forKey:@"PSMautomaticallyAnimates"];
- [aCoder encodeBool:_alwaysShowActiveTab forKey:@"PSMalwaysShowActiveTab"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder
-{
- self = [super initWithCoder:aDecoder];
- if (self) {
- // Initialization
- [self initAddedProperties];
- [self registerForDraggedTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil]];
-
- // resize
- [self setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frameDidChange:) name:NSViewFrameDidChangeNotification object:self];
- if ([aDecoder allowsKeyedCoding]) {
- _cells = [[aDecoder decodeObjectForKey:@"PSMcells"] retain];
- tabView = [[aDecoder decodeObjectForKey:@"PSMtabView"] retain];
- _overflowPopUpButton = [[aDecoder decodeObjectForKey:@"PSMoverflowPopUpButton"] retain];
- _addTabButton = [[aDecoder decodeObjectForKey:@"PSMaddTabButton"] retain];
- style = [[aDecoder decodeObjectForKey:@"PSMstyle"] retain];
- _orientation = (PSMTabBarOrientation)[aDecoder decodeIntegerForKey:@"PSMorientation"];
- _canCloseOnlyTab = [aDecoder decodeBoolForKey:@"PSMcanCloseOnlyTab"];
- _disableTabClose = [aDecoder decodeBoolForKey:@"PSMdisableTabClose"];
- _hideForSingleTab = [aDecoder decodeBoolForKey:@"PSMhideForSingleTab"];
- _allowsBackgroundTabClosing = [aDecoder decodeBoolForKey:@"PSMallowsBackgroundTabClosing"];
- _allowsResizing = [aDecoder decodeBoolForKey:@"PSMallowsResizing"];
- _selectsTabsOnMouseDown = [aDecoder decodeBoolForKey:@"PSMselectsTabsOnMouseDown"];
- _showAddTabButton = [aDecoder decodeBoolForKey:@"PSMshowAddTabButton"];
- _sizeCellsToFit = [aDecoder decodeBoolForKey:@"PSMsizeCellsToFit"];
- _cellMinWidth = [aDecoder decodeIntegerForKey:@"PSMcellMinWidth"];
- _cellMaxWidth = [aDecoder decodeIntegerForKey:@"PSMcellMaxWidth"];
- _cellOptimumWidth = [aDecoder decodeIntegerForKey:@"PSMcellOptimumWidth"];
- _currentStep = [aDecoder decodeIntegerForKey:@"PSMcurrentStep"];
- _isHidden = [aDecoder decodeBoolForKey:@"PSMisHidden"];
- partnerView = [[aDecoder decodeObjectForKey:@"PSMpartnerView"] retain];
- _awakenedFromNib = [aDecoder decodeBoolForKey:@"PSMawakenedFromNib"];
- _lastMouseDownEvent = [[aDecoder decodeObjectForKey:@"PSMlastMouseDownEvent"] retain];
- _useOverflowMenu = [aDecoder decodeBoolForKey:@"PSMuseOverflowMenu"];
- _automaticallyAnimates = [aDecoder decodeBoolForKey:@"PSMautomaticallyAnimates"];
- _alwaysShowActiveTab = [aDecoder decodeBoolForKey:@"PSMalwaysShowActiveTab"];
- delegate = [[aDecoder decodeObjectForKey:@"PSMdelegate"] retain];
- }
- }
- [self setTarget:self];
- return self;
-}
-
-#pragma mark -
-#pragma mark IB Palette
-
-- (NSSize)minimumFrameSizeFromKnobPosition:(NSInteger)position {
- return NSMakeSize(100.0, 22.0);
-}
-
-- (NSSize)maximumFrameSizeFromKnobPosition:(NSInteger)knobPosition {
- return NSMakeSize(10000.0, 22.0);
-}
-
-- (void)placeView:(NSRect)newFrame {
- // this is called any time the view is resized in IB
- [self setFrame:newFrame];
- [self update:NO];
-}
-
-#pragma mark -
-#pragma mark Convenience
-
-- (void)bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item {
- [self _bindPropertiesForCell:cell andTabViewItem:item];
-
- // watch for changes in the identifier
- [item addObserver:self forKeyPath:@"identifier" options:0 context:nil];
-}
-
-- (void)_bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item {
- // bind the indicator to the represented object's status (if it exists)
- [[cell indicator] setHidden:YES];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(isProcessing)]) {
- NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary];
- [bindingOptions setObject:NSNegateBooleanTransformerName forKey:@"NSValueTransformerName"];
- [[cell indicator] bind:@"animate" toObject:[item identifier] withKeyPath:@"isProcessing" options:nil];
- [[cell indicator] bind:@"hidden" toObject:[item identifier] withKeyPath:@"isProcessing" options:bindingOptions];
- [[item identifier] addObserver:cell forKeyPath:@"isProcessing" options:0 context:nil];
- }
- }
-
- // bind for the existence of an icon
- [cell setHasIcon:NO];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(icon)]) {
- NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary];
- [bindingOptions setObject:NSIsNotNilTransformerName forKey:@"NSValueTransformerName"];
- [cell bind:@"hasIcon" toObject:[item identifier] withKeyPath:@"icon" options:bindingOptions];
- [[item identifier] addObserver:cell forKeyPath:@"icon" options:0 context:nil];
- }
- }
-
- // bind for the existence of a counter
- [cell setCount:0];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(objectCount)]) {
- [cell bind:@"count" toObject:[item identifier] withKeyPath:@"objectCount" options:nil];
- [[item identifier] addObserver:cell forKeyPath:@"objectCount" options:0 context:nil];
- }
- }
-
- // bind for the color of a counter
- [cell setCountColor:nil];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(countColor)]) {
- [cell bind:@"countColor" toObject:[item identifier] withKeyPath:@"countColor" options:nil];
- [[item identifier] addObserver:cell forKeyPath:@"countColor" options:0 context:nil];
- }
- }
-
- // bind for a large image
- [cell setHasLargeImage:NO];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(largeImage)]) {
- NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary];
- [bindingOptions setObject:NSIsNotNilTransformerName forKey:@"NSValueTransformerName"];
- [cell bind:@"hasLargeImage" toObject:[item identifier] withKeyPath:@"largeImage" options:bindingOptions];
- [[item identifier] addObserver:cell forKeyPath:@"largeImage" options:0 context:nil];
- }
- }
-
- [cell setIsEdited:NO];
- if([item identifier] != nil) {
- if([[[cell representedObject] identifier] respondsToSelector:@selector(isEdited)]) {
- [cell bind:@"isEdited" toObject:[item identifier] withKeyPath:@"isEdited" options:nil];
- [[item identifier] addObserver:cell forKeyPath:@"isEdited" options:0 context:nil];
- }
- }
-
- // bind my string value to the label on the represented tab
- [cell bind:@"title" toObject:item withKeyPath:@"label" options:nil];
-}
-
-- (NSMutableArray *)representedTabViewItems {
- NSMutableArray *temp = [NSMutableArray arrayWithCapacity:[_cells count]];
- NSEnumerator *e = [_cells objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- if([cell representedObject]) {
- [temp addObject:[cell representedObject]];
- }
- }
- return temp;
-}
-
-- (id)cellForPoint:(NSPoint)point cellFrame:(NSRectPointer)outFrame {
- if([self orientation] == PSMTabBarHorizontalOrientation && !NSPointInRect(point, [self genericCellRect])) {
- return nil;
- }
-
- NSInteger i, cnt = [_cells count];
- for(i = 0; i < cnt; i++) {
- PSMTabBarCell *cell = [_cells objectAtIndex:i];
-
- if(NSPointInRect(point, [cell frame])) {
- if(outFrame) {
- *outFrame = [cell frame];
- }
- return cell;
- }
- }
- return nil;
-}
-
-- (PSMTabBarCell *)lastVisibleTab {
- NSInteger i, cellCount = [_cells count];
- for(i = 0; i < cellCount; i++) {
- if([[_cells objectAtIndex:i] isInOverflowMenu]) {
- return [_cells objectAtIndex:(i - 1)];
- }
- }
- return [_cells objectAtIndex:(cellCount - 1)];
-}
-
-- (NSInteger)numberOfVisibleTabs {
- NSUInteger i, cellCount = 0;
- PSMTabBarCell *nextCell;
-
- for(i = 0; i < [_cells count]; i++) {
- nextCell = [_cells objectAtIndex:i];
-
- if([nextCell isInOverflowMenu]) {
- break;
- }
-
- if(![nextCell isPlaceholder]) {
- cellCount++;
- }
- }
-
- return cellCount;
-}
-
-#pragma mark -
-#pragma mark Accessibility
-
--(BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString *)attribute {
- id attributeValue = nil;
- if([attribute isEqualToString: NSAccessibilityRoleAttribute]) {
- attributeValue = NSAccessibilityGroupRole;
- } else if([attribute isEqualToString: NSAccessibilityChildrenAttribute]) {
- attributeValue = NSAccessibilityUnignoredChildren(_cells);
- } else {
- attributeValue = [super accessibilityAttributeValue:attribute];
- }
- return attributeValue;
-}
-
-- (id)accessibilityHitTest:(NSPoint)point {
- id hitTestResult = self;
-
- NSEnumerator *enumerator = [_cells objectEnumerator];
- PSMTabBarCell *cell = nil;
- PSMTabBarCell *highlightedCell = nil;
-
- while(!highlightedCell && (cell = [enumerator nextObject])) {
- if([cell isHighlighted]) {
- highlightedCell = cell;
- }
- }
-
- if(highlightedCell) {
- hitTestResult = [highlightedCell accessibilityHitTest:point];
- }
-
- return hitTestResult;
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarController.h b/frontends/cocoa/PSMTabBarControl/PSMTabBarController.h
deleted file mode 100644
index a73a04f1f..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarController.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// PSMTabBarController.h
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 11/24/06.
-// Copyright 2006 Kent Sutherland. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@class PSMTabBarControl, PSMTabBarCell;
-
-@interface PSMTabBarController : NSObject
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
- <NSMenuDelegate>
-#endif
-{
- PSMTabBarControl *_control;
- NSMutableArray *_cellTrackingRects;
- NSMutableArray *_closeButtonTrackingRects;
- NSMutableArray *_cellFrames;
- NSRect _addButtonRect;
- NSMenu *_overflowMenu;
-}
-
-- (id)initWithTabBarControl:(PSMTabBarControl *)control;
-
-- (NSRect)addButtonRect;
-- (NSMenu *)overflowMenu;
-- (NSRect)cellTrackingRectAtIndex:(NSUInteger)index;
-- (NSRect)closeButtonTrackingRectAtIndex:(NSUInteger)index;
-- (NSRect)cellFrameAtIndex:(NSUInteger)index;
-
-- (void)setSelectedCell:(PSMTabBarCell *)cell;
-
-- (void)layoutCells;
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarController.m b/frontends/cocoa/PSMTabBarControl/PSMTabBarController.m
deleted file mode 100644
index 68e1bc498..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabBarController.m
+++ /dev/null
@@ -1,643 +0,0 @@
-//
-// PSMTabBarController.m
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 11/24/06.
-// Copyright 2006 Kent Sutherland. All rights reserved.
-//
-
-#import "PSMTabBarController.h"
-#import "PSMTabBarControl.h"
-#import "PSMTabBarCell.h"
-#import "PSMTabStyle.h"
-#import "NSString_AITruncation.h"
-
-#define MAX_OVERFLOW_MENUITEM_TITLE_LENGTH 60
-
-@interface PSMTabBarController (Private)
-- (NSArray *)_generateWidthsFromCells:(NSArray *)cells;
-- (void)_setupCells:(NSArray *)cells withWidths:(NSArray *)widths;
-@end
-
-@implementation PSMTabBarController
-
-/*!
- @method initWithTabBarControl:
- @abstract Creates a new PSMTabBarController instance.
- @discussion Creates a new PSMTabBarController for controlling a PSMTabBarControl. Should only be called by
- PSMTabBarControl.
- @param A PSMTabBarControl.
- @returns A newly created PSMTabBarController instance.
- */
-
-- (id)initWithTabBarControl:(PSMTabBarControl *)control {
- if((self = [super init])) {
- _control = control;
- _cellTrackingRects = [[NSMutableArray alloc] init];
- _closeButtonTrackingRects = [[NSMutableArray alloc] init];
- _cellFrames = [[NSMutableArray alloc] init];
- _addButtonRect = NSZeroRect;
- }
- return self;
-}
-
-- (void)dealloc {
- [_cellTrackingRects release];
- [_closeButtonTrackingRects release];
- [_cellFrames release];
- [super dealloc];
-}
-
-/*!
- @method addButtonRect
- @abstract Returns the position for the add tab button.
- @discussion Returns the position for the add tab button.
- @returns The rect for the add button rect.
- */
-
-- (NSRect)addButtonRect {
- return _addButtonRect;
-}
-
-/*!
- @method overflowMenu
- @abstract Returns current overflow menu or nil if there is none.
- @discussion Returns current overflow menu or nil if there is none.
- @returns The current overflow menu.
- */
-
-- (NSMenu *)overflowMenu {
- return _overflowMenu;
-}
-
-/*!
- @method cellTrackingRectAtIndex:
- @abstract Returns the rect for the tracking rect at the requested index.
- @discussion Returns the rect for the tracking rect at the requested index.
- @param Index of a cell.
- @returns The tracking rect of the cell at the requested index.
- */
-
-- (NSRect)cellTrackingRectAtIndex:(NSUInteger)index {
- NSRect rect;
- if(index < [_cellTrackingRects count]) {
- rect = [[_cellTrackingRects objectAtIndex:index] rectValue];
- } else {
- NSLog(@"cellTrackingRectAtIndex: Invalid index (%ld)", (long)index);
- rect = NSZeroRect;
- }
- return rect;
-}
-
-/*!
- @method closeButtonTrackingRectAtIndex:
- @abstract Returns the tracking rect for the close button at the requested index.
- @discussion Returns the tracking rect for the close button at the requested index.
- @param Index of a cell.
- @returns The close button tracking rect of the cell at the requested index.
- */
-
-- (NSRect)closeButtonTrackingRectAtIndex:(NSUInteger)index {
- NSRect rect;
- if(index < [_closeButtonTrackingRects count]) {
- rect = [[_closeButtonTrackingRects objectAtIndex:index] rectValue];
- } else {
- NSLog(@"closeButtonTrackingRectAtIndex: Invalid index (%ld)", (long)index);
- rect = NSZeroRect;
- }
- return rect;
-}
-
-/*!
- @method cellFrameAtIndex:
- @abstract Returns the frame for the cell at the requested index.
- @discussion Returns the frame for the cell at the requested index.
- @param Index of a cell.
- @returns The frame of the cell at the requested index.
- */
-
-- (NSRect)cellFrameAtIndex:(NSUInteger)index {
- NSRect rect;
-
- if(index < [_cellFrames count]) {
- rect = [[_cellFrames objectAtIndex:index] rectValue];
- } else {
- NSLog(@"cellFrameAtIndex: Invalid index (%ld)", (long)index);
- rect = NSZeroRect;
- }
- return rect;
-}
-
-/*!
- @method setSelectedCell:
- @abstract Changes the cell states so the given cell is the currently selected cell.
- @discussion Makes the given cell the active cell and properly recalculates the tab states for surrounding cells.
- @param An instance of PSMTabBarCell to make active.
- */
-
-- (void)setSelectedCell:(PSMTabBarCell *)cell {
- NSArray *cells = [_control cells];
- NSEnumerator *enumerator = [cells objectEnumerator];
- PSMTabBarCell *lastCell = nil, *nextCell;
-
- //deselect the previously selected tab
- while((nextCell = [enumerator nextObject]) && ([nextCell state] == NSOffState)) {
- lastCell = nextCell;
- }
-
- [nextCell setState:NSOffState];
- [nextCell setTabState:PSMTab_PositionMiddleMask];
-
- if(lastCell && lastCell != [_control lastVisibleTab]) {
- [lastCell setTabState:~[lastCell tabState] & PSMTab_RightIsSelectedMask];
- }
-
- if((nextCell = [enumerator nextObject])) {
- [nextCell setTabState:~[lastCell tabState] & PSMTab_LeftIsSelectedMask];
- }
-
- [cell setState:NSOnState];
- [cell setTabState:PSMTab_SelectedMask];
-
- if(![cell isInOverflowMenu]) {
- NSUInteger cellIndex = [cells indexOfObject:cell];
-
- if(cellIndex > 0) {
- nextCell = [cells objectAtIndex:cellIndex - 1];
- [nextCell setTabState:[nextCell tabState] | PSMTab_RightIsSelectedMask];
- }
-
- if(cellIndex < [cells count] - 1) {
- nextCell = [cells objectAtIndex:cellIndex + 1];
- [nextCell setTabState:[nextCell tabState] | PSMTab_LeftIsSelectedMask];
- }
- }
-}
-
-/*!
- @method layoutCells
- @abstract Recalculates cell positions and states.
- @discussion This method calculates the proper frame, tabState and overflow menu status for all cells in the
- tab bar control.
- */
-
-- (void)layoutCells {
- NSArray *cells = [_control cells];
- NSInteger cellCount = [cells count];
-
- // make sure all of our tabs are accounted for before updating
- if([[_control tabView] numberOfTabViewItems] != cellCount) {
- return;
- }
-
- [_cellTrackingRects removeAllObjects];
- [_closeButtonTrackingRects removeAllObjects];
- [_cellFrames removeAllObjects];
-
- NSArray *cellWidths = [self _generateWidthsFromCells:cells];
- [self _setupCells:cells withWidths:cellWidths];
-
- //set up the rect from the add tab button
- _addButtonRect = [_control genericCellRect];
- _addButtonRect.size = [[_control addTabButton] frame].size;
- if([_control orientation] == PSMTabBarHorizontalOrientation) {
- _addButtonRect.origin.y = MARGIN_Y;
- _addButtonRect.origin.x += [[cellWidths valueForKeyPath:@"@sum.floatValue"] doubleValue] + 2;
- } else {
- _addButtonRect.origin.x = 0;
- _addButtonRect.origin.y = [[cellWidths lastObject] doubleValue];
- }
-}
-
-/*!
- * @method _shrinkWidths:towardMinimum:withAvailableWidth:
- * @abstract Decreases widths in an array toward a minimum until they fit within availableWidth, if possible
- * @param An array of NSNumbers
- * @param The target minimum
- * @param The maximum available width
- * @returns The amount by which the total array width was shrunk
- */
-- (NSInteger)_shrinkWidths:(NSMutableArray *)newWidths towardMinimum:(NSInteger)minimum withAvailableWidth:(CGFloat)availableWidth {
- BOOL changed = NO;
- NSInteger count = [newWidths count];
- NSInteger totalWidths = [[newWidths valueForKeyPath:@"@sum.intValue"] integerValue];
- NSInteger originalTotalWidths = totalWidths;
-
- do {
- changed = NO;
-
- for(NSInteger q = (count - 1); q >= 0; q--) {
- CGFloat cellWidth = [[newWidths objectAtIndex:q] doubleValue];
- if(cellWidth - 1 >= minimum) {
- cellWidth--;
- totalWidths--;
-
- [newWidths replaceObjectAtIndex:q
- withObject:[NSNumber numberWithDouble:cellWidth]];
-
- changed = YES;
- }
- }
- } while(changed && (totalWidths > availableWidth));
-
- return(originalTotalWidths - totalWidths);
-}
-
-/*!
- * @function potentialMinimumForArray()
- * @abstract Calculate the minimum total for a given array of widths
- * @discussion The array is summed using, for each item, the minimum between the current value and the passed minimum value.
- * This is useful for getting a sum if the array has size-to-fit widths which will be allowed to be less than the
- * specified minimum.
- * @param An array of widths
- * @param The minimum
- * @returns The smallest possible sum for the array
- */
-static NSInteger potentialMinimumForArray(NSArray *array, NSInteger minimum){
- NSInteger runningTotal = 0;
- NSInteger count = [array count];
-
- for(NSInteger i = 0; i < count; i++) {
- NSInteger currentValue = [[array objectAtIndex:i] integerValue];
- runningTotal += MIN(currentValue, minimum);
- }
-
- return runningTotal;
-}
-
-/*!
- @method _generateWidthsFromCells:
- @abstract Calculates the width of cells that would be visible.
- @discussion Calculates the width of cells in the tab bar and returns an array of widths for the cells that would be
- visible. Uses large blocks of code that were previously in PSMTabBarControl's update method.
- @param An array of PSMTabBarCells.
- @returns An array of numbers representing the widths of cells that would be visible.
- */
-
-- (NSArray *)_generateWidthsFromCells:(NSArray *)cells {
- NSInteger cellCount = [cells count], i, numberOfVisibleCells = ([_control orientation] == PSMTabBarHorizontalOrientation) ? 1 : 0;
- NSMutableArray *newWidths = [NSMutableArray arrayWithCapacity:cellCount];
- id <PSMTabStyle> style = [_control style];
- CGFloat availableWidth = [_control availableCellWidth], currentOrigin = 0, totalOccupiedWidth = 0.0, width;
- NSRect cellRect = [_control genericCellRect], controlRect = [_control frame];
- PSMTabBarCell *currentCell;
-
- if([_control orientation] == PSMTabBarVerticalOrientation) {
- currentOrigin = [style topMarginForTabBarControl];
- }
-
- //Don't let cells overlap the add tab button if it is visible
- if([_control showAddTabButton]) {
- availableWidth -= [self addButtonRect].size.width;
- }
-
- for(i = 0; i < cellCount; i++) {
- currentCell = [cells objectAtIndex:i];
-
- // supress close button?
- [currentCell setCloseButtonSuppressed:((cellCount == 1 && [_control canCloseOnlyTab] == NO) ||
- [_control disableTabClose] ||
- ([[_control delegate] respondsToSelector:@selector(tabView:disableTabCloseForTabViewItem:)] &&
- [[_control delegate] tabView:[_control tabView] disableTabCloseForTabViewItem:[currentCell representedObject]]))];
-
- if([_control orientation] == PSMTabBarHorizontalOrientation) {
- // Determine cell width
- if([_control sizeCellsToFit]) {
- width = [currentCell desiredWidthOfCell];
- if(width > [_control cellMaxWidth]) {
- width = [_control cellMaxWidth];
- }
- } else {
- width = [_control cellOptimumWidth];
- }
-
- width = ceil(width);
-
- //check to see if there is not enough space to place all tabs as preferred
- if(totalOccupiedWidth + width >= availableWidth) {
- //There's not enough space to add currentCell at its preferred width!
-
- //If we're not going to use the overflow menu, cram all the tab cells into the bar regardless of minimum width
- if(![_control useOverflowMenu]) {
- NSInteger j, averageWidth = (availableWidth / cellCount);
-
- numberOfVisibleCells = cellCount;
- [newWidths removeAllObjects];
-
- for(j = 0; j < cellCount; j++) {
- CGFloat desiredWidth = [[cells objectAtIndex:j] desiredWidthOfCell];
- [newWidths addObject:[NSNumber numberWithDouble:(desiredWidth < averageWidth && [_control sizeCellsToFit]) ? desiredWidth : averageWidth]];
- }
-
- totalOccupiedWidth = [[newWidths valueForKeyPath:@"@sum.intValue"] integerValue];
- break;
- }
-
- //We'll be using the overflow menu if needed.
- numberOfVisibleCells = i;
- if([_control sizeCellsToFit]) {
- BOOL remainingCellsMustGoToOverflow = NO;
-
- totalOccupiedWidth = [[newWidths valueForKeyPath:@"@sum.intValue"] integerValue];
-
- /* Can I squeeze it in without violating min cell width? This is the width we would take up
- * if every cell so far were at the control minimum size (or their current size if that is less than the control minimum).
- */
- if((potentialMinimumForArray(newWidths, [_control cellMinWidth]) + MIN(width, [_control cellMinWidth])) <= availableWidth) {
- /* It's definitely possible for cells so far to be visible.
- * Shrink other cells to allow this one to fit
- */
- NSInteger cellMinWidth = [_control cellMinWidth];
-
- /* Start off adding it to the array; we know that it will eventually fit because
- * (the potential minimum <= availableWidth)
- *
- * This allows average and minimum aggregates on the NSArray to work.
- */
- [newWidths addObject:[NSNumber numberWithDouble:width]];
- numberOfVisibleCells++;
-
- totalOccupiedWidth += width;
-
- //First, try to shrink tabs toward the average. Tabs smaller than average won't change
- totalOccupiedWidth -= [self _shrinkWidths:newWidths
- towardMinimum:[[newWidths valueForKeyPath:@"@avg.intValue"] integerValue]
- withAvailableWidth:availableWidth];
-
-
-
- if(totalOccupiedWidth > availableWidth) {
- //Next, shrink tabs toward the smallest of the existing tabs. The smallest tab won't change.
- NSInteger smallestTabWidth = [[newWidths valueForKeyPath:@"@min.intValue"] integerValue];
- if(smallestTabWidth > cellMinWidth) {
- totalOccupiedWidth -= [self _shrinkWidths:newWidths
- towardMinimum:smallestTabWidth
- withAvailableWidth:availableWidth];
- }
- }
-
- if(totalOccupiedWidth > availableWidth) {
- //Finally, shrink tabs toward the imposed minimum size. All tabs larger than the minimum wll change.
- totalOccupiedWidth -= [self _shrinkWidths:newWidths
- towardMinimum:cellMinWidth
- withAvailableWidth:availableWidth];
- }
-
- if(totalOccupiedWidth > availableWidth) {
- NSLog(@"**** -[PSMTabBarController generateWidthsFromCells:] This is a failure (available %f, total %f, width is %f)",
- availableWidth, totalOccupiedWidth, width);
- remainingCellsMustGoToOverflow = YES;
- }
-
- if(totalOccupiedWidth < availableWidth) {
- /* We're not using all available space not but exceeded available width before;
- * stretch all cells to fully fit the bar
- */
- NSInteger leftoverWidth = availableWidth - totalOccupiedWidth;
- if(leftoverWidth > 0) {
- NSInteger q;
- for(q = numberOfVisibleCells - 1; q >= 0; q--) {
- NSInteger desiredAddition = (NSInteger)leftoverWidth / (q + 1);
- NSInteger newCellWidth = (NSInteger)[[newWidths objectAtIndex:q] doubleValue] + desiredAddition;
- [newWidths replaceObjectAtIndex:q withObject:[NSNumber numberWithDouble:newCellWidth]];
- leftoverWidth -= desiredAddition;
- totalOccupiedWidth += desiredAddition;
- }
- }
- }
- } else {
- // stretch - distribute leftover room among cells, since we can't add this cell
- NSInteger leftoverWidth = availableWidth - totalOccupiedWidth;
- NSInteger q;
- for(q = i - 1; q >= 0; q--) {
- NSInteger desiredAddition = (NSInteger)leftoverWidth / (q + 1);
- NSInteger newCellWidth = (NSInteger)[[newWidths objectAtIndex:q] doubleValue] + desiredAddition;
- [newWidths replaceObjectAtIndex:q withObject:[NSNumber numberWithDouble:newCellWidth]];
- leftoverWidth -= desiredAddition;
- }
-
- remainingCellsMustGoToOverflow = YES;
- }
-
- // done assigning widths; remaining cells go in overflow menu
- if(remainingCellsMustGoToOverflow) {
- break;
- }
- } else {
- //We're not using size-to-fit
- NSInteger revisedWidth = availableWidth / (i + 1);
- if(revisedWidth >= [_control cellMinWidth]) {
- NSUInteger q;
- totalOccupiedWidth = 0;
-
- for(q = 0; q < [newWidths count]; q++) {
- [newWidths replaceObjectAtIndex:q withObject:[NSNumber numberWithDouble:revisedWidth]];
- totalOccupiedWidth += revisedWidth;
- }
- // just squeezed this one in...
- [newWidths addObject:[NSNumber numberWithDouble:revisedWidth]];
- totalOccupiedWidth += revisedWidth;
- numberOfVisibleCells++;
- } else {
- // couldn't fit that last one...
- break;
- }
- }
- } else {
- //(totalOccupiedWidth < availableWidth)
- numberOfVisibleCells = cellCount;
- [newWidths addObject:[NSNumber numberWithDouble:width]];
- totalOccupiedWidth += width;
- }
- } else {
- //lay out vertical tabs
- if(currentOrigin + cellRect.size.height <= controlRect.size.height) {
- [newWidths addObject:[NSNumber numberWithDouble:currentOrigin]];
- numberOfVisibleCells++;
- currentOrigin += cellRect.size.height;
- } else {
- //out of room, the remaining tabs go into overflow
- if([newWidths count] > 0 && controlRect.size.height - currentOrigin < 17) {
- [newWidths removeLastObject];
- numberOfVisibleCells--;
- }
- break;
- }
- }
- }
-
- //make sure there are at least two items in the horizontal tab bar
- if([_control orientation] == PSMTabBarHorizontalOrientation) {
- if(numberOfVisibleCells < 2 && [cells count] > 1) {
- PSMTabBarCell *cell1 = [cells objectAtIndex:0], *cell2 = [cells objectAtIndex:1];
- NSNumber *cellWidth;
-
- [newWidths removeAllObjects];
- totalOccupiedWidth = 0;
-
- cellWidth = [NSNumber numberWithDouble:[cell1 desiredWidthOfCell] < availableWidth * 0.5f ?[cell1 desiredWidthOfCell] : availableWidth * 0.5f];
- [newWidths addObject:cellWidth];
- totalOccupiedWidth += [cellWidth doubleValue];
-
- cellWidth = [NSNumber numberWithDouble:[cell2 desiredWidthOfCell] < (availableWidth - totalOccupiedWidth) ?[cell2 desiredWidthOfCell] : (availableWidth - totalOccupiedWidth)];
- [newWidths addObject:cellWidth];
- totalOccupiedWidth += [cellWidth doubleValue];
-
- if(totalOccupiedWidth < availableWidth) {
- [newWidths replaceObjectAtIndex:0 withObject:[NSNumber numberWithDouble:availableWidth - [cellWidth doubleValue]]];
- }
-
- numberOfVisibleCells = 2;
- }
- }
-
- return newWidths;
-}
-
-/*!
- @method _setupCells:withWidths
- @abstract Creates tracking rect arrays and sets the frames of the visible cells.
- @discussion Creates tracking rect arrays and sets the cells given in the widths array.
- */
-
-- (void)_setupCells:(NSArray *)cells withWidths:(NSArray *)widths {
- NSUInteger i, tabState, cellCount = [cells count];
- NSRect cellRect = [_control genericCellRect];
- PSMTabBarCell *cell;
- NSTabViewItem *selectedTabViewItem = [[_control tabView] selectedTabViewItem];
- NSMenuItem *menuItem;
-
- [_overflowMenu release], _overflowMenu = nil;
-
- for(i = 0; i < cellCount; i++) {
- cell = [cells objectAtIndex:i];
-
- if(i < [widths count]) {
- tabState = 0;
-
- // set cell frame
- if([_control orientation] == PSMTabBarHorizontalOrientation) {
- cellRect.size.width = [[widths objectAtIndex:i] doubleValue];
- } else {
- cellRect.size.width = [_control frame].size.width;
- cellRect.origin.y = [[widths objectAtIndex:i] doubleValue];
- cellRect.origin.x = 0;
- }
-
- [_cellFrames addObject:[NSValue valueWithRect:cellRect]];
-
- //add tracking rects to arrays
- [_closeButtonTrackingRects addObject:[NSValue valueWithRect:[cell closeButtonRectForFrame:cellRect]]];
- [_cellTrackingRects addObject:[NSValue valueWithRect:cellRect]];
-
- if([[cell representedObject] isEqualTo:selectedTabViewItem]) {
- [cell setState:NSOnState];
- tabState |= PSMTab_SelectedMask;
- // previous cell
- if(i > 0) {
- [[cells objectAtIndex:i - 1] setTabState:([(PSMTabBarCell *)[cells objectAtIndex:i - 1] tabState] | PSMTab_RightIsSelectedMask)];
- }
- // next cell - see below
- } else {
- [cell setState:NSOffState];
- // see if prev cell was selected
- if((i > 0) && ([[cells objectAtIndex:i - 1] state] == NSOnState)) {
- tabState |= PSMTab_LeftIsSelectedMask;
- }
- }
-
- // more tab states
- if([widths count] == 1) {
- tabState |= PSMTab_PositionLeftMask | PSMTab_PositionRightMask | PSMTab_PositionSingleMask;
- } else if(i == 0) {
- tabState |= PSMTab_PositionLeftMask;
- } else if(i == [widths count] - 1) {
- tabState |= PSMTab_PositionRightMask;
- }
-
- [cell setTabState:tabState];
- [cell setIsInOverflowMenu:NO];
-
- // indicator
- if(![[cell indicator] isHidden] && ![_control isTabBarHidden]) {
- if(![[_control subviews] containsObject:[cell indicator]]) {
- [_control addSubview:[cell indicator]];
- [[cell indicator] startAnimation:self];
- }
- }
-
- // next...
- cellRect.origin.x += [[widths objectAtIndex:i] doubleValue];
- } else {
- [cell setState:NSOffState];
- [cell setIsInOverflowMenu:YES];
- [[cell indicator] removeFromSuperview];
-
- //position the cell well offscreen
- if([_control orientation] == PSMTabBarHorizontalOrientation) {
- cellRect.origin.x += [[_control style] rightMarginForTabBarControl] + 20;
- } else {
- cellRect.origin.y = [_control frame].size.height + 2;
- }
-
- [_cellFrames addObject:[NSValue valueWithRect:cellRect]];
-
- if(_overflowMenu == nil) {
- _overflowMenu = [[NSMenu alloc] init];
- [_overflowMenu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0]; // Because the overflowPupUpButton is a pull down menu
- [_overflowMenu setDelegate:self];
- }
-
- // Each item's title is limited to 60 characters. If more than 60 characters, use an ellipsis to indicate that more exists.
- menuItem = [_overflowMenu addItemWithTitle:[[[cell attributedStringValue] string] stringWithEllipsisByTruncatingToLength:MAX_OVERFLOW_MENUITEM_TITLE_LENGTH]
- action:@selector(overflowMenuAction:)
- keyEquivalent:@""];
- [menuItem setTarget:_control];
- [menuItem setRepresentedObject:[cell representedObject]];
-
- if([cell count] > 0) {
- [menuItem setTitle:[[menuItem title] stringByAppendingFormat:@" (%lu)", (unsigned long)[cell count]]];
- }
- }
- }
-}
-
-- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)menuItem atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel {
- if(menu == _overflowMenu) {
- if([[[menuItem representedObject] identifier] respondsToSelector:@selector(icon)]) {
- [menuItem setImage:[[[menuItem representedObject] identifier] valueForKey:@"icon"]];
- }
- }
-
- return TRUE;
-}
-
-- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu {
- if(menu == _overflowMenu) {
- return [_overflowMenu numberOfItems];
- } else {
- NSLog(@"Warning: Unexpected menu delegate call for menu %@", menu);
- return 0;
- }
-}
-
-@end
-
-/*
- PSMTabBarController will store what the current tab frame state should be like based off the last layout. PSMTabBarControl
- has to handle fetching the new frame and then changing the tab cell frame.
- Tab states will probably be changed immediately.
-
- Tabs that aren't going to be visible need to have their frame set offscreen. Treat them as if they were visible.
-
- The overflow menu is rebuilt and stored by the controller.
-
- Arrays of tracking rects will be created here, but not applied.
- Tracking rects are removed and added by PSMTabBarControl at the end of an animate/display cycle.
-
- The add tab button frame is handled by this controller. Visibility and location are set by the control.
-
- isInOverflowMenu should probably be removed in favor of a call that returns yes/no to if a cell is in overflow. (Not yet implemented)
-
- Still need to rewrite most of the code in PSMTabDragAssistant.
- */
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.h b/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.h
deleted file mode 100644
index 2632e11a0..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-// PSMTabDragAssistant.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 4/10/06.
-// Copyright 2006 Positive Spin Media. All rights reserved.
-//
-
-/*
- This class is a sigleton that manages the details of a tab drag and drop. The details were beginning to overwhelm me when keeping all of this in the control and cells :-)
- */
-
-#import <Cocoa/Cocoa.h>
-#import "PSMTabBarControl.h"
-
-#define kPSMTabDragAnimationSteps 8
-
-@class PSMTabBarCell, PSMTabDragWindowController;
-
-@interface PSMTabDragAssistant : NSObject {
- PSMTabBarControl *_sourceTabBar;
- PSMTabBarControl *_destinationTabBar;
- NSMutableSet *_participatingTabBars;
- PSMTabBarCell *_draggedCell;
- NSUInteger _draggedCellIndex; // for snap back
- BOOL _isDragging;
-
- // Support for dragging into new windows
- PSMTabDragWindowController *_draggedTab;
- PSMTabDragWindowController *_draggedView;
- NSSize _dragWindowOffset;
- NSTimer *_fadeTimer;
- BOOL _centersDragWindows;
- PSMTabBarTearOffStyle _currentTearOffStyle;
-
- // Animation
- NSTimer *_animationTimer;
- NSMutableArray *_sineCurveWidths;
- NSPoint _currentMouseLoc;
- PSMTabBarCell *_targetCell;
-}
-
-// Creation/destruction
-+ (PSMTabDragAssistant *)sharedDragAssistant;
-
-// Accessors
-- (PSMTabBarControl *)sourceTabBar;
-- (void)setSourceTabBar:(PSMTabBarControl *)tabBar;
-- (PSMTabBarControl *)destinationTabBar;
-- (void)setDestinationTabBar:(PSMTabBarControl *)tabBar;
-- (PSMTabBarCell *)draggedCell;
-- (void)setDraggedCell:(PSMTabBarCell *)cell;
-- (NSInteger)draggedCellIndex;
-- (void)setDraggedCellIndex:(NSInteger)value;
-- (BOOL)isDragging;
-- (void)setIsDragging:(BOOL)value;
-- (NSPoint)currentMouseLoc;
-- (void)setCurrentMouseLoc:(NSPoint)point;
-- (PSMTabBarCell *)targetCell;
-- (void)setTargetCell:(PSMTabBarCell *)cell;
-
-// Functionality
-- (void)startDraggingCell:(PSMTabBarCell *)cell fromTabBar:(PSMTabBarControl *)control withMouseDownEvent:(NSEvent *)event;
-- (void)draggingEnteredTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc;
-- (void)draggingUpdatedInTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc;
-- (void)draggingExitedTabBar:(PSMTabBarControl *)control;
-- (void)performDragOperation;
-- (void)draggedImageEndedAt:(NSPoint) aPoint operation:(NSDragOperation)operation;
-- (void)finishDrag;
-
-- (void)draggingBeganAt:(NSPoint)aPoint;
-- (void)draggingMovedTo:(NSPoint)aPoint;
-
-// Animation
-- (void)animateDrag:(NSTimer *)timer;
-- (void)calculateDragAnimationForTabBar:(PSMTabBarControl *)control;
-
-// Placeholder
-- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control withDraggedCell:(PSMTabBarCell *)cell;
-- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control;
-- (void)removeAllPlaceholdersFromTabBar:(PSMTabBarControl *)control;
-
-@end
-
-@interface PSMTabBarControl (DragAccessors)
-
-- (id<PSMTabStyle>)style;
-- (NSMutableArray *)cells;
-- (void)setControlView:(id)view;
-- (id)cellForPoint:(NSPoint) point cellFrame:(NSRectPointer)outFrame;
-- (PSMTabBarCell *)lastVisibleTab;
-- (NSInteger)numberOfVisibleTabs;
-
-@end
-
-void CGContextCopyWindowCaptureContentsToRect(void *grafport, CGRect rect, NSInteger cid, NSInteger wid, NSInteger zero);
-OSStatus CGSSetWindowTransform(NSInteger cid, NSInteger wid, CGAffineTransform transform);
-
-@interface NSApplication (CoreGraphicsUndocumented)
-- (NSInteger)contextID;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m b/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m
deleted file mode 100644
index 4542e8d02..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m
+++ /dev/null
@@ -1,834 +0,0 @@
-//
-// PSMTabDragAssistant.m
-// PSMTabBarControl
-//
-// Created by John Pannell on 4/10/06.
-// Copyright 2006 Positive Spin Media. All rights reserved.
-//
-
-#import "PSMTabDragAssistant.h"
-#import "PSMTabBarCell.h"
-#import "PSMTabStyle.h"
-#import "PSMTabDragWindowController.h"
-
-#define PI 3.1417
-
-@interface PSMTabBarControl (Private)
-- (void)update:(BOOL)animate;
-@end
-
-@interface PSMTabDragAssistant (Private)
-- (NSImage *)_imageForViewOfCell:(PSMTabBarCell *)cell styleMask:(NSUInteger *)outMask;
-- (NSImage *)_miniwindowImageOfWindow:(NSWindow *)window;
-- (void)_expandWindow:(NSWindow *)window atPoint:(NSPoint)point;
-@end
-
-@implementation PSMTabDragAssistant
-
-static PSMTabDragAssistant *sharedDragAssistant = nil;
-
-#pragma mark -
-#pragma mark Creation/Destruction
-
-+ (PSMTabDragAssistant *)sharedDragAssistant {
- if(!sharedDragAssistant) {
- sharedDragAssistant = [[PSMTabDragAssistant alloc] init];
- }
-
- return sharedDragAssistant;
-}
-
-- (id)init {
- if((self = [super init])) {
- _sourceTabBar = nil;
- _destinationTabBar = nil;
- _participatingTabBars = [[NSMutableSet alloc] init];
- _draggedCell = nil;
- _animationTimer = nil;
- _sineCurveWidths = [[NSMutableArray alloc] initWithCapacity:kPSMTabDragAnimationSteps];
- _targetCell = nil;
- _isDragging = NO;
- }
-
- return self;
-}
-
-- (void)dealloc {
- [_sourceTabBar release];
- [_destinationTabBar release];
- [_participatingTabBars release];
- [_draggedCell release];
- [_animationTimer release];
- [_sineCurveWidths release];
- [_targetCell release];
- [super dealloc];
-}
-
-#pragma mark -
-#pragma mark Accessors
-
-- (PSMTabBarControl *)sourceTabBar {
- return _sourceTabBar;
-}
-
-- (void)setSourceTabBar:(PSMTabBarControl *)tabBar {
- [tabBar retain];
- [_sourceTabBar release];
- _sourceTabBar = tabBar;
-}
-
-- (PSMTabBarControl *)destinationTabBar {
- return _destinationTabBar;
-}
-
-- (void)setDestinationTabBar:(PSMTabBarControl *)tabBar {
- [tabBar retain];
- [_destinationTabBar release];
- _destinationTabBar = tabBar;
-}
-
-- (PSMTabBarCell *)draggedCell {
- return _draggedCell;
-}
-
-- (void)setDraggedCell:(PSMTabBarCell *)cell {
- [cell retain];
- [_draggedCell release];
- _draggedCell = cell;
-}
-
-- (NSInteger)draggedCellIndex {
- return _draggedCellIndex;
-}
-
-- (void)setDraggedCellIndex:(NSInteger)value {
- _draggedCellIndex = value;
-}
-
-- (BOOL)isDragging {
- return _isDragging;
-}
-
-- (void)setIsDragging:(BOOL)value {
- _isDragging = value;
-}
-
-- (NSPoint)currentMouseLoc {
- return _currentMouseLoc;
-}
-
-- (void)setCurrentMouseLoc:(NSPoint)point {
- _currentMouseLoc = point;
-}
-
-- (PSMTabBarCell *)targetCell {
- return _targetCell;
-}
-
-- (void)setTargetCell:(PSMTabBarCell *)cell {
- [cell retain];
- [_targetCell release];
- _targetCell = cell;
-}
-
-#pragma mark -
-#pragma mark Functionality
-
-- (void)startDraggingCell:(PSMTabBarCell *)cell fromTabBar:(PSMTabBarControl *)control withMouseDownEvent:(NSEvent *)event {
- [self setIsDragging:YES];
- [self setSourceTabBar:control];
- [self setDestinationTabBar:control];
- [_participatingTabBars addObject:control];
- [self setDraggedCell:cell];
- [self setDraggedCellIndex:[[control cells] indexOfObject:cell]];
-
- NSRect cellFrame = [cell frame];
- // list of widths for animation
- NSInteger i;
- CGFloat cellStepSize = ([control orientation] == PSMTabBarHorizontalOrientation) ? (cellFrame.size.width + 6) : (cellFrame.size.height + 1);
- for(i = 0; i < kPSMTabDragAnimationSteps - 1; i++) {
- NSInteger thisWidth = (NSInteger)(cellStepSize - ((cellStepSize / 2.0) + ((sin((PI / 2.0) + ((CGFloat)i / (CGFloat)kPSMTabDragAnimationSteps) * PI) * cellStepSize) / 2.0)));
- [_sineCurveWidths addObject:[NSNumber numberWithInteger:thisWidth]];
- }
- [_sineCurveWidths addObject:[NSNumber numberWithInteger:([control orientation] == PSMTabBarHorizontalOrientation) ? cellFrame.size.width : cellFrame.size.height]];
-
- // hide UI buttons
- [[control overflowPopUpButton] setHidden:YES];
- [[control addTabButton] setHidden:YES];
-
- [[NSCursor closedHandCursor] set];
-
- NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- NSImage *dragImage = [cell dragImage];
- [[cell indicator] removeFromSuperview];
- [self distributePlaceholdersInTabBar:control withDraggedCell:cell];
-
- if([control isFlipped]) {
- cellFrame.origin.y += cellFrame.size.height;
- }
- [cell setHighlighted:NO];
- NSSize offset = NSZeroSize;
- [pboard declareTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil] owner: nil];
- [pboard setString:[[NSNumber numberWithInteger:[[control cells] indexOfObject:cell]] stringValue] forType:@"PSMTabBarControlItemPBType"];
- _animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(animateDrag:) userInfo:nil repeats:YES];
-
- [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidBeginNotification object:nil];
-
- //retain the control in case the drag operation causes the control to be released
- [control retain];
-
- if([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] &&
- [[control delegate] tabView:[control tabView] shouldDropTabViewItem:[[self draggedCell] representedObject] inTabBar:nil]) {
- _currentTearOffStyle = [control tearOffStyle];
- _draggedTab = [[PSMTabDragWindowController alloc] initWithImage:dragImage styleMask:NSBorderlessWindowMask tearOffStyle:_currentTearOffStyle];
-
- cellFrame.origin.y -= cellFrame.size.height;
- [control dragImage:[[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] autorelease] at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:NO];
- } else {
- [control dragImage:dragImage at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:YES];
- }
-
- [control release];
-}
-
-- (void)draggingEnteredTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc {
- if(_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![self destinationTabBar]) {
- [_draggedTab switchImages];
- }
-
- [self setDestinationTabBar:control];
- [self setCurrentMouseLoc:mouseLoc];
- // hide UI buttons
- [[control overflowPopUpButton] setHidden:YES];
- [[control addTabButton] setHidden:YES];
- if([[control cells] count] == 0 || ![[[control cells] objectAtIndex:0] isPlaceholder]) {
- [self distributePlaceholdersInTabBar:control];
- }
- [_participatingTabBars addObject:control];
-
- //tell the drag window to display only the header if there is one
- if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow && _draggedView) {
- if(_fadeTimer) {
- [_fadeTimer invalidate];
- }
-
- [[_draggedTab window] orderFront:nil];
- _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeOutDragWindow:) userInfo:nil repeats:YES];
- }
-}
-
-- (void)draggingUpdatedInTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc {
- if([self destinationTabBar] != control) {
- [self setDestinationTabBar:control];
- }
- [self setCurrentMouseLoc:mouseLoc];
-}
-
-- (void)draggingExitedTabBar:(PSMTabBarControl *)control {
- if([[control delegate] respondsToSelector:@selector(tabView:shouldAllowTabViewItem:toLeaveTabBar:)] &&
- ![[control delegate] tabView:[control tabView] shouldAllowTabViewItem:[[self draggedCell] representedObject] toLeaveTabBar:control]) {
- return;
- }
-
- [self setDestinationTabBar:nil];
- [self setCurrentMouseLoc:NSMakePoint(-1.0, -1.0)];
-
- if(_fadeTimer) {
- [_fadeTimer invalidate];
- _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES];
- } else if(_draggedTab) {
- if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) {
- //create a new floating drag window
- if(!_draggedView) {
- NSUInteger styleMask;
- NSImage *viewImage = [self _imageForViewOfCell:[self draggedCell] styleMask:&styleMask];
-
- _draggedView = [[PSMTabDragWindowController alloc] initWithImage:viewImage styleMask:styleMask tearOffStyle:PSMTabBarTearOffAlphaWindow];
- [[_draggedView window] setAlphaValue:0.0];
- }
-
- NSPoint windowOrigin = [[control window] frame].origin;
-
- windowOrigin.x -= _dragWindowOffset.width;
- windowOrigin.y += _dragWindowOffset.height;
- [[_draggedView window] setFrameOrigin:windowOrigin];
- [[_draggedView window] orderWindow:NSWindowBelow relativeTo:[[_draggedTab window] windowNumber]];
- } else if(_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![_draggedTab alternateImage]) {
- NSImage *image;
- NSSize imageSize;
- NSUInteger mask; //we don't need this but we can't pass nil in for the style mask, as some delegate implementations will crash
-
- if(!(image = [self _miniwindowImageOfWindow:[control window]])) {
- image = [[self _imageForViewOfCell:[self draggedCell] styleMask:&mask] copy];
- }
-
- imageSize = [image size];
- [image setScalesWhenResized:YES];
-
- if(imageSize.width > imageSize.height) {
- [image setSize:NSMakeSize(125, 125 * (imageSize.height / imageSize.width))];
- } else {
- [image setSize:NSMakeSize(125 * (imageSize.width / imageSize.height), 125)];
- }
-
- [_draggedTab setAlternateImage:image];
- }
-
- //set the window's alpha mask to zero if the last tab is being dragged
- //don't fade out the old window if the delegate doesn't respond to the new tab bar method, just to be safe
- if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1 && [self sourceTabBar] == control &&
- [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) {
- [[[self sourceTabBar] window] setAlphaValue:0.0];
-
- if([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) {
- [[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha];
- } else {
- //#warning fix me - what should we do when the last tab is dragged as a miniwindow?
- }
- } else {
- if([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) {
- _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES];
- } else {
- [_draggedTab switchImages];
- _centersDragWindows = YES;
- }
- }
- }
-}
-
-- (void)performDragOperation {
- // move cell
- NSUInteger destinationIndex = [[[self destinationTabBar] cells] indexOfObject:[self targetCell]];
-
- //there is the slight possibility of the targetCell now being set properly, so avoid errors
- if(destinationIndex >= [[[self destinationTabBar] cells] count]) {
- destinationIndex = [[[self destinationTabBar] cells] count] - 1;
- }
-
- [[[self destinationTabBar] cells] replaceObjectAtIndex:destinationIndex withObject:[self draggedCell]];
- [[self draggedCell] setControlView:[self destinationTabBar]];
-
- // move actual NSTabViewItem
- if([self sourceTabBar] != [self destinationTabBar]) {
- //remove the tracking rects and bindings registered on the old tab
- [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]];
- [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]];
- [[self sourceTabBar] removeTabForCell:[self draggedCell]];
-
- NSUInteger i, insertIndex;
- NSArray *cells = [[self destinationTabBar] cells];
-
- //find the index of where the dragged cell was just dropped
- for(i = 0, insertIndex = 0; (i < [cells count]) && ([cells objectAtIndex:i] != [self draggedCell]); i++, insertIndex++) {
- if([[cells objectAtIndex:i] isPlaceholder]) {
- insertIndex--;
- }
- }
-
- [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]];
- [[[self destinationTabBar] tabView] insertTabViewItem:[[self draggedCell] representedObject] atIndex:insertIndex];
-
- //calculate the position for the dragged cell
- if([[self destinationTabBar] automaticallyAnimates]) {
- if(insertIndex > 0) {
- NSRect cellRect = [[cells objectAtIndex:insertIndex - 1] frame];
- cellRect.origin.x += cellRect.size.width;
- [[self draggedCell] setFrame:cellRect];
- }
- }
-
- //rebind the cell to the new control
- [[self destinationTabBar] bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]];
-
- //select the newly moved item in the destination tab view
- [[[self destinationTabBar] tabView] selectTabViewItem:[[self draggedCell] representedObject]];
- } else {
- //have to do this before checking the index of a cell otherwise placeholders will be counted
- [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]];
-
- //rearrange the tab view items
- NSTabView *tabView = [[self sourceTabBar] tabView];
- NSTabViewItem *item = [[self draggedCell] representedObject];
- BOOL reselect = ([tabView selectedTabViewItem] == item);
- NSArray *cells = [[self sourceTabBar] cells];
- NSUInteger index;
- //find the index of where the dragged cell was just dropped
- for(index = 0; index < [cells count] && [cells objectAtIndex:index] != [self draggedCell]; index++) {
- ;
- }
-
- //temporarily disable the delegate in order to move the tab to a different index
- id tempDelegate = [tabView delegate];
- [tabView setDelegate:nil];
- [item retain];
- [tabView removeTabViewItem:item];
- [tabView insertTabViewItem:item atIndex:index];
- if(reselect) {
- [tabView selectTabViewItem:item];
- }
- [tabView setDelegate:tempDelegate];
- }
-
- if(([self sourceTabBar] != [self destinationTabBar] || [[[self sourceTabBar] cells] indexOfObject:[self draggedCell]] != _draggedCellIndex) && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) {
- [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:[self destinationTabBar]];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil];
-
- [self finishDrag];
-}
-
-- (void)draggedImageEndedAt:(NSPoint)aPoint operation:(NSDragOperation)operation {
- if([self isDragging]) { // means there was not a successful drop (performDragOperation)
- id sourceDelegate = [[self sourceTabBar] delegate];
-
- //split off the dragged tab into a new window
- if([self destinationTabBar] == nil &&
- sourceDelegate && [sourceDelegate respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] &&
- [sourceDelegate tabView:[[self sourceTabBar] tabView] shouldDropTabViewItem:[[self draggedCell] representedObject] inTabBar:nil] &&
- [sourceDelegate respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) {
- PSMTabBarControl *control = [sourceDelegate tabView:[[self sourceTabBar] tabView] newTabBarForDraggedTabViewItem:[[self draggedCell] representedObject] atPoint:aPoint];
-
- if(control) {
- //add the dragged tab to the new window
- [[control cells] insertObject:[self draggedCell] atIndex:0];
-
- //remove the tracking rects and bindings registered on the old tab
- [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]];
- [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]];
- [[self sourceTabBar] removeTabForCell:[self draggedCell]];
-
- //rebind the cell to the new control
- [control bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]];
-
- [[self draggedCell] setControlView:control];
-
- [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]];
-
- [[control tabView] addTabViewItem:[[self draggedCell] representedObject]];
- [control update:NO]; //make sure the new tab is set in the correct position
-
- if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) {
- [[control window] makeKeyAndOrderFront:nil];
- } else {
- //center the window over where we ended dragging
- [self _expandWindow:[control window] atPoint:[NSEvent mouseLocation]];
- }
-
- if([sourceDelegate respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) {
- [sourceDelegate tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:control];
- }
- } else {
- NSLog(@"Delegate returned no control to add to.");
- [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]];
- }
- } else {
- // put cell back
- [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil];
-
- [self finishDrag];
- }
-}
-
-- (void)finishDrag {
- if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 0 && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:closeWindowForLastTabViewItem:)]) {
- [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] closeWindowForLastTabViewItem:[[self draggedCell] representedObject]];
- }
-
- if(_draggedTab) {
- [[_draggedTab window] orderOut:nil];
- [_draggedTab release];
- _draggedTab = nil;
- }
-
- if(_draggedView) {
- [[_draggedView window] orderOut:nil];
- [_draggedView release];
- _draggedView = nil;
- }
-
- _centersDragWindows = NO;
-
- [self setIsDragging:NO];
- [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]];
- [self setSourceTabBar:nil];
- [self setDestinationTabBar:nil];
- NSEnumerator *e = [_participatingTabBars objectEnumerator];
- PSMTabBarControl *tabBar;
- while((tabBar = [e nextObject])) {
- [self removeAllPlaceholdersFromTabBar:tabBar];
- }
- [_participatingTabBars removeAllObjects];
- [self setDraggedCell:nil];
- [_animationTimer invalidate];
- _animationTimer = nil;
- [_sineCurveWidths removeAllObjects];
- [self setTargetCell:nil];
-}
-
-- (void)draggingBeganAt:(NSPoint)aPoint {
- if(_draggedTab) {
- [[_draggedTab window] setFrameTopLeftPoint:aPoint];
- [[_draggedTab window] orderFront:nil];
-
- if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1) {
- [self draggingExitedTabBar:[self sourceTabBar]];
- [[_draggedTab window] setAlphaValue:0.0];
- }
- }
-}
-
-- (void)draggingMovedTo:(NSPoint)aPoint {
- if(_draggedTab) {
- if(_centersDragWindows) {
- if([_draggedTab isAnimating]) {
- return;
- }
-
- //Ignore aPoint, as it seems to give wacky values
- NSRect frame = [[_draggedTab window] frame];
- frame.origin = [NSEvent mouseLocation];
- frame.origin.x -= frame.size.width / 2;
- frame.origin.y -= frame.size.height / 2;
- [[_draggedTab window] setFrame:frame display:NO];
- } else {
- [[_draggedTab window] setFrameTopLeftPoint:aPoint];
- }
-
- if(_draggedView) {
- //move the view representation with the tab
- //the relative position of the dragged view window will be different
- //depending on the position of the tab bar relative to the controlled tab view
-
- aPoint.y -= [[_draggedTab window] frame].size.height;
- aPoint.x -= _dragWindowOffset.width;
- aPoint.y += _dragWindowOffset.height;
- [[_draggedView window] setFrameTopLeftPoint:aPoint];
- }
- }
-}
-
-- (void)fadeInDragWindow:(NSTimer *)timer {
- CGFloat value = [[_draggedView window] alphaValue];
- if(value >= kPSMTabDragWindowAlpha || _draggedTab == nil) {
- [timer invalidate];
- _fadeTimer = nil;
- } else {
- [[_draggedTab window] setAlphaValue:[[_draggedTab window] alphaValue] - kPSMTabDragAlphaInterval];
- [[_draggedView window] setAlphaValue:value + kPSMTabDragAlphaInterval];
- }
-}
-
-- (void)fadeOutDragWindow:(NSTimer *)timer {
- CGFloat value = [[_draggedView window] alphaValue];
- NSWindow *tabWindow = [_draggedTab window], *viewWindow = [_draggedView window];
-
- if(value <= 0.0) {
- [viewWindow setAlphaValue:0.0];
- [tabWindow setAlphaValue:kPSMTabDragWindowAlpha];
-
- [timer invalidate];
- _fadeTimer = nil;
- } else {
- if([tabWindow alphaValue] < kPSMTabDragWindowAlpha) {
- [tabWindow setAlphaValue:[tabWindow alphaValue] + kPSMTabDragAlphaInterval];
- }
- [viewWindow setAlphaValue:value - kPSMTabDragAlphaInterval];
- }
-}
-
-#pragma mark -
-#pragma mark Private
-
-- (NSImage *)_imageForViewOfCell:(PSMTabBarCell *)cell styleMask:(NSUInteger *)outMask {
- PSMTabBarControl *control = [cell controlView];
- NSImage *viewImage = nil;
-
- if(outMask) {
- *outMask = NSBorderlessWindowMask;
- }
-
- if([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:imageForTabViewItem:offset:styleMask:)]) {
- //get a custom image representation of the view to drag from the delegate
- NSImage *tabImage = [_draggedTab image];
- NSPoint drawPoint;
- _dragWindowOffset = NSZeroSize;
- viewImage = [[control delegate] tabView:[control tabView] imageForTabViewItem:[cell representedObject] offset:&_dragWindowOffset styleMask:outMask];
- [viewImage lockFocus];
-
- //draw the tab into the returned window, that way we don't have two windows being dragged (this assumes the tab will be on the window)
- drawPoint = NSMakePoint(_dragWindowOffset.width, [viewImage size].height - _dragWindowOffset.height);
-
- if([control orientation] == PSMTabBarHorizontalOrientation) {
- drawPoint.y += [[control style] tabCellHeight] - [tabImage size].height;
- _dragWindowOffset.height -= [[control style] tabCellHeight] - [tabImage size].height;
- } else {
- drawPoint.x += [control frame].size.width - [tabImage size].width;
- }
-
- [tabImage compositeToPoint:drawPoint operation:NSCompositeSourceOver];
-
- [viewImage unlockFocus];
- } else {
- //the delegate doesn't give a custom image, so use an image of the view
- NSView *tabView = [[cell representedObject] view];
- viewImage = [[[NSImage alloc] initWithSize:[tabView frame].size] autorelease];
- [viewImage lockFocus];
- [tabView drawRect:[tabView bounds]];
- [viewImage unlockFocus];
- }
-
- if(*outMask | NSBorderlessWindowMask) {
- _dragWindowOffset.height += 22;
- }
-
- return viewImage;
-}
-
-- (NSImage *)_miniwindowImageOfWindow:(NSWindow *)window {
- NSRect rect = [window frame];
- NSImage *image = [[[NSImage alloc] initWithSize:rect.size] autorelease];
- [image lockFocus];
- rect.origin = NSZeroPoint;
- CGContextCopyWindowCaptureContentsToRect([[NSGraphicsContext currentContext] graphicsPort], *(CGRect *)&rect, [NSApp contextID], [window windowNumber], 0);
- [image unlockFocus];
-
- return image;
-}
-
-- (void)_expandWindow:(NSWindow *)window atPoint:(NSPoint)point {
- NSRect frame = [window frame];
- [window setFrameTopLeftPoint:NSMakePoint(point.x - frame.size.width / 2, point.y + frame.size.height / 2)];
- [window setAlphaValue:0.0];
- [window makeKeyAndOrderFront:nil];
-
- NSAnimation *animation = [[NSAnimation alloc] initWithDuration:0.25 animationCurve:NSAnimationEaseInOut];
- [animation setAnimationBlockingMode:NSAnimationNonblocking];
- [animation setCurrentProgress:0.1];
- [animation startAnimation];
- NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(_expandWindowTimerFired:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys:window, @"Window", animation, @"Animation", nil] repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
-}
-
-- (void)_expandWindowTimerFired:(NSTimer *)timer {
- NSWindow *window = [[timer userInfo] objectForKey:@"Window"];
- NSAnimation *animation = [[timer userInfo] objectForKey:@"Animation"];
- CGAffineTransform transform;
- NSPoint translation;
- NSRect winFrame = [window frame];
-
- translation.x = (winFrame.size.width / 2.0);
- translation.y = (winFrame.size.height / 2.0);
- transform = CGAffineTransformMakeTranslation(translation.x, translation.y);
- transform = CGAffineTransformScale(transform, 1.0 / [animation currentValue], 1.0 / [animation currentValue]);
- transform = CGAffineTransformTranslate(transform, -translation.x, -translation.y);
-
- translation.x = -winFrame.origin.x;
- translation.y = winFrame.origin.y + winFrame.size.height - [[NSScreen mainScreen] frame].size.height;
-
- transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
-
- CGSSetWindowTransform([NSApp contextID], [window windowNumber], transform);
-
- [window setAlphaValue:[animation currentValue]];
-
- if(![animation isAnimating]) {
- [timer invalidate];
- [animation release];
- }
-}
-
-#pragma mark -
-#pragma mark Animation
-
-- (void)animateDrag:(NSTimer *)timer {
- NSEnumerator *e = [[[_participatingTabBars copy] autorelease] objectEnumerator];
- PSMTabBarControl *tabBar;
- while((tabBar = [e nextObject])) {
- [self calculateDragAnimationForTabBar:tabBar];
- [[NSRunLoop currentRunLoop] performSelector:@selector(display) target:tabBar argument:nil order:1 modes:[NSArray arrayWithObjects:@"NSEventTrackingRunLoopMode", @"NSDefaultRunLoopMode", nil]];
- }
-}
-
-- (void)calculateDragAnimationForTabBar:(PSMTabBarControl *)control {
- BOOL removeFlag = YES;
- NSMutableArray *cells = [control cells];
- NSInteger i, cellCount = [cells count];
- CGFloat position = [control orientation] == PSMTabBarHorizontalOrientation ?[[control style] leftMarginForTabBarControl] :[[control style] topMarginForTabBarControl];
-
- // identify target cell
- // mouse at beginning of tabs
- NSPoint mouseLoc = [self currentMouseLoc];
- if([self destinationTabBar] == control) {
- removeFlag = NO;
- if(mouseLoc.x < [[control style] leftMarginForTabBarControl]) {
- [self setTargetCell:[cells objectAtIndex:0]];
- } else {
- NSRect overCellRect;
- PSMTabBarCell *overCell = [control cellForPoint:mouseLoc cellFrame:&overCellRect];
- if(overCell) {
- // mouse among cells - placeholder
- if([overCell isPlaceholder]) {
- [self setTargetCell:overCell];
- } else if([control orientation] == PSMTabBarHorizontalOrientation) {
- // non-placeholders - horizontal orientation
- if(mouseLoc.x < (overCellRect.origin.x + (overCellRect.size.width / 2.0))) {
- // mouse on left side of cell
- [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]];
- } else {
- // mouse on right side of cell
- [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]];
- }
- } else {
- // non-placeholders - vertical orientation
- if(mouseLoc.y < (overCellRect.origin.y + (overCellRect.size.height / 2.0))) {
- // mouse on top of cell
- [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]];
- } else {
- // mouse on bottom of cell
- [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]];
- }
- }
- } else {
- // out at end - must find proper cell (could be more in overflow menu)
- [self setTargetCell:[control lastVisibleTab]];
- }
- }
- } else {
- [self setTargetCell:nil];
- }
-
- for(i = 0; i < cellCount; i++) {
- PSMTabBarCell *cell = [cells objectAtIndex:i];
- NSRect newRect = [cell frame];
- if(![cell isInOverflowMenu]) {
- if([cell isPlaceholder]) {
- if(cell == [self targetCell]) {
- [cell setCurrentStep:([cell currentStep] + 1)];
- } else {
- [cell setCurrentStep:([cell currentStep] - 1)];
- if([cell currentStep] > 0) {
- removeFlag = NO;
- }
- }
-
- if([control orientation] == PSMTabBarHorizontalOrientation) {
- newRect.size.width = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue];
- } else {
- newRect.size.height = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue];
- }
- }
- } else {
- break;
- }
-
- if([control orientation] == PSMTabBarHorizontalOrientation) {
- newRect.origin.x = position;
- position += newRect.size.width;
- } else {
- newRect.origin.y = position;
- position += newRect.size.height;
- }
- [cell setFrame:newRect];
- if([cell indicator]) {
- [[cell indicator] setFrame:[[control style] indicatorRectForTabCell:cell]];
- }
- }
- if(removeFlag) {
- [_participatingTabBars removeObject:control];
- [self removeAllPlaceholdersFromTabBar:control];
- }
-}
-
-#pragma mark -
-#pragma mark Placeholders
-
-- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control withDraggedCell:(PSMTabBarCell *)cell {
- // called upon first drag - must distribute placeholders
- [self distributePlaceholdersInTabBar:control];
-
- NSMutableArray *cells = [control cells];
-
- // replace dragged cell with a placeholder, and clean up surrounding cells
- NSInteger cellIndex = [cells indexOfObject:cell];
- PSMTabBarCell *pc = [[[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:YES inControlView:control] autorelease];
- [cells replaceObjectAtIndex:cellIndex withObject:pc];
- [cells removeObjectAtIndex:(cellIndex + 1)];
- [cells removeObjectAtIndex:(cellIndex - 1)];
-
- if(cellIndex - 2 >= 0) {
- pc = [cells objectAtIndex:cellIndex - 2];
- [pc setTabState:~[pc tabState] & PSMTab_RightIsSelectedMask];
- }
-}
-
-- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control {
- NSUInteger i, numVisibleTabs = [control numberOfVisibleTabs];
- for(i = 0; i < numVisibleTabs; i++) {
- PSMTabBarCell *pc = [[[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control] autorelease];
- [[control cells] insertObject:pc atIndex:(2 * i)];
- }
-
- PSMTabBarCell *pc = [[[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control] autorelease];
- if([[control cells] count] > (2 * numVisibleTabs)) {
- [[control cells] insertObject:pc atIndex:(2 * numVisibleTabs)];
- } else {
- [[control cells] addObject:pc];
- }
-}
-
-- (void)removeAllPlaceholdersFromTabBar:(PSMTabBarControl *)control {
- NSInteger i, cellCount = [[control cells] count];
- for(i = (cellCount - 1); i >= 0; i--) {
- PSMTabBarCell *cell = [[control cells] objectAtIndex:i];
- if([cell isPlaceholder]) {
- [control removeTabForCell:cell];
- }
- }
- // redraw
- [control update:NO];
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder {
- //[super encodeWithCoder:aCoder];
- if([aCoder allowsKeyedCoding]) {
- [aCoder encodeObject:_sourceTabBar forKey:@"sourceTabBar"];
- [aCoder encodeObject:_destinationTabBar forKey:@"destinationTabBar"];
- [aCoder encodeObject:_participatingTabBars forKey:@"participatingTabBars"];
- [aCoder encodeObject:_draggedCell forKey:@"draggedCell"];
- [aCoder encodeInteger:_draggedCellIndex forKey:@"draggedCellIndex"];
- [aCoder encodeBool:_isDragging forKey:@"isDragging"];
- [aCoder encodeObject:_animationTimer forKey:@"animationTimer"];
- [aCoder encodeObject:_sineCurveWidths forKey:@"sineCurveWidths"];
- [aCoder encodePoint:_currentMouseLoc forKey:@"currentMouseLoc"];
- [aCoder encodeObject:_targetCell forKey:@"targetCell"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder {
- //self = [super initWithCoder:aDecoder];
- //if (self) {
- if([aDecoder allowsKeyedCoding]) {
- _sourceTabBar = [[aDecoder decodeObjectForKey:@"sourceTabBar"] retain];
- _destinationTabBar = [[aDecoder decodeObjectForKey:@"destinationTabBar"] retain];
- _participatingTabBars = [[aDecoder decodeObjectForKey:@"participatingTabBars"] retain];
- _draggedCell = [[aDecoder decodeObjectForKey:@"draggedCell"] retain];
- _draggedCellIndex = [aDecoder decodeIntegerForKey:@"draggedCellIndex"];
- _isDragging = [aDecoder decodeBoolForKey:@"isDragging"];
- _animationTimer = [[aDecoder decodeObjectForKey:@"animationTimer"] retain];
- _sineCurveWidths = [[aDecoder decodeObjectForKey:@"sineCurveWidths"] retain];
- _currentMouseLoc = [aDecoder decodePointForKey:@"currentMouseLoc"];
- _targetCell = [[aDecoder decodeObjectForKey:@"targetCell"] retain];
- }
- //}
- return self;
-}
-
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragView.h b/frontends/cocoa/PSMTabBarControl/PSMTabDragView.h
deleted file mode 100644
index f8018d290..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragView.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// PSMTabDragView.h
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/17/07.
-// Copyright 2007 Kent Sutherland. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@interface PSMTabDragView : NSView {
- NSImage *_image;
- NSImage *_alternateImage;
- CGFloat _alpha;
-}
-- (void)setFadeValue:(CGFloat)value;
-- (NSImage *)image;
-- (void)setImage:(NSImage *)image;
-- (NSImage *)alternateImage;
-- (void)setAlternateImage:(NSImage *)image;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragView.m b/frontends/cocoa/PSMTabBarControl/PSMTabDragView.m
deleted file mode 100644
index 2c9781dbc..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragView.m
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// PSMTabDragView.m
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/17/07.
-// Copyright 2007 Kent Sutherland. All rights reserved.
-//
-
-#import "PSMTabDragView.h"
-
-
-@implementation PSMTabDragView
-
-- (id)initWithFrame:(NSRect)frame {
- if((self = [super initWithFrame:frame])) {
- _alpha = 1.0;
- }
- return self;
-}
-
-- (void)dealloc {
- [_image release];
- [_alternateImage release];
- [super dealloc];
-}
-
-- (void)drawRect:(NSRect)rect {
- //1.0 fade means show the primary image
- //0.0 fade means show the secondary image
- CGFloat primaryAlpha = _alpha + 0.001f, alternateAlpha = 1.001f - _alpha;
- NSRect srcRect;
- srcRect.origin = NSZeroPoint;
- srcRect.size = [_image size];
-
- [_image drawInRect:[self bounds] fromRect:srcRect operation:NSCompositeSourceOver fraction:primaryAlpha];
- srcRect.size = [_alternateImage size];
- [_alternateImage drawInRect:[self bounds] fromRect:srcRect operation:NSCompositeSourceOver fraction:alternateAlpha];
-}
-
-- (void)setFadeValue:(CGFloat)value {
- _alpha = value;
-}
-
-- (NSImage *)image {
- return _image;
-}
-
-- (void)setImage:(NSImage *)image {
- [_image release];
- _image = [image retain];
-}
-
-- (NSImage *)alternateImage {
- return _alternateImage;
-}
-
-- (void)setAlternateImage:(NSImage *)image {
- [_alternateImage release];
- _alternateImage = [image retain];
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.h b/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.h
deleted file mode 100644
index 04cde248c..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// PSMTabDragWindow.h
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/1/06.
-// Copyright 2006 Kent Sutherland. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@class PSMTabDragView;
-
-@interface PSMTabDragWindow : NSWindow {
- PSMTabDragView *_dragView;
-}
-+ (PSMTabDragWindow *)dragWindowWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask;
-
-- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask;
-- (PSMTabDragView *)dragView;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.m b/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.m
deleted file mode 100644
index d6fcc95a3..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindow.m
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// PSMTabDragWindow.m
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/1/06.
-// Copyright 2006 Kent Sutherland. All rights reserved.
-//
-
-#import "PSMTabDragWindow.h"
-#import "PSMTabDragView.h"
-
-@implementation PSMTabDragWindow
-
-+ (PSMTabDragWindow *)dragWindowWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask {
- return [[[PSMTabDragWindow alloc] initWithImage:image styleMask:styleMask] autorelease];
-}
-
-- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask {
- NSSize size = [image size];
-
- if((self = [super initWithContentRect:NSMakeRect(0, 0, size.width, size.height) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO])) {
- _dragView = [[[PSMTabDragView alloc] initWithFrame:NSMakeRect(0, 0, size.width, size.height)] autorelease];
- [self setContentView:_dragView];
- [self setLevel:NSStatusWindowLevel];
- [self setIgnoresMouseEvents:YES];
- [self setOpaque:NO];
-
- [_dragView setImage:image];
-
- //Set the size of the window to be the exact size of the drag image
- NSRect windowFrame = [self frame];
- windowFrame.origin.y += windowFrame.size.height - size.height;
- windowFrame.size = size;
-
- if(styleMask | NSBorderlessWindowMask) {
- windowFrame.size.height += 22;
- }
-
- [self setFrame:windowFrame display:YES];
- }
- return self;
-}
-
-- (PSMTabDragView *)dragView {
- return _dragView;
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.h b/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.h
deleted file mode 100644
index 5948207f2..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// PSMTabDragWindowController.h
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/18/07.
-// Copyright 2007 Kent Sutherland. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-#import "PSMTabBarControl.h"
-
-#define kPSMTabDragWindowAlpha 0.75
-#define kPSMTabDragAlphaInterval 0.15
-
-@class PSMTabDragView;
-
-@interface PSMTabDragWindowController : NSWindowController {
- PSMTabBarTearOffStyle _tearOffStyle;
- PSMTabDragView *_view;
- NSAnimation *_animation;
- NSTimer *_timer;
-
- BOOL _showingAlternate;
- NSRect _originalWindowFrame;
-}
-- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger) styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle;
-
-- (NSImage *)image;
-- (NSImage *)alternateImage;
-- (void)setAlternateImage:(NSImage *)image;
-- (BOOL)isAnimating;
-- (void)switchImages;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.m b/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.m
deleted file mode 100644
index 3a6e8c663..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabDragWindowController.m
+++ /dev/null
@@ -1,111 +0,0 @@
-//
-// PSMTabDragWindowController.m
-// PSMTabBarControl
-//
-// Created by Kent Sutherland on 6/18/07.
-// Copyright 2007 Kent Sutherland. All rights reserved.
-//
-
-#import "PSMTabDragWindowController.h"
-#import "PSMTabDragWindow.h"
-#import "PSMTabDragView.h"
-
-@implementation PSMTabDragWindowController
-
-- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle {
- PSMTabDragWindow *window = [PSMTabDragWindow dragWindowWithImage:image styleMask:styleMask];
- if((self = [super initWithWindow:window])) {
- _view = [[window dragView] retain];
- _tearOffStyle = tearOffStyle;
-
- if(tearOffStyle == PSMTabBarTearOffMiniwindow) {
- [window setBackgroundColor:[NSColor clearColor]];
- [window setHasShadow:YES];
- }
-
- [window setAlphaValue:kPSMTabDragWindowAlpha];
- }
- return self;
-}
-
-- (void)dealloc {
- if(_timer) {
- [_timer invalidate];
- }
-
- if(_animation) {
- [_animation release];
- }
-
- [_view release];
- [super dealloc];
-}
-
-- (NSImage *)image {
- return [_view image];
-}
-
-- (NSImage *)alternateImage {
- return [_view alternateImage];
-}
-
-- (void)setAlternateImage:(NSImage *)image {
- [_view setAlternateImage:image];
-}
-
-- (BOOL)isAnimating {
- return _animation != nil;
-}
-
-- (void)switchImages {
- if(_tearOffStyle != PSMTabBarTearOffMiniwindow || ![_view alternateImage]) {
- return;
- }
-
- CGFloat progress = 0;
- _showingAlternate = !_showingAlternate;
-
- if(_animation) {
- //An animation already exists, get the current progress
- progress = 1.0f - [_animation currentProgress];
- [_animation stopAnimation];
- [_animation release];
- }
-
- //begin animating
- _animation = [[NSAnimation alloc] initWithDuration:0.25 animationCurve:NSAnimationEaseInOut];
- [_animation setAnimationBlockingMode:NSAnimationNonblocking];
- [_animation setCurrentProgress:progress];
- [_animation startAnimation];
-
- _originalWindowFrame = [[self window] frame];
-
- if(_timer) {
- [_timer invalidate];
- }
- _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f / 30.0f target:self selector:@selector(animateTimer:) userInfo:nil repeats:YES];
-}
-
-- (void)animateTimer:(NSTimer *)timer {
- NSRect frame = _originalWindowFrame;
- NSImage *currentImage = _showingAlternate ?[_view alternateImage] :[_view image];
- NSSize size = [currentImage size];
- NSPoint mousePoint = [NSEvent mouseLocation];
- CGFloat animationValue = [_animation currentValue];
-
- frame.size.width = _originalWindowFrame.size.width + (size.width - _originalWindowFrame.size.width) * animationValue;
- frame.size.height = _originalWindowFrame.size.height + (size.height - _originalWindowFrame.size.height) * animationValue;
- frame.origin.x = mousePoint.x - (frame.size.width / 2);
- frame.origin.y = mousePoint.y - (frame.size.height / 2);
-
- [_view setFadeValue:_showingAlternate ? 1.0f - animationValue : animationValue];
- [[self window] setFrame:frame display:YES];
-
- if(![_animation isAnimating]) {
- [_animation release], _animation = nil;
- [timer invalidate];
- _timer = nil;
- }
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabStyle.h b/frontends/cocoa/PSMTabBarControl/PSMTabStyle.h
deleted file mode 100644
index ca3717435..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMTabStyle.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// PSMTabStyle.h
-// PSMTabBarControl
-//
-// Created by John Pannell on 2/17/06.
-// Copyright 2006 Positive Spin Media. All rights reserved.
-//
-
-/*
- Protocol to be observed by all style delegate objects. These objects handle the drawing responsibilities for PSMTabBarCell; once the control has been assigned a style, the background and cells draw consistent with that style. Design pattern and implementation by David Smith, Seth Willits, and Chris Forsythe, all touch up and errors by John P. :-)
- */
-
-#import "PSMTabBarCell.h"
-#import "PSMTabBarControl.h"
-
-@protocol PSMTabStyle <NSObject>
-
-// identity
-- (NSString *)name;
-
-// control specific parameters
-- (CGFloat)leftMarginForTabBarControl;
-- (CGFloat)rightMarginForTabBarControl;
-- (CGFloat)topMarginForTabBarControl;
-- (void)setOrientation:(PSMTabBarOrientation)value;
-
-// add tab button
-- (NSImage *)addTabButtonImage;
-- (NSImage *)addTabButtonPressedImage;
-- (NSImage *)addTabButtonRolloverImage;
-
-// cell specific parameters
-- (NSRect)dragRectForTabCell:(PSMTabBarCell *)cell orientation:(PSMTabBarOrientation)orientation;
-- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame;
-- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell;
-- (NSRect)indicatorRectForTabCell:(PSMTabBarCell *)cell;
-- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell;
-- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell;
-- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell;
-- (CGFloat)tabCellHeight;
-
-// cell values
-- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell;
-- (NSAttributedString *)attributedStringValueForTabCell:(PSMTabBarCell *)cell;
-
-// drawing
-- (void)drawTabCell:(PSMTabBarCell *)cell;
-- (void)drawBackgroundInRect:(NSRect)rect;
-- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect;
-
-@end
-
-@interface PSMTabBarControl (StyleAccessors)
-
-- (NSMutableArray *)cells;
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.h b/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.h
deleted file mode 100644
index 20202536a..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// PSMUnifiedTabStyle.h
-// --------------------
-//
-// Created by Keith Blount on 30/04/2006.
-// Copyright 2006 __MyCompanyName__. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-#import "PSMTabStyle.h"
-
-@interface PSMUnifiedTabStyle : NSObject <PSMTabStyle> {
- NSImage *unifiedCloseButton;
- NSImage *unifiedCloseButtonDown;
- NSImage *unifiedCloseButtonOver;
- NSImage *unifiedCloseDirtyButton;
- NSImage *unifiedCloseDirtyButtonDown;
- NSImage *unifiedCloseDirtyButtonOver;
- NSImage *_addTabButtonImage;
- NSImage *_addTabButtonPressedImage;
- NSImage *_addTabButtonRolloverImage;
-
- NSDictionary *_objectCountStringAttributes;
-
- CGFloat leftMargin;
- PSMTabBarControl *tabBar;
-}
-- (void)setLeftMarginForTabBarControl:(CGFloat)margin;
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.m b/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.m
deleted file mode 100644
index 77be601be..000000000
--- a/frontends/cocoa/PSMTabBarControl/PSMUnifiedTabStyle.m
+++ /dev/null
@@ -1,573 +0,0 @@
-//
-// PSMUnifiedTabStyle.m
-// --------------------
-//
-// Created by Keith Blount on 30/04/2006.
-// Copyright 2006 __MyCompanyName__. All rights reserved.
-//
-
-#import "PSMUnifiedTabStyle.h"
-#import "PSMTabBarCell.h"
-#import "PSMTabBarControl.h"
-#import "NSBezierPath_AMShading.h"
-
-#define kPSMUnifiedObjectCounterRadius 7.0
-#define kPSMUnifiedCounterMinWidth 20
-
-@interface PSMUnifiedTabStyle (Private)
-- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView;
-@end
-
-@implementation PSMUnifiedTabStyle
-
-- (NSString *)name {
- return @"Unified";
-}
-
-#pragma mark -
-#pragma mark Creation/Destruction
-
-- (id) init {
- if((self = [super init])) {
- unifiedCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]];
- unifiedCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]];
- unifiedCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]];
-
- unifiedCloseDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front"]];
- unifiedCloseDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Pressed"]];
- unifiedCloseDirtyButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Rollover"]];
-
- _addTabButtonImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNew"]];
- _addTabButtonPressedImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewPressed"]];
- _addTabButtonRolloverImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewRollover"]];
-
- _objectCountStringAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[[NSFontManager sharedFontManager] convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask], NSFontAttributeName,
- [[NSColor whiteColor] colorWithAlphaComponent:0.85], NSForegroundColorAttributeName,
- nil, nil];
-
- leftMargin = 5.0;
- }
- return self;
-}
-
-- (void)dealloc {
- [unifiedCloseButton release];
- [unifiedCloseButtonDown release];
- [unifiedCloseButtonOver release];
- [unifiedCloseDirtyButton release];
- [unifiedCloseDirtyButtonDown release];
- [unifiedCloseDirtyButtonOver release];
- [_addTabButtonImage release];
- [_addTabButtonPressedImage release];
- [_addTabButtonRolloverImage release];
-
- [_objectCountStringAttributes release];
-
- [super dealloc];
-}
-
-#pragma mark -
-#pragma mark Control Specific
-
-- (void)setLeftMarginForTabBarControl:(CGFloat)margin {
- leftMargin = margin;
-}
-
-- (CGFloat)leftMarginForTabBarControl {
- return leftMargin;
-}
-
-- (CGFloat)rightMarginForTabBarControl {
- return 24.0f;
-}
-
-- (CGFloat)topMarginForTabBarControl {
- return 10.0f;
-}
-
-- (void)setOrientation:(PSMTabBarOrientation)value {
-}
-
-#pragma mark -
-#pragma mark Add Tab Button
-
-- (NSImage *)addTabButtonImage {
- return _addTabButtonImage;
-}
-
-- (NSImage *)addTabButtonPressedImage {
- return _addTabButtonPressedImage;
-}
-
-- (NSImage *)addTabButtonRolloverImage {
- return _addTabButtonRolloverImage;
-}
-
-#pragma mark -
-#pragma mark Cell Specific
-
-- (NSRect)dragRectForTabCell:(PSMTabBarCell *)cell orientation:(PSMTabBarOrientation)orientation {
- NSRect dragRect = [cell frame];
- dragRect.size.width++;
- return dragRect;
-}
-
-- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame {
- if([cell hasCloseButton] == NO) {
- return NSZeroRect;
- }
-
- NSRect result;
- result.size = [unifiedCloseButton size];
- result.origin.x = cellFrame.origin.x + MARGIN_X;
- result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
-
- return result;
-}
-
-- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell {
- NSRect cellFrame = [cell frame];
-
- if([cell hasIcon] == NO) {
- return NSZeroRect;
- }
-
- NSRect result;
- result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth);
- result.origin.x = cellFrame.origin.x + MARGIN_X;
- result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0;
-
- if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
- result.origin.x += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
- }
-
- return result;
-}
-
-- (NSRect)indicatorRectForTabCell:(PSMTabBarCell *)cell {
- NSRect cellFrame = [cell frame];
-
- if([[cell indicator] isHidden]) {
- return NSZeroRect;
- }
-
- NSRect result;
- result.size = NSMakeSize(kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth);
- result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - kPSMTabBarIndicatorWidth;
- result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0;
-
- return result;
-}
-
-- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell {
- NSRect cellFrame = [cell frame];
-
- if([cell count] == 0) {
- return NSZeroRect;
- }
-
- CGFloat countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width;
- countWidth += (2 * kPSMUnifiedObjectCounterRadius - 6.0);
- if(countWidth < kPSMUnifiedCounterMinWidth) {
- countWidth = kPSMUnifiedCounterMinWidth;
- }
-
- NSRect result;
- result.size = NSMakeSize(countWidth, 2 * kPSMUnifiedObjectCounterRadius); // temp
- result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width;
- result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
-
- if(![[cell indicator] isHidden]) {
- result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding;
- }
-
- return result;
-}
-
-
-- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell {
- CGFloat resultWidth = 0.0;
-
- // left margin
- resultWidth = MARGIN_X;
-
- // close button?
- if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
- resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
- }
-
- // icon?
- if([cell hasIcon]) {
- resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
- }
-
- // the label
- resultWidth += kPSMMinimumTitleWidth;
-
- // object counter?
- if([cell count] > 0) {
- resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
- }
-
- // indicator?
- if([[cell indicator] isHidden] == NO) {
- resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
- }
-
- // right margin
- resultWidth += MARGIN_X;
-
- return ceil(resultWidth);
-}
-
-- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell {
- CGFloat resultWidth = 0.0;
-
- // left margin
- resultWidth = MARGIN_X;
-
- // close button?
- if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
- resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
- }
-
- // icon?
- if([cell hasIcon]) {
- resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
- }
-
- // the label
- resultWidth += [[cell attributedStringValue] size].width;
-
- // object counter?
- if([cell count] > 0) {
- resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
- }
-
- // indicator?
- if([[cell indicator] isHidden] == NO) {
- resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
- }
-
- // right margin
- resultWidth += MARGIN_X;
-
- return ceil(resultWidth);
-}
-
-- (CGFloat)tabCellHeight {
- return kPSMTabBarControlHeight;
-}
-
-#pragma mark -
-#pragma mark Cell Values
-
-- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell {
- NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[cell count]];
- return [[[NSMutableAttributedString alloc] initWithString:contents attributes:_objectCountStringAttributes] autorelease];
-}
-
-- (NSAttributedString *)attributedStringValueForTabCell:(PSMTabBarCell *)cell {
- NSMutableAttributedString *attrStr;
- NSString * contents = [cell stringValue];
- attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
- NSRange range = NSMakeRange(0, [contents length]);
-
- [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
-
- // Paragraph Style for Truncating Long Text
- static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil;
- if(!TruncatingTailParagraphStyle) {
- TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
- [TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
- }
- [attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range];
-
- return attrStr;
-}
-
-#pragma mark -
-#pragma mark ---- drawing ----
-
-- (void)drawTabCell:(PSMTabBarCell *)cell {
- NSRect cellFrame = [cell frame];
-
- NSToolbar *toolbar = [[[cell controlView] window] toolbar];
- BOOL showsBaselineSeparator = (toolbar && [toolbar respondsToSelector:@selector(showsBaselineSeparator)] && [toolbar showsBaselineSeparator]);
- if(!showsBaselineSeparator) {
- cellFrame.origin.y += 1.0;
- cellFrame.size.height -= 1.0;
- }
-
- NSColor * lineColor = nil;
- NSBezierPath* bezier = [NSBezierPath bezierPath];
- lineColor = [NSColor colorWithCalibratedWhite:0.576 alpha:1.0];
-
- if(!showsBaselineSeparator || [cell state] == NSOnState) {
- // selected tab
- NSRect aRect = NSMakeRect(cellFrame.origin.x + 0.5, cellFrame.origin.y - 0.5, cellFrame.size.width, cellFrame.size.height);
-
- // frame
- CGFloat radius = MIN(6.0, 0.5f * MIN(NSWidth(aRect), NSHeight(aRect)));
- NSRect rect = NSInsetRect(aRect, radius, radius);
-
- [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0];
-
- [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0];
-
- NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect));
- [bezier appendBezierPathWithPoints:&cornerPoint count:1];
-
- cornerPoint = NSMakePoint(NSMinX(aRect), NSMaxY(aRect));
- [bezier appendBezierPathWithPoints:&cornerPoint count:1];
-
- [bezier closePath];
-
- //[[NSColor windowBackgroundColor] set];
- //[bezier fill];
- if([NSApp isActive]) {
- if([cell state] == NSOnState) {
- [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.99 alpha:1.0]
- endColor:[NSColor colorWithCalibratedWhite:0.941 alpha:1.0]];
- } else if([cell isHighlighted]) {
- [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0]
- endColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0]];
- } else {
- [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0]
- endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
- }
- }
-
- [lineColor set];
- [bezier stroke];
- } else{
- // unselected tab
- NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
- aRect.origin.y += 0.5;
- aRect.origin.x += 1.5;
- aRect.size.width -= 1;
-
- aRect.origin.x -= 1;
- aRect.size.width += 1;
-
- // rollover
- if([cell isHighlighted]) {
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set];
- NSRectFillUsingOperation(aRect, NSCompositeSourceAtop);
- }
-
- // frame
-
- [lineColor set];
- [bezier moveToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y - 0.5)];
- if(!([cell tabState] & PSMTab_RightIsSelectedMask)) {
- [bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))];
- }
-
- [bezier stroke];
-
- // Create a thin lighter line next to the dividing line for a bezel effect
- if(!([cell tabState] & PSMTab_RightIsSelectedMask)) {
- [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(aRect) + 1.0, aRect.origin.y - 0.5)
- toPoint:NSMakePoint(NSMaxX(aRect) + 1.0, NSMaxY(aRect) - 2.5)];
- }
-
- // If this is the leftmost tab, we want to draw a line on the left, too
- if([cell tabState] & PSMTab_PositionLeftMask) {
- [lineColor set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x, aRect.origin.y - 0.5)
- toPoint:NSMakePoint(aRect.origin.x, NSMaxY(aRect) - 2.5)];
- [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x + 1.0, aRect.origin.y - 0.5)
- toPoint:NSMakePoint(aRect.origin.x + 1.0, NSMaxY(aRect) - 2.5)];
- }
- }
-
- [self drawInteriorWithTabCell:cell inView:[cell controlView]];
-}
-
-
-- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView {
- NSRect cellFrame = [cell frame];
- CGFloat labelPosition = cellFrame.origin.x + MARGIN_X;
-
- // close button
- if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
- NSSize closeButtonSize = NSZeroSize;
- NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame];
- NSImage * closeButton = nil;
-
- closeButton = [cell isEdited] ? unifiedCloseDirtyButton : unifiedCloseButton;
-
- if([cell closeButtonOver]) {
- closeButton = [cell isEdited] ? unifiedCloseDirtyButtonOver : unifiedCloseButtonOver;
- }
- if([cell closeButtonPressed]) {
- closeButton = [cell isEdited] ? unifiedCloseDirtyButtonDown : unifiedCloseButtonDown;
- }
-
- closeButtonSize = [closeButton size];
- if([controlView isFlipped]) {
- closeButtonRect.origin.y += closeButtonRect.size.height;
- }
-
- [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0];
-
- // scoot label over
- labelPosition += closeButtonSize.width + kPSMTabBarCellPadding;
- }
-
- // icon
- if([cell hasIcon]) {
- NSRect iconRect = [self iconRectForTabCell:cell];
- NSImage *icon = [[[cell representedObject] identifier] icon];
- if([controlView isFlipped]) {
- iconRect.origin.y += iconRect.size.height;
- }
-
- // center in available space (in case icon image is smaller than kPSMTabBarIconWidth)
- if([icon size].width < kPSMTabBarIconWidth) {
- iconRect.origin.x += (kPSMTabBarIconWidth - [icon size].width) / 2.0;
- }
- if([icon size].height < kPSMTabBarIconWidth) {
- iconRect.origin.y -= (kPSMTabBarIconWidth - [icon size].height) / 2.0;
- }
-
- [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0];
-
- // scoot label over
- labelPosition += iconRect.size.width + kPSMTabBarCellPadding;
- }
-
- // label rect
- NSRect labelRect;
- labelRect.origin.x = labelPosition;
- labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding;
- NSSize s = [[cell attributedStringValue] size];
- labelRect.origin.y = cellFrame.origin.y + (cellFrame.size.height - s.height) / 2.0 - 1.0;
- labelRect.size.height = s.height;
-
- if(![[cell indicator] isHidden]) {
- labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding);
- }
-
- // object counter
- if([cell count] > 0) {
- [[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set];
- NSBezierPath *path = [NSBezierPath bezierPath];
- NSRect myRect = [self objectCounterRectForTabCell:cell];
- myRect.origin.y -= 1.0;
- [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y)];
- [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y)];
- [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:270.0 endAngle:90.0];
- [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + myRect.size.height)];
- [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:90.0 endAngle:270.0];
- [path fill];
-
- // draw attributed string centered in area
- NSRect counterStringRect;
- NSAttributedString *counterString = [self attributedObjectCountValueForTabCell:cell];
- counterStringRect.size = [counterString size];
- counterStringRect.origin.x = myRect.origin.x + ((myRect.size.width - counterStringRect.size.width) / 2.0) + 0.25;
- counterStringRect.origin.y = myRect.origin.y + ((myRect.size.height - counterStringRect.size.height) / 2.0) + 0.5;
- [counterString drawInRect:counterStringRect];
-
- labelRect.size.width -= myRect.size.width + kPSMTabBarCellPadding;
- }
-
- // label
- [[cell attributedStringValue] drawInRect:labelRect];
-}
-
-- (void)drawBackgroundInRect:(NSRect)rect {
- //Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area
- rect = [tabBar bounds];
-
- NSRect gradientRect = rect;
- gradientRect.size.height -= 1.0;
-
- NSBezierPath *path = [NSBezierPath bezierPathWithRect:gradientRect];
- [path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0]
- endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
- [[NSColor colorWithCalibratedWhite:0.576 alpha:1.0] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, NSMaxY(rect) - 0.5)
- toPoint:NSMakePoint(NSMaxX(rect), NSMaxY(rect) - 0.5)];
-
- if(![[[tabBar tabView] window] isKeyWindow]) {
- [[NSColor windowBackgroundColor] set];
- NSRectFill(gradientRect);
- }
-}
-
-- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect {
- tabBar = bar;
- [self drawBackgroundInRect:rect];
-
- // no tab view == not connected
- if(![bar tabView]) {
- NSRect labelRect = rect;
- labelRect.size.height -= 4.0;
- labelRect.origin.y += 4.0;
- NSMutableAttributedString *attrStr;
- NSString *contents = @"PSMTabBarControl";
- attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
- NSRange range = NSMakeRange(0, [contents length]);
- [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
- NSMutableParagraphStyle *centeredParagraphStyle = nil;
- if(!centeredParagraphStyle) {
- centeredParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
- [centeredParagraphStyle setAlignment:NSCenterTextAlignment];
- }
- [attrStr addAttribute:NSParagraphStyleAttributeName value:centeredParagraphStyle range:range];
- [attrStr drawInRect:labelRect];
- return;
- }
-
- // draw cells
- NSEnumerator *e = [[bar cells] objectEnumerator];
- PSMTabBarCell *cell;
- while((cell = [e nextObject])) {
- if([bar isAnimating] || (![cell isInOverflowMenu] && NSIntersectsRect([cell frame], rect))) {
- [cell drawWithFrame:[cell frame] inView:bar];
- }
- }
-}
-
-#pragma mark -
-#pragma mark Archiving
-
-- (void)encodeWithCoder:(NSCoder *)aCoder {
- //[super encodeWithCoder:aCoder];
- if([aCoder allowsKeyedCoding]) {
- [aCoder encodeObject:unifiedCloseButton forKey:@"unifiedCloseButton"];
- [aCoder encodeObject:unifiedCloseButtonDown forKey:@"unifiedCloseButtonDown"];
- [aCoder encodeObject:unifiedCloseButtonOver forKey:@"unifiedCloseButtonOver"];
- [aCoder encodeObject:unifiedCloseDirtyButton forKey:@"unifiedCloseDirtyButton"];
- [aCoder encodeObject:unifiedCloseDirtyButtonDown forKey:@"unifiedCloseDirtyButtonDown"];
- [aCoder encodeObject:unifiedCloseDirtyButtonOver forKey:@"unifiedCloseDirtyButtonOver"];
- [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"];
- [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"];
- [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"];
- }
-}
-
-- (id)initWithCoder:(NSCoder *)aDecoder {
- // self = [super initWithCoder:aDecoder];
- //if (self) {
- if([aDecoder allowsKeyedCoding]) {
- unifiedCloseButton = [[aDecoder decodeObjectForKey:@"unifiedCloseButton"] retain];
- unifiedCloseButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonDown"] retain];
- unifiedCloseButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonOver"] retain];
- unifiedCloseDirtyButton = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButton"] retain];
- unifiedCloseDirtyButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonDown"] retain];
- unifiedCloseDirtyButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonOver"] retain];
- _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain];
- _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain];
- _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain];
- }
- //}
- return self;
-}
-
-@end
diff --git a/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/TXT.rtf b/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/TXT.rtf
deleted file mode 100644
index acd9372a2..000000000
--- a/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/TXT.rtf
+++ /dev/null
@@ -1,186 +0,0 @@
-{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf380
-{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;\f2\fswiss\fcharset77 Helvetica-Oblique;
-\f3\fnil\fcharset77 Monaco;}
-{\colortbl;\red255\green255\blue255;\red118\green15\blue80;\red0\green0\blue255;\red35\green110\blue37;
-}
-{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid1}}
-{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}}
-\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
-
-\f0\b\fs24 \cf0 \
-PSMTabBarControl (and related classes)\
-
-\f1\b0 developed by John Pannell, Positive Spin Media\
-\
-as seen in the super-cool app...\
-\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
-\cf0 {{\NeXTGraphic startpage.gif \width7200 \height2820
-}¬}\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
-\cf0 \
-\
-\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
-\cf0 This source code and all related materials are released under the BSD license, which is explained at the end of this document, along with some other legalese. I've made my best effort to make everything bug free, but please let me know of any bugs found or suggestions you have: johnp@positivespinmedia.com.\
-\
-
-\f0\b Purpose
-\f1\b0 \
-\
-PSMTabBarControl seeks to provide developers with a high-quality, easy to use GUI to manage an NSTabView (or subclasses) in a manner similar to Safari's tabbed browsing implementation. It attempts to add a few features as well. Here's what you get:\
-\
-
-\f0\b The look:
-\f1\b0 a control/cell architecture that draws the expected tab appearance below a toolbar or similar view. Included styles work consistently in Aqua, Metal, or customized metal variations by basing fills on the window's background color. Includes drawing of a close button, and rollover states for the close button and tab cell. Also provides pop-up button and menu when tabs overflow available space, and support for individual tab progress indicators, icons, and object counters. Tabs can be drawn sized to fit the string content of the label, or uniformly sized.\
-\
-
-\f0\b The functionality:
-\f1\b0 Close button removes tabs, click on a tab cell selects. Indicators start, stop, and hide if things are hooked up correctly.\
-\
-
-\f0\b Extras:
-\f1\b0 Supports multi-window drag-and-drop reordering of the tabs with aqua-licious animation.\
-\
-
-\f0\b Files
-\f1\b0 \
-\
-Your project will need the files in the "Framework" folder of the project. The actual framework packages these (and some images) up nicely for you, if desired. Please look over the "TabBarControlDemo" target of the source code project to see exactly what is needed to get everything to build. Building and playing with the demo is also a good way to get a feel for the features provided by these classes.\
-\
-
-\f0\b Usage
-\f1\b0 \
-\
-Simply drag a custom view object from the views palette in IB, read the PSMTabBarControl class into IB, and set the view's custom class to PSMTabBarControl. Then connect the control's tabview outlet to the tab view being controlled, and make the control the delegate of the tab view. You can also connect the control's "partner view" outlet to another view that will resize in response to the hide/show behavior of the control.\
-\
-Alternately, you can build the Palette subproject and add the built IB palette to Interface Builder. In this case, creating and configuring an instance is as easy and drag, drop, and a few clicks. A demo movie and the built palette are available in a separate download from my website: http://www.positivespinmedia.com/dev/PSMTabBarControl.html\
-\
-
-\f2\i Please read the PSMTabBarControlDoc.html file in the documentation folder of this project. It provides an Apple-ish page describing the interface and usage of this object.
-\f1\i0 \
-\
-
-\f0\b Patterns of Use
-\f1\b0 \
-\
-There are a few random notes I can think of for usage guidelines...\
-\
-- You may see a line between the toolbar and the control in your app; it is part of the toolbar. In Tiger, you can eliminate the appearance of this line:\
-\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f3\fs20 \cf0 \CocoaLigature0 SInt32 MacVersion;\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-\cf2 if\cf0 (Gestalt(gestaltSystemVersion, &MacVersion) == noErr)\{\
- \cf2 if\cf0 (MacVersion >= \cf3 0x1040\cf0 )\{\
- \cf4 // this call is Tiger only\cf0 \
- [toolbar setShowsBaselineSeparator:\cf2 NO\cf0 ];\
- \}\
-\}\
-\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f1\fs24 \cf0 - In general, there is no reason for your app objects to communicate (outside of configuration) with the PSMTabBarControl at all. Changes made to the NSTabView instance programmatically should be directed at the NSTabView instance itself, and the control will update to reflect the changes made.\
-\
-- Your app might want to receive tab view delegate notifications in order to perform some actions. No problem, simply make the desired object the delegate of the PSMTabBarControl instance... it passes along all tab view notifications. Note that it uses these notifications to make changes itself - read the source code to make sure you aren't tripping over something.\
-\
-- The control creates bindings between each cell's progress indicator and the represented NSTabViewItem's identifier object, if it can. In my app design, I set an instance of NSObjectController as the NSTabViewItem's identifier, and then bind to the "isProcessing" key of the controller's content object. All of this can be seen in the source of the demo app...\
-\
-- The control can be set to hide itself when there is only a single tab, and can also be told to hide/show on demand. It can animate to appear and disappear, and will resize something to compensate for the missing window real estate. By default, it will resize the window, but you can also connect the "partnerView" outlet in IB to specify another view to resize to take up the missing space. Note that this takes some attention to sizing springs and wires to get right, and complex views may need a container view to achieve the desired effect.\
-\
-- The control can be configured to draw an attractive "Add Tab" button at the end of the tab cells. Unfortunately, the button is all looks and no brains - it has no idea what your app wants to do when adding a tab. If you configure your app to show the add tab button, you need to hook up the add tab button to the proper target with the proper selector. Something like this will do nicely in your app controller's awakeFromNib:\
-\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f3\fs20 \cf4 // hook up add tab button\cf0 \
-[[tabBar addTabButton] setTarget:\cf2 self\cf0 ];\
-[[tabBar addTabButton] setAction:\cf2 @selector\cf0 (addNewTab:)];
-\f1\fs24 \
-\
-- The tabs have some sizing options: You can specify the minimum width, maximum width, and optimum width, as well as spcifying if the tabs should size to fit their label or not. The sizing bahavior of the tabs is as follows: If "size to fit" is specified, then tabs will be generated to fit the label, but will never exceed the specified max or min widths. Once the end of the control is reached, the overflow menu will appear as tabs are added; the last tab will squeeze in if it can, or the remaining tabs will stretch to occupy the full control. If "size to fit" is not specified, then all successive tabs will appear at the optimum width. Once the end of the control is reached, adding new tabs will cause all tabs to shrink to accomodate, until the minumum width is reached, and then the overflow menu will be used; max width is ignored in this case. Hopefully that all makes sense :-)\
-\
-- PSMTabBarControl will load the existing tabs from the tabView outlet at startup. However, many of the advanced features (icon display, progress indicator, object count) rely on binding to a controller that is likely not set up in IB. Solution? Nuke the existing tabs in the NSTabView and add new ones, configured the way you like. The demo app does this in the awakeFromNib: method of the app controller.\
-\
-- As a design choice, I elected to keep a cell object around until its tab was closed, instead of "churning" cell objects in each update cycle. Each cell keeps its NSTabViewItem as its representedObject and maintains reference that way, rather than by any index. As a result of this, drag-and-drop reordering of tabs does not change the underlying NSTabView instance at all. All that to say: don't rely on numerical indices if communicating with both the control and the tab view - the indices may not correlate if the user moved some tabs around (and remember - you shouldn't need to communicate with the control anyway :-). The Shiira Project, from which I gained much insight and inspiration from for this UI element, elected to scrap and rebuild the array of cells each time through the update cycle, and rely on indices to correlate between cells and NSTabViewItems. I felt the representedObject route was cleaner, and preferred not to churn objects.\
-\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f0\b \cf0 Improvements?
-\f1\b0 \
-\
-Pipe up if you think of something you'd like to see; here's my current list:\
-\
-- "Pop-up" tabs - like pop-up folders in the finder, in case you want to drag to a destination in another tab.\
-- Support for the
-\f3\fs22 \CocoaLigature1 NSUnifiedTitleAndToolbarWindowMask
-\f1\fs24 \CocoaLigature0 "unified" window appearance. (Help! I really searched around to try to make this work... the color pattern of the title and toolbar seem to be top secret! The new "unified" style is an excellent replication of a unified look, but isn't "built from" the unified appearance like the metal is.)\
-- During multi-window drag, having a "drag window/image" that shows the represented view getting moved to the other window.\
-- During multi-window drag, support for dragging out solo tabs to consolidate in another window, removing the source window in the process.\
-- Support vertical as well as horizontal alignment.\
-\
-
-\f0\b Version History
-\f1\b0 \
-\
-Version 1.3 (May 29, 2006)\
-- new feature: Unified tab style, compliments of Keith Blount\
-- new feature: allow multi-window drag config option (again from Keith).\
-- fixed bug: Palette installation/usage instructions were wrong.\
-- enhancement: exposed the
-\f3\fs20 representedTabViewItems
-\f1\fs24 method, which can be used to retrieve the order of the tabs as displayed in the control, since the underlying NSTabView does not get reordered during drag and drop rearrangement.\
-\
-Version 1.2 (April 20, 2006)\
-- new feature: multi-window drag and drop support.\
-- bug fixed: zombie issue with tabView:didCloseTabViewItem\
-- bugs fixed: some drawing issues around the progress indicators in tabs, and the add tab button.\
-- enhancement: the hide/show animation has been improved with less "flickering" of progress indicators during the hide and show.\
-\
-Version 1.1.2 (April 5, 2006)\
-- fixed bug: tabs of non-integer width resulted in occasional anti-aliased drawing issues of dividers between tabs in the Metal style (Thanks, Kent).\
-- added feature: delegate can now respond to -tabView:shouldCloseTabViewItem: and -tabView:willCloseTabViewItem:, and -tabView:didCloseTabViewItem: messages, so your app can take care of any needed setup/cleanup for these actions.\
-- fixed bug: tab close buttons now show down state when pressed down.\
-\
-Version 1.1.1 (March 16, 2006)\
-- fixed bug: Palette inspector would not reflect state of previously instantiated control. This has been fixed (Thanks, Guillaume).\
-- enhancement: Overflow button now highlights when mouse down (Thanks, Kent).\
-- fixed bug: when set to not close a solo tab, the close button would be hidden for the tab, but could still be closed if you clicked the tab in the right location. This has been fixed (Thanks, malcom).\
-\
-Version 1.1 (March 10, 2006)\
-- Bound the "title" of the cell to the "label" of the source tabview item. Just in case you wanted to change the label on the tab during the running of your application.\
-- PSMTabBarCell factored to support new tab "styles", or appearances in drawing. Now supported are the existing "Metal" style and a new "Aqua" style. Many thanks to David Smith, Seth Willits, and Chris Forsythe for their contributions!\
-- Control can be configured to "Hide for single tab", so it doesn't appear unless there are more than a single tab view present. Features animated show/hide behavior (that can be called anytime, and is called automatically in the case that a single tab exists). The show/hide behavior can also be set up to resize either the window (default) or a selected "partner view" to compensate for the lost height of the tab bar.\
-- Control can be configured for "Can close only tab" behavior. If set to NO, no close button will appear on a lone tab.\
-- Cells can be set to "size to fit", or given uniform min/max/optimum sizes.\
-- Added support for display of an icon and an object count, if the proper app design pattern is followed.\
-- Sweet animated drag-and-drop drawing!\
-- A few drawing bugs surrounding the progress indicators in cells were squished.\
-- New documentation, in case you found this read me a little pithy.\
-\
-Version 1.0 (December 2005)\
-Initial release of safari-like tab implementation.\
-\
-
-\f0\b The standard disavowal of this beautiful mess
-\f1\b0 \
-\
-I should note that portions of this source code were inspired by the Shiira project's implementation of Safari-style tabs. While I made some different design decisions, the drawing and some other aspects are only slight modifications of their excellent work. As such, I note their copyright under their BSD licence:\
-\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f3\fs20 \cf4 Portions of this software Copyright 2004 The Shiira Project. All rights reserved.\
-\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\tx10560\tx11520\tx12480\tx13440\tx14400\tx15360\tx16320\tx17280\tx18240\tx19200\tx20160\tx21120\tx22080\tx23040\tx24000\tx24960\tx25920\tx26880\tx27840\tx28800\tx29760\tx30720\tx31680\tx32640\tx33600\tx34560\tx35520\tx36480\tx37440\tx38400\tx39360\tx40320\tx41280\tx42240\tx43200\tx44160\tx45120\tx46080\tx47040\tx48000\tx48960\tx49920\tx50880\tx51840\tx52800\tx53760\tx54720\tx55680\tx56640\tx57600\tx58560\tx59520\tx60480\tx61440\tx62400\tx63360\tx64320\tx65280\tx66240\tx67200\tx68160\tx69120\tx70080\tx71040\tx72000\tx72960\tx73920\tx74880\tx75840\tx76800\tx77760\tx78720\tx79680\tx80640\tx81600\tx82560\tx83520\tx84480\tx85440\tx86400\tx87360\tx88320\tx89280\tx90240\tx91200\tx92160\tx93120\tx94080\tx95040\tx96000\ql\qnatural\pardirnatural
-
-\f1\fs24 \cf0 Check them out at: http://hmdt-web.net/shiira/\
-\
-This source code is provided under BSD license, the conditions of which are listed below. I hope you'll make note somewhere in your about window or ReadMe stating the sweet coding goodness of Positive Spin Media and link to the fascinating and informative website at www.positivespinmedia.com\
-\
-\pard\pardeftab720\sa320\ql\qnatural
-\cf0 \CocoaLigature1 Copyright (c) 2005, Positive Spin Media\uc0\u8232 All rights reserved.\
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
-\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
-\ls1\ilvl0\cf0 {\listtext \'a5 }Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\
-{\listtext \'a5 }Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\
-{\listtext \'a5 }Neither the name of Positive Spin Media nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\
- \
-\pard\pardeftab720\sa320\ql\qnatural
-\cf0 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\CocoaLigature0 \
-} \ No newline at end of file
diff --git a/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/startpage.gif b/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/startpage.gif
deleted file mode 100644
index 8707a77ab..000000000
--- a/frontends/cocoa/PSMTabBarControl/ReadMe.rtfd/startpage.gif
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/PreferencesWindowController.h b/frontends/cocoa/PreferencesWindowController.h
deleted file mode 100644
index 8f72907a3..000000000
--- a/frontends/cocoa/PreferencesWindowController.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface PreferencesWindowController : NSWindowController
-
-@property (readwrite, copy, nonatomic) NSString *homepageURL;
-
-- (IBAction) useCurrentPageAsHomepage: (id) sender;
-
-@end
diff --git a/frontends/cocoa/PreferencesWindowController.m b/frontends/cocoa/PreferencesWindowController.m
deleted file mode 100644
index 590a96818..000000000
--- a/frontends/cocoa/PreferencesWindowController.m
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "utils/nsoption.h"
-#import "utils/nsurl.h"
-#import "netsurf/browser_window.h"
-
-#import "cocoa/PreferencesWindowController.h"
-#import "cocoa/NetsurfApp.h"
-#import "cocoa/gui.h"
-#import "cocoa/BrowserViewController.h"
-
-@implementation PreferencesWindowController
-
-- init;
-{
- if ((self = [super initWithWindowNibName: @"PreferencesWindow"]) == nil) return nil;
-
- return self;
-}
-
-- (IBAction) useCurrentPageAsHomepage: (id) sender;
-{
- struct browser_window *bw = [[(NetSurfApp *)NSApp frontTab] browser];
- const char *url = nsurl_access(browser_window_get_url(bw));
- [self setHomepageURL: [NSString stringWithUTF8String: url]];
-}
-
-- (void) setHomepageURL: (NSString *) newUrl;
-{
- nsoption_set_charp(homepage_url, strdup( [newUrl UTF8String] ));
- [[NSUserDefaults standardUserDefaults] setObject: newUrl forKey: kHomepageURLOption];
- [[NSUserDefaults standardUserDefaults] synchronize];
-}
-
-- (NSString *) homepageURL;
-{
- return [NSString stringWithUTF8String: nsoption_charp(homepage_url)];
-}
-
-@end
diff --git a/frontends/cocoa/Prefix.pch b/frontends/cocoa/Prefix.pch
deleted file mode 100644
index 7fa2c0547..000000000
--- a/frontends/cocoa/Prefix.pch
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <Carbon/Carbon.h>
-
-#ifdef __OBJC__
-#import <Cocoa/Cocoa.h>
-#endif
-
-#undef offsetof
-
-#define HISTORY_COLOUR_BACKGROUND 0x000000
-#define HISTORY_COLOUR_FOREGROUND 0xFFFFFF
-#define HISTORY_COLOUR_SELECTED 0xFF6D27 \ No newline at end of file
diff --git a/frontends/cocoa/ScrollableView.h b/frontends/cocoa/ScrollableView.h
deleted file mode 100644
index 071a11825..000000000
--- a/frontends/cocoa/ScrollableView.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface ScrollableView : NSView {
- NSSize minimumSize;
- NSView *observedSuperview;
-}
-
-@property (readwrite, assign, nonatomic) NSSize minimumSize;
-
-- (void) adjustFrame;
-
-@end
diff --git a/frontends/cocoa/ScrollableView.m b/frontends/cocoa/ScrollableView.m
deleted file mode 100644
index 8f27b2b56..000000000
--- a/frontends/cocoa/ScrollableView.m
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/ScrollableView.h"
-
-@interface ScrollableView ()
-
-- (void) frameChangeNotification: (NSNotification *) note;
-
-@end
-
-@implementation ScrollableView
-@synthesize minimumSize;
-
-- (void) setMinimumSize: (NSSize)newSize
-{
- minimumSize = newSize;
- [self adjustFrame];
-}
-
-- (void) adjustFrame
-{
- NSSize frameSize = [[self superview] frame].size;
- [self setFrameSize: NSMakeSize( MAX( minimumSize.width, frameSize.width ),
- MAX( minimumSize.height, frameSize.height ) )];
-}
-
-- (void) frameChangeNotification: (NSNotification *) note
-{
- [self adjustFrame];
-}
-
-- (void) viewDidMoveToSuperview
-{
- if (observedSuperview) {
- [[NSNotificationCenter defaultCenter]
- removeObserver: self
- name: NSViewFrameDidChangeNotification
- object: observedSuperview];
- observedSuperview = nil;
- }
-
- NSView *newSuperView = [self superview];
-
- if (nil != newSuperView) {
- observedSuperview = newSuperView;
- [[NSNotificationCenter defaultCenter]
- addObserver: self
- selector: @selector(frameChangeNotification:)
- name: NSViewFrameDidChangeNotification
- object: observedSuperview];
- [observedSuperview setPostsFrameChangedNotifications: YES];
- }
-}
-
-@end
diff --git a/frontends/cocoa/SearchWindowController.h b/frontends/cocoa/SearchWindowController.h
deleted file mode 100644
index 7ce8c00c9..000000000
--- a/frontends/cocoa/SearchWindowController.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#import <Cocoa/Cocoa.h>
-
-@class BrowserViewController;
-
-typedef enum {
- SearchBackward,
- SearchForward
-} SearchDirection;
-
-@interface SearchWindowController : NSWindowController {
- BOOL caseSensitive;
- BOOL selectAll;
- BOOL canGoBack;
- BOOL canGoForward;
- NSString *searchString;
- BrowserViewController *browser;
-}
-
-@property (readwrite, assign, nonatomic) BOOL caseSensitive;
-@property (readwrite, assign, nonatomic) BOOL selectAll;
-@property (readwrite, assign, nonatomic) BOOL canGoBack;
-@property (readwrite, assign, nonatomic) BOOL canGoForward;
-@property (readwrite, copy, nonatomic) NSString *searchString;
-@property (readwrite, assign, nonatomic) BrowserViewController *browser;
-
-- (IBAction) searchNext: (id) sender;
-- (IBAction) searchPrevious: (id) sender;
-
-- (IBAction) searchStringDidChange: (id) sender;
-
-- (void) search: (SearchDirection)direction;
-
-@end
-
-struct gui_search_table *cocoa_search_table;
diff --git a/frontends/cocoa/SearchWindowController.m b/frontends/cocoa/SearchWindowController.m
deleted file mode 100644
index 95372fc19..000000000
--- a/frontends/cocoa/SearchWindowController.m
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#import "cocoa/SearchWindowController.h"
-#import "cocoa/BrowserViewController.h"
-
-#import "netsurf/search.h"
-#import "netsurf/browser_window.h"
-#import "desktop/search.h"
-
-static void cocoa_search_set_back( bool active, void *p );
-static void cocoa_search_set_forward( bool active, void *p );
-
-static struct gui_search_table search_table = {
- .forward_state = cocoa_search_set_forward,
- .back_state = cocoa_search_set_back,
-};
-
-struct gui_search_table *cocoa_search_table = &search_table;
-
-@implementation SearchWindowController
-
-@synthesize caseSensitive;
-@synthesize selectAll;
-@synthesize canGoBack;
-@synthesize canGoForward;
-@synthesize searchString;
-@synthesize browser;
-
-- init;
-{
- if ((self = [super initWithWindowNibName: @"SearchWindow"]) == nil) return nil;
-
- [self bind: @"browser" toObject: NSApp withKeyPath: @"frontTab" options: nil];
- canGoBack = canGoForward = YES;
-
- return self;
-}
-
-- (void) dealloc;
-{
- [self unbind: @"browser"];
- [super dealloc];
-}
-
-- (IBAction) searchNext: (id) sender;
-{
- [self search: SearchForward];
-}
-
-- (IBAction) searchPrevious: (id) sender;
-{
- [self search: SearchBackward];
-}
-
-- (void) search: (SearchDirection)direction;
-{
- search_flags_t flags = (direction == SearchForward) ? SEARCH_FLAG_FORWARDS : 0;
- if (caseSensitive) flags |= SEARCH_FLAG_CASE_SENSITIVE;
- if (selectAll) flags |= SEARCH_FLAG_SHOWALL;
-
- struct browser_window *bw = [browser browser];
- browser_window_search( bw, self, flags, [searchString UTF8String] );
-}
-
-- (IBAction) searchStringDidChange: (id) sender;
-{
- struct browser_window *bw = [browser browser];
- browser_window_search_clear( bw );
-
- [self setCanGoBack: YES];
- [self setCanGoForward: YES];
-}
-
-- (void) setCaseSensitive: (BOOL) newValue;
-{
- if (caseSensitive != newValue) {
- caseSensitive = newValue;
- [self setCanGoBack: YES];
- [self setCanGoForward: YES];
- }
-}
-
-- (void) setSelectAll: (BOOL) newValue;
-{
- if (selectAll != newValue) {
- selectAll = newValue;
- [self setCanGoBack: YES];
- [self setCanGoForward: YES];
- }
-}
-
-static void cocoa_search_set_back( bool active, void *p )
-{
- [(SearchWindowController *)p setCanGoBack: active];
-}
-
-static void cocoa_search_set_forward( bool active, void *p )
-{
- [(SearchWindowController *)p setCanGoForward: active];
-}
-
-@end
diff --git a/frontends/cocoa/Tree.h b/frontends/cocoa/Tree.h
deleted file mode 100644
index 25c93b709..000000000
--- a/frontends/cocoa/Tree.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "cocoa/desktop-tree.h"
-
-@class Tree;
-
-@protocol TreeDelegate
-
-- (void) tree: (Tree *)tree requestedRedrawInRect: (NSRect) rect;
-- (void) tree: (Tree *)tree resized: (NSSize) size;
-- (void) tree: (Tree *)tree scrollPoint: (NSPoint) point;
-- (NSSize) treeWindowSize: (Tree *)tree;
-
-@end
-
-
-@interface Tree : NSObject {
- id <TreeDelegate> delegate;
- struct tree *tree;
-}
-
-@property (readwrite, assign, nonatomic) id <TreeDelegate> delegate;
-
-- (id)initWithFlags: (unsigned int) flags;
-
-- (struct tree *) tree;
-
-@end
-
-
-@interface Tree (ViewInterface)
-
-- (void) drawRect: (NSRect) rect inView: (NSView *) view;
-- (void) mouseAction: (browser_mouse_state)state atPoint: (NSPoint)point;
-- (void) mouseDragEnd: (browser_mouse_state)state fromPoint: (NSPoint)p0 toPoint: (NSPoint) p1;
-- (void) keyPress: (uint32_t) key;
-
-@end
diff --git a/frontends/cocoa/Tree.m b/frontends/cocoa/Tree.m
deleted file mode 100644
index b5d4a3f06..000000000
--- a/frontends/cocoa/Tree.m
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/Tree.h"
-#import "cocoa/coordinates.h"
-#import "cocoa/font.h"
-#import "cocoa/plotter.h"
-
-#import "netsurf/plotters.h"
-#import "cocoa/desktop-tree.h"
-
-@implementation Tree
-
-@synthesize delegate;
-
-static void tree_redraw_request( int x, int y, int w, int h, void *data );
-static void tree_resized( struct tree *tree, int w, int h, void *data );
-static void tree_scroll_visible( int y, int height, void *data );
-static void tree_get_window_dimensions( int *width, int *height, void *data );
-
-static const struct treeview_table cocoa_tree_callbacks = {
- .redraw_request = tree_redraw_request,
- .resized = tree_resized,
- .scroll_visible = tree_scroll_visible,
- .get_window_dimensions = tree_get_window_dimensions
-};
-
-- (id)initWithFlags: (unsigned int)flags
-{
- if ((self = [super init]) == nil) return nil;
-
- tree = tree_create( flags, &cocoa_tree_callbacks, self );
- if (tree == NULL) {
- [self release];
- return nil;
- }
-
- return self;
-}
-
-
-- (void) dealloc
-{
- tree_delete( tree );
- [super dealloc];
-}
-
-- (struct tree *) tree
-{
- return tree;
-}
-
-- (void) setRedrawing: (BOOL) newRedrawing
-{
-}
-
-
-+ (void) initialize
-{
-}
-
-//MARK: -
-//MARK: Callbacks
-
-static void tree_redraw_request( int x, int y, int w, int h, void *data )
-{
- id <TreeDelegate> delegate = ((Tree *)data)->delegate;
- [delegate tree: (Tree *)data requestedRedrawInRect: cocoa_rect_wh( x, y, w, h )];
-}
-
-static void tree_resized( struct tree *tree, int w, int h, void *data )
-{
- id <TreeDelegate> delegate = ((Tree *)data)->delegate;
- [delegate tree: (Tree *)data resized: cocoa_size( w, h )];
-}
-
-static void tree_scroll_visible( int y, int height, void *data )
-{
- id <TreeDelegate> delegate = ((Tree *)data)->delegate;
- [delegate tree: (Tree *)data scrollPoint: cocoa_point( 0, y )];
-}
-
-static void tree_get_window_dimensions( int *width, int *height, void *data )
-{
- id <TreeDelegate> delegate = ((Tree *)data)->delegate;
- if (delegate == nil) return;
-
- NSSize size = [delegate treeWindowSize: (Tree *)data];
-
- if (width != NULL) *width = cocoa_pt_to_px( size.width );
- if (height != NULL) *height = cocoa_pt_to_px( size.height );
-}
-
-@end
-
-@implementation Tree (ViewInterface)
-
-- (void) drawRect: (NSRect) rect inView: (NSView *) view
-{
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &cocoa_plotters
- };
-
- tree_draw(tree, 0, 0,
- cocoa_pt_to_px(NSMinX( rect )),
- cocoa_pt_to_px(NSMinY( rect )),
- cocoa_pt_to_px(NSWidth( rect )),
- cocoa_pt_to_px(NSHeight( rect )),
- &ctx );
-}
-
-- (void) mouseAction: (browser_mouse_state)state atPoint: (NSPoint)point
-{
- tree_mouse_action(tree, state,
- cocoa_pt_to_px( point.x ), cocoa_pt_to_px( point.y ));
-}
-
-- (void) mouseDragEnd: (browser_mouse_state)state fromPoint: (NSPoint)p0 toPoint: (NSPoint) p1
-{
- tree_drag_end(tree, state,
- cocoa_pt_to_px( p0.x ), cocoa_pt_to_px( p0.y ),
- cocoa_pt_to_px( p1.x ), cocoa_pt_to_px( p1.y ));
-}
-
-- (void) keyPress: (uint32_t) key;
-{
- tree_keypress( tree, key );
-}
-
-@end
diff --git a/frontends/cocoa/TreeView.h b/frontends/cocoa/TreeView.h
deleted file mode 100644
index 31dedbb0f..000000000
--- a/frontends/cocoa/TreeView.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "cocoa/ScrollableView.h"
-@class Tree;
-
-@interface TreeView : ScrollableView {
- Tree *tree;
-
- BOOL isDragging;
- NSPoint dragStart;
-
-}
-
-@property (readwrite, retain, nonatomic) Tree *tree;
-
-@end
diff --git a/frontends/cocoa/TreeView.m b/frontends/cocoa/TreeView.m
deleted file mode 100644
index 949c3c228..000000000
--- a/frontends/cocoa/TreeView.m
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/TreeView.h"
-#import "cocoa/Tree.h"
-
-#import "netsurf/plotters.h"
-#import "netsurf/keypress.h"
-
-@interface TreeView () <TreeDelegate>
-@end
-
-@implementation TreeView
-
-@synthesize tree;
-
-- (void)drawRect:(NSRect)dirtyRect
-{
- [tree drawRect: dirtyRect inView: self];
-}
-
-- (BOOL) isFlipped
-{
- return YES;
-}
-
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-- (void) dealloc
-{
- [self setTree: nil];
- [super dealloc];
-}
-
-- (void) setTree: (Tree *)newTree
-{
- if (tree != newTree) {
- [tree setRedrawing: NO];
- [tree setDelegate: nil];
- [tree release];
-
- tree = [newTree retain];
- [tree setDelegate: self];
- [tree setRedrawing: YES];
-
- [self setNeedsDisplay: YES];
- }
-}
-
-//MARK: -
-//MARK: Event handlers
-
-- (void)mouseDown: (NSEvent *)event
-{
- isDragging = NO;
- dragStart = [self convertPoint: [event locationInWindow] fromView: nil];
- [tree mouseAction: BROWSER_MOUSE_PRESS_1 atPoint: dragStart];
-}
-
-#define squared(x) ((x)*(x))
-#define MinDragDistance (5.0)
-
-- (void) mouseDragged: (NSEvent *)event
-{
- const NSPoint point = [self convertPoint: [event locationInWindow] fromView: nil];
-
- if (!isDragging) {
- const CGFloat distance = squared( dragStart.x - point.x ) + squared( dragStart.y - point.y );
- if (distance >= squared( MinDragDistance)) {
- isDragging = YES;
- }
- }
-}
-
-- (void) mouseUp: (NSEvent *)event
-{
- const NSPoint point = [self convertPoint: [event locationInWindow] fromView: nil];
-
- browser_mouse_state modifierFlags = 0;
-
- if (isDragging) {
- isDragging = NO;
- [tree mouseDragEnd: modifierFlags fromPoint: dragStart toPoint: point];
- } else {
- modifierFlags |= BROWSER_MOUSE_CLICK_1;
- if ([event clickCount] == 2) {
- modifierFlags |= BROWSER_MOUSE_DOUBLE_CLICK;
- }
- [tree mouseAction: modifierFlags atPoint: point];
- }
-}
-
-//MARK: Keyboard events
-
-- (void) keyDown: (NSEvent *)theEvent
-{
- [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
-}
-
-- (void) insertText: (id)string
-{
- for (NSUInteger i = 0, length = [string length]; i < length; i++) {
- unichar ch = [string characterAtIndex: i];
- [tree keyPress: ch];
- }
-}
-
-- (void) moveLeft: (id)sender
-{
- [tree keyPress: NS_KEY_LEFT];
-}
-
-- (void) moveRight: (id)sender
-{
- [tree keyPress: NS_KEY_RIGHT];
-}
-
-- (void) moveUp: (id)sender
-{
- [tree keyPress: NS_KEY_UP];
-}
-
-- (void) moveDown: (id)sender
-{
- [tree keyPress: NS_KEY_DOWN];
-}
-
-- (void) deleteBackward: (id)sender
-{
- [tree keyPress: NS_KEY_DELETE_LEFT];
-}
-
-- (void) deleteForward: (id)sender
-{
- [tree keyPress: NS_KEY_DELETE_RIGHT];
-}
-
-- (void) cancelOperation: (id)sender
-{
- [tree keyPress: NS_KEY_ESCAPE];
-}
-
-- (void) scrollPageUp: (id)sender
-{
- [tree keyPress: NS_KEY_PAGE_UP];
-}
-
-- (void) scrollPageDown: (id)sender
-{
- [tree keyPress: NS_KEY_PAGE_DOWN];
-}
-
-- (void) insertTab: (id)sender
-{
- [tree keyPress: NS_KEY_TAB];
-}
-
-- (void) insertBacktab: (id)sender
-{
- [tree keyPress: NS_KEY_SHIFT_TAB];
-}
-
-- (void) moveToBeginningOfLine: (id)sender
-{
- [tree keyPress: NS_KEY_LINE_START];
-}
-
-- (void) moveToEndOfLine: (id)sender
-{
- [tree keyPress: NS_KEY_LINE_END];
-}
-
-- (void) moveToBeginningOfDocument: (id)sender
-{
- [tree keyPress: NS_KEY_TEXT_START];
-}
-
-- (void) moveToEndOfDocument: (id)sender
-{
- [tree keyPress: NS_KEY_TEXT_END];
-}
-
-- (void) insertNewline: (id)sender
-{
- [tree keyPress: NS_KEY_NL];
-}
-
-- (void) selectAll: (id)sender
-{
- [tree keyPress: NS_KEY_SELECT_ALL];
-}
-
-- (void) copy: (id) sender
-{
- [tree keyPress: NS_KEY_COPY_SELECTION];
-}
-
-- (void) cut: (id) sender
-{
- [tree keyPress: NS_KEY_CUT_SELECTION];
-}
-
-- (void) paste: (id) sender
-{
- [tree keyPress: NS_KEY_PASTE];
-}
-
-//MARK: -
-//MARK: Tree delegate methods
-
-- (void) tree: (Tree *)t requestedRedrawInRect: (NSRect) rect
-{
- [self setNeedsDisplayInRect: rect];
-}
-
-- (void) tree: (Tree *)t resized: (NSSize) size
-{
- [self setMinimumSize: size];
-}
-
-- (void) tree: (Tree *)t scrollPoint: (NSPoint) point
-{
- [self scrollPoint: point];
-}
-
-- (NSSize) treeWindowSize: (Tree *)t
-{
- return [self frame].size;
-}
-
-@end
diff --git a/frontends/cocoa/URLFieldCell.h b/frontends/cocoa/URLFieldCell.h
deleted file mode 100644
index 38a75a139..000000000
--- a/frontends/cocoa/URLFieldCell.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-
-@interface URLFieldCell : NSTextFieldCell {
- NSButtonCell *refreshCell;
- NSImage *favicon;
-}
-
-@property (readwrite, assign, nonatomic) SEL refreshAction;
-@property (readwrite, assign, nonatomic) id refreshTarget;
-@property (readwrite, retain, nonatomic) NSImage *favicon;
-
-@end
diff --git a/frontends/cocoa/URLFieldCell.m b/frontends/cocoa/URLFieldCell.m
deleted file mode 100644
index e9e66476e..000000000
--- a/frontends/cocoa/URLFieldCell.m
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import "cocoa/URLFieldCell.h"
-
-#import "utils/nsurl.h"
-#import "netsurf/url_db.h"
-
-@interface URLFieldCell ()
-
-@property (readonly, retain, nonatomic) NSButtonCell *refreshCell;
-
-- (NSRect) buttonFrame: (NSRect) cellFrame;
-- (NSRect) urlFrame: (NSRect) cellFrame;
-- (NSRect) iconFrame: (NSRect) cellFrame;
-
-@end
-
-
-@implementation URLFieldCell
-
-@synthesize favicon;
-
-- (void) setFavicon: (NSImage *)newIcon;
-{
- if (favicon != newIcon) {
- [favicon release];
- favicon = [newIcon retain];
- [[self controlView] setNeedsDisplay: YES];
- }
-}
-
-#define BUTTON_SIZE 32
-#define PADDING 2
-
-- (void) drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView *)controlView;
-{
- [favicon drawInRect: [self iconFrame: cellFrame] fromRect: NSZeroRect
- operation: NSCompositeSourceOver fraction: 1.0];
-
- [super drawInteriorWithFrame: [self urlFrame: cellFrame] inView: controlView];
-
- [[self refreshCell] drawInteriorWithFrame: [self buttonFrame: cellFrame]
- inView: controlView];
-}
-
-- (void) selectWithFrame: (NSRect)aRect inView: (NSView *)controlView editor: (NSText *)textObj
- delegate: (id)anObject start: (NSInteger)selStart length: (NSInteger)selLength;
-{
- const NSRect textFrame = [self urlFrame: aRect];
- [super selectWithFrame: textFrame inView: controlView editor: textObj
- delegate: anObject start: selStart length: selLength];
-}
-
-- (void) editWithFrame: (NSRect)aRect inView: (NSView *)controlView editor: (NSText *)textObj
- delegate: (id)anObject event: (NSEvent *)theEvent;
-{
- const NSRect textFrame = [self urlFrame: aRect];
- [super editWithFrame: textFrame inView: controlView editor: textObj
- delegate: anObject event: theEvent];
-}
-
-- (void) startDragURLAt: (NSPoint) point inView: (NSView *) view;
-{
- NSString *url = [self stringValue];
- NSString *title = url;
- nsurl *nsurl;
-
- if (nsurl_create( [url UTF8String] , &nsurl ) != NSERROR_OK)
- return;
-
- const struct url_data *data = urldb_get_url_data( nsurl );
-
- nsurl_unref(nsurl);
-
- if (data && data->title) title = [NSString stringWithUTF8String: data->title];
-
- NSPasteboard *pb = [NSPasteboard pasteboardWithName: NSDragPboard];
- [pb declareTypes: [NSArray arrayWithObjects: NSStringPboardType, NSURLPboardType,
- @"public.url", @"public.url-name", nil] owner: nil];
- [pb setString: url forType: NSStringPboardType];
- [pb setString: url forType: @"public.url"];
- [pb setString: title forType: @"public.url-name"];
- [[NSURL URLWithString: url] writeToPasteboard: pb];
-
- NSRect urlBounds = NSZeroRect;
- urlBounds.size = [title sizeWithAttributes: nil];
- urlBounds.size.width += urlBounds.size.height + 2;
-
- NSImage *image = [[NSImage alloc] initWithSize: urlBounds.size];
-
- [image lockFocus];
- [favicon drawInRect: NSMakeRect( urlBounds.origin.x, urlBounds.origin.y, urlBounds.size.height, urlBounds.size.height )
- fromRect: NSZeroRect operation: NSCompositeCopy fraction: 1.0];
- urlBounds.origin.x += urlBounds.size.height + 2;
- [title drawInRect: urlBounds withAttributes: nil];
- [image unlockFocus];
-
- point.x -= urlBounds.size.height / 2;
- point.y += urlBounds.size.height / 2;
-
- [view dragImage: image at: point offset: NSZeroSize event: [NSApp currentEvent]
- pasteboard: pb source: self slideBack: YES];
-
- [image release];
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
-{
- return NSDragOperationCopy | NSDragOperationGeneric;
-}
-
-- (BOOL) trackMouse: (NSEvent *)theEvent inRect: (NSRect)cellFrame ofView: (NSView *)controlView untilMouseUp: (BOOL)flag;
-{
- const NSPoint point = [controlView convertPoint: [theEvent locationInWindow] fromView: nil];
- const NSRect buttonRect = [self buttonFrame: cellFrame];
- if (NSPointInRect( point, [self iconFrame: cellFrame] )) {
- [self startDragURLAt: point inView: controlView];
- return NO;
- } else if (NSPointInRect( point, buttonRect )) {
- return [[self refreshCell] trackMouse: theEvent inRect: buttonRect
- ofView: controlView untilMouseUp: flag];
- } else {
- cellFrame.size.width -= BUTTON_SIZE + PADDING;
- return [super trackMouse: theEvent inRect: cellFrame ofView: controlView untilMouseUp: YES];
- }
-}
-
-- (void) dealloc;
-{
- [refreshCell release];
-
- [super dealloc];
-}
-
-- (NSRect) buttonFrame: (NSRect) cellFrame;
-{
- NSRect buttonRect = cellFrame;
- buttonRect.origin.x = NSMaxX( cellFrame ) - BUTTON_SIZE;
- buttonRect.size.width = BUTTON_SIZE;
- return buttonRect;
-}
-
-- (NSRect) urlFrame: (NSRect) cellFrame;
-{
- NSRect textFrame = cellFrame;
- textFrame.origin.x += cellFrame.size.height;
- textFrame.size.width -= cellFrame.size.height + BUTTON_SIZE + PADDING;
- return textFrame;
-}
-
-- (NSRect) iconFrame: (NSRect)cellFrame;
-{
- NSRect iconFrame = {
- .origin = {
- .x = cellFrame.origin.x + PADDING,
- .y = cellFrame.origin.y,
- },
- .size = NSMakeSize( NSHeight( cellFrame ), NSHeight( cellFrame ) )
- };
- return NSInsetRect( iconFrame, 2 * PADDING, 2 * PADDING );
-}
-
-- (NSButtonCell *) refreshCell;
-{
- if (nil == refreshCell) {
- refreshCell = [[NSButtonCell alloc] initImageCell: [NSImage imageNamed: NSImageNameRefreshTemplate]];
- [refreshCell setButtonType: NSMomentaryPushInButton];
- [refreshCell setBordered: NO];
- }
- return refreshCell;
-}
-
-- (void) setRefreshTarget: (id) newTarget;
-{
- [[self refreshCell] setTarget: newTarget];
-}
-
-- (id) refreshTarget;
-{
- return [[self refreshCell] target];
-}
-
-- (void) setRefreshAction: (SEL) newAction;
-{
- [[self refreshCell] setAction: newAction];
-}
-
-- (SEL) refreshAction;
-{
- return [[self refreshCell] action];
-}
-
-@end
diff --git a/frontends/cocoa/apple_image.m b/frontends/cocoa/apple_image.m
deleted file mode 100644
index 0bbaabd10..000000000
--- a/frontends/cocoa/apple_image.m
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef WITH_APPLE_IMAGE
-
-#import "cocoa/apple_image.h"
-
-#include "utils/config.h"
-#include "utils/utils.h"
-#include "netsurf/bitmap.h"
-#include "netsurf/plotters.h"
-#include "netsurf/content.h"
-#include "content/llcache.h"
-#include "content/content_protected.h"
-
-#import "cocoa/schedule.h"
-#import "cocoa/bitmap.h"
-
-typedef struct apple_image_content {
- struct content base;
-
- struct bitmap *bitmap; /**< Created NetSurf bitmap */
-
- NSUInteger frames;
- NSUInteger currentFrame;
- int *frameTimes;
-} apple_image_content;
-
-
-static void *apple_image_get_internal(const struct content *c, void *context)
-{
- apple_image_content *ai_c = (apple_image_content *)c;
-
- return ai_c->bitmap;
-}
-
-static nserror apple_image_create(const content_handler *handler,
- lwc_string *imime_type, const struct http_parameter *params,
- llcache_handle *llcache, const char *fallback_charset,
- bool quirks, struct content **c)
-{
- apple_image_content *ai;
- nserror error;
-
- ai = calloc(1, sizeof(apple_image_content));
- if (ai == NULL)
- return NSERROR_NOMEM;
-
- error = content__init(&ai->base, handler, imime_type, params,
- llcache, fallback_charset, quirks);
- if (error != NSERROR_OK) {
- free(ai);
- return error;
- }
-
- *c = (struct content *) ai;
-
- return NSERROR_OK;
-}
-
-
-static void animate_image_cb( void *ptr )
-{
- struct apple_image_content *ai = ptr;
- ++ai->currentFrame;
- if (ai->currentFrame >= ai->frames) ai->currentFrame = 0;
-
- [(NSBitmapImageRep *)ai->bitmap setProperty: NSImageCurrentFrame withValue: [NSNumber numberWithUnsignedInteger: ai->currentFrame]];
- cocoa_bitmap_modified( ai->bitmap );
-
- union content_msg_data data;
- data.redraw.full_redraw = true;
- data.redraw.x = data.redraw.object_x = 0;
- data.redraw.y = data.redraw.object_y = 0;
- data.redraw.width = data.redraw.object_width = ai->base.width;
- data.redraw.height = data.redraw.object_height = ai->base.height;
- data.redraw.object = &ai->base;
- content_broadcast( &ai->base, CONTENT_MSG_REDRAW, data );
-
- cocoa_schedule(ai->frameTimes[ai->currentFrame], animate_image_cb, ai );
-}
-
-/**
- * Convert a CONTENT_APPLE_IMAGE for display.
- */
-static bool apple_image_convert(struct content *c)
-{
- apple_image_content *ai_c = (apple_image_content *)c;
- unsigned long size;
- const char *bytes = content__get_source_data(c, &size);
-
- NSData *data = [NSData dataWithBytesNoCopy: (char *)bytes length: size freeWhenDone: NO];
- NSBitmapImageRep *image = [[NSBitmapImageRep imageRepWithData: data] retain];
-
- if (image == nil) {
- union content_msg_data msg_data;
- msg_data.error = "cannot decode image";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
- return false;
- }
-
- c->width = [image pixelsWide];
- c->height = [image pixelsHigh];
- ai_c->bitmap = (void *)image;
-
- NSString *url = [NSString stringWithUTF8String: nsurl_access(llcache_handle_get_url( content_get_llcache_handle( c )) )];
- NSString *title = [NSString stringWithFormat: @"%@ (%dx%d)", [url lastPathComponent], c->width, c->height];
- content__set_title(c, [title UTF8String] );
-
- content_set_ready(c);
- content_set_done(c);
- content_set_status(c, "");
-
- struct apple_image_content *ai = (struct apple_image_content *)c;
- NSUInteger frames = [[image valueForProperty: NSImageFrameCount] unsignedIntegerValue];
- if (frames > 1) {
- ai->frames = frames;
- ai->currentFrame = 0;
- ai->frameTimes = calloc( ai->frames , sizeof(int));
- for (NSUInteger i = 0; i < frames; i++) {
- [image setProperty: NSImageCurrentFrame withValue: [NSNumber numberWithUnsignedInteger: i]];
- ai->frameTimes[i] = 1000 * [[image valueForProperty: NSImageCurrentFrameDuration] floatValue];
- }
- [image setProperty: NSImageCurrentFrame withValue: [NSNumber numberWithUnsignedInteger: 0]];
- cocoa_schedule( ai->frameTimes[0], animate_image_cb, ai );
- }
-
- return true;
-}
-
-
-static void apple_image_destroy(struct content *c)
-{
- apple_image_content *ai_c = (apple_image_content *)c;
-
- [(id)ai_c->bitmap release];
- ai_c->bitmap = NULL;
- cocoa_schedule(-1, animate_image_cb, c );
-}
-
-
-static nserror apple_image_clone(const struct content *old, struct content **newc)
-{
- apple_image_content *ai;
- apple_image_content *ai_old = (apple_image_content *)old;
- nserror error;
-
- ai = calloc(1, sizeof(apple_image_content));
- if (ai == NULL)
- return NSERROR_NOMEM;
-
- error = content__clone(old, &ai->base);
- if (error != NSERROR_OK) {
- content_destroy(&ai->base);
- return error;
- }
-
- if (old->status == CONTENT_STATUS_READY ||
- old->status == CONTENT_STATUS_DONE) {
- ai->base.width = old->width;
- ai->base.height = old->height;
- ai->bitmap = (void *)[(id)ai_old->bitmap retain];
- }
-
- *newc = (struct content *) ai;
-
- return NSERROR_OK;
-}
-
-static content_type apple_image_content_type(void)
-{
- return CONTENT_IMAGE;
-}
-
-/**
- * Redraw a CONTENT_APPLE_IMAGE with appropriate tiling.
- */
-static bool apple_image_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx)
-{
- apple_image_content *ai_c = (apple_image_content *)c;
- bitmap_flags_t flags = BITMAPF_NONE;
-
- if (data->repeat_x)
- flags |= BITMAPF_REPEAT_X;
- if (data->repeat_y)
- flags |= BITMAPF_REPEAT_Y;
-
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- ai_c->bitmap, data->background_colour, flags);
-}
-
-static const content_handler apple_image_content_handler = {
- .create = apple_image_create,
- .data_complete = apple_image_convert,
- .destroy = apple_image_destroy,
- .redraw = apple_image_redraw,
- .clone = apple_image_clone,
- .get_internal = apple_image_get_internal,
- .type = apple_image_content_type,
- .no_share = false
-};
-
-static nserror register_for_type( NSString *mime )
-{
- const char *type = [mime UTF8String];
- /* nsgif has priority since it supports animated GIF */
-#ifdef WITH_GIF
- if (strcmp(type, "image/gif") == 0)
- return NSERROR_OK;
-#endif
-
- nserror error = content_factory_register_handler( type, &apple_image_content_handler );
- if (error != NSERROR_OK) return error;
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in cocoa/apple_image.h */
-nserror apple_image_init(void)
-{
- NSArray *utis = [NSBitmapImageRep imageTypes];
- for (NSString *uti in utis) {
- NSDictionary *declaration = [(NSDictionary *)UTTypeCopyDeclaration( (CFStringRef)uti ) autorelease];
- id mimeTypes = [[declaration objectForKey: (NSString *)kUTTypeTagSpecificationKey] objectForKey: (NSString *)kUTTagClassMIMEType];
-
- if (mimeTypes == nil) continue;
-
- if (![mimeTypes isKindOfClass: [NSArray class]]) {
- mimeTypes = [NSArray arrayWithObject: mimeTypes];
- }
-
- for (NSString *mime in mimeTypes) {
- nserror error = register_for_type( mime );
- if (error != NSERROR_OK) return error;
- }
- }
-
- return NSERROR_OK;
-}
-
-#endif /* WITH_APPLE_IMAGE */
diff --git a/frontends/cocoa/bitmap.m b/frontends/cocoa/bitmap.m
deleted file mode 100644
index 1ab8c3e2f..000000000
--- a/frontends/cocoa/bitmap.m
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Cocoa implementation of bitmap operations.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "netsurf/browser_window.h"
-#import "netsurf/plotters.h"
-#import "netsurf/bitmap.h"
-#import "netsurf/content.h"
-
-#import "cocoa/plotter.h"
-#import "cocoa/bitmap.h"
-
-#define BITS_PER_SAMPLE (8)
-#define SAMPLES_PER_PIXEL (4)
-#define BITS_PER_PIXEL (BITS_PER_SAMPLE * SAMPLES_PER_PIXEL)
-#define BYTES_PER_PIXEL (BITS_PER_PIXEL / 8)
-#define RED_OFFSET (0)
-#define GREEN_OFFSET (1)
-#define BLUE_OFFSET (2)
-#define ALPHA_OFFSET (3)
-
-static CGImageRef cocoa_prepare_bitmap( void *bitmap );
-static NSMapTable *cocoa_get_bitmap_cache( void );
-
-static int bitmap_get_width(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp pixelsWide];
-}
-
-static int bitmap_get_height(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp pixelsHigh];
-}
-
-static bool bitmap_get_opaque(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp isOpaque];
-}
-
-static void bitmap_destroy(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
-
- NSMapTable *cache = cocoa_get_bitmap_cache();
- CGImageRef image = NSMapGet( cache, bitmap );
- if (NULL != image) {
- CGImageRelease( image );
- NSMapRemove( cache, bitmap );
- }
-
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- [bmp release];
-}
-
-static void *bitmap_create(int width, int height, unsigned int state)
-{
- NSBitmapImageRep *bmp = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes: NULL
- pixelsWide: width
- pixelsHigh: height
- bitsPerSample: BITS_PER_SAMPLE
- samplesPerPixel: SAMPLES_PER_PIXEL
- hasAlpha: YES
- isPlanar: NO
- colorSpaceName: NSDeviceRGBColorSpace
- bitmapFormat: NSAlphaNonpremultipliedBitmapFormat
- bytesPerRow: BYTES_PER_PIXEL * width
- bitsPerPixel: BITS_PER_PIXEL];
-
- return bmp;
-}
-
-static void bitmap_set_opaque(void *bitmap, bool opaque)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- [bmp setOpaque: opaque ? YES : NO];
-}
-
-static unsigned char *bitmap_get_buffer(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp bitmapData];
-}
-
-static size_t bitmap_get_rowstride(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp bytesPerRow];
-}
-
-static size_t bitmap_get_bpp(void *bitmap)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
- return [bmp bitsPerPixel] / 8;
-}
-
-static bool bitmap_test_opaque(void *bitmap)
-{
- NSCParameterAssert( bitmap_get_bpp( bitmap ) == BYTES_PER_PIXEL );
-
- unsigned char *buf = bitmap_get_buffer( bitmap );
-
- const size_t height = bitmap_get_height( bitmap );
- const size_t width = bitmap_get_width( bitmap );
-
- const size_t line_step = bitmap_get_rowstride( bitmap ) - BYTES_PER_PIXEL * width;
-
- for (size_t y = 0; y < height; y++) {
- for (size_t x = 0; x < height; x++) {
- if (buf[ALPHA_OFFSET] != 0xFF) return false;
- buf += BYTES_PER_PIXEL;
- }
- buf += line_step;
- }
-
- return true;
-}
-
-static bool bitmap_save(void *bitmap, const char *path, unsigned flags)
-{
- NSCParameterAssert( NULL != bitmap );
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
-
- NSData *tiff = [bmp TIFFRepresentation];
- return [tiff writeToFile: [NSString stringWithUTF8String: path] atomically: YES];
-}
-
-void cocoa_bitmap_modified(void *bitmap)
-{
- NSMapTable *cache = cocoa_get_bitmap_cache();
- CGImageRef image = NSMapGet( cache, bitmap );
- if (NULL != image) {
- CGImageRelease( image );
- NSMapRemove( cache, bitmap );
- }
-}
-
-CGImageRef cocoa_get_cgimage( void *bitmap )
-{
- NSMapTable *cache = cocoa_get_bitmap_cache();
-
- CGImageRef result = NSMapGet( cache, bitmap );
- if (NULL == result) {
- result = cocoa_prepare_bitmap( bitmap );
- NSMapInsertKnownAbsent( cache, bitmap, result );
- }
-
- return result;
-}
-
-static inline NSMapTable *cocoa_get_bitmap_cache( void )
-{
- static NSMapTable *cache = nil;
- if (cache == nil) {
- cache = NSCreateMapTable( NSNonOwnedPointerMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 0 );
- }
- return cache;
-}
-
-static CGImageRef cocoa_prepare_bitmap( void *bitmap )
-{
- NSCParameterAssert( NULL != bitmap );
-
- NSBitmapImageRep *bmp = (NSBitmapImageRep *)bitmap;
-
- size_t w = [bmp pixelsWide];
- size_t h = [bmp pixelsHigh];
-
- CGImageRef original = [bmp CGImage];
-
- if (h <= 1) return CGImageRetain( original );
-
- void *data = malloc( 4 * w * h );
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGContextRef context = CGBitmapContextCreate( data, w, h, BITS_PER_SAMPLE,
- BYTES_PER_PIXEL * w, colorSpace,
- [bmp isOpaque] ? kCGImageAlphaNoneSkipLast
- : kCGImageAlphaPremultipliedLast );
- CGColorSpaceRelease( colorSpace );
-
- CGContextTranslateCTM( context, 0.0, h );
- CGContextScaleCTM( context, 1.0, -1.0 );
-
- CGRect rect = CGRectMake( 0, 0, w, h );
- CGContextClearRect( context, rect );
- CGContextDrawImage( context, rect, original );
-
- CGImageRef result = CGBitmapContextCreateImage( context );
-
- CGContextRelease( context );
- free( data );
-
- return result;
-}
-
-static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
-{
- int bwidth = bitmap_get_width( bitmap );
- int bheight = bitmap_get_height( bitmap );
-
- struct redraw_context ctx = {
- .interactive = false,
- .background_images = true,
- .plot = &cocoa_plotters
- };
-
- CGColorSpaceRef cspace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
- CGContextRef bitmapContext = CGBitmapContextCreate( bitmap_get_buffer( bitmap ),
- bwidth, bheight,
- bitmap_get_bpp( bitmap ) * 8 / 4,
- bitmap_get_rowstride( bitmap ),
- cspace, kCGImageAlphaNoneSkipLast );
- CGColorSpaceRelease( cspace );
-
- size_t width = MIN( content_get_width( content ), 1024 );
- size_t height = ((width * bheight) + bwidth / 2) / bwidth;
-
- CGContextTranslateCTM( bitmapContext, 0, bheight );
- CGContextScaleCTM( bitmapContext, (CGFloat)bwidth / width, -(CGFloat)bheight / height );
-
- [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: bitmapContext flipped: YES]];
-
- content_scaled_redraw( content, width, height, &ctx );
-
- [NSGraphicsContext setCurrentContext: nil];
- CGContextRelease( bitmapContext );
-
- cocoa_bitmap_modified( bitmap );
-
- return true;
-}
-
-static struct gui_bitmap_table bitmap_table = {
- .create = bitmap_create,
- .destroy = bitmap_destroy,
- .set_opaque = bitmap_set_opaque,
- .get_opaque = bitmap_get_opaque,
- .test_opaque = bitmap_test_opaque,
- .get_buffer = bitmap_get_buffer,
- .get_rowstride = bitmap_get_rowstride,
- .get_width = bitmap_get_width,
- .get_height = bitmap_get_height,
- .get_bpp = bitmap_get_bpp,
- .save = bitmap_save,
- .modified = cocoa_bitmap_modified,
- .render = bitmap_render,
-};
-
-struct gui_bitmap_table *cocoa_bitmap_table = &bitmap_table;
diff --git a/frontends/cocoa/compile-xib.sh b/frontends/cocoa/compile-xib.sh
deleted file mode 100755
index 576f9bfd0..000000000
--- a/frontends/cocoa/compile-xib.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-# call: compile-xib.sh [xib file] [language] [(optional output nib file)]
-DIR=`dirname "$1"`
-XIB=`basename -s .xib "$1"`
-
-STRINGS_FILE="$DIR/$2.lproj/$XIB.xib.strings"
-TRANSLATE=""
-if [ -f $STRINGS_FILE ]
-then
- TRANSLATE="--strings-file $STRINGS_FILE"
-fi
-
-OUTPUT="$2.$XIB.nib"
-
-if [ "x$3" != "x" ]
-then
- OUTPUT="$3"
-fi
-
-exec /usr/bin/ibtool $TRANSLATE --compile $OUTPUT $1
diff --git a/frontends/cocoa/coordinates.h b/frontends/cocoa/coordinates.h
deleted file mode 100644
index a9614389b..000000000
--- a/frontends/cocoa/coordinates.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COCOA_COORDINATES_H
-#define COCOA_COORDINATES_H
-
-extern CGFloat cocoa_scale_factor;
-
-static inline CGFloat cocoa_px_to_pt( int location ) __attribute__((always_inline,pure));
-static inline CGFloat cocoa_px_to_pt_f( CGFloat location ) __attribute__((always_inline,pure));
-
-static inline int cocoa_pt_to_px( CGFloat location ) __attribute__((always_inline,pure));
-
-static inline NSPoint cocoa_point( int x, int y ) __attribute__((always_inline,pure));
-static inline NSPoint cocoa_scaled_point( CGFloat scale, int x, int y ) __attribute__((always_inline,pure));
-
-static inline NSSize cocoa_size( int w, int h ) __attribute__((always_inline,pure));
-static inline NSSize cocoa_scaled_size( CGFloat scale, int w, int h ) __attribute__((always_inline,pure));
-
-static inline NSRect cocoa_rect( int x0, int y0, int x1, int y1 ) __attribute__((always_inline,pure));
-static inline NSRect cocoa_rect_wh( int x, int y, int w, int h ) __attribute__((always_inline,pure));
-
-static inline NSRect cocoa_scaled_rect( CGFloat scale, int x0, int y0, int x1, int y1 ) __attribute__((always_inline,pure));
-static inline NSRect cocoa_scaled_rect_wh( CGFloat scale, int x, int y, int w, int h ) __attribute__((always_inline,pure));
-
-static inline CGFloat cocoa_px_to_pt( int location )
-{
- return (CGFloat)location * cocoa_scale_factor;
-}
-
-static inline CGFloat cocoa_px_to_pt_f( CGFloat location )
-{
- return floor( location ) * cocoa_scale_factor;
-}
-
-static inline int cocoa_pt_to_px( CGFloat location )
-{
- return location / cocoa_scale_factor;
-}
-
-static inline NSPoint cocoa_point( int x, int y )
-{
- return NSMakePoint( cocoa_px_to_pt( x ), cocoa_px_to_pt( y ) );
-}
-
-static inline NSPoint cocoa_scaled_point( CGFloat scale, int x, int y )
-{
- return NSMakePoint( cocoa_px_to_pt_f( scale * x ), cocoa_px_to_pt_f( scale * y ) );
-}
-
-static inline NSSize cocoa_size( int w, int h )
-{
- return NSMakeSize( cocoa_px_to_pt( w ), cocoa_px_to_pt( h ) );
-}
-
-static inline NSSize cocoa_scaled_size( CGFloat scale, int w, int h )
-{
- return NSMakeSize( cocoa_px_to_pt_f( scale * w ), cocoa_px_to_pt_f( scale * h ) );
-}
-
-static inline NSRect cocoa_rect( int x0, int y0, int x1, int y1 )
-{
- return cocoa_rect_wh( x0, y0, x1 - x0, y1 - y0 );
-}
-
-static inline NSRect cocoa_rect_wh( int x, int y, int w, int h )
-{
- const NSRect result = {
- .origin = cocoa_point( x, y ),
- .size = cocoa_size( w, h )
- };
- return result;
-}
-
-static inline NSRect cocoa_scaled_rect_wh( CGFloat scale, int x, int y, int w, int h )
-{
- const NSRect result = {
- .origin = cocoa_scaled_point( scale, x, y ),
- .size = cocoa_scaled_size( scale, w, h )
- };
- return result;
-}
-
-static inline NSRect cocoa_scaled_rect( CGFloat scale, int x0, int y0, int x1, int y1 )
-{
- return cocoa_scaled_rect_wh( scale, x0, y0, x1 - x0, y1 - y0 );
-}
-
-
-#endif
diff --git a/frontends/cocoa/desktop-tree.h b/frontends/cocoa/desktop-tree.h
deleted file mode 100644
index f8864e167..000000000
--- a/frontends/cocoa/desktop-tree.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * deprecated compatibility layer for new treeview modules. Do not use.
- */
-
-#ifndef _NETSURF_DESKTOP_TREE_H_
-#define _NETSURF_DESKTOP_TREE_H_
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "netsurf/mouse.h"
-
-struct sslcert_session_data;
-struct tree;
-struct redraw_context;
-
-/**
- * Current ssl session data for treeview
- *
- * @todo FIXME global certificate treeview state must go away, this is
- * just wrong.
- */
-extern struct sslcert_session_data *ssl_current_session;
-extern const char *tree_hotlist_path;
-
-/* Tree flags */
-enum tree_flags {
- TREE_HISTORY,
- TREE_COOKIES,
- TREE_SSLCERT,
- TREE_HOTLIST
-};
-
-typedef enum {
- TREE_NO_DRAG = 0,
- TREE_SELECT_DRAG,
- TREE_MOVE_DRAG,
- TREE_TEXTAREA_DRAG, /** < A drag that is passed to a textarea */
- TREE_UNKNOWN_DRAG /** < A drag the tree itself won't handle */
-} tree_drag_type;
-
-/** callbacks to perform necessary operations on treeview. */
-struct treeview_table {
- void (*redraw_request)(int x, int y, int width, int height,
- void *data); /**< request a redraw. */
- void (*resized)(struct tree *tree, int width, int height,
- void *data); /**< resize treeview area. */
- void (*scroll_visible)(int y, int height, void *data); /**< scroll visible treeview area. */
- void (*get_window_dimensions)(int *width, int *height, void *data); /**< get dimensions of window */
-};
-
-struct tree *tree_create(unsigned int flags,
- const struct treeview_table *callbacks,
- void *client_data);
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-void tree_delete(struct tree *tree);
-tree_drag_type tree_drag_status(struct tree *tree);
-void tree_draw(struct tree *tree, int x, int y,
- int clip_x, int clip_y, int clip_width, int clip_height,
- const struct redraw_context *ctx);
-bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse,
- int x, int y);
-void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
- int x1, int y1);
-bool tree_keypress(struct tree *tree, uint32_t key);
-
-
-#endif
diff --git a/frontends/cocoa/desktop-tree.m b/frontends/cocoa/desktop-tree.m
deleted file mode 100644
index c3c729660..000000000
--- a/frontends/cocoa/desktop-tree.m
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * deprecated compatibility layer for new treeview modules. Do not use.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "utils/nsoption.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/core_window.h"
-#include "content/content.h"
-#include "content/hlcache.h"
-
-#import "cocoa/desktop-tree.h"
-
-struct tree {
- unsigned int flags; /* Tree flags */
- tree_drag_type drag;
- const struct treeview_table *callbacks;
- void *client_data; /* User assigned data for the callbacks */
-};
-
-#include "netsurf/misc.h"
-#include "desktop/gui_internal.h"
-#include "desktop/treeview.h"
-#include "desktop/hotlist.h"
-#include "desktop/cookie_manager.h"
-#include "desktop/global_history.h"
-#include "desktop/sslcert_viewer.h"
-
-struct sslcert_session_data *ssl_current_session = NULL;
-const char *tree_hotlist_path = NULL;
-
-static void treeview_test_redraw_request(struct core_window *cw,
- const struct rect *r)
-{
- struct tree *tree = (struct tree *)cw;
-
- tree->callbacks->redraw_request(r->x0, r->y0,
- r->x1 - r->x0, r->y1 - r->y0,
- tree->client_data);
-}
-
-static void treeview_test_update_size(struct core_window *cw,
- int width, int height)
-{
- struct tree *tree = (struct tree *)cw;
-
- tree->callbacks->resized(tree, width, height, tree->client_data);
-}
-
-static void treeview_test_scroll_visible(struct core_window *cw,
- const struct rect *r)
-{
-}
-
-static void treeview_test_get_window_dimensions(struct core_window *cw,
- int *width, int *height)
-{
- struct tree *tree = (struct tree *)cw;
-
- tree->callbacks->get_window_dimensions(width, height,
- tree->client_data);
-}
-
-static void treeview_test_drag_status(struct core_window *cw,
- core_window_drag_status ds)
-{
- struct tree *tree = (struct tree *)cw;
-
- switch (ds) {
- case CORE_WINDOW_DRAG_NONE:
- tree->drag = TREE_NO_DRAG;
- break;
-
- case CORE_WINDOW_DRAG_SELECTION:
- tree->drag = TREE_SELECT_DRAG;
- break;
-
- case CORE_WINDOW_DRAG_MOVE:
- tree->drag = TREE_MOVE_DRAG;
- break;
-
- case CORE_WINDOW_DRAG_TEXT_SELECTION:
- tree->drag = TREE_TEXTAREA_DRAG;
- break;
-
- default:
- break;
- }
-}
-
-struct core_window_callback_table cw_t = {
- .redraw_request = treeview_test_redraw_request,
- .update_size = treeview_test_update_size,
- .scroll_visible = treeview_test_scroll_visible,
- .get_window_dimensions = treeview_test_get_window_dimensions,
- .drag_status = treeview_test_drag_status
-};
-
-static bool treeview_test_init(struct tree *tree)
-{
- nserror err;
-
- switch (tree->flags) {
- case TREE_COOKIES:
- err = cookie_manager_init(&cw_t, (struct core_window *)tree);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't init new cookie manager.", 0);
- break;
- case TREE_HISTORY:
- err = global_history_init(&cw_t, (struct core_window *)tree);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't init new global history.", 0);
- break;
- case TREE_HOTLIST:
- err = hotlist_init(tree_hotlist_path);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't init new hotlist.", 0);
- err = hotlist_manager_init(&cw_t, (struct core_window *)tree);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't init hotlist manager.", 0);
- break;
- case TREE_SSLCERT:
- assert(ssl_current_session == NULL &&
- "Call sslcert_viewer_init directly, "
- "this compat. layer can't cope with simultanious "
- "sslcert viewers");
- err = sslcert_viewer_init(&cw_t, (struct core_window *)tree,
- ssl_current_session);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't init new sslcert viewer.", 0);
- break;
- }
-
- return true;
-}
-
-static bool treeview_test_fini(struct tree *tree)
-{
- nserror err;
-
- switch (tree->flags) {
- case TREE_COOKIES:
- err = cookie_manager_fini();
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't finalise cookie manager.", 0);
- break;
- case TREE_HISTORY:
- err = global_history_fini();
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't finalise cookie manager.", 0);
- break;
- case TREE_HOTLIST:
- err = hotlist_fini(tree_hotlist_path);
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't finalise hotlist.", 0);
- break;
- case TREE_SSLCERT:
- assert(ssl_current_session != NULL &&
- "Can't use sslcert window after sslcert_viewer_fini()");
- err = sslcert_viewer_fini(ssl_current_session);
- ssl_current_session = NULL;
- if (err != NSERROR_OK)
- guit->misc->warning("Couldn't finalise sslcert viewer.", 0);
- break;
- }
-
- return true;
-}
-
-static bool treeview_test_redraw(struct tree *tree, int x, int y,
- int clip_x, int clip_y, int clip_width, int clip_height,
- const struct redraw_context *ctx)
-{
- struct rect clip;
-
- clip.x0 = clip_x;
- clip.y0 = clip_y;
- clip.x1 = clip_x + clip_width;
- clip.y1 = clip_y + clip_height;
-
- switch (tree->flags) {
- case TREE_SSLCERT:
- if (ssl_current_session != NULL) {
- sslcert_viewer_redraw(ssl_current_session, x, y, &clip, ctx);
- }
- return true;
- case TREE_COOKIES:
- cookie_manager_redraw(x, y, &clip, ctx);
- return true;
- case TREE_HISTORY:
- global_history_redraw(x, y, &clip, ctx);
- return true;
- case TREE_HOTLIST:
- hotlist_redraw(x, y, &clip, ctx);
- return true;
- }
-
- return false;
-}
-
-static bool treeview_test_mouse_action(struct tree *tree,
- browser_mouse_state mouse, int x, int y)
-{
- switch (tree->flags) {
- case TREE_SSLCERT:
- assert(ssl_current_session != NULL &&
- "Can't use sslcert window after sslcert_viewer_fini()");
- sslcert_viewer_mouse_action(ssl_current_session, mouse, x, y);
- return true;
- case TREE_COOKIES:
- cookie_manager_mouse_action(mouse, x, y);
- return true;
- case TREE_HISTORY:
- global_history_mouse_action(mouse, x, y);
- return true;
- case TREE_HOTLIST:
- hotlist_mouse_action(mouse, x, y);
- return true;
- }
-
- return false;
-}
-
-static bool treeview_test_keypress(struct tree *tree, uint32_t key)
-{
- switch (tree->flags) {
- case TREE_SSLCERT:
- assert(ssl_current_session != NULL &&
- "Can't use sslcert window after sslcert_viewer_fini()");
- sslcert_viewer_keypress(ssl_current_session, key);
- return true;
- case TREE_COOKIES:
- cookie_manager_keypress(key);
- return true;
- case TREE_HISTORY:
- global_history_keypress(key);
- return true;
- case TREE_HOTLIST:
- hotlist_keypress(key);
- return true;
- }
-
- return false;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-struct tree *tree_create(unsigned int flags,
- const struct treeview_table *callbacks, void *client_data)
-{
- struct tree *tree;
-
- tree = calloc(sizeof(struct tree), 1);
- if (tree == NULL) {
- LOG("calloc failed");
- guit->misc->warning(messages_get_errorcode(NSERROR_NOMEM), 0);
- return NULL;
- }
-
- tree->flags = flags;
- tree->drag = TREE_NO_DRAG;
- tree->callbacks = callbacks;
- tree->client_data = client_data;
-
- treeview_test_init(tree);
-
- return tree;
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-void tree_delete(struct tree *tree)
-{
- treeview_test_fini(tree);
- free(tree);
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-void tree_draw(struct tree *tree, int x, int y,
- int clip_x, int clip_y, int clip_width, int clip_height,
- const struct redraw_context *ctx)
-{
- assert(tree != NULL);
-
- treeview_test_redraw(tree, x, y, clip_x, clip_y,
- clip_width, clip_height, ctx);
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x,
- int y)
-{
- assert(tree != NULL);
-
- if (treeview_test_mouse_action(tree, mouse, x, y)) {
- return true;
- }
-
- return false;
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
- int x1, int y1)
-{
- assert(tree != NULL);
-
- treeview_test_mouse_action(tree, BROWSER_MOUSE_HOVER, x1, y1);
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-bool tree_keypress(struct tree *tree, uint32_t key)
-{
- if (treeview_test_keypress(tree, key)) {
- return true;
- }
-
- return false;
-}
-
-/** deprecated compatibility layer for new treeview modules. Do not use. */
-tree_drag_type tree_drag_status(struct tree *tree)
-{
- assert(tree != NULL);
- return tree->drag;
-}
diff --git a/frontends/cocoa/extract-strings.sh b/frontends/cocoa/extract-strings.sh
deleted file mode 100755
index c3f582619..000000000
--- a/frontends/cocoa/extract-strings.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-for i in $1/*.xib
-do
- xib=`basename "$i"`
- strings="$2/$xib.strings"
-
- ibtool "$i" --generate-strings-file "$strings"
-done
-
-
diff --git a/frontends/cocoa/fetch.h b/frontends/cocoa/fetch.h
deleted file mode 100644
index 1b0991ef5..000000000
--- a/frontends/cocoa/fetch.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-extern struct gui_fetch_table *cocoa_fetch_table;
diff --git a/frontends/cocoa/fetch.m b/frontends/cocoa/fetch.m
deleted file mode 100644
index 0bbce09f6..000000000
--- a/frontends/cocoa/fetch.m
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "utils/log.h"
-#import "utils/nsurl.h"
-#import "netsurf/fetch.h"
-
-#import "cocoa/fetch.h"
-
-static char cocoafiletype[200];
-
-static const struct mimemap_s {
- const char const *extension;
- const char const *mimetype;
-} cocoamimemap[] = {
- { "css", "text/css" },
- { "f79", "text/css" },
- { "jpg", "image/jpeg" },
- { "jpeg", "image/jpeg" },
- { "gif", "image/gif" },
- { "png", "image/png" },
- { "b60", "image/png" },
- { "jng", "image/jng" },
- { "svg", "image/svg" },
- { NULL, "text/html" }
-};
-
-
-static const char *fetch_filetype(const char *unix_path)
-{
- NSString *uti;
- NSString *mimeType = nil;
- NSError *utiError = nil;
-
- uti = [[NSWorkspace sharedWorkspace] typeOfFile: [NSString stringWithUTF8String: unix_path] error:&utiError];
- if (nil != uti) {
- LOG("Looking for mimetype from uti \"%s\"", [uti UTF8String] );
- mimeType = (NSString *)UTTypeCopyPreferredTagWithClass( (CFStringRef)uti, kUTTagClassMIMEType );
- } else {
- NSAlert *utiAlert = [NSAlert alertWithError:utiError];
- [utiAlert runModal]; // Ignore return value.
-
- LOG("uti call failed");
-
- strncpy(cocoafiletype, "text/html", sizeof(cocoafiletype));
- return cocoafiletype;
- }
-
- if (nil != mimeType) {
- strncpy(cocoafiletype, [mimeType UTF8String], sizeof(cocoafiletype));
- [mimeType release];
- } else {
- const char *extension;
-
- LOG("mimetype from uti failed");
-
- extension = [(NSString *)UTTypeCopyPreferredTagWithClass( (CFStringRef)uti, kUTTagClassFilenameExtension) UTF8String];
-
- if (extension == NULL) {
- /* give up and go with default */
- LOG("No extension going with default type");
- strncpy(cocoafiletype, "text/html", sizeof(cocoafiletype)); } else {
- int eidx = 0; /* index of extension entry */
-
- while ((cocoamimemap[eidx].extension != NULL) &&
- (strcmp(cocoamimemap[eidx].extension, extension) != 0)) {
- eidx++;
- }
-
- strncpy(cocoafiletype,
- cocoamimemap[eidx].mimetype,
- sizeof(cocoafiletype));
- }
- }
-
- LOG("\tMIME type for '%s' is '%s'", unix_path, cocoafiletype);
-
- return cocoafiletype;
-}
-
-static nsurl *gui_get_resource_url(const char *path)
-{
- nsurl *url = NULL;
- NSString *nspath = [[NSBundle mainBundle] pathForResource: [NSString stringWithUTF8String: path] ofType: @""];
- if (nspath == nil) return NULL;
- nsurl_create([[[NSURL fileURLWithPath: nspath] absoluteString] UTF8String], &url);
- return url;
-}
-
-static struct gui_fetch_table fetch_table = {
- .filetype = fetch_filetype,
-
- .get_resource_url = gui_get_resource_url,
-};
-
-struct gui_fetch_table *cocoa_fetch_table = &fetch_table;
diff --git a/frontends/cocoa/font.h b/frontends/cocoa/font.h
deleted file mode 100644
index ed0479765..000000000
--- a/frontends/cocoa/font.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COCOA_FONT_H
-#define COCOA_FONT_H
-
-#import "netsurf/plot_style.h"
-
-void cocoa_draw_string( CGFloat x, CGFloat y, const char *bytes, size_t length, const struct plot_font_style *style );
-
-struct gui_layout_table *cocoa_layout_table;
-
-#endif
diff --git a/frontends/cocoa/font.m b/frontends/cocoa/font.m
deleted file mode 100644
index 17212fff9..000000000
--- a/frontends/cocoa/font.m
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "utils/nsoption.h"
-#import "netsurf/layout.h"
-#import "netsurf/plotters.h"
-
-#import "cocoa/coordinates.h"
-#import "cocoa/plotter.h"
-#import "cocoa/font.h"
-
-static NSLayoutManager *cocoa_prepare_layout_manager( const char *string, size_t length,
- const plot_font_style_t *style );
-
-static CGFloat cocoa_layout_width( NSLayoutManager *layout );
-static CGFloat cocoa_layout_width_chars( NSLayoutManager *layout, size_t characters );
-static NSUInteger cocoa_glyph_for_location( NSLayoutManager *layout, CGFloat x );
-static size_t cocoa_bytes_for_characters( const char *string, size_t characters );
-static NSDictionary *cocoa_font_attributes( const plot_font_style_t *style );
-
-static NSTextStorage *cocoa_text_storage = nil;
-static NSTextContainer *cocoa_text_container = nil;
-
-static nserror cocoa_font_width(const plot_font_style_t *style,
- const char *string, size_t length,
- int *width)
-{
- NSLayoutManager *layout;
- layout = cocoa_prepare_layout_manager( string, length, style );
- *width = cocoa_layout_width( layout );
- return NSERROR_OK;
-}
-
-static nserror cocoa_font_position(const plot_font_style_t *style,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- NSLayoutManager *layout = cocoa_prepare_layout_manager( string, length, style );
- if (layout == nil) {
- return NSERROR_BAD_PARAMETER;
- }
-
- NSUInteger glyphIndex = cocoa_glyph_for_location( layout, x );
- NSUInteger chars = [layout characterIndexForGlyphAtIndex: glyphIndex];
-
- if (chars >= [cocoa_text_storage length]) *char_offset = length;
- else *char_offset = cocoa_bytes_for_characters( string, chars );
-
- *actual_x = cocoa_pt_to_px( NSMaxX( [layout boundingRectForGlyphRange: NSMakeRange( glyphIndex - 1, 1 )
- inTextContainer: cocoa_text_container] ) );
-
- return NSERROR_OK;
-}
-
-static nserror cocoa_font_split(const plot_font_style_t *style,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- NSLayoutManager *layout = cocoa_prepare_layout_manager( string, length, style );
- if (layout == nil) return NSERROR_BAD_PARAMETER;
-
- NSUInteger glyphIndex = cocoa_glyph_for_location( layout, x );
- NSUInteger chars = [layout characterIndexForGlyphAtIndex: glyphIndex];
-
- if (chars >= [cocoa_text_storage length]) {
- *char_offset = length;
- *actual_x = cocoa_layout_width( layout );
- return NSERROR_OK;
- }
-
-
- chars = [[cocoa_text_storage string] rangeOfString: @" " options: NSBackwardsSearch range: NSMakeRange( 0, chars + 1 )].location;
- if (chars == NSNotFound) {
- *char_offset = 0;
- *actual_x = 0;
- return NSERROR_OK;
- }
-
- *char_offset = cocoa_bytes_for_characters( string, chars );
- *actual_x = cocoa_layout_width_chars( layout, chars );
-
- return NSERROR_OK;
-}
-
-
-static struct gui_layout_table layout_table = {
- .width = cocoa_font_width,
- .position = cocoa_font_position,
- .split = cocoa_font_split,
-};
-
-struct gui_layout_table *cocoa_layout_table = &layout_table;
-
-
-#pragma mark -
-
-void cocoa_draw_string( CGFloat x, CGFloat y, const char *bytes, size_t length, const plot_font_style_t *style )
-{
- NSLayoutManager *layout = cocoa_prepare_layout_manager( bytes, length, style );
- if (layout == nil) return;
-
- NSFont *font = [cocoa_text_storage attribute: NSFontAttributeName atIndex: 0 effectiveRange: NULL];
- CGFloat baseline = [layout defaultLineHeightForFont: font] * 3.0 / 4.0;
-
- NSRange glyphRange = [layout glyphRangeForTextContainer: cocoa_text_container];
- [layout drawGlyphsForGlyphRange: glyphRange atPoint: NSMakePoint( x, y - baseline )];
-}
-
-
-#pragma mark -
-
-static inline CGFloat cocoa_layout_width( NSLayoutManager *layout )
-{
- if (layout == nil) return 0.0;
-
- return cocoa_pt_to_px( NSWidth( [layout usedRectForTextContainer: cocoa_text_container] ) );
-}
-
-static inline CGFloat cocoa_layout_width_chars( NSLayoutManager *layout, size_t characters )
-{
- NSUInteger glyphIndex = [layout glyphIndexForCharacterAtIndex: characters];
- return cocoa_pt_to_px( [layout locationForGlyphAtIndex: glyphIndex].x );
-}
-
-static inline NSUInteger cocoa_glyph_for_location( NSLayoutManager *layout, CGFloat x )
-{
- CGFloat fraction = 0.0;
- NSUInteger glyphIndex = [layout glyphIndexForPoint: NSMakePoint( cocoa_px_to_pt( x ), 0 )
- inTextContainer: cocoa_text_container
- fractionOfDistanceThroughGlyph: &fraction];
- if (fraction >= 1.0) ++glyphIndex;
- return glyphIndex;
-}
-
-static inline size_t cocoa_bytes_for_characters( const char *string, size_t chars )
-{
- size_t offset = 0;
- while (chars-- > 0) {
- uint8_t ch = ((uint8_t *)string)[offset];
-
- if (0xC2 <= ch && ch <= 0xDF) offset += 2;
- else if (0xE0 <= ch && ch <= 0xEF) offset += 3;
- else if (0xF0 <= ch && ch <= 0xF4) offset += 4;
- else offset++;
- }
- return offset;
-}
-
-static NSLayoutManager *cocoa_prepare_layout_manager( const char *bytes, size_t length,
- const plot_font_style_t *style )
-{
- if (NULL == bytes || 0 == length) return nil;
-
- NSString *string = [[[NSString alloc] initWithBytes: bytes length:length encoding:NSUTF8StringEncoding] autorelease];
- if (string == nil) return nil;
-
- static NSLayoutManager *layout = nil;
- if (nil == layout) {
- cocoa_text_container = [[NSTextContainer alloc] initWithContainerSize: NSMakeSize( CGFLOAT_MAX, CGFLOAT_MAX )];
- [cocoa_text_container setLineFragmentPadding: 0];
-
- layout = [[NSLayoutManager alloc] init];
- [layout addTextContainer: cocoa_text_container];
- }
-
- static NSString *oldString = 0;
- static plot_font_style_t oldStyle = { 0, 0, 0, 0, 0, 0 };
-
- const bool styleChanged = memcmp( style, &oldStyle, sizeof oldStyle ) != 0;
-
- if ([oldString isEqualToString: string] && !styleChanged) {
- return layout;
- }
-
- [oldString release];
- oldString = [string copy];
- oldStyle = *style;
-
- static NSDictionary *attributes = nil;
- if (styleChanged || attributes == nil) {
- [attributes release];
- attributes = [cocoa_font_attributes( style ) retain];
- }
-
- [cocoa_text_storage release];
- cocoa_text_storage = [[NSTextStorage alloc] initWithString: string attributes: attributes];
- [cocoa_text_storage addLayoutManager: layout];
-
- [layout ensureLayoutForTextContainer: cocoa_text_container];
-
- return layout;
-}
-
-static NSString * const cocoa_font_families[PLOT_FONT_FAMILY_COUNT] = {
- [PLOT_FONT_FAMILY_SERIF] = @"Times",
- [PLOT_FONT_FAMILY_SANS_SERIF] = @"Helvetica",
- [PLOT_FONT_FAMILY_MONOSPACE] = @"Courier",
- [PLOT_FONT_FAMILY_CURSIVE] = @"Apple Chancery",
- [PLOT_FONT_FAMILY_FANTASY] = @"Marker Felt"
-};
-
-static inline NSFont *cocoa_font_get_nsfont( const plot_font_style_t *style )
-{
- NSFont *font = [NSFont fontWithName: cocoa_font_families[style->family]
- size: (CGFloat)style->size / FONT_SIZE_SCALE];
-
- NSFontTraitMask traits = 0;
- if (style->flags & FONTF_ITALIC || style->flags & FONTF_OBLIQUE) traits |= NSItalicFontMask;
- if (style->flags & FONTF_SMALLCAPS) traits |= NSSmallCapsFontMask;
- if (style->weight > 400) traits |= NSBoldFontMask;
-
- if (0 != traits) {
- NSFontManager *fm = [NSFontManager sharedFontManager];
- font = [fm convertFont: font toHaveTrait: traits];
- }
-
- return font;
-}
-
-static inline NSDictionary *cocoa_font_attributes( const plot_font_style_t *style )
-{
- return [NSDictionary dictionaryWithObjectsAndKeys:
- cocoa_font_get_nsfont( style ), NSFontAttributeName,
- cocoa_convert_colour( style->foreground ), NSForegroundColorAttributeName,
- nil];
-}
diff --git a/frontends/cocoa/gui.h b/frontends/cocoa/gui.h
deleted file mode 100644
index b34e9b702..000000000
--- a/frontends/cocoa/gui.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-extern struct gui_window_table *cocoa_window_table;
-extern struct gui_clipboard_table *cocoa_clipboard_table;
-extern struct gui_misc_table *cocoa_misc_table;
-
-extern NSString * const kCookiesFileOption;
-extern NSString * const kURLsFileOption;
-extern NSString * const kHotlistFileOption;
-extern NSString * const kHomepageURLOption;
-extern NSString * const kOptionsFileOption;
-extern NSString * const kAlwaysCancelDownload;
-extern NSString * const kAlwaysCloseMultipleTabs;
-
-void cocoa_autorelease( void );
-
-nserror cocoa_warning(const char *warning, const char *detail);
diff --git a/frontends/cocoa/gui.m b/frontends/cocoa/gui.m
deleted file mode 100644
index 7e180fa24..000000000
--- a/frontends/cocoa/gui.m
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "utils/nsoption.h"
-#import "utils/utils.h"
-#import "utils/log.h"
-#import "utils/nsurl.h"
-#import "netsurf/mouse.h"
-#import "netsurf/window.h"
-#import "netsurf/misc.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/content.h"
-
-#import "cocoa/gui.h"
-#import "cocoa/coordinates.h"
-#import "cocoa/plotter.h"
-#import "cocoa/BrowserView.h"
-#import "cocoa/BrowserViewController.h"
-#import "cocoa/BrowserWindowController.h"
-#import "cocoa/FormSelectMenu.h"
-#import "cocoa/fetch.h"
-#import "cocoa/schedule.h"
-
-
-NSString * const kCookiesFileOption = @"CookiesFile";
-NSString * const kURLsFileOption = @"URLsFile";
-NSString * const kHotlistFileOption = @"Hotlist";
-NSString * const kHomepageURLOption = @"HomepageURL";
-NSString * const kOptionsFileOption = @"ClassicOptionsFile";
-NSString * const kAlwaysCancelDownload = @"AlwaysCancelDownload";
-NSString * const kAlwaysCloseMultipleTabs = @"AlwaysCloseMultipleTabs";
-
-#define UNIMPL() NSLog( @"Function '%s' unimplemented", __func__ )
-
-struct browser_window;
-
-/* exported function docuemnted in cocoa/gui.h */
-nserror cocoa_warning(const char *warning, const char *detail)
-{
- NSRunAlertPanel( NSLocalizedString( @"Warning",
- @"Warning title" ),
- NSLocalizedString( @"Warning %s%s%s",
- @"Warning message" ),
- NSLocalizedString( @"OK", @"" ), nil, nil,
- warning, detail != NULL ? ": " : "",
- detail != NULL ? detail : "" );
- return NSERROR_OK;
-}
-
-
-static struct gui_window *
-gui_window_create(struct browser_window *bw,
- struct gui_window *existing,
- gui_window_create_flags flags)
-{
- BrowserWindowController *window = nil;
- BrowserViewController *result;
-
- browser_window_set_scale(bw, (float)nsoption_int(scale) / 100, false);
- if (existing != NULL) {
- window = [(BrowserViewController *)(existing) windowController];
- }
-
- result = [[BrowserViewController alloc] initWithBrowser: bw];
-
- if (!(flags & GW_CREATE_TAB) || nil == window) {
- window = [[[BrowserWindowController alloc] init] autorelease];
- [[window window] makeKeyAndOrderFront: nil];
- }
- [window addTab: result];
-
- return (struct gui_window *)result;
-}
-
-static void gui_window_destroy(struct gui_window *g)
-{
- BrowserViewController *vc = (BrowserViewController *)g;
- [vc release];
-}
-
-static void gui_window_set_title(struct gui_window *g, const char *title)
-{
- [(BrowserViewController *)g setTitle: [NSString stringWithUTF8String: title]];
-}
-
-static void gui_window_redraw_window(struct gui_window *g)
-{
- [[(BrowserViewController *)g browserView] setNeedsDisplay: YES];
-}
-
-static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
-{
- const NSRect nsrect = cocoa_scaled_rect_wh(
- browser_window_get_scale([(BrowserViewController *)g browser]),
- rect->x0, rect->y0,
- rect->x1 - rect->x0, rect->y1 - rect->y0 );
- [[(BrowserViewController *)g browserView] setNeedsDisplayInRect: nsrect];
-}
-
-static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
-{
- NSCParameterAssert( g != NULL && sx != NULL && sy != NULL );
-
- NSRect visible = [[(BrowserViewController *)g browserView] visibleRect];
- *sx = cocoa_pt_to_px( NSMinX( visible ) );
- *sy = cocoa_pt_to_px( NSMinY( visible ) );
- return true;
-}
-
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
-{
- [[(BrowserViewController *)g browserView] scrollPoint: cocoa_point( sx, sy )];
-}
-
-/**
- * callback from core to reformat a window.
- */
-static void cocoa_window_reformat(struct gui_window *gw)
-{
- if (gw != NULL) {
- [[(BrowserViewController *)gw browserView] reformat ];
- }
-}
-
-
-static void gui_window_get_dimensions(struct gui_window *g,
- int *width, int *height,
- bool scaled)
-{
- NSCParameterAssert( width != NULL && height != NULL );
-
- NSRect frame = [[[(BrowserViewController *)g browserView] superview] frame];
- if (scaled) {
- const CGFloat scale = browser_window_get_scale([(BrowserViewController *)g browser]);
- frame.size.width /= scale;
- frame.size.height /= scale;
- }
- *width = cocoa_pt_to_px( NSWidth( frame ) );
- *height = cocoa_pt_to_px( NSHeight( frame ) );
-}
-
-static void gui_window_update_extent(struct gui_window *g)
-{
- BrowserViewController * const window = (BrowserViewController *)g;
- int width;
- int height;
- struct browser_window *browser = [window browser];
-
- browser_window_get_extents(browser, false, &width, &height);
-
- [[window browserView] setMinimumSize:
- cocoa_scaled_size( browser_window_get_scale(browser), width, height )];
-}
-
-static void gui_window_set_status(struct gui_window *g, const char *text)
-{
- [(BrowserViewController *)g setStatus: [NSString stringWithUTF8String: text]];
-}
-
-static void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
-{
- switch (shape) {
- case GUI_POINTER_DEFAULT:
- case GUI_POINTER_WAIT:
- case GUI_POINTER_PROGRESS:
- [[NSCursor arrowCursor] set];
- break;
-
- case GUI_POINTER_CROSS:
- [[NSCursor crosshairCursor] set];
- break;
-
- case GUI_POINTER_POINT:
- case GUI_POINTER_MENU:
- [[NSCursor pointingHandCursor] set];
- break;
-
- case GUI_POINTER_CARET:
- [[NSCursor IBeamCursor] set];
- break;
-
- case GUI_POINTER_MOVE:
- [[NSCursor closedHandCursor] set];
- break;
-
- default:
- NSLog( @"Other cursor %d requested", shape );
- [[NSCursor arrowCursor] set];
- break;
- }
-}
-
-static nserror gui_window_set_url(struct gui_window *g, struct nsurl *url)
-{
- [(BrowserViewController *)g setUrl: [NSString stringWithUTF8String: nsurl_access(url)]];
- return NSERROR_OK;
-}
-
-static void gui_window_start_throbber(struct gui_window *g)
-{
- [(BrowserViewController *)g setIsProcessing: YES];
- [(BrowserViewController *)g updateBackForward];
-}
-
-static void gui_window_stop_throbber(struct gui_window *g)
-{
- [(BrowserViewController *)g setIsProcessing: NO];
- [(BrowserViewController *)g updateBackForward];
-}
-
-static void gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon)
-{
- NSBitmapImageRep *bmp = NULL;
- NSImage *image = nil;
-
- if (icon != NULL) {
- bmp = (NSBitmapImageRep *)content_get_bitmap( icon );
- }
-
- if (bmp != nil) {
- image = [[NSImage alloc] initWithSize: NSMakeSize( 32, 32 )];
- [image addRepresentation: bmp];
- } else {
- image = [[NSImage imageNamed: @"NetSurf"] copy];
- }
- [image setFlipped: YES];
-
- [(BrowserViewController *)g setFavicon: image];
- [image release];
-}
-
-static void
-gui_window_place_caret(struct gui_window *g, int x, int y, int height,
- const struct rect *clip)
-{
- [[(BrowserViewController *)g browserView]
- addCaretAt: cocoa_point( x, y )
- height: cocoa_px_to_pt( height )];
-}
-
-static void gui_window_remove_caret(struct gui_window *g)
-{
- [[(BrowserViewController *)g browserView] removeCaret];
-}
-
-static void gui_window_new_content(struct gui_window *g)
-{
- [(BrowserViewController *)g contentUpdated];
-}
-
-
-static void gui_create_form_select_menu(struct gui_window *g,
- struct form_control *control)
-{
- BrowserViewController * const window = (BrowserViewController *)g;
- FormSelectMenu *menu = [[FormSelectMenu alloc]
- initWithControl: control
- forWindow: [window browser]];
- [menu runInView: [window browserView]];
- [menu release];
-}
-
-static nserror gui_launch_url(nsurl *url)
-{
- [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: [NSString stringWithUTF8String: nsurl_access(url)]]];
- return NSERROR_OK;
-}
-
-struct ssl_cert_info;
-
-static nserror
-gui_cert_verify(nsurl *url,
- const struct ssl_cert_info *certs,
- unsigned long num,
- nserror (*cb)(bool proceed,void *pw), void *cbpw)
-{
- return NSERROR_NOT_IMPLEMENTED;
-}
-
-
-static struct gui_window_table window_table = {
- .create = gui_window_create,
- .destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
- .get_scroll = gui_window_get_scroll,
- .set_scroll = gui_window_set_scroll,
- .get_dimensions = gui_window_get_dimensions,
- .update_extent = gui_window_update_extent,
- .reformat = cocoa_window_reformat,
-
- .set_title = gui_window_set_title,
- .set_url = gui_window_set_url,
- .set_icon = gui_window_set_icon,
- .set_status = gui_window_set_status,
- .set_pointer = gui_window_set_pointer,
- .place_caret = gui_window_place_caret,
- .remove_caret = gui_window_remove_caret,
- .new_content = gui_window_new_content,
- .start_throbber = gui_window_start_throbber,
- .stop_throbber = gui_window_stop_throbber,
- .create_form_select_menu = gui_create_form_select_menu,
-};
-
-struct gui_window_table *cocoa_window_table = &window_table;
-
-
-static struct gui_misc_table browser_table = {
- .schedule = cocoa_schedule,
- .warning = cocoa_warning,
-
- .launch_url = gui_launch_url,
- .cert_verify = gui_cert_verify,
-};
-
-struct gui_misc_table *cocoa_misc_table = &browser_table;
diff --git a/frontends/cocoa/plotter.h b/frontends/cocoa/plotter.h
deleted file mode 100644
index ce4865336..000000000
--- a/frontends/cocoa/plotter.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COCOA_PLOTTER_H
-#define COCOA_PLOTTER_H
-
-#import <Cocoa/Cocoa.h>
-#import "netsurf/plot_style.h"
-
-extern const struct plotter_table cocoa_plotters;
-
-NSColor *cocoa_convert_colour( colour clr );
-
-void cocoa_update_scale_factor( void );
-
-void cocoa_set_clip( NSRect rect );
-
-#endif
diff --git a/frontends/cocoa/plotter.m b/frontends/cocoa/plotter.m
deleted file mode 100644
index dea3245bb..000000000
--- a/frontends/cocoa/plotter.m
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <Cocoa/Cocoa.h>
-
-#import "utils/log.h"
-#import "utils/utils.h"
-#import "netsurf/browser_window.h"
-#import "netsurf/plotters.h"
-
-#import "cocoa/font.h"
-#import "cocoa/coordinates.h"
-#import "cocoa/plotter.h"
-#import "cocoa/bitmap.h"
-
-static void cocoa_plot_render_path(NSBezierPath *path,const plot_style_t *pstyle);
-static void cocoa_plot_path_set_stroke_pattern(NSBezierPath *path,const plot_style_t *pstyle);
-static inline void cocoa_center_pixel( bool x, bool y );
-
-static NSRect cocoa_plot_clip_rect;
-
-#define colour_red_component( c ) (((c) >> 0) & 0xFF)
-#define colour_green_component( c ) (((c) >> 8) & 0xFF)
-#define colour_blue_component( c ) (((c) >> 16) & 0xFF)
-#define colour_alpha_component( c ) (((c) >> 24) & 0xFF)
-#define colour_from_rgba( r, g, b, a) ((((colour)(r)) << 0) | \
- (((colour)(g)) << 8) | \
- (((colour)(b)) << 16) | \
- (((colour)(a)) << 24))
-#define colour_from_rgb( r, g, b ) colour_from_rgba( (r), (g), (b), 0xFF )
-
-NSColor *cocoa_convert_colour( colour clr )
-{
- return [NSColor colorWithDeviceRed: (float)colour_red_component( clr ) / 0xFF
- green: (float)colour_green_component( clr ) / 0xFF
- blue: (float)colour_blue_component( clr ) / 0xFF
- alpha: 1.0];
-}
-
-static void cocoa_plot_path_set_stroke_pattern(NSBezierPath *path,const plot_style_t *pstyle)
-{
- static const CGFloat dashed_pattern[2] = { 5.0, 2.0 };
- static const CGFloat dotted_pattern[2] = { 2.0, 2.0 };
-
- switch (pstyle->stroke_type) {
- case PLOT_OP_TYPE_DASH:
- [path setLineDash: dashed_pattern count: 2 phase: 0];
- break;
-
- case PLOT_OP_TYPE_DOT:
- [path setLineDash: dotted_pattern count: 2 phase: 0];
- break;
-
- default:
- // ignore
- break;
- }
-
- [path setLineWidth: cocoa_px_to_pt( pstyle->stroke_width > 0 ? pstyle->stroke_width : 1 )];
-}
-
-static bool plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
-{
- if (pstyle->stroke_type == PLOT_OP_TYPE_NONE) return true;
-
- [NSGraphicsContext saveGraphicsState];
- [NSBezierPath clipRect: cocoa_plot_clip_rect];
-
- NSBezierPath *path = [NSBezierPath bezierPath];
- [path moveToPoint: cocoa_point( x0, y0 )];
- [path lineToPoint: cocoa_point( x1, y1 )];
- cocoa_plot_path_set_stroke_pattern( path, pstyle );
-
- const bool horizontal = y0 == y1;
- const bool vertical = x0 == x1;
- const bool oddThickness = pstyle->stroke_width != 0 ? (pstyle->stroke_width % 2) != 0 : true;
-
- if (oddThickness) cocoa_center_pixel( !horizontal, !vertical );
-
- [cocoa_convert_colour( pstyle->stroke_colour ) set];
- [path stroke];
-
- [NSGraphicsContext restoreGraphicsState];
-
- return true;
-}
-
-static bool plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
-{
- NSRect rect = cocoa_rect( x0, y0, x1, y1 );
- NSBezierPath *path = [NSBezierPath bezierPathWithRect: rect];
- cocoa_plot_render_path( path, pstyle );
-
- return true;
-}
-
-static bool plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
-{
- [NSGraphicsContext saveGraphicsState];
- [NSBezierPath clipRect: cocoa_plot_clip_rect];
-
- cocoa_draw_string( cocoa_px_to_pt( x ), cocoa_px_to_pt( y ), text, length, fstyle );
-
- [NSGraphicsContext restoreGraphicsState];
-
- return true;
-}
-
-void cocoa_set_clip( NSRect rect )
-{
- cocoa_plot_clip_rect = rect;
-}
-
-static bool plot_clip(const struct rect *clip)
-{
- cocoa_plot_clip_rect = cocoa_rect( clip->x0, clip->y0, clip->x1, clip->y1 );
- return true;
-}
-
-void cocoa_plot_render_path(NSBezierPath *path,const plot_style_t *pstyle)
-{
- [NSGraphicsContext saveGraphicsState];
- [NSBezierPath clipRect: cocoa_plot_clip_rect];
-
- if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
- [cocoa_convert_colour( pstyle->fill_colour ) setFill];
- [path fill];
- }
-
- if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
- if (pstyle->stroke_width == 0 || pstyle->stroke_width % 2 != 0) cocoa_center_pixel( true, true );
-
- cocoa_plot_path_set_stroke_pattern(path,pstyle);
-
- [cocoa_convert_colour( pstyle->stroke_colour ) set];
-
- [path stroke];
- }
-
- [NSGraphicsContext restoreGraphicsState];
-}
-
-static bool plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle)
-{
- NSBezierPath *path = [NSBezierPath bezierPath];
- [path appendBezierPathWithArcWithCenter: NSMakePoint( x, y ) radius: radius
- startAngle: angle1 endAngle: angle2
- clockwise: NO];
-
- cocoa_plot_render_path( path, pstyle);
-
- return true;
-}
-
-static bool plot_disc(int x, int y, int radius, const plot_style_t *pstyle)
-{
- NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:
- NSMakeRect( x - radius, y-radius, 2*radius, 2*radius )];
-
- cocoa_plot_render_path( path, pstyle );
-
- return true;
-}
-
-static bool plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle)
-{
- if (n <= 1) return true;
-
- NSBezierPath *path = [NSBezierPath bezierPath];
- [path moveToPoint: cocoa_point( p[0], p[1] )];
- for (unsigned i = 1; i < n; i++) {
- [path lineToPoint: cocoa_point( p[2*i], p[2*i+1] )];
- }
- [path closePath];
-
- cocoa_plot_render_path( path, pstyle );
-
- return true;
-}
-
-/* complex path (for SVG) */
-static bool plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- if (n == 0) return true;
-
- if (*p != PLOTTER_PATH_MOVE) {
- LOG("Path does not start with move");
- return false;
- }
-
- NSBezierPath *path = [NSBezierPath bezierPath];
-
-#define NEXT_POINT() NSMakePoint( *p++, *p++ )
-
- while (n--) {
- switch ((int)*p++) {
- case PLOTTER_PATH_MOVE: {
- const NSPoint pt = NEXT_POINT();
- [path moveToPoint: pt];
- break;
- }
-
- case PLOTTER_PATH_LINE: {
- const NSPoint pt = NEXT_POINT();
- [path lineToPoint: pt];
- break;
- }
-
- case PLOTTER_PATH_BEZIER: {
- const NSPoint cp1 = NEXT_POINT();
- const NSPoint cp2 = NEXT_POINT();
- const NSPoint ep = NEXT_POINT();
- [path curveToPoint: ep controlPoint1: cp1 controlPoint2: cp2];
- break;
- }
-
- case PLOTTER_PATH_CLOSE:
- [path closePath];
- break;
-
- default:
- LOG("Invalid path");
- return false;
- }
- }
-
-#undef NEXT_POINT
-
- [path setLineWidth: width];
-
- CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState( context );
-
- CGContextClipToRect( context, NSRectToCGRect( cocoa_plot_clip_rect ) );
-
- CGContextConcatCTM( context, CGAffineTransformMake( transform[0], transform[1], transform[2],
- transform[3], transform[4], transform[5] ) );
-
- if (fill != NS_TRANSPARENT) {
- [cocoa_convert_colour( fill ) setFill];
- [path fill];
- }
-
- if (c != NS_TRANSPARENT) {
- cocoa_center_pixel( true, true );
- [cocoa_convert_colour( c ) set];
- [path stroke];
- }
-
- CGContextRestoreGState( context );
-
- return true;
-}
-
-/* Image */
-static bool plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
-{
- CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState( context );
-
- CGContextClipToRect( context, NSRectToCGRect( cocoa_plot_clip_rect ) );
-
- const bool tileX = flags & BITMAPF_REPEAT_X;
- const bool tileY = flags & BITMAPF_REPEAT_Y;
-
- CGImageRef img = cocoa_get_cgimage( bitmap );
-
- CGRect rect = NSRectToCGRect( cocoa_rect_wh( x, y, width, height ) );
-
- if (tileX || tileY) {
- CGContextDrawTiledImage( context, rect, img );
- } else {
- CGContextDrawImage( context, rect, img );
- }
-
- CGContextRestoreGState( context );
-
- return true;
-}
-
-const struct plotter_table cocoa_plotters = {
- .clip = plot_clip,
- .arc = plot_arc,
- .disc = plot_disc,
- .rectangle = plot_rectangle,
- .line = plot_line,
- .polygon = plot_polygon,
-
- .path = plot_path,
-
- .bitmap = plot_bitmap,
-
- .text = plot_text,
-
- .option_knockout = true
-};
-
-
-CGFloat cocoa_scale_factor;
-static const CGFloat points_per_inch = 72.0;
-static CGFloat cocoa_half_pixel;
-
-void cocoa_update_scale_factor( void )
-{
- const CGFloat scale = [[NSScreen mainScreen] userSpaceScaleFactor];
- cocoa_scale_factor = scale == 1.0 ? 1.0 : 1.0 / scale;
- cocoa_half_pixel = 0.5 * cocoa_scale_factor;
- browser_set_dpi( points_per_inch * scale );
-}
-
-static inline void cocoa_center_pixel( bool x, bool y )
-{
- NSAffineTransform *transform = [NSAffineTransform transform];
- [transform translateXBy: x ? cocoa_half_pixel : 0.0 yBy: y ? cocoa_half_pixel : 0.0];
- [transform concat];
-}
diff --git a/frontends/cocoa/res/BookmarksWindow.xib b/frontends/cocoa/res/BookmarksWindow.xib
deleted file mode 100644
index b038e6ca1..000000000
--- a/frontends/cocoa/res/BookmarksWindow.xib
+++ /dev/null
@@ -1,610 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="1"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">BookmarksController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 80}, {350, 400}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">Bookmarks</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
- <string key="NSWindowContentMinSize">{200, 100}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSScrollView" id="79136560">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSClipView" id="286793088">
- <reference key="NSNextResponder" ref="79136560"/>
- <int key="NSvFlags">2304</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomView" id="347174519">
- <reference key="NSNextResponder" ref="286793088"/>
- <int key="NSvFlags">274</int>
- <string key="NSFrameSize">{350, 360}</string>
- <reference key="NSSuperview" ref="286793088"/>
- <string key="NSClassName">TreeView</string>
- </object>
- </object>
- <string key="NSFrame">{{1, 1}, {350, 360}}</string>
- <reference key="NSSuperview" ref="79136560"/>
- <reference key="NSNextKeyView" ref="347174519"/>
- <reference key="NSDocView" ref="347174519"/>
- <object class="NSColor" key="NSBGColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <int key="NScvFlags">4</int>
- </object>
- <object class="NSScroller" id="343618412">
- <reference key="NSNextResponder" ref="79136560"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{353, 1}, {15, 313}}</string>
- <reference key="NSSuperview" ref="79136560"/>
- <reference key="NSTarget" ref="79136560"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSCurValue">1</double>
- <double key="NSPercent">0.96363627910614014</double>
- </object>
- <object class="NSScroller" id="885399726">
- <reference key="NSNextResponder" ref="79136560"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{1, 314}, {352, 15}}</string>
- <reference key="NSSuperview" ref="79136560"/>
- <int key="NSsFlags">1</int>
- <reference key="NSTarget" ref="79136560"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSPercent">0.50602412223815918</double>
- </object>
- </object>
- <string key="NSFrame">{{-1, 39}, {352, 362}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSNextKeyView" ref="286793088"/>
- <int key="NSsFlags">562</int>
- <reference key="NSVScroller" ref="343618412"/>
- <reference key="NSHScroller" ref="885399726"/>
- <reference key="NSContentView" ref="286793088"/>
- </object>
- <object class="NSButton" id="1013386414">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">292</int>
- <string key="NSFrame">{{7, 7}, {29, 25}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="1030859690">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents"/>
- <object class="NSFont" key="NSSupport" id="1037042855">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">13</double>
- <int key="NSfFlags">1044</int>
- </object>
- <reference key="NSControlView" ref="1013386414"/>
- <int key="NSButtonFlags">-2033958657</int>
- <int key="NSButtonFlags2">163</int>
- <object class="NSCustomResource" key="NSNormalImage">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSAddTemplate</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSButton" id="812276353">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">292</int>
- <string key="NSFrame">{{43, 7}, {29, 25}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="142633288">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="1037042855"/>
- <reference key="NSControlView" ref="812276353"/>
- <int key="NSButtonFlags">-2033958657</int>
- <int key="NSButtonFlags2">163</int>
- <object class="NSCustomResource" key="NSNormalImage">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSRemoveTemplate</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSButton" id="482147213">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">292</int>
- <string key="NSFrame">{{80, 7}, {38, 25}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="586666285">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Edit</string>
- <reference key="NSSupport" ref="1037042855"/>
- <reference key="NSControlView" ref="482147213"/>
- <int key="NSButtonFlags">-2038152961</int>
- <int key="NSButtonFlags2">163</int>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- </object>
- <string key="NSFrameSize">{350, 400}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMinSize">{200, 122}</string>
- <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
- <bool key="NSAutorecalculatesContentBorderThicknessMinY">NO</bool>
- <double key="NSContentBorderThicknessMinY">39</double>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">3</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">view</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="347174519"/>
- </object>
- <int key="connectionID">8</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">addFolder:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1013386414"/>
- </object>
- <int key="connectionID">17</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">deleteSelected:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="812276353"/>
- </object>
- <int key="connectionID">18</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">editSelected:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="482147213"/>
- </object>
- <int key="connectionID">19</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">initialFirstResponder</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="347174519"/>
- </object>
- <int key="connectionID">20</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <reference key="object" ref="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="79136560"/>
- <reference ref="1013386414"/>
- <reference ref="812276353"/>
- <reference ref="482147213"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="79136560"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="343618412"/>
- <reference ref="885399726"/>
- <reference ref="347174519"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="343618412"/>
- <reference key="parent" ref="79136560"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">6</int>
- <reference key="object" ref="885399726"/>
- <reference key="parent" ref="79136560"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">7</int>
- <reference key="object" ref="347174519"/>
- <reference key="parent" ref="79136560"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">11</int>
- <reference key="object" ref="1013386414"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1030859690"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">12</int>
- <reference key="object" ref="1030859690"/>
- <reference key="parent" ref="1013386414"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">13</int>
- <reference key="object" ref="812276353"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="142633288"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">14</int>
- <reference key="object" ref="142633288"/>
- <reference key="parent" ref="812276353"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">15</int>
- <reference key="object" ref="482147213"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="586666285"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">16</int>
- <reference key="object" ref="586666285"/>
- <reference key="parent" ref="482147213"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>1.windowTemplate.hasMinSize</string>
- <string>1.windowTemplate.minSize</string>
- <string>11.IBPluginDependency</string>
- <string>11.IBViewBoundsToFrameTransform</string>
- <string>12.IBPluginDependency</string>
- <string>13.IBPluginDependency</string>
- <string>13.IBViewBoundsToFrameTransform</string>
- <string>14.IBPluginDependency</string>
- <string>15.IBPluginDependency</string>
- <string>15.IBViewBoundsToFrameTransform</string>
- <string>16.IBPluginDependency</string>
- <string>2.IBPluginDependency</string>
- <string>4.IBPluginDependency</string>
- <string>4.IBViewBoundsToFrameTransform</string>
- <string>5.IBPluginDependency</string>
- <string>6.IBPluginDependency</string>
- <string>7.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{226, 417}, {350, 400}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{226, 417}, {350, 400}}</string>
- <integer value="1"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <boolean value="YES"/>
- <string>{200, 100}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABAwAAAwfAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCJAAAwfAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCmAAAwfAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAAC/gAAAw7eAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">20</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">BookmarksController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>addBookmark:</string>
- <string>addFolder:</string>
- <string>deleteSelected:</string>
- <string>editSelected:</string>
- <string>openBookmarkURL:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>addBookmark:</string>
- <string>addFolder:</string>
- <string>deleteSelected:</string>
- <string>editSelected:</string>
- <string>openBookmarkURL:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">addBookmark:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">addFolder:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">deleteSelected:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">editSelected:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">openBookmarkURL:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>defaultMenu</string>
- <string>view</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSMenu</string>
- <string>TreeView</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>defaultMenu</string>
- <string>view</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBToOneOutletInfo">
- <string key="name">defaultMenu</string>
- <string key="candidateClassName">NSMenu</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">view</string>
- <string key="candidateClassName">TreeView</string>
- </object>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BookmarksController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">ScrollableView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ScrollableView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">TreeView</string>
- <string key="superclassName">ScrollableView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">TreeView.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSAddTemplate</string>
- <string>NSRemoveTemplate</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{8, 8}</string>
- <string>{8, 8}</string>
- </object>
- </object>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/Browser.xib b/frontends/cocoa/res/Browser.xib
deleted file mode 100644
index 35ff885b5..000000000
--- a/frontends/cocoa/res/Browser.xib
+++ /dev/null
@@ -1,399 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="41"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">BrowserViewController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSView" id="716999560">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSScrollView" id="140458632">
- <reference key="NSNextResponder" ref="716999560"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSClipView" id="461870317">
- <reference key="NSNextResponder" ref="140458632"/>
- <int key="NSvFlags">2304</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomView" id="623715071">
- <reference key="NSNextResponder" ref="461870317"/>
- <int key="NSvFlags">274</int>
- <string key="NSFrameSize">{691, 631}</string>
- <reference key="NSSuperview" ref="461870317"/>
- <string key="NSClassName">BrowserView</string>
- </object>
- </object>
- <string key="NSFrame">{{1, 1}, {691, 631}}</string>
- <reference key="NSSuperview" ref="140458632"/>
- <reference key="NSNextKeyView" ref="623715071"/>
- <reference key="NSDocView" ref="623715071"/>
- <object class="NSColor" key="NSBGColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <int key="NScvFlags">4</int>
- </object>
- <object class="NSScroller" id="411009984">
- <reference key="NSNextResponder" ref="140458632"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{677, 1}, {15, 616}}</string>
- <reference key="NSSuperview" ref="140458632"/>
- <reference key="NSTarget" ref="140458632"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSCurValue">1</double>
- <double key="NSPercent">0.96363627910614014</double>
- </object>
- <object class="NSScroller" id="17116469">
- <reference key="NSNextResponder" ref="140458632"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{1, 617}, {676, 15}}</string>
- <reference key="NSSuperview" ref="140458632"/>
- <int key="NSsFlags">1</int>
- <reference key="NSTarget" ref="140458632"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSPercent">0.50602412223815918</double>
- </object>
- </object>
- <string key="NSFrame">{{-1, 0}, {693, 633}}</string>
- <reference key="NSSuperview" ref="716999560"/>
- <reference key="NSNextKeyView" ref="461870317"/>
- <int key="NSsFlags">562</int>
- <reference key="NSVScroller" ref="411009984"/>
- <reference key="NSHScroller" ref="17116469"/>
- <reference key="NSContentView" ref="461870317"/>
- </object>
- </object>
- <string key="NSFrameSize">{691, 632}</string>
- <reference key="NSSuperview"/>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">view</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="716999560"/>
- </object>
- <int key="connectionID">52</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">browserView</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="623715071"/>
- </object>
- <int key="connectionID">53</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <reference key="object" ref="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">41</int>
- <reference key="object" ref="716999560"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="140458632"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">44</int>
- <reference key="object" ref="140458632"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="623715071"/>
- <reference ref="17116469"/>
- <reference ref="411009984"/>
- </object>
- <reference key="parent" ref="716999560"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">45</int>
- <reference key="object" ref="623715071"/>
- <reference key="parent" ref="140458632"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">46</int>
- <reference key="object" ref="17116469"/>
- <reference key="parent" ref="140458632"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">47</int>
- <reference key="object" ref="411009984"/>
- <reference key="parent" ref="140458632"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>41.IBEditorWindowLastContentRect</string>
- <string>41.IBPluginDependency</string>
- <string>44.IBPluginDependency</string>
- <string>44.IBViewBoundsToFrameTransform</string>
- <string>45.IBPluginDependency</string>
- <string>46.IBPluginDependency</string>
- <string>47.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{290, 199}, {691, 632}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAAC/gAAAw5EAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">53</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserView</string>
- <string key="superclassName">ScrollableView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserViewController</string>
- <string key="superclassName">NSViewController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>goBack:</string>
- <string>goForward:</string>
- <string>navigate:</string>
- <string>reloadPage:</string>
- <string>stopLoading:</string>
- <string>zoomIn:</string>
- <string>zoomOriginal:</string>
- <string>zoomOut:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>goBack:</string>
- <string>goForward:</string>
- <string>navigate:</string>
- <string>reloadPage:</string>
- <string>stopLoading:</string>
- <string>zoomIn:</string>
- <string>zoomOriginal:</string>
- <string>zoomOut:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">goBack:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">goForward:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">navigate:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">reloadPage:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">stopLoading:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomIn:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomOriginal:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomOut:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">browserView</string>
- <string key="NS.object.0">BrowserView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">browserView</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">browserView</string>
- <string key="candidateClassName">BrowserView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserViewController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">ScrollableView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ScrollableView.h</string>
- </object>
- </object>
- </object>
- <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBFrameworkSource</string>
- <string key="minorKey">Print.framework/Headers/PDEPluginInterface.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
- <integer value="1050" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/BrowserWindow.xib b/frontends/cocoa/res/BrowserWindow.xib
deleted file mode 100644
index 982144cb8..000000000
--- a/frontends/cocoa/res/BrowserWindow.xib
+++ /dev/null
@@ -1,1395 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
- <data>
- <int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">9L31a</string>
- <string key="IBDocument.InterfaceBuilderVersion">680</string>
- <string key="IBDocument.AppKitVersion">949.54</string>
- <string key="IBDocument.HIToolboxVersion">353.00</string>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="1" id="9"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">BrowserWindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">4111</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{139, 364}, {774, 554}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">NetSurf</string>
- <string key="NSWindowClass">BrowserWindow</string>
- <object class="NSToolbar" key="NSViewClass" id="71746575">
- <object class="NSMutableString" key="NSToolbarIdentifier">
- <characters key="NS.bytes">8335B5EA-A088-4DE8-BF4F-777E98920BB3</characters>
- </object>
- <nil key="NSToolbarDelegate"/>
- <bool key="NSToolbarPrefersToBeShown">YES</bool>
- <bool key="NSToolbarShowsBaselineSeparator">YES</bool>
- <bool key="NSToolbarAllowsUserCustomization">YES</bool>
- <bool key="NSToolbarAutosavesConfiguration">NO</bool>
- <int key="NSToolbarDisplayMode">2</int>
- <int key="NSToolbarSizeMode">1</int>
- <object class="NSMutableDictionary" key="NSToolbarIBIdentifiedItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>6D497003-6D4B-4335-ADCE-368C7CD87371</string>
- <string>9DB83278-4E60-41F8-8A7C-C0B2E00A552B</string>
- <string>BC5CEBFC-2E3B-420C-A75F-BE0760149C45</string>
- <string>E2E89C48-DD3F-47A5-9E6C-25985A970F69</string>
- <string>NSToolbarCustomizeToolbarItem</string>
- <string>NSToolbarFlexibleSpaceItem</string>
- <string>NSToolbarSeparatorItem</string>
- <string>NSToolbarSpaceItem</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSToolbarItem" id="16676378">
- <object class="NSMutableString" key="NSToolbarItemIdentifier">
- <characters key="NS.bytes">6D497003-6D4B-4335-ADCE-368C7CD87371</characters>
- </object>
- <string key="NSToolbarItemLabel">History</string>
- <string key="NSToolbarItemPaletteLabel">History</string>
- <nil key="NSToolbarItemToolTip"/>
- <object class="NSButton" key="NSToolbarItemView" id="229385913">
- <nil key="NSNextResponder"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{8, 14}, {30, 25}}</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="296571644">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents"/>
- <object class="NSFont" key="NSSupport" id="770988704">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.300000e+01</double>
- <int key="NSfFlags">1044</int>
- </object>
- <reference key="NSControlView" ref="229385913"/>
- <int key="NSButtonFlags">919355647</int>
- <int key="NSButtonFlags2">163</int>
- <object class="NSCustomResource" key="NSNormalImage" id="235904051">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSIconViewTemplate</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <reference key="NSToolbarItemImage" ref="235904051"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{22, 25}</string>
- <string key="NSToolbarItemMaxSize">{32, 25}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">0</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- </object>
- <object class="NSToolbarItem" id="694471322">
- <object class="NSMutableString" key="NSToolbarItemIdentifier">
- <characters key="NS.bytes">9DB83278-4E60-41F8-8A7C-C0B2E00A552B</characters>
- </object>
- <string key="NSToolbarItemLabel">Homepage</string>
- <string key="NSToolbarItemPaletteLabel">Homepage</string>
- <nil key="NSToolbarItemToolTip"/>
- <object class="NSButton" key="NSToolbarItemView" id="518219892">
- <nil key="NSNextResponder"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{18, 14}, {30, 25}}</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="413663381">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="770988704"/>
- <reference key="NSControlView" ref="518219892"/>
- <int key="NSButtonFlags">-2033434369</int>
- <int key="NSButtonFlags2">99</int>
- <object class="NSCustomResource" key="NSNormalImage" id="967303005">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">HomeTemplate</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <reference key="NSToolbarItemImage" ref="967303005"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{30, 25}</string>
- <string key="NSToolbarItemMaxSize">{30, 25}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">0</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- </object>
- <object class="NSToolbarItem" id="685547192">
- <object class="NSMutableString" key="NSToolbarItemIdentifier">
- <characters key="NS.bytes">BC5CEBFC-2E3B-420C-A75F-BE0760149C45</characters>
- </object>
- <string key="NSToolbarItemLabel"/>
- <string key="NSToolbarItemPaletteLabel">Back/Forward</string>
- <nil key="NSToolbarItemToolTip"/>
- <object class="NSSegmentedControl" key="NSToolbarItemView" id="692457026">
- <nil key="NSNextResponder"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{7, 14}, {67, 25}}</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSSegmentedCell" key="NSCell" id="845979064">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">0</int>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.300000e+01</double>
- <int key="NSfFlags">16</int>
- </object>
- <reference key="NSControlView" ref="692457026"/>
- <object class="NSMutableArray" key="NSSegmentImages">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSSegmentItem">
- <double key="NSSegmentItemWidth">3.000000e+01</double>
- <object class="NSCustomResource" key="NSSegmentItemImage">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSLeftFacingTriangleTemplate</string>
- </object>
- <string key="NSSegmentItemLabel"/>
- <string key="NSSegmentItemTooltip">Back</string>
- <int key="NSSegmentItemImageScaling">0</int>
- </object>
- <object class="NSSegmentItem">
- <double key="NSSegmentItemWidth">3.000000e+01</double>
- <object class="NSCustomResource" key="NSSegmentItemImage">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSRightFacingTriangleTemplate</string>
- </object>
- <string key="NSSegmentItemLabel"/>
- <string key="NSSegmentItemTooltip">Forward</string>
- <int key="NSSegmentItemTag">1</int>
- <int key="NSSegmentItemImageScaling">0</int>
- </object>
- </object>
- <int key="NSSelectedSegment">1</int>
- <int key="NSTrackingMode">2</int>
- <int key="NSSegmentStyle">2</int>
- </object>
- </object>
- <nil key="NSToolbarItemImage"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{67, 25}</string>
- <string key="NSToolbarItemMaxSize">{71, 25}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">0</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- </object>
- <object class="NSToolbarItem" id="192029103">
- <object class="NSMutableString" key="NSToolbarItemIdentifier">
- <characters key="NS.bytes">E2E89C48-DD3F-47A5-9E6C-25985A970F69</characters>
- </object>
- <string key="NSToolbarItemLabel"/>
- <string key="NSToolbarItemPaletteLabel">URL</string>
- <nil key="NSToolbarItemToolTip"/>
- <object class="NSTextField" key="NSToolbarItemView" id="77748234">
- <nil key="NSNextResponder"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{0, 14}, {96, 22}}</string>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="1053649244">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">268436480</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="770988704"/>
- <string key="NSPlaceholderString">Open this URL</string>
- <reference key="NSControlView" ref="77748234"/>
- <bool key="NSDrawsBackground">YES</bool>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textBackgroundColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textColor</string>
- <object class="NSColor" key="NSColor" id="733901069">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- </object>
- </object>
- <nil key="NSToolbarItemImage"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{96, 22}</string>
- <string key="NSToolbarItemMaxSize">{10000, 22}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">0</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- </object>
- <object class="NSToolbarItem" id="276197344">
- <string key="NSToolbarItemIdentifier">NSToolbarCustomizeToolbarItem</string>
- <string key="NSToolbarItemLabel">Customize</string>
- <string key="NSToolbarItemPaletteLabel">Customize</string>
- <string key="NSToolbarItemToolTip">Customize Toolbar</string>
- <nil key="NSToolbarItemView"/>
- <object class="NSImage" key="NSToolbarItemImage">
- <int key="NSImageFlags">683671552</int>
- <string key="NSSize">{32, 32}</string>
- <object class="NSMutableArray" key="NSReps">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0" id="8"/>
- <object class="NSBitmapImageRep">
- <object class="NSData" key="NSTIFFRepresentation">
- <bytes key="NS.bytes">TU0AKgAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAICAgbAAAABAAAAAAEBAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAQEBAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAENDQ0dJSUlW11dXbBpaWnDb29vzyAgIGUPDw8xAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAABsbGyUoKChIHh4ePSkpKUonJycsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDCEJCQoWvr6/i9fX1/fX19f7h4eH82dnZ+YODg9sYGBg8
-AAAAAAAAAAAAAAAAAAAAAAAAAAJFRUV6ZGRkvf39/f/+/v7//////0NDQ7QAAAAEAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PDx9ISEiH2tra8/7+/v/j4+P/2NjY/7a2tv+ysrL/
-i4uL7j09PeUKCgoSAAAAAAAAAAAAAAAAUVFRlo2NjfTIyMj6x8fH/56env97e3v/ISEhMAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8lRUVFjtDQ0Pb+/v7/4eHh/dDQ0P+NjY3/
-Tk5O6yoqKrIfHx+gGhoarCIiImwAAAABAAAAADg4OGWenp7/y8vL/d3d3f+8vLz/hYWF/0RERE0AAAAA
-AAAAAAAAAAAfHx8sAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj8/P2za2try9/f3/+vr6/7Kysr/
-dnZ2/D4+PvwgICB+EBAQNAICAgcAAAAPERERPQMDAwkQEBASh4eH2MHBwf/o6Oj/39/f/3R0dP88PDxO
-AAAAAAAAAAAAAAAAcnJylkNDQ58HBwcIAAAAAAAAAAAAAAAAAAAAAAAAAAAGBgYMfn5+uMvLy/3Hx8f+
-u7u7/5OTk/9CQkL7HRYL7AICAgQAAAAAAAAAAAAAAAAAAAAAAgICBS4uLjOWlpbz6urq/+7u7v+rq6v/
-IyMj0wAAAAAAAAAAAAAAAIGBgZGLi4v/QkJC2Q0NDSYAAAAAAAAAAAAAAAAAAAAAGRkZJF5eXoylpaXz
-pqam/4qKiv91dXX/YWFh+iwkHvojEADrJhcGoAgICA0AAAAAAAAAAAAAAAAAAAAAPj4+RJaWlvr19fX/
-6+vr/7W1tfVaWlrlAwMDbAAAAACKioqcoqKi/7+/v/9HR0fnDg4OJwAAAAAAAAAAHR0dK3V1dZ+pqanC
-+vr6/9vb2/99fX3+Y2Nj+EhISOgMCAP4JhIA8jgaAPBxNADsNyMMjgcHBwsAAAAAAAAAAAAAAAAMDAwO
-m5ub+Orq6v/y8vL/0NDQ7ICAgMtkZGTqcHBwzLOzs//Pz8//0tLS/0xMTNoJCQkhAAAAABoaGjZ/f3+4
-//////j4+P/9/f3/9vb2/0dHR/8oKCjkKSkpoAQCAJUNBQDXVSgA5XY5AOuTSADcOiUOewYGBgoAAAAA
-AAAAAB4eHmFlZWX76Ojo/+7u7v/5+fn/5OTk9Li4uO3f39//8PDw/+Hh4f/Ly8v/Ozs7rQICAgMAAAAA
-GBgYL3x8fP///////////7S0tP+np6f/QEBA+xUVFXUJCQkkBAQEDgcFA20jEQC7YzIA3n9BAOiiUwDK
-NiMObgYGBgoTExNIOzs74bGxsf3Dw8P/1dXV////////////////////////////8/Pz/3R0dOcPDw9H
-AAAAAQAAAAAAAAAAVVVVooCAgP/v7+//v7+//2VlZf86OjrLAQEBBgAAAAAAAAAAAAAAABENCVctFwCl
-ZTQA1oZFAOCqWgDAMiMTgzExMcKzs7P4wcHB/5+fn//W1tb///////v7+/v//////////729vfOFhYXy
-IyMjdAAAAAMAAAABAAAAAAAAAAAAAAAASkpKmlpaWv+RkZH/Nzc38hgYGG4AAAABAAAAAAAAAAAAAAAA
-AAAAAAsFAEUwGACbaDcAzXpCAOFnRiLjs7Kx+MTExP+pqan/09PT/3p6evpdXV3rbGxs6l1dXfVXV1fs
-UlJSxykpKWMAAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBmiMjI/8cHBysBQUFHQAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAsFAEAuGACfSzAT47y4s/24uLj/lJSU/9TU1P+Dg4PkMzMzzwYGBgw6OjpB
-QEBASQ8PDxYbGxshAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIimgoKCi4AAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAwJBYS9u7n4r6+v/4GBgf/Pz8//iISB6CYmJqoDAwMK
-AAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAABUwcHB7qurq/9ubm7/zs7O/5yOgPhlPhbf
-MhsCegAAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMnCgoKZsvLy++pqan/Wlpa/9LS0v+Nh4Hq
-SCYE4IdDAeSbTgDLNxsAhwAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMOxoaGobV1dXzq6ur/0ZGRv/Z2dn/
-hoaGxQkEAIY6HgCyaDMA2YVAAOuWSQDZPh4AngAAABEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgYGFEoKCio0tLS86urq/8xMTH/
-4uLi/4+Pj84AAABIAAAAAg8HAGg6HQDKaDIA4YI+APCVRQDsRSEAuAAAABMAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFhYrNTU1z9ra2vb8/Pz/
-FxcX/+rq6v+amprZAAAASAAAAAIAAAAAAAAAABAIAIY4GwDiaTEA6X46APeVRAD/SyIA0gAAABIAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICBT8/P4asrKz3
-0dHR//39/f/z8/P/paWl5gUFBVkAAAACAAAAAAAAAAAAAAAAAAAAABIJAKUxFgD6bTMA9no4AP9uLwD/
-KxIAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBwcO
-QUFBmpqamv+pqan/+Pj4/7GxsfIXFxeBAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAHAMogDgD/
-WSkA/zwaAPcuEwCyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAEBAQMnJydWUFBQ85aWlvqoqKjfKioqrQEBAQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAsFAOUXCQD6IA4AwgQCADMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAgICBBR0dHmi4uLnACAgIHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAgDAMwFAgA9AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE
-AAAACQAAABAAAAAYAAAAIAAAACoAAAAxAAAANgAAADkAAAA4AQEBOQAAAC8AAAAnAAAAHQAAABUAAAAO
-AAAACgAAAAsAAAAPAAAAFwAAACAAAAAqAAAAMQAAADQAAAAzAAAALQAAACQAAAAbAAAAEgAAAAsAAAAA
-AAAAAAAAAAQAAAAJAAAAEAAAABgAAAAgAAAAKgAAADEAAAA2AAAAOQAAADgAAAA1AAAALwAAACcAAAAd
-AAAAFQAAAA4AAAAKAAAACwAAAA8AAAAXAAAAIAAAACoAAAAxAAAANAAAADMAAAAtAAAAJAAAABsAAAAS
-AAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0BAAADAAAAAQAgAAABAQADAAAAAQAgAAABAgADAAAABAAA
-EKoBAwADAAAAAQABAAABBgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAE
-AAABFgADAAAAAQD8AAABFwAEAAAAAQAAEAABHAADAAAAAQABAAABUgADAAAAAQABAAABUwADAAAABAAA
-ELIAAAAAAAgACAAIAAgAAQABAAEAAQ</bytes>
- </object>
- </object>
- </object>
- </object>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MCAwAA</bytes>
- </object>
- </object>
- <nil key="NSToolbarItemTarget"/>
- <string key="NSToolbarItemAction">runToolbarCustomizationPalette:</string>
- <string key="NSToolbarItemMinSize">{0, 0}</string>
- <string key="NSToolbarItemMaxSize">{0, 0}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">-1</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- </object>
- <object class="NSToolbarFlexibleSpaceItem" id="568640167">
- <string key="NSToolbarItemIdentifier">NSToolbarFlexibleSpaceItem</string>
- <string key="NSToolbarItemLabel"/>
- <string key="NSToolbarItemPaletteLabel">Flexible Space</string>
- <nil key="NSToolbarItemToolTip"/>
- <nil key="NSToolbarItemView"/>
- <nil key="NSToolbarItemImage"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{1, 5}</string>
- <string key="NSToolbarItemMaxSize">{20000, 32}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">-1</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <object class="NSCustomResource" key="NSOnImage" id="945310746">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSMenuCheckmark</string>
- </object>
- <object class="NSCustomResource" key="NSMixedImage" id="969998504">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSMenuMixedState</string>
- </object>
- </object>
- </object>
- <object class="NSToolbarSeparatorItem" id="1012010237">
- <string key="NSToolbarItemIdentifier">NSToolbarSeparatorItem</string>
- <string key="NSToolbarItemLabel"/>
- <string key="NSToolbarItemPaletteLabel">Separator</string>
- <nil key="NSToolbarItemToolTip"/>
- <nil key="NSToolbarItemView"/>
- <nil key="NSToolbarItemImage"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{12, 5}</string>
- <string key="NSToolbarItemMaxSize">{12, 1000}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">-1</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="945310746"/>
- <reference key="NSMixedImage" ref="969998504"/>
- </object>
- </object>
- <object class="NSToolbarSpaceItem" id="661775936">
- <string key="NSToolbarItemIdentifier">NSToolbarSpaceItem</string>
- <string key="NSToolbarItemLabel"/>
- <string key="NSToolbarItemPaletteLabel">Space</string>
- <nil key="NSToolbarItemToolTip"/>
- <nil key="NSToolbarItemView"/>
- <nil key="NSToolbarItemImage"/>
- <nil key="NSToolbarItemTarget"/>
- <nil key="NSToolbarItemAction"/>
- <string key="NSToolbarItemMinSize">{32, 5}</string>
- <string key="NSToolbarItemMaxSize">{32, 32}</string>
- <bool key="NSToolbarItemEnabled">YES</bool>
- <bool key="NSToolbarItemAutovalidates">YES</bool>
- <int key="NSToolbarItemTag">-1</int>
- <bool key="NSToolbarIsUserRemovable">YES</bool>
- <int key="NSToolbarItemVisibilityPriority">0</int>
- <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="945310746"/>
- <reference key="NSMixedImage" ref="969998504"/>
- </object>
- </object>
- </object>
- </object>
- <object class="NSArray" key="NSToolbarIBAllowedItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="685547192"/>
- <reference ref="694471322"/>
- <reference ref="16676378"/>
- <reference ref="192029103"/>
- <reference ref="1012010237"/>
- <reference ref="661775936"/>
- <reference ref="568640167"/>
- <reference ref="276197344"/>
- </object>
- <object class="NSMutableArray" key="NSToolbarIBDefaultItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="685547192"/>
- <reference ref="694471322"/>
- <reference ref="16676378"/>
- <reference ref="192029103"/>
- </object>
- <object class="NSMutableArray" key="NSToolbarIBSelectableItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
- <string key="NSWindowContentMinSize">{273, 43}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomView" id="720246950">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">266</int>
- <string key="NSFrame">{{0, 532}, {774, 22}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <string key="NSClassName">PSMTabBarControl</string>
- </object>
- <object class="NSTextField" id="795357547">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">290</int>
- <string key="NSFrame">{{25, 3}, {732, 14}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="717772067">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">272761856</int>
- <string key="NSContents">Status bar</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.100000e+01</double>
- <int key="NSfFlags">3100</int>
- </object>
- <reference key="NSControlView" ref="795357547"/>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <reference key="NSColor" ref="733901069"/>
- </object>
- </object>
- </object>
- <object class="NSProgressIndicator" id="528651909">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">1316</int>
- <object class="NSPSMatrix" key="NSDrawMatrix"/>
- <string key="NSFrame">{{4, 2}, {16, 16}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <int key="NSpiFlags">28938</int>
- <double key="NSMaxValue">1.000000e+02</double>
- </object>
- <object class="NSTabView" id="477345536">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">18</int>
- <string key="NSFrame">{{0, 20}, {774, 512}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <object class="NSMutableArray" key="NSTabViewItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="NSFont" ref="770988704"/>
- <int key="NSTvFlags">6</int>
- <bool key="NSAllowTruncatedLabels">YES</bool>
- <bool key="NSDrawsBackground">YES</bool>
- </object>
- </object>
- <string key="NSFrameSize">{774, 554}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMinSize">{273, 97}</string>
- <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
- </object>
- <object class="NSObjectController" id="177599630">
- <object class="NSMutableArray" key="NSDeclaredKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>URL</string>
- <string>url</string>
- <string>status</string>
- <string>processing</string>
- <string>title</string>
- <string>isProcessing</string>
- <string>browserView.historyVisible</string>
- </object>
- <string key="NSObjectClassName">BrowserViewController</string>
- <bool key="NSEditable">YES</bool>
- <object class="_NSManagedProxy" key="_NSManagedProxy"/>
- </object>
- <object class="NSMenu" id="237938373">
- <string key="NSTitle">Forward</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMenu" id="353660550">
- <string key="NSTitle">Back</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">18</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="720246950"/>
- <reference key="destination" ref="1001"/>
- </object>
- <int key="connectionID">19</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">tabBar</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="720246950"/>
- </object>
- <int key="connectionID">20</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">tabView</string>
- <reference key="source" ref="720246950"/>
- <reference key="destination" ref="477345536"/>
- </object>
- <int key="connectionID">42</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="477345536"/>
- <reference key="destination" ref="720246950"/>
- </object>
- <int key="connectionID">43</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">tabView</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="477345536"/>
- </object>
- <int key="connectionID">56</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">navigate:</string>
- <reference key="source" ref="1003"/>
- <reference key="destination" ref="192029103"/>
- </object>
- <int key="connectionID">60</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">contentObject: activeBrowser</string>
- <reference key="source" ref="177599630"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="177599630"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">contentObject: activeBrowser</string>
- <string key="NSBinding">contentObject</string>
- <string key="NSKeyPath">activeBrowser</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">62</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: selection.url</string>
- <reference key="source" ref="77748234"/>
- <reference key="destination" ref="177599630"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="77748234"/>
- <reference key="NSDestination" ref="177599630"/>
- <string key="NSLabel">value: selection.url</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">selection.url</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">64</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: selection.status</string>
- <reference key="source" ref="795357547"/>
- <reference key="destination" ref="177599630"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="795357547"/>
- <reference key="NSDestination" ref="177599630"/>
- <string key="NSLabel">value: selection.status</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">selection.status</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">65</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">title: selection.title</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="177599630"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="1005"/>
- <reference key="NSDestination" ref="177599630"/>
- <string key="NSLabel">title: selection.title</string>
- <string key="NSBinding">title</string>
- <string key="NSKeyPath">selection.title</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">67</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="1001"/>
- </object>
- <int key="connectionID">68</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">animate: selection.isProcessing</string>
- <reference key="source" ref="528651909"/>
- <reference key="destination" ref="177599630"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="528651909"/>
- <reference key="NSDestination" ref="177599630"/>
- <string key="NSLabel">animate: selection.isProcessing</string>
- <string key="NSBinding">animate</string>
- <string key="NSKeyPath">selection.isProcessing</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">69</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">urlField</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1053649244"/>
- </object>
- <int key="connectionID">70</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">backForwardSelected:</string>
- <reference key="source" ref="1003"/>
- <reference key="destination" ref="685547192"/>
- </object>
- <int key="connectionID">74</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: selection.browserView.historyVisible</string>
- <reference key="source" ref="296571644"/>
- <reference key="destination" ref="177599630"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="296571644"/>
- <reference key="NSDestination" ref="177599630"/>
- <string key="NSLabel">value: selection.browserView.historyVisible</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">selection.browserView.historyVisible</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">79</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">activeBrowserController</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="177599630"/>
- </object>
- <int key="connectionID">80</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">navigationControl</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="692457026"/>
- </object>
- <int key="connectionID">81</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">goHome:</string>
- <reference key="source" ref="1003"/>
- <reference key="destination" ref="518219892"/>
- </object>
- <int key="connectionID">85</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">partnerView</string>
- <reference key="source" ref="720246950"/>
- <reference key="destination" ref="477345536"/>
- </object>
- <int key="connectionID">86</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">historyButton</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="229385913"/>
- </object>
- <int key="connectionID">87</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">historyForwardMenu</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="237938373"/>
- </object>
- <int key="connectionID">96</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">historyBackMenu</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="353660550"/>
- </object>
- <int key="connectionID">97</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="237938373"/>
- <reference key="destination" ref="1001"/>
- </object>
- <int key="connectionID">98</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="353660550"/>
- <reference key="destination" ref="1001"/>
- </object>
- <int key="connectionID">99</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <object class="NSArray" key="object" id="209349352">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="209349352"/>
- <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="209349352"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="209349352"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- <reference ref="71746575"/>
- </object>
- <reference key="parent" ref="209349352"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="528651909"/>
- <reference ref="795357547"/>
- <reference ref="720246950"/>
- <reference ref="477345536"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">26</int>
- <reference key="object" ref="795357547"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="717772067"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">27</int>
- <reference key="object" ref="717772067"/>
- <reference key="parent" ref="795357547"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">28</int>
- <reference key="object" ref="528651909"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">3</int>
- <reference key="object" ref="720246950"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">37</int>
- <reference key="object" ref="477345536"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">44</int>
- <reference key="object" ref="71746575"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="192029103"/>
- <reference ref="1012010237"/>
- <reference ref="276197344"/>
- <reference ref="568640167"/>
- <reference ref="661775936"/>
- <reference ref="685547192"/>
- <reference ref="16676378"/>
- <reference ref="694471322"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">49</int>
- <reference key="object" ref="192029103"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="77748234"/>
- </object>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">50</int>
- <reference key="object" ref="1012010237"/>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">51</int>
- <reference key="object" ref="276197344"/>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">52</int>
- <reference key="object" ref="568640167"/>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">53</int>
- <reference key="object" ref="661775936"/>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">54</int>
- <reference key="object" ref="77748234"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1053649244"/>
- </object>
- <reference key="parent" ref="192029103"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">55</int>
- <reference key="object" ref="1053649244"/>
- <reference key="parent" ref="77748234"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">61</int>
- <reference key="object" ref="177599630"/>
- <reference key="parent" ref="209349352"/>
- <string key="objectName">Active Browser</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">73</int>
- <reference key="object" ref="685547192"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="692457026"/>
- </object>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">71</int>
- <reference key="object" ref="692457026"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="845979064"/>
- </object>
- <reference key="parent" ref="685547192"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">72</int>
- <reference key="object" ref="845979064"/>
- <reference key="parent" ref="692457026"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">77</int>
- <reference key="object" ref="16676378"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="229385913"/>
- </object>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">75</int>
- <reference key="object" ref="229385913"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="296571644"/>
- </object>
- <reference key="parent" ref="16676378"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">76</int>
- <reference key="object" ref="296571644"/>
- <reference key="parent" ref="229385913"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">84</int>
- <reference key="object" ref="694471322"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="518219892"/>
- </object>
- <reference key="parent" ref="71746575"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">82</int>
- <reference key="object" ref="518219892"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="413663381"/>
- </object>
- <reference key="parent" ref="694471322"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">83</int>
- <reference key="object" ref="413663381"/>
- <reference key="parent" ref="518219892"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">88</int>
- <reference key="object" ref="237938373"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="parent" ref="209349352"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">92</int>
- <reference key="object" ref="353660550"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="parent" ref="209349352"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>1.windowTemplate.hasMinSize</string>
- <string>1.windowTemplate.minSize</string>
- <string>2.IBPluginDependency</string>
- <string>26.IBPluginDependency</string>
- <string>26.IBViewBoundsToFrameTransform</string>
- <string>27.IBPluginDependency</string>
- <string>28.IBPluginDependency</string>
- <string>28.IBViewBoundsToFrameTransform</string>
- <string>3.IBPluginDependency</string>
- <string>3.IBViewBoundsToFrameTransform</string>
- <string>37.IBPluginDependency</string>
- <string>37.IBViewBoundsToFrameTransform</string>
- <string>44.IBEditorWindowLastContentRect</string>
- <string>44.IBPluginDependency</string>
- <string>50.IBPluginDependency</string>
- <string>51.IBPluginDependency</string>
- <string>52.IBPluginDependency</string>
- <string>53.IBPluginDependency</string>
- <string>54.IBPluginDependency</string>
- <string>55.CustomClassName</string>
- <string>55.IBPluginDependency</string>
- <string>61.IBPluginDependency</string>
- <string>71.IBPluginDependency</string>
- <string>72.IBPluginDependency</string>
- <string>72.IBSegmentedControlInspectorSelectedSegmentMetadataKey</string>
- <string>75.IBAttributePlaceholdersKey</string>
- <string>75.IBPluginDependency</string>
- <string>76.IBPluginDependency</string>
- <string>82.IBAttributePlaceholdersKey</string>
- <string>82.IBPluginDependency</string>
- <string>83.IBPluginDependency</string>
- <string>88.IBPluginDependency</string>
- <string>92.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{103, 62}, {774, 554}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{103, 62}, {774, 554}}</string>
- <reference ref="9"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <boolean value="YES"/>
- <string>{273, 43}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDCAAAwaAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABAwAAAwWAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">AQAAAABEE8AAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDiwAAxAVAAA</bytes>
- </object>
- <string>{{355, 640}, {616, 0}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>URLFieldCell</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <reference ref="8"/>
- <object class="NSMutableDictionary">
- <string key="NS.key.0">ToolTip</string>
- <object class="IBToolTipAttribute" key="NS.object.0">
- <string key="name">ToolTip</string>
- <reference key="object" ref="229385913"/>
- <string key="toolTip">Show local history</string>
- </object>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSMutableDictionary">
- <string key="NS.key.0">ToolTip</string>
- <object class="IBToolTipAttribute" key="NS.object.0">
- <string key="name">ToolTip</string>
- <reference key="object" ref="518219892"/>
- <string key="toolTip">Go to your homepage</string>
- </object>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">99</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserView</string>
- <string key="superclassName">ScrollableView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserViewController</string>
- <string key="superclassName">NSViewController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>backForwardSelected:</string>
- <string>goBack:</string>
- <string>goForward:</string>
- <string>goHome:</string>
- <string>navigate:</string>
- <string>reloadPage:</string>
- <string>stopLoading:</string>
- <string>zoomIn:</string>
- <string>zoomOriginal:</string>
- <string>zoomOut:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">browserView</string>
- <string key="NS.object.0">BrowserView</string>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserViewController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserWindow</string>
- <string key="superclassName">NSWindow</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserWindow.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>closeCurrentTab:</string>
- <string>newTab:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>activeBrowserController</string>
- <string>historyBackMenu</string>
- <string>historyButton</string>
- <string>historyForwardMenu</string>
- <string>navigationControl</string>
- <string>tabBar</string>
- <string>tabView</string>
- <string>urlField</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSObjectController</string>
- <string>NSMenu</string>
- <string>NSButton</string>
- <string>NSMenu</string>
- <string>NSSegmentedControl</string>
- <string>PSMTabBarControl</string>
- <string>NSTabView</string>
- <string>URLFieldCell</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserWindowController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="238543186">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="472370996">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="395663776">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <reference key="sourceIdentifier" ref="472370996"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <string key="superclassName">NSControl</string>
- <object class="NSMutableDictionary" key="outlets">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>delegate</string>
- <string>partnerView</string>
- <string>style</string>
- <string>tabView</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>NSTabView</string>
- </object>
- </object>
- <reference key="sourceIdentifier" ref="395663776"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <reference key="sourceIdentifier" ref="238543186"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabStyle.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">ScrollableView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ScrollableView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">URLFieldCell</string>
- <string key="superclassName">NSTextFieldCell</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">URLFieldCell.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/DownloadWindow.xib b/frontends/cocoa/res/DownloadWindow.xib
deleted file mode 100644
index 039ff1914..000000000
--- a/frontends/cocoa/res/DownloadWindow.xib
+++ /dev/null
@@ -1,493 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="1"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">DownloadWindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 429}, {376, 90}}</string>
- <int key="NSWTFlags">544735232</int>
- <string key="NSWindowTitle">Download</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{1000, 90}</string>
- <string key="NSWindowContentMinSize">{330, 90}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSProgressIndicator" id="663127685">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">1290</int>
- <object class="NSPSMatrix" key="NSDrawMatrix"/>
- <string key="NSFrame">{{79, 33}, {279, 20}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <int key="NSpiFlags">16392</int>
- <double key="NSMaxValue">100</double>
- </object>
- <object class="NSImageView" id="454520484">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <object class="NSMutableSet" key="NSDragTypes">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="set.sortedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>Apple PDF pasteboard type</string>
- <string>Apple PICT pasteboard type</string>
- <string>Apple PNG pasteboard type</string>
- <string>NSFilenamesPboardType</string>
- <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
- <string>NeXT TIFF v4.0 pasteboard type</string>
- </object>
- </object>
- <string key="NSFrame">{{17, 17}, {56, 56}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSImageCell" key="NSCell" id="596224379">
- <int key="NSCellFlags">130560</int>
- <int key="NSCellFlags2">33554432</int>
- <int key="NSAlign">0</int>
- <int key="NSScale">3</int>
- <int key="NSStyle">0</int>
- <bool key="NSAnimates">NO</bool>
- </object>
- <bool key="NSEditable">YES</bool>
- </object>
- <object class="NSTextField" id="355449439">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">266</int>
- <string key="NSFrame">{{78, 56}, {261, 17}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="578533771">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents">Label</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">13</double>
- <int key="NSfFlags">1044</int>
- </object>
- <reference key="NSControlView" ref="355449439"/>
- <object class="NSColor" key="NSBackgroundColor" id="388192080">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor" id="1042936865">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- </object>
- </object>
- <object class="NSTextField" id="1027859209">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">266</int>
- <string key="NSFrame">{{78, 17}, {281, 14}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="882473472">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">272761856</int>
- <string key="NSContents">Label</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">11</double>
- <int key="NSfFlags">3100</int>
- </object>
- <reference key="NSControlView" ref="1027859209"/>
- <reference key="NSBackgroundColor" ref="388192080"/>
- <reference key="NSTextColor" ref="1042936865"/>
- </object>
- </object>
- </object>
- <string key="NSFrameSize">{376, 90}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMinSize">{330, 112}</string>
- <string key="NSMaxSize">{1000, 112}</string>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">3</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">maxValue: totalSize</string>
- <reference key="source" ref="663127685"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector" id="721881472">
- <reference key="NSSource" ref="663127685"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">maxValue: totalSize</string>
- <string key="NSBinding">maxValue</string>
- <string key="NSKeyPath">totalSize</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">6</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: receivedSize</string>
- <reference key="source" ref="663127685"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="663127685"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: receivedSize</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">receivedSize</string>
- <reference key="NSPreviousConnector" ref="721881472"/>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">7</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: fileName</string>
- <reference key="source" ref="355449439"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="355449439"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: fileName</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">fileName</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">22</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: icon</string>
- <reference key="source" ref="454520484"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="454520484"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: icon</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">icon</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">23</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: statusText</string>
- <reference key="source" ref="1027859209"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="1027859209"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: statusText</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">statusText</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">24</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="1001"/>
- </object>
- <int key="connectionID">25</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <reference key="object" ref="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="454520484"/>
- <reference ref="355449439"/>
- <reference ref="1027859209"/>
- <reference ref="663127685"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="663127685"/>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">14</int>
- <reference key="object" ref="454520484"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="596224379"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">15</int>
- <reference key="object" ref="596224379"/>
- <reference key="parent" ref="454520484"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">16</int>
- <reference key="object" ref="355449439"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="578533771"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">17</int>
- <reference key="object" ref="578533771"/>
- <reference key="parent" ref="355449439"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">18</int>
- <reference key="object" ref="1027859209"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="882473472"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">19</int>
- <reference key="object" ref="882473472"/>
- <reference key="parent" ref="1027859209"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>1.windowTemplate.hasMaxSize</string>
- <string>1.windowTemplate.hasMinSize</string>
- <string>1.windowTemplate.maxSize</string>
- <string>1.windowTemplate.minSize</string>
- <string>14.IBPluginDependency</string>
- <string>14.IBViewBoundsToFrameTransform</string>
- <string>15.IBPluginDependency</string>
- <string>16.IBPluginDependency</string>
- <string>16.IBViewBoundsToFrameTransform</string>
- <string>17.IBPluginDependency</string>
- <string>18.IBPluginDependency</string>
- <string>18.IBViewBoundsToFrameTransform</string>
- <string>19.IBPluginDependency</string>
- <string>2.IBPluginDependency</string>
- <string>4.IBPluginDependency</string>
- <string>4.IBViewBoundsToFrameTransform</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{305, 231}, {376, 90}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{305, 231}, {376, 90}}</string>
- <integer value="1"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <boolean value="YES"/>
- <boolean value="YES"/>
- <string>{1000, 90}</string>
- <string>{330, 90}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">AUGIAABBiAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCzAAAwo4AAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCnAAAwgAAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCngAAwkAAAA</bytes>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">25</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">DownloadWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">DownloadWindowController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- </object>
- <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBFrameworkSource</string>
- <string key="minorKey">Print.framework/Headers/PDEPluginInterface.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
- <integer value="1050" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/HistoryWindow.xib b/frontends/cocoa/res/HistoryWindow.xib
deleted file mode 100644
index a5ec90e1a..000000000
--- a/frontends/cocoa/res/HistoryWindow.xib
+++ /dev/null
@@ -1,338 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="1"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">HistoryWindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 112}, {327, 398}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">History</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSScrollView" id="329245506">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSClipView" id="429990844">
- <reference key="NSNextResponder" ref="329245506"/>
- <int key="NSvFlags">2304</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomView" id="920629225">
- <reference key="NSNextResponder" ref="429990844"/>
- <int key="NSvFlags">274</int>
- <string key="NSFrameSize">{312, 383}</string>
- <reference key="NSSuperview" ref="429990844"/>
- <string key="NSClassName">TreeView</string>
- </object>
- </object>
- <string key="NSFrame">{{1, 1}, {312, 383}}</string>
- <reference key="NSSuperview" ref="329245506"/>
- <reference key="NSNextKeyView" ref="920629225"/>
- <reference key="NSDocView" ref="920629225"/>
- <object class="NSColor" key="NSBGColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <int key="NScvFlags">4</int>
- </object>
- <object class="NSScroller" id="909448709">
- <reference key="NSNextResponder" ref="329245506"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{313, 1}, {15, 383}}</string>
- <reference key="NSSuperview" ref="329245506"/>
- <reference key="NSTarget" ref="329245506"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSCurValue">1</double>
- <double key="NSPercent">0.96363627910614014</double>
- </object>
- <object class="NSScroller" id="886582390">
- <reference key="NSNextResponder" ref="329245506"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{1, 384}, {312, 15}}</string>
- <reference key="NSSuperview" ref="329245506"/>
- <int key="NSsFlags">1</int>
- <reference key="NSTarget" ref="329245506"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSPercent">0.50602412223815918</double>
- </object>
- </object>
- <string key="NSFrame">{{-1, -1}, {329, 400}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSNextKeyView" ref="429990844"/>
- <int key="NSsFlags">50</int>
- <reference key="NSVScroller" ref="909448709"/>
- <reference key="NSHScroller" ref="886582390"/>
- <reference key="NSContentView" ref="429990844"/>
- </object>
- </object>
- <string key="NSFrameSize">{327, 398}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">3</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">view</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="920629225"/>
- </object>
- <int key="connectionID">8</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <reference key="object" ref="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="329245506"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="329245506"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="909448709"/>
- <reference ref="886582390"/>
- <reference ref="920629225"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="909448709"/>
- <reference key="parent" ref="329245506"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">6</int>
- <reference key="object" ref="886582390"/>
- <reference key="parent" ref="329245506"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">7</int>
- <reference key="object" ref="920629225"/>
- <reference key="parent" ref="329245506"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>2.IBPluginDependency</string>
- <string>4.IBPluginDependency</string>
- <string>5.IBPluginDependency</string>
- <string>6.IBPluginDependency</string>
- <string>7.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{361, 416}, {327, 398}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{361, 416}, {327, 398}}</string>
- <boolean value="NO"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">8</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">HistoryWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">view</string>
- <string key="NS.object.0">TreeView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">view</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">view</string>
- <string key="candidateClassName">TreeView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">HistoryWindowController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">ScrollableView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ScrollableView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">TreeView</string>
- <string key="superclassName">ScrollableView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">TreeView.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/HomeTemplate.pdf b/frontends/cocoa/res/HomeTemplate.pdf
deleted file mode 100644
index 42b88e9eb..000000000
--- a/frontends/cocoa/res/HomeTemplate.pdf
+++ /dev/null
@@ -1,106 +0,0 @@
-%PDF-1.5 %âãÏÓ
-1 0 obj <</Metadata 9 0 R/Pages 2 0 R/Type/Catalog>> endobj 9 0 obj <</Subtype/XML/Length 16417/Type/Metadata>>stream
-<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
-<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c036 46.277092, Fri Feb 23 2007 14:16:18 ">
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- <rdf:Description rdf:about=""
- xmlns:dc="http://purl.org/dc/elements/1.1/">
- <dc:format>application/pdf</dc:format>
- <dc:title>
- <rdf:Alt>
- <rdf:li xml:lang="x-default">HomeTemplate</rdf:li>
- </rdf:Alt>
- </dc:title>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:xap="http://ns.adobe.com/xap/1.0/"
- xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/">
- <xap:CreatorTool>Adobe Illustrator CS3</xap:CreatorTool>
- <xap:CreateDate>2011-02-08T14:59:01+01:00</xap:CreateDate>
- <xap:ModifyDate>2011-02-08T14:59:01+01:00</xap:ModifyDate>
- <xap:MetadataDate>2011-02-08T14:59:01+01:00</xap:MetadataDate>
- <xap:Thumbnails>
- <rdf:Alt>
- <rdf:li rdf:parseType="Resource">
- <xapGImg:width>256</xapGImg:width>
- <xapGImg:height>256</xapGImg:height>
- <xapGImg:format>JPEG</xapGImg:format>
- <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYqwz80/zT8uflz5cfVtWf1bqXkmm6ajAS3MoH2V68UWo5vSijxJAKrv&#xA;ys/NPy5+Y3lxNW0l/SuouKalprsDLbSkfZbpyRqHg9KMPAggKszxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVhn5p/mn5c/Lny4+ras/q3UvJNN01G&#xA;AluZQPsr14otRzelFHiSAVXwD5+8/eY/PPmOfXten9W4l+GGFaiKCIElYolJPFVr8ydzUnFXeQfP&#xA;3mPyN5jg17QZ/SuIvhmhapiniJBaKVQRyVqfMHcUIxV9/flZ+aflz8xvLiatpL+ldRcU1LTXYGW2&#xA;lI+y3TkjUPB6UYeBBAVZnirsVflXirsVdirsVfqpirsVdirsVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVdirDPzT/NPy5+XPlx9W1Z/VupeSabpqMBLcygfZXrxRajm9KKPEkAqvgHz95+8x&#xA;+efMc+va9P6txL8MMK1EUEQJKxRKSeKrX5k7mpOKscxV2Ksj8g+fvMfkbzHBr2gz+lcRfDNC1TFP&#xA;ESC0UqgjkrU+YO4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMttKR9lunJGoeD0ow8CCAqzPFX5&#xA;V4q7FXYq7FX6qYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWGfmn+aflz8ufL&#xA;j6tqz+rdS8k03TUYCW5lA+yvXii1HN6UUeJIBVfAPn7z95j88+Y59e16f1biX4YYVqIoIgSViiUk&#xA;8VWvzJ3NScVY5irsVdirsVZH5B8/eY/I3mODXtBn9K4i+GaFqmKeIkFopVBHJWp8wdxQjFX39+Vn&#xA;5p+XPzG8uJq2kv6V1FxTUtNdgZbaUj7LdOSNQ8HpRh4EEBV4H/zkj/zjd6H1rzr5Ktf3PxTazo0K&#xA;/Y7vcW6D9nu6Dp1G1QFXy1irsVdir9VMVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir&#xA;sVYZ+af5p+XPy58uPq2rP6t1LyTTdNRgJbmUD7K9eKLUc3pRR4kgFV8A+fvP3mPzz5jn17Xp/VuJ&#xA;fhhhWoigiBJWKJSTxVa/Mnc1JxVjmKuxV2KuxV2KuxVkfkHz95j8jeY4Ne0Gf0riL4ZoWqYp4iQW&#xA;ilUEclanzB3FCMVff35Wfmn5c/Mby4mraS/pXUXFNS012BltpSPst05I1DwelGHgQQFXgf8Azkj/&#xA;AM43eh9a86+SrX9z8U2s6NCv2O73Fug/Z7ug6dRtUBV8tYq7FX6qYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FWGfmn+aflz8ufLj6tqz+rdS8k03TUYCW5lA+yvXii1HN6UUeJIBVfAPn&#xA;7z95j88+Y59e16f1biX4YYVqIoIgSViiUk8VWvzJ3NScVY5irsVdirYBJoNycVV7/T7/AE68lstQ&#xA;tpbS8hIE1tOjRyISKjkjAEbGuKofFXYq7FWR+QfP3mPyN5jg17QZ/SuIvhmhapiniJBaKVQRyVqf&#xA;MHcUIxV9/flZ+aflz8xvLiatpL+ldRcU1LTXYGW2lI+y3TkjUPB6UYeBBAVeB/8AOSP/ADjd6H1r&#xA;zr5Ktf3PxTazo0K/Y7vcW6D9nu6Dp1G1QFXy1ir9VMVdirsVdirsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVYZ+af5p+XPy58uPq2rP6t1LyTTdNRgJbmUD7K9eKLUc3pRR4kgFV8A+fvP3mPzz5jn17X&#xA;p/VuJfhhhWoigiBJWKJSTxVa/Mnc1JxVjmKuxV2KtgEmg3JxV9c/843f843DTRa+dPOlrXUTxm0f&#xA;R5l/3n7rPOp/3b3RD9jqfi+yqz/8+fyG0v8AMbSzf2Ajs/NtnHSzvDsk6DcQTkdv5W6qfaoxV8Ja&#xA;xo+qaNqlzpWq20lnqNnIYrm2lFHRx2P6wRsRuMVQeKuxV2Ksj8g+fvMfkbzHBr2gz+lcRfDNC1TF&#xA;PESC0UqgjkrU+YO4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMttKR9lunJGoeD0ow8CCAq8D/5&#xA;yR/5xu9D61518lWv7n4ptZ0aFfsd3uLdB+z3dB06jaoCr6vxV2KuxV2KuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV2KsM/NP80/Ln5c+XH1bVn9W6l5JpumowEtzKB9levFFqOb0oo8SQCq+AfP3n7zH558xz&#xA;69r0/q3EvwwwrURQRAkrFEpJ4qtfmTuak4qxzFXYq7FWwCTQbk4q+uf+cbv+cbhpotfOnnS1rqJ4&#xA;zaPo8y/7z91nnU/7t7oh+x1PxfZVfTWKuxV5J+fP5DaX+Y2lm/sBHZ+bbOOlneHZJ0G4gnI7fyt1&#xA;U+1Rir4S1jR9U0bVLnStVtpLPUbOQxXNtKKOjjsf1gjYjcYqg8VdirsVZH5B8/eY/I3mODXtBn9K&#xA;4i+GaFqmKeIkFopVBHJWp8wdxQjFX39+Vn5p+XPzG8uJq2kv6V1FxTUtNdgZbaUj7LdOSNQ8HpRh&#xA;4EEBVmYAAoNgOgxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVhn5p/mn5c/Lny4+ras/q3UvJN&#xA;N01GAluZQPsr14otRzelFHiSAVXwD5+8/eY/PPmOfXten9W4l+GGFaiKCIElYolJPFVr8ydzUnFW&#xA;OYq7FXYq2ASaDcnFX1z/AM43f843DTRa+dPOlrXUTxm0fR5l/wB5+6zzqf8AdvdEP2Op+L7Kr6ax&#xA;V2KuxV2KvJPz5/IbS/zG0s39gI7PzbZx0s7w7JOg3EE5Hb+Vuqn2qMVfCWsaPqmjapc6VqttJZ6j&#xA;ZyGK5tpRR0cdj+sEbEbjFUHirsVdirI/IPn7zH5G8xwa9oM/pXEXwzQtUxTxEgtFKoI5K1PmDuKE&#xA;Yq+/vys/NPy5+Y3lxNW0l/SuouKalprsDLbSkfZbpyRqHg9KMPAggKszxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxVhn5p/mn5c/Lny4+ras/q3UvJNN01GAluZQPsr14otRzelFHiSAVXwD5+8/eY/PPm&#xA;OfXten9W4l+GGFaiKCIElYolJPFVr8ydzUnFWOYq7FXYq2ASaDcnFX1z/wA43f8AONw00WvnTzpa&#xA;11E8ZtH0eZf95+6zzqf9290Q/Y6n4vsqvprFXYq7FXYq7FXYq8k/Pn8htL/MbSzf2Ajs/NtnHSzv&#xA;Dsk6DcQTkdv5W6qfaoxV8Jaxo+qaNqlzpWq20lnqNnIYrm2lFHRx2P6wRsRuMVQeKuxV2Ksj8g+f&#xA;vMfkbzHBr2gz+lcRfDNC1TFPESC0UqgjkrU+YO4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMtt&#xA;KR9lunJGoeD0ow8CCAqzPFXYq7FXYq7FXYq7FXYq7FXYq7FWGfmn+aflz8ufLj6tqz+rdS8k03TU&#xA;YCW5lA+yvXii1HN6UUeJIBVfAPn7z95j88+Y59e16f1biX4YYVqIoIgSViiUk8VWvzJ3NScVY5ir&#xA;sVdirYBJoNycVfXP/ON3/ONw00WvnTzpa11E8ZtH0eZf95+6zzqf9290Q/Y6n4vsqvprFXYq7FXY&#xA;q7FXYq7FXYq8k/Pn8htL/MbSzf2Ajs/NtnHSzvDsk6DcQTkdv5W6qfaoxV8Jaxo+qaNqlzpWq20l&#xA;nqNnIYrm2lFHRx2P6wRsRuMVQeKuxV2Ksj8g+fvMfkbzHBr2gz+lcRfDNC1TFPESC0UqgjkrU+YO&#xA;4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMttKR9lunJGoeD0ow8CCAqzPFXYq7FXYq7FXYq7FX&#xA;Yq7FWGfmn+aflz8ufLj6tqz+rdS8k03TUYCW5lA+yvXii1HN6UUeJIBVfAPn7z95j88+Y59e16f1&#xA;biX4YYVqIoIgSViiUk8VWvzJ3NScVY5irsVdirYBJoNycVfXP/ON3/ONw00WvnTzpa11E8ZtH0eZ&#xA;f95+6zzqf9290Q/Y6n4vsqvprFXYq7FXYq7FXYq7FXYq7FXYq8k/Pn8htL/MbSzf2Ajs/NtnHSzv&#xA;Dsk6DcQTkdv5W6qfaoxV8Jaxo+qaNqlzpWq20lnqNnIYrm2lFHRx2P6wRsRuMVQeKuxV2Ksj8g+f&#xA;vMfkbzHBr2gz+lcRfDNC1TFPESC0UqgjkrU+YO4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMtt&#xA;KR9lunJGoeD0ow8CCAqzPFXYq7FXYq7FXYq7FWGfmn+aflz8ufLj6tqz+rdS8k03TUYCW5lA+yvX&#xA;ii1HN6UUeJIBVfAPn7z95j88+Y59e16f1biX4YYVqIoIgSViiUk8VWvzJ3NScVY5irsVdirYBJoN&#xA;ycVfXP8Azjd/zjcNNFr5086WtdRPGbR9HmX/AHn7rPOp/wB290Q/Y6n4vsqvprFXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq8k/Pn8htL/MbSzf2Ajs/NtnHSzvDsk6DcQTkdv5W6qfaoxV8Jaxo+qaNqlzpW&#xA;q20lnqNnIYrm2lFHRx2P6wRsRuMVQeKuxV2Ksj8g+fvMfkbzHBr2gz+lcRfDNC1TFPESC0Uqgjkr&#xA;U+YO4oRir7+/Kz80/Ln5jeXE1bSX9K6i4pqWmuwMttKR9lunJGoeD0ow8CCAqzPFXYq7FXYq7FWG&#xA;fmn+aflz8ufLj6tqz+rdS8k03TUYCW5lA+yvXii1HN6UUeJIBVfAPn7z95j88+Y59e16f1biX4YY&#xA;VqIoIgSViiUk8VWvzJ3NScVY5irsVdirYBJoNycVfXP/ADjd/wA43DTRa+dPOlrXUTxm0fR5l/3n&#xA;7rPOp/3b3RD9jqfi+yq+lzPAJ1gMiid1Z0iJHMohAZgvWgLqCfcYqvxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KpNF5v0GTzXceVPrITXbe1jvjaPsXt5GZOcZ/a4stG8NvHFXnv58/kNpf5jaWb+wEdn5ts&#xA;46Wd4dknQbiCcjt/K3VT7VGKvhLWNH1TRtUudK1W2ks9Rs5DFc20oo6OOx/WCNiNxiqDxV2KuxVk&#xA;fkHz95j8jeY4Ne0Gf0riL4ZoWqYp4iQWilUEclanzB3FCMVff35Wfmn5c/Mby4mraS/pXUXFNS01&#xA;2BltpSPst05I1DwelGHgQQFWZ4q7FXYqwz80/wA0/Ln5c+XH1bVn9W6l5JpumowEtzKB9levFFqO&#xA;b0oo8SQCq+AfP3n7zH558xz69r0/q3EvwwwrURQRAkrFEpJ4qtfmTuak4qxzFXYq7FWwCTQbk4q+&#xA;uf8AnG7/AJxuGmi186edLWuonjNo+jzL/vP3WedT/u3uiH7HU/F9lV7x5/8APnl/yN5ZufMGtzcL&#xA;aH4YYV3knmYEpDEO7NT6BUnYHFXzz/zjl+ZXmPz9+e2vazrEpCSaJOLSxViYbeJLy24Rxg+AY1P7&#xA;RqcVfVGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV8X/85V69q+gfnpp+saRdPZ6jZabay29xGaFWEk23&#xA;uCNmB2I2OKvof8kfzo0j8yvL/qfu7TzFZKBqumA9D0E0VdzE5/4E/CexKqW/nz+Q2l/mNpZv7AR2&#xA;fm2zjpZ3h2SdBuIJyO38rdVPtUYq+EtY0fVNG1S50rVbaSz1GzkMVzbSijo47H9YI2I3GKoPFXYq&#xA;7FWR+QfP3mPyN5jg17QZ/SuIvhmhapiniJBaKVQRyVqfMHcUIxV9/flZ+aflz8xvLiatpL+ldRcU&#xA;1LTXYGW2lI+y3TkjUPB6UYeBBAVZnirsVeT/AJ+fkZY/mTpCXdm62vmnToyun3LEiOVKlvq83+SW&#xA;JKt+yfaoxV8H6xo+qaNqlzpWq20lnqNnIYrm2lFHRx2P6wRsRuMVQeKuxVsAk0G5OKvrn/nG7/nG&#xA;4aaLXzp50ta6ieM2j6PMv+8/dZ51P+7e6IfsdT8X2VX0N5n8zaL5Y0K813WrlbXTbJDJNKdz4Kqr&#xA;1ZmOyqOpxV+fv5x/m5rX5k+Zm1C65W+k2vKPSdNr8MMRP2mANDK+3Nvo6AYq9C/5wq/8mnqv/bDu&#xA;P+oy0xV9qYq7FXwB/wA5R/8Ak9vM3/Rj/wB0+3xV5VirsVdir7//AOcXP/JE+Wf+j7/uoXGKvVcV&#xA;dirsVdirsVfEH/OZP/k3If8AtlW3/J2bFXkvk7zjr/k/zDa69oVyba/tWr4pIh+3FKv7SONiP44q&#xA;/QT8pvzU0H8x/LEeracRBexUj1TTGYNJbTeB6ckelUem48CCAqxn8+fyG0v8xtLN/YCOz822cdLO&#xA;8OyToNxBOR2/lbqp9qjFXwlrGj6po2qXOlarbSWeo2chiubaUUdHHY/rBGxG4xVB4q7FU+8keSPM&#xA;XnTzFbaDoNsZ72c1dzURwxgjlLK1DxRa7n6BUkDFX37+Uv5S+Xfy38urp2nKJ9RnCvqmqOoElxIB&#xA;9PGNangldvckkqs5xV2KuxV5J+fP5DaX+Y2lm/sBHZ+bbOOlneHZJ0G4gnI7fyt1U+1Rir4S1jR9&#xA;U0bVLnStVtpLPUbOQxXNtKKOjjsf1gjYjcYqhACTQbk4q+uf+cbv+cbhpotfOnnS1rqJ4zaPo8y/&#xA;7z91nnU/7t7oh+x1PxfZVfSOp6np+l6fcajqNxHaWNpG0tzcysFREUVLMTir4K/Pv877/wDMjXRB&#xA;aF7byrp7n9G2bbNI1KG4mA/bb9kfsrt1LEqvKcVfQH/OFX/k09V/7Ydx/wBRlpir7UxV2KvgD/nK&#xA;P/ye3mb/AKMf+6fb4q8qxV2KuxV9/wD/ADi5/wCSJ8s/9H3/AHULjFXquKuxV2KuxV2KviD/AJzJ&#xA;/wDJuQ/9sq2/5OzYq8KxVlP5b/mL5g8g+Z7fXdGkNUIS8tGNIrmAkF4pOvWmxpVTuMVfoN+Xv5ge&#xA;X/Pflm21/RJeUMo43FsxHq28wHxwygdGX8RQjY4qwn8+fyG0v8xtLN/YCOz822cdLO8OyToNxBOR&#xA;2/lbqp9qjFXwlrGj6po2qXOlarbSWeo2chiubaUUdHHY/rBGxG4xVMvJHkjzF508xW2g6DbGe9nN&#xA;Xc1EcMYI5SytQ8UWu5+gVJAxV9+/lL+Uvl38t/Lq6dpyifUZwr6pqjqBJcSAfTxjWp4JXb3JJKrO&#xA;cVdirsVdirsVeSfnz+Q2l/mNpZv7AR2fm2zjpZ3h2SdBuIJyO38rdVPtUYqwT/nHf/nGaTRLiLzZ&#xA;55tV/S0L8tL0dyrrbsp2nm4llaTaqL0X7X2qcVX0tir4d/5yO/PybzxqL+XfL8zR+UrKT45AafXp&#xA;kO0rCgPpKf7tT1+0d6BVXhuKuxV9Af8AOFX/AJNPVf8Ath3H/UZaYq+1MVdir4A/5yj/APJ7eZv+&#xA;jH/un2+KvKsVdirsVff/APzi5/5Inyz/ANH3/dQuMVeq4q7FXYq7FXYq+IP+cyf/ACbkP/bKtv8A&#xA;k7NirwrFXYqzr8ofzY1z8t/MyanYkz6dcFY9W00miXEIPav2ZEqSjdvkSCq/RrFXk356/kHpP5k2&#xA;C3tk0Wn+a7VQtrqDgiOWMf7puOIZiv8AKwBK+42xVkH5S/lL5d/Lfy6unacon1GcK+qao6gSXEgH&#xA;08Y1qeCV29ySSqznFXYq7FXYq7FXYq7FXYq7FX5V4q7FXYq+gP8AnCr/AMmnqv8A2w7j/qMtMVfa&#xA;mKuxV8Af85R/+T28zf8ARj/3T7fFXlWKuxV2Kvv/AP5xc/8AJE+Wf+j7/uoXGKvVcVdirsVdirsV&#xA;fEn/ADmdA0f5sWbkgibR7d1p2AnuE3+lMVeDYq7FXYq/VTFXYq7FXYq7FXYq7FXYq7FXYq7FXYq/&#xA;KvFXYq7FX0B/zhV/5NPVf+2Hcf8AUZaYq+1MVdir4A/5yj/8nt5m/wCjH/un2+KvKsVdirsVff8A&#xA;/wA4uf8AkifLP/R9/wB1C4xV6rirsVdirsVdir4r/wCc1f8Ayaelf9sO3/6jLvFXz/irsVdir9VM&#xA;VdirsVdirsVdirsVdirsVdirsVdir8q8VdirsVfQH/OFX/k09V/7Ydx/1GWmKvtTFXYq+AP+co//&#xA;ACe3mb/ox/7p9viryrFXYq7FX3//AM4uf+SJ8s/9H3/dQuMVeq4q7FXYq7FXYq+K/wDnNX/yaelf&#xA;9sO3/wCoy7xV8/4q7FXYq/VTFXYq7FXYq7FXYq7FXYq7FXYq7FXYq/KvFXYq7FX0B/zhV/5NPVf+&#xA;2Hcf9Rlpir7UxV2KvgD/AJyj/wDJ7eZv+jH/ALp9viryrFXYq7FX3/8A84uf+SJ8s/8AR9/3ULjF&#xA;XquKuxV2KuxV2Kviv/nNX/yaelf9sO3/AOoy7xV8/wCKuxV2Kv1UxV2KuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KvyrxV2KuxV9Af8AOFX/AJNPVf8Ath3H/UZaYq+1MVdir4A/5yj/APJ7eZv+jH/un2+KvKsV&#xA;dirsVff/APzi5/5Inyz/ANH3/dQuMVeq4q7FXYq7FXYq+K/+c1f/ACaelf8AbDt/+oy7xV8/4q7F&#xA;XYq/VTFXYq7FXYq7FXYq7FXYq7FXYq7FXYq/KvFXYq7FXoH5Kfmv/wAqy81XWvfov9L/AFmxksfq&#xA;3r/VuPqTRS8+fpzVp6NKce/XFXtX/Q8//fk/9zT/ALM8Vd/0PP8A9+T/ANzT/szxV3/Q8/8A35P/&#xA;AHNP+zPFXf8AQ8//AH5P/c0/7M8Vd/0PP/35P/c0/wCzPFXf9Dz/APfk/wDc0/7M8Vd/0PP/AN+T&#xA;/wBzT/szxV3/AEPP/wB+T/3NP+zPFXf9Dz/9+T/3NP8AszxV3/Q8/wD35P8A3NP+zPFXf9Dz/wDf&#xA;k/8Ac0/7M8Vd/wBDz/8Afk/9zT/szxV4r+df5r/8rN81Wuvfov8ARH1axjsfq3r/AFnl6c0svPn6&#xA;cNK+tSnHt1xV5/irsVdir9VMVdirsVdirsVdirsVdirsVdirsVdir8q8VdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdir9VMVdirsVdirsVdirsVdirsVdirsVdir8q8VdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdir9VMVdirsVdirsVdirsVdirsVdirsVdir8q8Vdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir9VMVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd&#xA;ir//2Q==</xapGImg:image>
- </rdf:li>
- </rdf:Alt>
- </xap:Thumbnails>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/">
- <xapMM:DocumentID>uuid:FF364C322635E01192F88CC5416A78CF</xapMM:DocumentID>
- <xapMM:InstanceID>uuid:be6b4bae-323e-c246-9a75-1280d64495f2</xapMM:InstanceID>
- <xapMM:DerivedFrom rdf:parseType="Resource"/>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:xapTPg="http://ns.adobe.com/xap/1.0/t/pg/"
- xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
- xmlns:xapG="http://ns.adobe.com/xap/1.0/g/">
- <xapTPg:NPages>1</xapTPg:NPages>
- <xapTPg:HasVisibleTransparency>False</xapTPg:HasVisibleTransparency>
- <xapTPg:HasVisibleOverprint>False</xapTPg:HasVisibleOverprint>
- <xapTPg:MaxPageSize rdf:parseType="Resource">
- <stDim:w>16.000000</stDim:w>
- <stDim:h>16.000000</stDim:h>
- <stDim:unit>Points</stDim:unit>
- </xapTPg:MaxPageSize>
- <xapTPg:PlateNames>
- <rdf:Seq>
- <rdf:li>Cyan</rdf:li>
- <rdf:li>Magenta</rdf:li>
- <rdf:li>Yellow</rdf:li>
- <rdf:li>Black</rdf:li>
- </rdf:Seq>
- </xapTPg:PlateNames>
- <xapTPg:SwatchGroups>
- <rdf:Seq>
- <rdf:li rdf:parseType="Resource">
- <xapG:groupName>Default Swatch Group</xapG:groupName>
- <xapG:groupType>0</xapG:groupType>
- </rdf:li>
- </rdf:Seq>
- </xapTPg:SwatchGroups>
- </rdf:Description>
- <rdf:Description rdf:about=""
- xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
- <pdf:Producer>Adobe PDF library 8.00</pdf:Producer>
- </rdf:Description>
- </rdf:RDF>
-</x:xmpmeta>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<?xpacket end="w"?> endstream endobj 2 0 obj <</Count 1/Type/Pages/Kids[5 0 R]>> endobj 5 0 obj <</Parent 2 0 R/Contents 7 0 R/BleedBox[0.0 0.0 16.0 16.0]/ArtBox[0.0 0.0 15.7812 15.7812]/MediaBox[0.0 0.0 16.0 16.0]/TrimBox[0.0 0.0 16.0 16.0]/Resources<</Properties<</MC0<</Color[20224 32768 65535]/Visible true/Editable true/Dimmed false/Preview true/Printed true/Title(Layer 1)>>>>/ExtGState<</GS0 6 0 R>>>>/Type/Page>> endobj 7 0 obj <</Length 218/Filter/FlateDecode>>stream
-H‰d‘;R1 †{ŸB°V²lÉnI24¤`8Ã@(’"¡âöH»!³q!}–~ëáééõûýÓ~Cð°Ý@"ˆs9¤éñ…àð•ÎÀóƒ¡u6à†TeÀÛiN>¥l(dp5Ç”ŽêÜQ5˜š@.Wôhm&Ž†EgqÑîø‘žW%™p˜*6îº*©(½º{œÝ1 bçØ‘Gƒò3£Igìt‡ÅûåHöNYý©?ÿ7ñ
-0000000016 00000 n
-0000016570 00000 n
-0000000004 00001 f
-0000000000 00000 f
-0000016621 00000 n
-0000017247 00000 n
-0000016961 00000 n
-0000017359 00000 n
-0000000076 00000 n
-trailer <</Size 10/Root 1 0 R/Info 8 0 R/ID[<ADA186DB0F3649B8AC5BA40BFA30D11D><8A6AD6F969574B3A87EA4AAF57E7FEB8>]>> startxref 17534 %%EOF \ No newline at end of file
diff --git a/frontends/cocoa/res/Icons b/frontends/cocoa/res/Icons
deleted file mode 120000
index 187efd6f9..000000000
--- a/frontends/cocoa/res/Icons
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/Icons/ \ No newline at end of file
diff --git a/frontends/cocoa/res/LocalHistoryPanel.xib b/frontends/cocoa/res/LocalHistoryPanel.xib
deleted file mode 100644
index 794d2db54..000000000
--- a/frontends/cocoa/res/LocalHistoryPanel.xib
+++ /dev/null
@@ -1,357 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="2"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">LocalHistoryController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 240}, {480, 270}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">Window</string>
- <string key="NSWindowClass">ArrowWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSScrollView" id="488267087">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSClipView" id="753770525">
- <reference key="NSNextResponder" ref="488267087"/>
- <int key="NSvFlags">2304</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomView" id="820702167">
- <reference key="NSNextResponder" ref="753770525"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrameSize">{480, 270}</string>
- <reference key="NSSuperview" ref="753770525"/>
- <string key="NSClassName">HistoryView</string>
- </object>
- </object>
- <string key="NSFrame">{{1, 1}, {480, 270}}</string>
- <reference key="NSSuperview" ref="488267087"/>
- <reference key="NSNextKeyView" ref="820702167"/>
- <reference key="NSDocView" ref="820702167"/>
- <object class="NSColor" key="NSBGColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
- </object>
- </object>
- <int key="NScvFlags">2</int>
- </object>
- <object class="NSScroller" id="84195230">
- <reference key="NSNextResponder" ref="488267087"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{470, 1}, {11, 255}}</string>
- <reference key="NSSuperview" ref="488267087"/>
- <int key="NSsFlags">256</int>
- <int key="NSArrowsLoc">2</int>
- <reference key="NSTarget" ref="488267087"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSCurValue">1</double>
- <double key="NSPercent">0.96363627910614014</double>
- </object>
- <object class="NSScroller" id="645365106">
- <reference key="NSNextResponder" ref="488267087"/>
- <int key="NSvFlags">-2147483392</int>
- <string key="NSFrame">{{1, 260}, {465, 11}}</string>
- <reference key="NSSuperview" ref="488267087"/>
- <int key="NSsFlags">257</int>
- <int key="NSArrowsLoc">2</int>
- <reference key="NSTarget" ref="488267087"/>
- <string key="NSAction">_doScroller:</string>
- <double key="NSPercent">0.50602412223815918</double>
- </object>
- </object>
- <string key="NSFrame">{{-1, -1}, {482, 272}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSNextKeyView" ref="753770525"/>
- <int key="NSsFlags">562</int>
- <reference key="NSVScroller" ref="84195230"/>
- <reference key="NSHScroller" ref="645365106"/>
- <reference key="NSContentView" ref="753770525"/>
- </object>
- </object>
- <string key="NSFrameSize">{480, 270}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">7</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">history</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="820702167"/>
- </object>
- <int key="connectionID">8</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <reference key="object" ref="0"/>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="488267087"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">3</int>
- <reference key="object" ref="488267087"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="84195230"/>
- <reference ref="645365106"/>
- <reference ref="820702167"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="84195230"/>
- <reference key="parent" ref="488267087"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="645365106"/>
- <reference key="parent" ref="488267087"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">6</int>
- <reference key="object" ref="820702167"/>
- <reference key="parent" ref="488267087"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>2.IBPluginDependency</string>
- <string>3.IBPluginDependency</string>
- <string>3.IBViewBoundsToFrameTransform</string>
- <string>4.CustomClassName</string>
- <string>4.IBPluginDependency</string>
- <string>5.CustomClassName</string>
- <string>5.IBPluginDependency</string>
- <string>6.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{364, 310}, {480, 270}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{364, 310}, {480, 270}}</string>
- <boolean value="NO"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAAC/gAAAw4aAAA</bytes>
- </object>
- <string>BlackScroller</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>BlackScroller</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">8</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">ArrowWindow</string>
- <string key="superclassName">NSWindow</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ArrowWindow.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BlackScroller</string>
- <string key="superclassName">NSScroller</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BlackScroller.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">HistoryView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">HistoryView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">LocalHistoryController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">history</string>
- <string key="NS.object.0">HistoryView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">history</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">history</string>
- <string key="candidateClassName">HistoryView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">LocalHistoryController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/MainMenu.xib b/frontends/cocoa/res/MainMenu.xib
deleted file mode 100644
index d38240bfd..000000000
--- a/frontends/cocoa/res/MainMenu.xib
+++ /dev/null
@@ -1,2369 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">10J567</string>
- <string key="IBDocument.InterfaceBuilderVersion">804</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
- <string key="IBDocument.HIToolboxVersion">462.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string key="NS.object.0">804</string>
- </object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="29"/>
- <integer value="853"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
- <integer value="1" key="NS.object.0"/>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1021">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSCustomObject" id="1014">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1050">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSMenu" id="649796088">
- <string key="NSTitle">Main Menu</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="694149608">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">NetSurf</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <object class="NSCustomResource" key="NSOnImage" id="756751024">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSMenuCheckmark</string>
- </object>
- <object class="NSCustomResource" key="NSMixedImage" id="908425081">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSMenuMixedState</string>
- </object>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="110575045">
- <string key="NSTitle">NetSurf</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="238522557">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">About NetSurf</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="304266470">
- <reference key="NSMenu" ref="110575045"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="609285721">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Preferences…</string>
- <string key="NSKeyEquiv">,</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="481834944">
- <reference key="NSMenu" ref="110575045"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="1046388886">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Services</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="752062318">
- <string key="NSTitle">Services</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <string key="NSName">_NSServicesMenu</string>
- </object>
- </object>
- <object class="NSMenuItem" id="646227648">
- <reference key="NSMenu" ref="110575045"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="755159360">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Hide NetSurf</string>
- <string key="NSKeyEquiv">h</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="342932134">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Hide Others</string>
- <string key="NSKeyEquiv">h</string>
- <int key="NSKeyEquivModMask">1572864</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="908899353">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Show All</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="1056857174">
- <reference key="NSMenu" ref="110575045"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="632727374">
- <reference key="NSMenu" ref="110575045"/>
- <string key="NSTitle">Quit NetSurf</string>
- <string key="NSKeyEquiv">q</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- <string key="NSName">_NSAppleMenu</string>
- </object>
- </object>
- <object class="NSMenuItem" id="379814623">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">File</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="720053764">
- <string key="NSTitle">File</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="705341025">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">New Window</string>
- <string key="NSKeyEquiv">n</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="72022292">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">New Tab</string>
- <string key="NSKeyEquiv">t</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="722745758">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">Open File…</string>
- <string key="NSKeyEquiv">o</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="425164168">
- <reference key="NSMenu" ref="720053764"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="776162233">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">Close</string>
- <string key="NSKeyEquiv">w</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="117038363">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">Save As…</string>
- <string key="NSKeyEquiv">s</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="1010469920">
- <reference key="NSMenu" ref="720053764"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="294629803">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">Page Setup...</string>
- <string key="NSKeyEquiv">P</string>
- <int key="NSKeyEquivModMask">1179648</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSToolTip"/>
- </object>
- <object class="NSMenuItem" id="49223823">
- <reference key="NSMenu" ref="720053764"/>
- <string key="NSTitle">Print…</string>
- <string key="NSKeyEquiv">p</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- </object>
- </object>
- <object class="NSMenuItem" id="584895621">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">Edit</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="141080932">
- <string key="NSTitle">Edit</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="80034836">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Undo</string>
- <string key="NSKeyEquiv">z</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="128588396">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Redo</string>
- <string key="NSKeyEquiv">Z</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="165057028">
- <reference key="NSMenu" ref="141080932"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="5858980">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Cut</string>
- <string key="NSKeyEquiv">x</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="704355768">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Copy</string>
- <string key="NSKeyEquiv">c</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="275307167">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Paste</string>
- <string key="NSKeyEquiv">v</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="714155551">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Delete</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="197377228">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Select All</string>
- <string key="NSKeyEquiv">a</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="246962120">
- <reference key="NSMenu" ref="141080932"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="602982148">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Find</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="930654435">
- <string key="NSTitle">Find</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="671868626">
- <reference key="NSMenu" ref="930654435"/>
- <string key="NSTitle">Find…</string>
- <string key="NSKeyEquiv">f</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <int key="NSTag">1</int>
- </object>
- <object class="NSMenuItem" id="497741775">
- <reference key="NSMenu" ref="930654435"/>
- <string key="NSTitle">Find Next</string>
- <string key="NSKeyEquiv">g</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <int key="NSTag">2</int>
- </object>
- <object class="NSMenuItem" id="285322108">
- <reference key="NSMenu" ref="930654435"/>
- <string key="NSTitle">Find Previous</string>
- <string key="NSKeyEquiv">G</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <int key="NSTag">3</int>
- </object>
- <object class="NSMenuItem" id="456308224">
- <reference key="NSMenu" ref="930654435"/>
- <string key="NSTitle">Use Selection for Find</string>
- <string key="NSKeyEquiv">e</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <int key="NSTag">7</int>
- </object>
- </object>
- </object>
- </object>
- <object class="NSMenuItem" id="1046338161">
- <reference key="NSMenu" ref="141080932"/>
- <string key="NSTitle">Speech</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="390929284">
- <string key="NSTitle">Speech</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="787796378">
- <reference key="NSMenu" ref="390929284"/>
- <string key="NSTitle">Start Speaking</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="831785675">
- <reference key="NSMenu" ref="390929284"/>
- <string key="NSTitle">Stop Speaking</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- </object>
- </object>
- </object>
- </object>
- </object>
- <object class="NSMenuItem" id="586577488">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">View</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="466310130">
- <string key="NSTitle">View</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="102151532">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Show Toolbar</string>
- <string key="NSKeyEquiv">t</string>
- <int key="NSKeyEquivModMask">1572864</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="237841660">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Customize Toolbar…</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="588542073">
- <reference key="NSMenu" ref="466310130"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="1008284068">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Stop Loading</string>
- <string key="NSKeyEquiv">.</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="997106205">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Reload Page</string>
- <string key="NSKeyEquiv">r</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="403460345">
- <reference key="NSMenu" ref="466310130"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="924072330">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Original Size</string>
- <string key="NSKeyEquiv">0</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="157577355">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Zoom In</string>
- <string key="NSKeyEquiv">+</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="148271458">
- <reference key="NSMenu" ref="466310130"/>
- <string key="NSTitle">Zoom Out</string>
- <string key="NSKeyEquiv">-</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- </object>
- </object>
- <object class="NSMenuItem" id="603467951">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">Bookmarks</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="1062528031">
- <string key="NSTitle">Bookmarks</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- </object>
- <object class="NSMenuItem" id="713487014">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">Window</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="835318025">
- <string key="NSTitle">Window</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="1011231497">
- <reference key="NSMenu" ref="835318025"/>
- <string key="NSTitle">Minimize</string>
- <string key="NSKeyEquiv">m</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="575023229">
- <reference key="NSMenu" ref="835318025"/>
- <string key="NSTitle">Zoom</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="971013910">
- <reference key="NSMenu" ref="835318025"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="532573582">
- <reference key="NSMenu" ref="835318025"/>
- <string key="NSTitle">History</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="299356726">
- <reference key="NSMenu" ref="835318025"/>
- <bool key="NSIsDisabled">YES</bool>
- <bool key="NSIsSeparator">YES</bool>
- <string key="NSTitle"/>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="625202149">
- <reference key="NSMenu" ref="835318025"/>
- <string key="NSTitle">Bring All to Front</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- <string key="NSName">_NSWindowsMenu</string>
- </object>
- </object>
- <object class="NSMenuItem" id="391199113">
- <reference key="NSMenu" ref="649796088"/>
- <string key="NSTitle">Help</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- <string key="NSAction">submenuAction:</string>
- <object class="NSMenu" key="NSSubmenu" id="374024848">
- <string key="NSTitle">Help</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="238773614">
- <reference key="NSMenu" ref="374024848"/>
- <string key="NSTitle">NetSurf Help</string>
- <string key="NSKeyEquiv">?</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- <string key="NSName">_NSHelpMenu</string>
- </object>
- </object>
- </object>
- <string key="NSName">_NSMainMenu</string>
- </object>
- <object class="NSCustomObject" id="1026802243">
- <string key="NSClassName">NetSurfAppDelegate</string>
- </object>
- <object class="NSCustomObject" id="867741866">
- <string key="NSClassName">BookmarksController</string>
- </object>
- <object class="NSMenu" id="509997857">
- <string key="NSTitle">Default Bookmark Actions</string>
- <object class="NSMutableArray" key="NSMenuItems">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMenuItem" id="844807595">
- <reference key="NSMenu" ref="509997857"/>
- <string key="NSTitle">Add bookmark</string>
- <string key="NSKeyEquiv">d</string>
- <int key="NSKeyEquivModMask">1048576</int>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- <object class="NSMenuItem" id="832858329">
- <reference key="NSMenu" ref="509997857"/>
- <string key="NSTitle">Show bookmarks...</string>
- <string key="NSKeyEquiv"/>
- <int key="NSMnemonicLoc">2147483647</int>
- <reference key="NSOnImage" ref="756751024"/>
- <reference key="NSMixedImage" ref="908425081"/>
- </object>
- </object>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">performMiniaturize:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="1011231497"/>
- </object>
- <int key="connectionID">37</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">arrangeInFront:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="625202149"/>
- </object>
- <int key="connectionID">39</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">print:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="49223823"/>
- </object>
- <int key="connectionID">86</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">runPageLayout:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="294629803"/>
- </object>
- <int key="connectionID">87</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">orderFrontStandardAboutPanel:</string>
- <reference key="source" ref="1021"/>
- <reference key="destination" ref="238522557"/>
- </object>
- <int key="connectionID">142</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">performZoom:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="575023229"/>
- </object>
- <int key="connectionID">240</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">showHelp:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="238773614"/>
- </object>
- <int key="connectionID">360</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">saveDocumentAs:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="117038363"/>
- </object>
- <int key="connectionID">363</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">runToolbarCustomizationPalette:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="237841660"/>
- </object>
- <int key="connectionID">365</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">toggleToolbarShown:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="102151532"/>
- </object>
- <int key="connectionID">366</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">hide:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="755159360"/>
- </object>
- <int key="connectionID">369</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">hideOtherApplications:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="342932134"/>
- </object>
- <int key="connectionID">370</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">unhideAllApplications:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="908899353"/>
- </object>
- <int key="connectionID">372</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">terminate:</string>
- <reference key="source" ref="1021"/>
- <reference key="destination" ref="632727374"/>
- </object>
- <int key="connectionID">448</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">cut:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="5858980"/>
- </object>
- <int key="connectionID">741</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">paste:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="275307167"/>
- </object>
- <int key="connectionID">742</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">redo:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="128588396"/>
- </object>
- <int key="connectionID">745</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">undo:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="80034836"/>
- </object>
- <int key="connectionID">749</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">startSpeaking:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="787796378"/>
- </object>
- <int key="connectionID">751</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">copy:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="704355768"/>
- </object>
- <int key="connectionID">755</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">delete:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="714155551"/>
- </object>
- <int key="connectionID">756</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">selectAll:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="197377228"/>
- </object>
- <int key="connectionID">758</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">stopSpeaking:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="831785675"/>
- </object>
- <int key="connectionID">759</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="1050"/>
- <reference key="destination" ref="1026802243"/>
- </object>
- <int key="connectionID">821</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">newDocument:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="705341025"/>
- </object>
- <int key="connectionID">823</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">openDocument:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="722745758"/>
- </object>
- <int key="connectionID">824</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">zoomIn:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="157577355"/>
- </object>
- <int key="connectionID">829</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">zoomOut:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="148271458"/>
- </object>
- <int key="connectionID">830</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">stopLoading:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="1008284068"/>
- </object>
- <int key="connectionID">835</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">reloadPage:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="997106205"/>
- </object>
- <int key="connectionID">836</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">zoomOriginal:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="924072330"/>
- </object>
- <int key="connectionID">837</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">newTab:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="72022292"/>
- </object>
- <int key="connectionID">839</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">showSearchWindow:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="671868626"/>
- </object>
- <int key="connectionID">841</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">searchNext:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="497741775"/>
- </object>
- <int key="connectionID">842</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">searchPrevious:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="285322108"/>
- </object>
- <int key="connectionID">843</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">performClose:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="776162233"/>
- </object>
- <int key="connectionID">844</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">showPreferences:</string>
- <reference key="source" ref="1026802243"/>
- <reference key="destination" ref="609285721"/>
- </object>
- <int key="connectionID">845</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">showGlobalHistory:</string>
- <reference key="source" ref="1014"/>
- <reference key="destination" ref="532573582"/>
- </object>
- <int key="connectionID">846</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">delegate</string>
- <reference key="source" ref="1062528031"/>
- <reference key="destination" ref="867741866"/>
- </object>
- <int key="connectionID">851</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">defaultMenu</string>
- <reference key="source" ref="867741866"/>
- <reference key="destination" ref="509997857"/>
- </object>
- <int key="connectionID">856</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">addBookmark:</string>
- <reference key="source" ref="867741866"/>
- <reference key="destination" ref="844807595"/>
- </object>
- <int key="connectionID">857</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">showWindow:</string>
- <reference key="source" ref="867741866"/>
- <reference key="destination" ref="832858329"/>
- </object>
- <int key="connectionID">859</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <object class="NSArray" key="object" id="0">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="children" ref="1048"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1021"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1014"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1050"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">29</int>
- <reference key="object" ref="649796088"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="713487014"/>
- <reference ref="694149608"/>
- <reference ref="391199113"/>
- <reference ref="379814623"/>
- <reference ref="586577488"/>
- <reference ref="584895621"/>
- <reference ref="603467951"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">19</int>
- <reference key="object" ref="713487014"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="835318025"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">56</int>
- <reference key="object" ref="694149608"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="110575045"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">103</int>
- <reference key="object" ref="391199113"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="374024848"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">83</int>
- <reference key="object" ref="379814623"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="720053764"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">81</int>
- <reference key="object" ref="720053764"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="117038363"/>
- <reference ref="49223823"/>
- <reference ref="722745758"/>
- <reference ref="705341025"/>
- <reference ref="294629803"/>
- <reference ref="776162233"/>
- <reference ref="1010469920"/>
- <reference ref="425164168"/>
- <reference ref="72022292"/>
- </object>
- <reference key="parent" ref="379814623"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">80</int>
- <reference key="object" ref="117038363"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">78</int>
- <reference key="object" ref="49223823"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">72</int>
- <reference key="object" ref="722745758"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">82</int>
- <reference key="object" ref="705341025"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">77</int>
- <reference key="object" ref="294629803"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">73</int>
- <reference key="object" ref="776162233"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">74</int>
- <reference key="object" ref="1010469920"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">106</int>
- <reference key="object" ref="374024848"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="238773614"/>
- </object>
- <reference key="parent" ref="391199113"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">111</int>
- <reference key="object" ref="238773614"/>
- <reference key="parent" ref="374024848"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">57</int>
- <reference key="object" ref="110575045"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="238522557"/>
- <reference ref="755159360"/>
- <reference ref="908899353"/>
- <reference ref="632727374"/>
- <reference ref="646227648"/>
- <reference ref="609285721"/>
- <reference ref="481834944"/>
- <reference ref="304266470"/>
- <reference ref="1046388886"/>
- <reference ref="1056857174"/>
- <reference ref="342932134"/>
- </object>
- <reference key="parent" ref="694149608"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">58</int>
- <reference key="object" ref="238522557"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">134</int>
- <reference key="object" ref="755159360"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">150</int>
- <reference key="object" ref="908899353"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">136</int>
- <reference key="object" ref="632727374"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">144</int>
- <reference key="object" ref="646227648"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">129</int>
- <reference key="object" ref="609285721"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">143</int>
- <reference key="object" ref="481834944"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">236</int>
- <reference key="object" ref="304266470"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">131</int>
- <reference key="object" ref="1046388886"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="752062318"/>
- </object>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">149</int>
- <reference key="object" ref="1056857174"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">145</int>
- <reference key="object" ref="342932134"/>
- <reference key="parent" ref="110575045"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">130</int>
- <reference key="object" ref="752062318"/>
- <reference key="parent" ref="1046388886"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">24</int>
- <reference key="object" ref="835318025"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="299356726"/>
- <reference ref="625202149"/>
- <reference ref="575023229"/>
- <reference ref="1011231497"/>
- <reference ref="971013910"/>
- <reference ref="532573582"/>
- </object>
- <reference key="parent" ref="713487014"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">92</int>
- <reference key="object" ref="299356726"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="625202149"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">239</int>
- <reference key="object" ref="575023229"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">23</int>
- <reference key="object" ref="1011231497"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">295</int>
- <reference key="object" ref="586577488"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="466310130"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">296</int>
- <reference key="object" ref="466310130"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="102151532"/>
- <reference ref="237841660"/>
- <reference ref="588542073"/>
- <reference ref="148271458"/>
- <reference ref="924072330"/>
- <reference ref="157577355"/>
- <reference ref="403460345"/>
- <reference ref="1008284068"/>
- <reference ref="997106205"/>
- </object>
- <reference key="parent" ref="586577488"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">297</int>
- <reference key="object" ref="102151532"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">298</int>
- <reference key="object" ref="237841660"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">79</int>
- <reference key="object" ref="425164168"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">684</int>
- <reference key="object" ref="584895621"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="141080932"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">685</int>
- <reference key="object" ref="141080932"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="80034836"/>
- <reference ref="128588396"/>
- <reference ref="165057028"/>
- <reference ref="5858980"/>
- <reference ref="704355768"/>
- <reference ref="275307167"/>
- <reference ref="714155551"/>
- <reference ref="197377228"/>
- <reference ref="246962120"/>
- <reference ref="602982148"/>
- <reference ref="1046338161"/>
- </object>
- <reference key="parent" ref="584895621"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">686</int>
- <reference key="object" ref="80034836"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">687</int>
- <reference key="object" ref="128588396"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">688</int>
- <reference key="object" ref="165057028"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">689</int>
- <reference key="object" ref="5858980"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">690</int>
- <reference key="object" ref="704355768"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">691</int>
- <reference key="object" ref="275307167"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">693</int>
- <reference key="object" ref="714155551"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">694</int>
- <reference key="object" ref="197377228"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">695</int>
- <reference key="object" ref="246962120"/>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">696</int>
- <reference key="object" ref="602982148"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="930654435"/>
- </object>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">700</int>
- <reference key="object" ref="1046338161"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="390929284"/>
- </object>
- <reference key="parent" ref="141080932"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">711</int>
- <reference key="object" ref="390929284"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="787796378"/>
- <reference ref="831785675"/>
- </object>
- <reference key="parent" ref="1046338161"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">712</int>
- <reference key="object" ref="787796378"/>
- <reference key="parent" ref="390929284"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">713</int>
- <reference key="object" ref="831785675"/>
- <reference key="parent" ref="390929284"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">734</int>
- <reference key="object" ref="930654435"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="671868626"/>
- <reference ref="497741775"/>
- <reference ref="285322108"/>
- <reference ref="456308224"/>
- </object>
- <reference key="parent" ref="602982148"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">735</int>
- <reference key="object" ref="671868626"/>
- <reference key="parent" ref="930654435"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">736</int>
- <reference key="object" ref="497741775"/>
- <reference key="parent" ref="930654435"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">737</int>
- <reference key="object" ref="285322108"/>
- <reference key="parent" ref="930654435"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">738</int>
- <reference key="object" ref="456308224"/>
- <reference key="parent" ref="930654435"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">817</int>
- <reference key="object" ref="971013910"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">818</int>
- <reference key="object" ref="532573582"/>
- <reference key="parent" ref="835318025"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">820</int>
- <reference key="object" ref="1026802243"/>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">825</int>
- <reference key="object" ref="588542073"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">826</int>
- <reference key="object" ref="148271458"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">827</int>
- <reference key="object" ref="924072330"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">828</int>
- <reference key="object" ref="157577355"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">832</int>
- <reference key="object" ref="403460345"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">833</int>
- <reference key="object" ref="1008284068"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">834</int>
- <reference key="object" ref="997106205"/>
- <reference key="parent" ref="466310130"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">838</int>
- <reference key="object" ref="72022292"/>
- <reference key="parent" ref="720053764"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">847</int>
- <reference key="object" ref="867741866"/>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">848</int>
- <reference key="object" ref="603467951"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1062528031"/>
- </object>
- <reference key="parent" ref="649796088"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">849</int>
- <reference key="object" ref="1062528031"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="parent" ref="603467951"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">853</int>
- <reference key="object" ref="509997857"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="844807595"/>
- <reference ref="832858329"/>
- </object>
- <reference key="parent" ref="0"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">854</int>
- <reference key="object" ref="844807595"/>
- <reference key="parent" ref="509997857"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">855</int>
- <reference key="object" ref="832858329"/>
- <reference key="parent" ref="509997857"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>-3.IBPluginDependency</string>
- <string>103.IBPluginDependency</string>
- <string>103.ImportedFromIB2</string>
- <string>106.IBEditorWindowLastContentRect</string>
- <string>106.IBPluginDependency</string>
- <string>106.ImportedFromIB2</string>
- <string>106.editorWindowContentRectSynchronizationRect</string>
- <string>111.IBPluginDependency</string>
- <string>111.ImportedFromIB2</string>
- <string>129.IBPluginDependency</string>
- <string>129.ImportedFromIB2</string>
- <string>130.IBEditorWindowLastContentRect</string>
- <string>130.IBPluginDependency</string>
- <string>130.ImportedFromIB2</string>
- <string>130.editorWindowContentRectSynchronizationRect</string>
- <string>131.IBPluginDependency</string>
- <string>131.ImportedFromIB2</string>
- <string>134.IBPluginDependency</string>
- <string>134.ImportedFromIB2</string>
- <string>136.IBPluginDependency</string>
- <string>136.ImportedFromIB2</string>
- <string>143.IBPluginDependency</string>
- <string>143.ImportedFromIB2</string>
- <string>144.IBPluginDependency</string>
- <string>144.ImportedFromIB2</string>
- <string>145.IBPluginDependency</string>
- <string>145.ImportedFromIB2</string>
- <string>149.IBPluginDependency</string>
- <string>149.ImportedFromIB2</string>
- <string>150.IBPluginDependency</string>
- <string>150.ImportedFromIB2</string>
- <string>19.IBPluginDependency</string>
- <string>19.ImportedFromIB2</string>
- <string>23.IBPluginDependency</string>
- <string>23.ImportedFromIB2</string>
- <string>236.IBPluginDependency</string>
- <string>236.ImportedFromIB2</string>
- <string>239.IBPluginDependency</string>
- <string>239.ImportedFromIB2</string>
- <string>24.IBEditorWindowLastContentRect</string>
- <string>24.IBPluginDependency</string>
- <string>24.ImportedFromIB2</string>
- <string>24.editorWindowContentRectSynchronizationRect</string>
- <string>29.IBEditorWindowLastContentRect</string>
- <string>29.IBPluginDependency</string>
- <string>29.ImportedFromIB2</string>
- <string>29.WindowOrigin</string>
- <string>29.editorWindowContentRectSynchronizationRect</string>
- <string>295.IBPluginDependency</string>
- <string>296.IBEditorWindowLastContentRect</string>
- <string>296.IBPluginDependency</string>
- <string>296.editorWindowContentRectSynchronizationRect</string>
- <string>297.IBPluginDependency</string>
- <string>298.IBPluginDependency</string>
- <string>5.IBPluginDependency</string>
- <string>5.ImportedFromIB2</string>
- <string>56.IBPluginDependency</string>
- <string>56.ImportedFromIB2</string>
- <string>57.IBEditorWindowLastContentRect</string>
- <string>57.IBPluginDependency</string>
- <string>57.ImportedFromIB2</string>
- <string>57.editorWindowContentRectSynchronizationRect</string>
- <string>58.IBPluginDependency</string>
- <string>58.ImportedFromIB2</string>
- <string>684.IBPluginDependency</string>
- <string>685.IBEditorWindowLastContentRect</string>
- <string>685.IBPluginDependency</string>
- <string>686.IBPluginDependency</string>
- <string>687.IBPluginDependency</string>
- <string>688.IBPluginDependency</string>
- <string>689.IBPluginDependency</string>
- <string>690.IBPluginDependency</string>
- <string>691.IBPluginDependency</string>
- <string>693.IBPluginDependency</string>
- <string>694.IBPluginDependency</string>
- <string>695.IBPluginDependency</string>
- <string>696.IBPluginDependency</string>
- <string>700.IBPluginDependency</string>
- <string>711.IBEditorWindowLastContentRect</string>
- <string>711.IBPluginDependency</string>
- <string>712.IBPluginDependency</string>
- <string>713.IBPluginDependency</string>
- <string>72.IBPluginDependency</string>
- <string>72.ImportedFromIB2</string>
- <string>73.IBPluginDependency</string>
- <string>73.ImportedFromIB2</string>
- <string>734.IBEditorWindowLastContentRect</string>
- <string>734.IBPluginDependency</string>
- <string>735.IBPluginDependency</string>
- <string>736.IBPluginDependency</string>
- <string>737.IBPluginDependency</string>
- <string>738.IBPluginDependency</string>
- <string>74.IBPluginDependency</string>
- <string>74.ImportedFromIB2</string>
- <string>77.IBPluginDependency</string>
- <string>77.ImportedFromIB2</string>
- <string>78.IBPluginDependency</string>
- <string>78.ImportedFromIB2</string>
- <string>79.IBPluginDependency</string>
- <string>79.ImportedFromIB2</string>
- <string>80.IBPluginDependency</string>
- <string>80.ImportedFromIB2</string>
- <string>81.IBEditorWindowLastContentRect</string>
- <string>81.IBPluginDependency</string>
- <string>81.ImportedFromIB2</string>
- <string>81.editorWindowContentRectSynchronizationRect</string>
- <string>817.IBPluginDependency</string>
- <string>818.IBPluginDependency</string>
- <string>82.IBPluginDependency</string>
- <string>82.ImportedFromIB2</string>
- <string>820.IBPluginDependency</string>
- <string>825.IBPluginDependency</string>
- <string>826.IBPluginDependency</string>
- <string>827.IBPluginDependency</string>
- <string>828.IBPluginDependency</string>
- <string>83.IBPluginDependency</string>
- <string>83.ImportedFromIB2</string>
- <string>832.IBPluginDependency</string>
- <string>833.IBPluginDependency</string>
- <string>834.IBPluginDependency</string>
- <string>838.IBPluginDependency</string>
- <string>847.IBPluginDependency</string>
- <string>848.IBPluginDependency</string>
- <string>849.IBEditorWindowLastContentRect</string>
- <string>849.IBPluginDependency</string>
- <string>853.IBEditorWindowLastContentRect</string>
- <string>853.IBPluginDependency</string>
- <string>854.IBPluginDependency</string>
- <string>855.IBPluginDependency</string>
- <string>92.IBPluginDependency</string>
- <string>92.ImportedFromIB2</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{881, 774}, {157, 23}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{596, 852}, {216, 23}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{509, 573}, {64, 6}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{436, 809}, {64, 6}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{876, 712}, {194, 103}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{525, 802}, {197, 73}}</string>
- <string>{{604, 815}, {446, 20}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{74, 862}</string>
- <string>{{11, 977}, {478, 20}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{823, 465}, {234, 163}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{475, 832}, {234, 43}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{668, 632}, {186, 183}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{23, 794}, {245, 183}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{782, 612}, {151, 203}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{933, 592}, {150, 43}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{933, 572}, {238, 83}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{740, 652}, {179, 163}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>{{323, 672}, {199, 203}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{824, 809}, {64, 6}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{616, 718}, {206, 43}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <integer value="1"/>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">859</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">BookmarksController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>addBookmark:</string>
- <string>openBookmarkURL:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>addBookmark:</string>
- <string>openBookmarkURL:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">addBookmark:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">openBookmarkURL:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">defaultMenu</string>
- <string key="NS.object.0">NSMenu</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">defaultMenu</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">defaultMenu</string>
- <string key="candidateClassName">NSMenu</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BookmarksController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserView</string>
- <string key="superclassName">ScrollableView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserViewController</string>
- <string key="superclassName">NSViewController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>backForwardSelected:</string>
- <string>goBack:</string>
- <string>goForward:</string>
- <string>goHome:</string>
- <string>navigate:</string>
- <string>reloadPage:</string>
- <string>stopLoading:</string>
- <string>zoomIn:</string>
- <string>zoomOriginal:</string>
- <string>zoomOut:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>backForwardSelected:</string>
- <string>goBack:</string>
- <string>goForward:</string>
- <string>goHome:</string>
- <string>navigate:</string>
- <string>reloadPage:</string>
- <string>stopLoading:</string>
- <string>zoomIn:</string>
- <string>zoomOriginal:</string>
- <string>zoomOut:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">backForwardSelected:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">goBack:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">goForward:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">goHome:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">navigate:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">reloadPage:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">stopLoading:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomIn:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomOriginal:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">zoomOut:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">browserView</string>
- <string key="NS.object.0">BrowserView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">browserView</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">browserView</string>
- <string key="candidateClassName">BrowserView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserViewController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">BrowserWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>closeCurrentTab:</string>
- <string>newTab:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>closeCurrentTab:</string>
- <string>newTab:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">closeCurrentTab:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">newTab:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="outlets">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>activeBrowserController</string>
- <string>navigationControl</string>
- <string>tabBar</string>
- <string>tabView</string>
- <string>urlField</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSObjectController</string>
- <string>NSSegmentedControl</string>
- <string>PSMTabBarControl</string>
- <string>NSTabView</string>
- <string>URLFieldCell</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>activeBrowserController</string>
- <string>navigationControl</string>
- <string>tabBar</string>
- <string>tabView</string>
- <string>urlField</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBToOneOutletInfo">
- <string key="name">activeBrowserController</string>
- <string key="candidateClassName">NSObjectController</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">navigationControl</string>
- <string key="candidateClassName">NSSegmentedControl</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">tabBar</string>
- <string key="candidateClassName">PSMTabBarControl</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">tabView</string>
- <string key="candidateClassName">NSTabView</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">urlField</string>
- <string key="candidateClassName">URLFieldCell</string>
- </object>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">BrowserWindowController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="294109393">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="831067236">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier" id="354078772">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NetSurfAppDelegate</string>
- <string key="superclassName">NSObject</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>searchBackward:</string>
- <string>searchForward:</string>
- <string>showGlobalHistory:</string>
- <string>showPreferences:</string>
- <string>showSearchWindow:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>searchBackward:</string>
- <string>searchForward:</string>
- <string>showGlobalHistory:</string>
- <string>showPreferences:</string>
- <string>showSearchWindow:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">searchBackward:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">searchForward:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">showGlobalHistory:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">showPreferences:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">showSearchWindow:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">NetSurfAppDelegate.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <reference key="sourceIdentifier" ref="831067236"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <string key="superclassName">NSControl</string>
- <object class="NSMutableDictionary" key="outlets">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>delegate</string>
- <string>partnerView</string>
- <string>style</string>
- <string>tabView</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- <string>NSTabView</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>delegate</string>
- <string>partnerView</string>
- <string>style</string>
- <string>tabView</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBToOneOutletInfo">
- <string key="name">delegate</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">partnerView</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">style</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBToOneOutletInfo">
- <string key="name">tabView</string>
- <string key="candidateClassName">NSTabView</string>
- </object>
- </object>
- </object>
- <reference key="sourceIdentifier" ref="354078772"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <reference key="sourceIdentifier" ref="294109393"/>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PSMTabBarControl</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabStyle.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">ScrollableView</string>
- <string key="superclassName">NSView</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">ScrollableView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">SearchWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>searchNext:</string>
- <string>searchPrevious:</string>
- <string>searchStringDidChange:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>searchNext:</string>
- <string>searchPrevious:</string>
- <string>searchStringDidChange:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBActionInfo">
- <string key="name">searchNext:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">searchPrevious:</string>
- <string key="candidateClassName">id</string>
- </object>
- <object class="IBActionInfo">
- <string key="name">searchStringDidChange:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">SearchWindowController.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">URLFieldCell</string>
- <string key="superclassName">NSTextFieldCell</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">URLFieldCell.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
- <integer value="1050" key="NS.object.0"/>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSMenuCheckmark</string>
- <string>NSMenuMixedState</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{9, 8}</string>
- <string>{7, 2}</string>
- </object>
- </object>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/NetSurf-Info.plist b/frontends/cocoa/res/NetSurf-Info.plist
deleted file mode 100644
index 60bf6820e..000000000
--- a/frontends/cocoa/res/NetSurf-Info.plist
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleDocumentTypes</key>
- <array>
- <dict>
- <key>CFBundleTypeExtensions</key>
- <array/>
- <key>CFBundleTypeMIMETypes</key>
- <array/>
- <key>CFBundleTypeName</key>
- <string>HTML</string>
- <key>CFBundleTypeRole</key>
- <string>Viewer</string>
- <key>LSItemContentTypes</key>
- <array>
- <string>public.html</string>
- </array>
- </dict>
- </array>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIconFile</key>
- <string>NetSurf</string>
- <key>CFBundleIdentifier</key>
- <string>org.netsurf-browser.${PRODUCT_NAME:rfc1034identifier}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>${NETSURF_VERSION}</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleURLTypes</key>
- <array>
- <dict>
- <key>CFBundleURLName</key>
- <string>org.netsurf-browser.NetSurf.URI</string>
- <key>CFBundleURLSchemes</key>
- <array>
- <string>http</string>
- <string>https</string>
- </array>
- </dict>
- </array>
- <key>CFBundleVersion</key>
- <string>${NETSURF_SHORT_VERSION}</string>
- <key>LSMinimumSystemVersion</key>
- <string>${MACOSX_DEPLOYMENT_TARGET}</string>
- <key>NSMainNibFile</key>
- <string>MainMenu</string>
- <key>NSPrincipalClass</key>
- <string>NetSurfApp</string>
- <key>NSServices</key>
- <array/>
- <key>UTExportedTypeDeclarations</key>
- <array/>
- <key>UTImportedTypeDeclarations</key>
- <array>
- <dict>
- <key>UTTypeConformsTo</key>
- <array>
- <string>public.text</string>
- </array>
- <key>UTTypeDescription</key>
- <string>HTML</string>
- <key>UTTypeIdentifier</key>
- <string>public.html</string>
- <key>UTTypeTagSpecification</key>
- <dict>
- <key>public.filename-extension</key>
- <array>
- <string>html</string>
- <string>htm</string>
- </array>
- <key>public.mime-type</key>
- <array>
- <string>text/html</string>
- </array>
- </dict>
- </dict>
- <dict>
- <key>UTTypeConformsTo</key>
- <array>
- <string>public.source-code</string>
- </array>
- <key>UTTypeDescription</key>
- <string>CSS</string>
- <key>UTTypeIdentifier</key>
- <string>org.w3.css</string>
- <key>UTTypeTagSpecification</key>
- <dict>
- <key>public.filename-extension</key>
- <array>
- <string>css</string>
- </array>
- <key>public.mime-type</key>
- <array>
- <string>text/css</string>
- </array>
- </dict>
- </dict>
- </array>
-</dict>
-</plist>
diff --git a/frontends/cocoa/res/NetSurf.icns b/frontends/cocoa/res/NetSurf.icns
deleted file mode 100644
index 654942373..000000000
--- a/frontends/cocoa/res/NetSurf.icns
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/PreferencesWindow.xib b/frontends/cocoa/res/PreferencesWindow.xib
deleted file mode 100644
index c4ea6b3b6..000000000
--- a/frontends/cocoa/res/PreferencesWindow.xib
+++ /dev/null
@@ -1,512 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
- <data>
- <int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">9L31a</string>
- <string key="IBDocument.InterfaceBuilderVersion">680</string>
- <string key="IBDocument.AppKitVersion">949.54</string>
- <string key="IBDocument.HIToolboxVersion">353.00</string>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="2"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">PreferencesWindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">7</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 362}, {455, 148}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">Preferences</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSTextField" id="343066491">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{98, 106}, {337, 22}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="218234675">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <object class="NSFont" key="NSSupport" id="1015231142">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.300000e+01</double>
- <int key="NSfFlags">1044</int>
- </object>
- <reference key="NSControlView" ref="343066491"/>
- <bool key="NSDrawsBackground">YES</bool>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textBackgroundColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textColor</string>
- <object class="NSColor" key="NSColor" id="751207648">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- </object>
- </object>
- <object class="NSTextField" id="662601838">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{17, 108}, {76, 17}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="633183289">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents">Homepage:</string>
- <reference key="NSSupport" ref="1015231142"/>
- <reference key="NSControlView" ref="662601838"/>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <reference key="NSColor" ref="751207648"/>
- </object>
- </object>
- </object>
- <object class="NSButton" id="272890940">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{222, 70}, {219, 32}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="136693114">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Use current page</string>
- <reference key="NSSupport" ref="1015231142"/>
- <reference key="NSControlView" ref="272890940"/>
- <int key="NSButtonFlags">-2038284033</int>
- <int key="NSButtonFlags2">129</int>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- <object class="NSButton" id="748375959">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{96, 38}, {341, 18}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="497902592">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">Cancel downloads without asking</string>
- <reference key="NSSupport" ref="1015231142"/>
- <reference key="NSControlView" ref="748375959"/>
- <int key="NSButtonFlags">1211912703</int>
- <int key="NSButtonFlags2">2</int>
- <object class="NSCustomResource" key="NSNormalImage" id="118883570">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSSwitch</string>
- </object>
- <object class="NSButtonImageSource" key="NSAlternateImage" id="21608943">
- <string key="NSImageName">NSSwitch</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- <object class="NSButton" id="832107887">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{96, 18}, {341, 18}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="616812964">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">Close multiple tabs without asking</string>
- <reference key="NSSupport" ref="1015231142"/>
- <reference key="NSControlView" ref="832107887"/>
- <int key="NSButtonFlags">1211912703</int>
- <int key="NSButtonFlags2">2</int>
- <reference key="NSNormalImage" ref="118883570"/>
- <reference key="NSAlternateImage" ref="21608943"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- </object>
- <string key="NSFrameSize">{455, 148}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
- </object>
- <object class="NSUserDefaultsController" id="562818373">
- <bool key="NSSharedInstance">YES</bool>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">3</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: values.AlwaysCancelDownload</string>
- <reference key="source" ref="748375959"/>
- <reference key="destination" ref="562818373"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="748375959"/>
- <reference key="NSDestination" ref="562818373"/>
- <string key="NSLabel">value: values.AlwaysCancelDownload</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">values.AlwaysCancelDownload</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">21</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: values.AlwaysCloseMultipleTabs</string>
- <reference key="source" ref="832107887"/>
- <reference key="destination" ref="562818373"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="832107887"/>
- <reference key="NSDestination" ref="562818373"/>
- <string key="NSLabel">value: values.AlwaysCloseMultipleTabs</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">values.AlwaysCloseMultipleTabs</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">22</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">useCurrentPageAsHomepage:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="272890940"/>
- </object>
- <int key="connectionID">23</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: homepageURL</string>
- <reference key="source" ref="343066491"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="343066491"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: homepageURL</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">homepageURL</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">25</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <object class="NSArray" key="object" id="854144324">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="854144324"/>
- <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="854144324"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="854144324"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="854144324"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="343066491"/>
- <reference ref="662601838"/>
- <reference ref="272890940"/>
- <reference ref="748375959"/>
- <reference ref="832107887"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">9</int>
- <reference key="object" ref="343066491"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="218234675"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">10</int>
- <reference key="object" ref="218234675"/>
- <reference key="parent" ref="343066491"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">11</int>
- <reference key="object" ref="662601838"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="633183289"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">12</int>
- <reference key="object" ref="633183289"/>
- <reference key="parent" ref="662601838"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">13</int>
- <reference key="object" ref="272890940"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="136693114"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">14</int>
- <reference key="object" ref="136693114"/>
- <reference key="parent" ref="272890940"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">15</int>
- <reference key="object" ref="748375959"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="497902592"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">16</int>
- <reference key="object" ref="497902592"/>
- <reference key="parent" ref="748375959"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">17</int>
- <reference key="object" ref="832107887"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="616812964"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">18</int>
- <reference key="object" ref="616812964"/>
- <reference key="parent" ref="832107887"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">19</int>
- <reference key="object" ref="562818373"/>
- <reference key="parent" ref="854144324"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>10.IBPluginDependency</string>
- <string>11.IBPluginDependency</string>
- <string>11.IBViewBoundsToFrameTransform</string>
- <string>12.IBPluginDependency</string>
- <string>13.IBPluginDependency</string>
- <string>13.IBViewBoundsToFrameTransform</string>
- <string>14.IBPluginDependency</string>
- <string>15.IBPluginDependency</string>
- <string>16.IBPluginDependency</string>
- <string>17.IBPluginDependency</string>
- <string>17.IBViewBoundsToFrameTransform</string>
- <string>18.IBPluginDependency</string>
- <string>2.IBPluginDependency</string>
- <string>9.IBPluginDependency</string>
- <string>9.IBViewBoundsToFrameTransform</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{176, 384}, {455, 148}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{176, 384}, {455, 148}}</string>
- <integer value="1"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCYAAAw2sAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABClgAAw3wAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABCwAAAwggAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDSQAAw2sAAA</bytes>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">25</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">PreferencesWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PreferencesWindowController.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/SearchWindow.xib b/frontends/cocoa/res/SearchWindow.xib
deleted file mode 100644
index 8e9315b51..000000000
--- a/frontends/cocoa/res/SearchWindow.xib
+++ /dev/null
@@ -1,614 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
- <data>
- <int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">9L31a</string>
- <string key="IBDocument.InterfaceBuilderVersion">680</string>
- <string key="IBDocument.AppKitVersion">949.54</string>
- <string key="IBDocument.HIToolboxVersion">353.00</string>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="2"/>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">SearchWindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">7</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 354}, {480, 156}}</string>
- <int key="NSWTFlags">1618477056</int>
- <string key="NSWindowTitle">Search</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSTextField" id="656125083">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{67, 114}, {393, 22}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="175732045">
- <int key="NSCellFlags">-1803944383</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <object class="NSFont" key="NSSupport" id="926601808">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.300000e+01</double>
- <int key="NSfFlags">1044</int>
- </object>
- <reference key="NSControlView" ref="656125083"/>
- <bool key="NSDrawsBackground">YES</bool>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textBackgroundColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">textColor</string>
- <object class="NSColor" key="NSColor" id="92132461">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MAA</bytes>
- </object>
- </object>
- </object>
- </object>
- <object class="NSTextField" id="90768291">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{17, 116}, {45, 14}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="874604921">
- <int key="NSCellFlags">68288064</int>
- <int key="NSCellFlags2">71435264</int>
- <string key="NSContents">Find:</string>
- <object class="NSFont" key="NSSupport">
- <string key="NSName">LucidaGrande</string>
- <double key="NSSize">1.100000e+01</double>
- <int key="NSfFlags">3100</int>
- </object>
- <reference key="NSControlView" ref="90768291"/>
- <object class="NSColor" key="NSBackgroundColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlColor</string>
- <object class="NSColor" key="NSColor">
- <int key="NSColorSpace">3</int>
- <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
- </object>
- </object>
- <object class="NSColor" key="NSTextColor">
- <int key="NSColorSpace">6</int>
- <string key="NSCatalogName">System</string>
- <string key="NSColorName">controlTextColor</string>
- <reference key="NSColor" ref="92132461"/>
- </object>
- </object>
- </object>
- <object class="NSButton" id="1016680565">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{370, 12}, {96, 32}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="567819516">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Next</string>
- <reference key="NSSupport" ref="926601808"/>
- <reference key="NSControlView" ref="1016680565"/>
- <int key="NSButtonFlags">-2038284033</int>
- <int key="NSButtonFlags2">129</int>
- <string key="NSAlternateContents"/>
- <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- <object class="NSButton" id="88766619">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{274, 12}, {96, 32}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="450885469">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Previous</string>
- <reference key="NSSupport" ref="926601808"/>
- <reference key="NSControlView" ref="88766619"/>
- <int key="NSButtonFlags">-2038284033</int>
- <int key="NSButtonFlags2">129</int>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- <object class="NSButton" id="650505141">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{139, 90}, {323, 18}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="657985060">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">Case sensitive</string>
- <reference key="NSSupport" ref="926601808"/>
- <reference key="NSControlView" ref="650505141"/>
- <int key="NSButtonFlags">1211912703</int>
- <int key="NSButtonFlags2">2</int>
- <object class="NSCustomResource" key="NSNormalImage" id="312987126">
- <string key="NSClassName">NSImage</string>
- <string key="NSResourceName">NSSwitch</string>
- </object>
- <object class="NSButtonImageSource" key="NSAlternateImage" id="973359313">
- <string key="NSImageName">NSSwitch</string>
- </object>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- <object class="NSButton" id="331870754">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">268</int>
- <string key="NSFrame">{{139, 70}, {323, 18}}</string>
- <reference key="NSSuperview" ref="1006"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="239506938">
- <int key="NSCellFlags">-2080244224</int>
- <int key="NSCellFlags2">0</int>
- <string key="NSContents">Select all</string>
- <reference key="NSSupport" ref="926601808"/>
- <reference key="NSControlView" ref="331870754"/>
- <int key="NSButtonFlags">1211912703</int>
- <int key="NSButtonFlags2">2</int>
- <reference key="NSNormalImage" ref="312987126"/>
- <reference key="NSAlternateImage" ref="973359313"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">200</int>
- <int key="NSPeriodicInterval">25</int>
- </object>
- </object>
- </object>
- <string key="NSFrameSize">{480, 156}</string>
- <reference key="NSSuperview"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
- <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">searchNext:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1016680565"/>
- </object>
- <int key="connectionID">15</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">searchPrevious:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="88766619"/>
- </object>
- <int key="connectionID">16</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">enabled: canGoForward</string>
- <reference key="source" ref="1016680565"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="1016680565"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">enabled: canGoForward</string>
- <string key="NSBinding">enabled</string>
- <string key="NSKeyPath">canGoForward</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">17</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">enabled: canGoBack</string>
- <reference key="source" ref="88766619"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="88766619"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">enabled: canGoBack</string>
- <string key="NSBinding">enabled</string>
- <string key="NSKeyPath">canGoBack</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">18</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBActionConnection" key="connection">
- <string key="label">searchStringDidChange:</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="656125083"/>
- </object>
- <int key="connectionID">22</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">23</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: searchString</string>
- <reference key="source" ref="656125083"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="656125083"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: searchString</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">searchString</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">24</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: caseSensitive</string>
- <reference key="source" ref="650505141"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="650505141"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: caseSensitive</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">caseSensitive</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">25</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: selectAll</string>
- <reference key="source" ref="331870754"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="331870754"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: selectAll</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">selectAll</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">27</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <object class="NSArray" key="object" id="729119712">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="729119712"/>
- <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="729119712"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="729119712"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="729119712"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="656125083"/>
- <reference ref="90768291"/>
- <reference ref="1016680565"/>
- <reference ref="88766619"/>
- <reference ref="331870754"/>
- <reference ref="650505141"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">3</int>
- <reference key="object" ref="656125083"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="175732045"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">4</int>
- <reference key="object" ref="175732045"/>
- <reference key="parent" ref="656125083"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="90768291"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="874604921"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">6</int>
- <reference key="object" ref="874604921"/>
- <reference key="parent" ref="90768291"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">7</int>
- <reference key="object" ref="1016680565"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="567819516"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">8</int>
- <reference key="object" ref="567819516"/>
- <reference key="parent" ref="1016680565"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">9</int>
- <reference key="object" ref="88766619"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="450885469"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">10</int>
- <reference key="object" ref="450885469"/>
- <reference key="parent" ref="88766619"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">11</int>
- <reference key="object" ref="650505141"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="657985060"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">12</int>
- <reference key="object" ref="657985060"/>
- <reference key="parent" ref="650505141"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">13</int>
- <reference key="object" ref="331870754"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="239506938"/>
- </object>
- <reference key="parent" ref="1006"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">14</int>
- <reference key="object" ref="239506938"/>
- <reference key="parent" ref="331870754"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1.IBEditorWindowLastContentRect</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>1.WindowOrigin</string>
- <string>1.editorWindowContentRectSynchronizationRect</string>
- <string>10.IBPluginDependency</string>
- <string>11.IBPluginDependency</string>
- <string>11.IBViewBoundsToFrameTransform</string>
- <string>12.IBPluginDependency</string>
- <string>13.IBPluginDependency</string>
- <string>13.IBViewBoundsToFrameTransform</string>
- <string>14.IBPluginDependency</string>
- <string>2.IBPluginDependency</string>
- <string>3.IBPluginDependency</string>
- <string>4.IBPluginDependency</string>
- <string>5.IBPluginDependency</string>
- <string>5.IBViewBoundsToFrameTransform</string>
- <string>6.IBPluginDependency</string>
- <string>7.IBPluginDependency</string>
- <string>7.IBViewBoundsToFrameTransform</string>
- <string>8.IBPluginDependency</string>
- <string>9.IBPluginDependency</string>
- <string>9.IBViewBoundsToFrameTransform</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>{{185, 223}, {480, 156}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{185, 223}, {480, 156}}</string>
- <boolean value="NO"/>
- <string>{196, 240}</string>
- <string>{{202, 428}, {480, 270}}</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDCwAAwpQAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDk4AAwpQAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAw3IAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDuQAAwigAAA</bytes>
- </object>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <object class="NSAffineTransform">
- <bytes key="NSTransformStruct">P4AAAL+AAABDiQAAwigAAA</bytes>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">27</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">NSApplication</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabDragAssistant.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarCell.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">PSMTabBarControl/PSMTabBarControl.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">SearchWindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>searchNext:</string>
- <string>searchPrevious:</string>
- <string>searchStringDidChange:</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>id</string>
- <string>id</string>
- <string>id</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">SearchWindowController.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.LastKnownRelativeProjectPath">../NetSurf.xcodeproj</string>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
diff --git a/frontends/cocoa/res/adblock.css b/frontends/cocoa/res/adblock.css
deleted file mode 120000
index ff2485622..000000000
--- a/frontends/cocoa/res/adblock.css
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
diff --git a/frontends/cocoa/res/ca-bundle b/frontends/cocoa/res/ca-bundle
deleted file mode 120000
index 0b0e416ad..000000000
--- a/frontends/cocoa/res/ca-bundle
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
diff --git a/frontends/cocoa/res/de.lproj/BookmarksWindow.xib.strings b/frontends/cocoa/res/de.lproj/BookmarksWindow.xib.strings
deleted file mode 100644
index 5fa44a11e..000000000
--- a/frontends/cocoa/res/de.lproj/BookmarksWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/BrowserWindow.xib.strings b/frontends/cocoa/res/de.lproj/BrowserWindow.xib.strings
deleted file mode 100644
index a0c782cd6..000000000
--- a/frontends/cocoa/res/de.lproj/BrowserWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/DownloadWindow.xib.strings b/frontends/cocoa/res/de.lproj/DownloadWindow.xib.strings
deleted file mode 100644
index d92040249..000000000
--- a/frontends/cocoa/res/de.lproj/DownloadWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/HistoryWindow.xib.strings b/frontends/cocoa/res/de.lproj/HistoryWindow.xib.strings
deleted file mode 100644
index c43bc418e..000000000
--- a/frontends/cocoa/res/de.lproj/HistoryWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/Localizable.strings b/frontends/cocoa/res/de.lproj/Localizable.strings
deleted file mode 100644
index 04180f485..000000000
--- a/frontends/cocoa/res/de.lproj/Localizable.strings
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ... of (total size) */
-" of %@" = " von %@";
-
-/* time remaining: hours, minutes */
-"%2:%02u hours" = "%1$:%2$u Stunden";
-
-/* time remaining */
-"%u seconds" = "%u Sekunden";
-
-/* time remaining: minutes, seconds */
-"%u:%02u minutes" = "%1$u:%2$u Minuten";
-
-/* Context menu */
-"Back" = "Zurück";
-
-/* Download */
-"Cancel download?" = "Download abbrechen?";
-
-/* Context menu */
-"Copy image" = "Bild kopieren";
-
-/* Context menu */
-"Copy link" = "Link kopieren";
-
-/* No comment provided by engineer. */
-"Do you really want to close this window?" = "Wollen Sie dieses Fenster wirklich schließen?";
-
-/* show error */
-"Error" = "Fehler";
-
-/* Context menu */
-"Forward" = "Vorwärts";
-
-/* time remaining */
-"less than 10 seconds" = "weniger als 10 Sekunden";
-
-/* 'No' button */
-"No" = "Nein";
-
-/* 'OK' button */
-"OK" = "OK";
-
-/* Context menu */
-"Open image in new tab" = "Bild in neuem Tab öffnen";
-
-/* Context menu */
-"Open image in new window" = "Bild in neuem Fenster öffnen";
-
-/* Context menu */
-"Open link in new tab" = "Link in neuem Tab öffnen";
-
-/* Context menu */
-"Open link in new window" = "Link in neuem Fenster öffnen";
-
-/* Context menu */
-"Reload" = "Neu laden";
-
-/* Context menu */
-"Save image as" = "Bild speichern";
-
-/* Context menu */
-"Save link target" = "Linkziel speichern";
-
-/* Download */
-"Should the download of '%@' really be cancelled?" = "Soll der Download von '%@' wirklich abgebrochen werden?";
-
-/* No comment provided by engineer. */
-"There are %d tabs open, do you want to close them all?" = "Es sind noch %d tabs offen. Sollen alle geschlossen werden?";
-
-/* Warning title */
-"Warning" = "Warnung";
-
-/* Warning message */
-"Warning %s%s%s" = "Warnung %1$s%2$s%3$s";
-
-/* 'Yes' button */
-"Yes" = "Ja";
-
diff --git a/frontends/cocoa/res/de.lproj/MainMenu.xib.strings b/frontends/cocoa/res/de.lproj/MainMenu.xib.strings
deleted file mode 100644
index 3fc91c48c..000000000
--- a/frontends/cocoa/res/de.lproj/MainMenu.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/Messages b/frontends/cocoa/res/de.lproj/Messages
deleted file mode 120000
index 32530a151..000000000
--- a/frontends/cocoa/res/de.lproj/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../../!NetSurf/Resources/de/Messages \ No newline at end of file
diff --git a/frontends/cocoa/res/de.lproj/PreferencesWindow.xib.strings b/frontends/cocoa/res/de.lproj/PreferencesWindow.xib.strings
deleted file mode 100644
index fbe9762f2..000000000
--- a/frontends/cocoa/res/de.lproj/PreferencesWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/de.lproj/SearchWindow.xib.strings b/frontends/cocoa/res/de.lproj/SearchWindow.xib.strings
deleted file mode 100644
index 31fdea76b..000000000
--- a/frontends/cocoa/res/de.lproj/SearchWindow.xib.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/default.css b/frontends/cocoa/res/default.css
deleted file mode 120000
index a8579eb7c..000000000
--- a/frontends/cocoa/res/default.css
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
diff --git a/frontends/cocoa/res/en.lproj/Localizable.strings b/frontends/cocoa/res/en.lproj/Localizable.strings
deleted file mode 100644
index 9ac7a7b4d..000000000
--- a/frontends/cocoa/res/en.lproj/Localizable.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/en.lproj/Messages b/frontends/cocoa/res/en.lproj/Messages
deleted file mode 120000
index a26483244..000000000
--- a/frontends/cocoa/res/en.lproj/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../../!NetSurf/Resources/en/Messages \ No newline at end of file
diff --git a/frontends/cocoa/res/fr.lproj/Localizable.strings b/frontends/cocoa/res/fr.lproj/Localizable.strings
deleted file mode 100644
index 9ac7a7b4d..000000000
--- a/frontends/cocoa/res/fr.lproj/Localizable.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/fr.lproj/Messages b/frontends/cocoa/res/fr.lproj/Messages
deleted file mode 120000
index 467559b12..000000000
--- a/frontends/cocoa/res/fr.lproj/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../../!NetSurf/Resources/fr/Messages \ No newline at end of file
diff --git a/frontends/cocoa/res/internal.css b/frontends/cocoa/res/internal.css
deleted file mode 120000
index 17f9f1504..000000000
--- a/frontends/cocoa/res/internal.css
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
diff --git a/frontends/cocoa/res/it.lproj/Localizable.strings b/frontends/cocoa/res/it.lproj/Localizable.strings
deleted file mode 100644
index 5927796a6..000000000
--- a/frontends/cocoa/res/it.lproj/Localizable.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/it.lproj/Messages b/frontends/cocoa/res/it.lproj/Messages
deleted file mode 120000
index 00fc6d1ed..000000000
--- a/frontends/cocoa/res/it.lproj/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../../!NetSurf/Resources/it/Messages \ No newline at end of file
diff --git a/frontends/cocoa/res/netsurf.png b/frontends/cocoa/res/netsurf.png
deleted file mode 120000
index 905512c25..000000000
--- a/frontends/cocoa/res/netsurf.png
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
diff --git a/frontends/cocoa/res/nl.lproj/Localizable.strings b/frontends/cocoa/res/nl.lproj/Localizable.strings
deleted file mode 100644
index 9ac7a7b4d..000000000
--- a/frontends/cocoa/res/nl.lproj/Localizable.strings
+++ /dev/null
Binary files differ
diff --git a/frontends/cocoa/res/nl.lproj/Messages b/frontends/cocoa/res/nl.lproj/Messages
deleted file mode 120000
index c8a9cbe81..000000000
--- a/frontends/cocoa/res/nl.lproj/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../../!NetSurf/Resources/nl/Messages \ No newline at end of file
diff --git a/frontends/cocoa/res/quirks.css b/frontends/cocoa/res/quirks.css
deleted file mode 120000
index 88aabe48c..000000000
--- a/frontends/cocoa/res/quirks.css
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
diff --git a/frontends/cocoa/schedule.h b/frontends/cocoa/schedule.h
deleted file mode 100644
index 43b2c1462..000000000
--- a/frontends/cocoa/schedule.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-nserror cocoa_schedule(int t, void (*callback)(void *p), void *p);
diff --git a/frontends/cocoa/schedule.m b/frontends/cocoa/schedule.m
deleted file mode 100644
index f0896bd9d..000000000
--- a/frontends/cocoa/schedule.m
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "utils/errors.h"
-
-#import "cocoa/schedule.h"
-
-@interface ScheduledCallback : NSObject {
- void (*callback)( void *userData );
- void *userData;
-}
-
-- initWithCallback: (void (*)(void *))cb userData: (void *)ud;
-- (void) schedule: (NSTimeInterval) ti;
-
-@end
-
-@implementation ScheduledCallback
-
-- initWithCallback: (void (*)(void *))cb userData: (void *)ud;
-{
- callback = cb;
- userData = ud;
-
- return self;
-}
-
-static NSMutableSet *timerSet = nil;
-
-- (void) schedule: (NSTimeInterval) ti;
-{
- if (nil == timerSet) {
- timerSet = [[NSMutableSet alloc] init];
- }
-
- [self performSelector: @selector(timerFired) withObject: nil afterDelay: ti];
- [timerSet addObject: self];
-}
-
-- (void) timerFired;
-{
- if ([timerSet containsObject: self]) {
- [timerSet removeObject: self];
- callback( userData );
- }
-}
-
-- (BOOL) isEqual: (id)object
-{
- if (object == self) return YES;
- if ([object class] != [self class]) return NO;
- return ((ScheduledCallback *)object)->callback == callback && ((ScheduledCallback *)object)->userData == userData;
-}
-
-- (NSUInteger) hash;
-{
- return (NSUInteger)callback + (NSUInteger)userData;
-}
-
-@end
-
-/* exported interface documented in cocoa/schedule.h */
-nserror cocoa_schedule(int t, void (*callback)(void *p), void *p)
-{
- ScheduledCallback *cb = [[ScheduledCallback alloc] initWithCallback: callback userData: p];
- [timerSet removeObject: cb];
- if (t >= 0) {
- [cb schedule: (NSTimeInterval)t / 1000];
- }
- [cb release];
-
- return NSERROR_OK;
-}
diff --git a/frontends/cocoa/selection.h b/frontends/cocoa/selection.h
deleted file mode 100644
index 67331ea83..000000000
--- a/frontends/cocoa/selection.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-struct gui_clipboard_table *cocoa_clipboard_table;
diff --git a/frontends/cocoa/selection.m b/frontends/cocoa/selection.m
deleted file mode 100644
index 37562bc07..000000000
--- a/frontends/cocoa/selection.m
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "cocoa/BrowserViewController.h"
-#import "cocoa/selection.h"
-
-#import "netsurf/clipboard.h"
-
-
-static NSMutableString *cocoa_clipboard_string;
-
-/**
- * Core asks front end for clipboard contents.
- *
- * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
- * \param length Byte length of UTF-8 text in buffer
- */
-static void gui_get_clipboard(char **buffer, size_t *length)
-{
- NSPasteboard *pb = [NSPasteboard generalPasteboard];
- NSString *string = [pb stringForType: NSStringPboardType];
-
- *buffer = NULL;
- *length = 0;
-
- if (string) {
- const char *text = [string UTF8String];
- *length = strlen(text);
-
- *buffer = malloc(*length);
-
- if (*buffer != NULL) {
- memcpy(*buffer, text, *length);
- } else {
- *length = 0;
- }
- }
-}
-
-/**
- * Core tells front end to put given text in clipboard
- *
- * \param buffer UTF-8 text, owned by core
- * \param length Byte length of UTF-8 text in buffer
- * \param styles Array of styles given to text runs, owned by core, or NULL
- * \param n_styles Number of text run styles in array
- */
-static void gui_set_clipboard(const char *buffer, size_t length,
- nsclipboard_styles styles[], int n_styles)
-{
- /* Empty clipboard string */
- if (nil == cocoa_clipboard_string) {
- cocoa_clipboard_string = [[NSMutableString alloc] init];
- } else {
- [cocoa_clipboard_string setString: @""];
- }
-
- /* Add text to clipboard string */
- if (nil == cocoa_clipboard_string) return;
-
- [cocoa_clipboard_string appendString: [[[NSString alloc]
- initWithBytes: buffer
- length: length
- encoding: NSUTF8StringEncoding]
- autorelease]];
-
- /* Stick it on the pasteboard */
- NSPasteboard *pb = [NSPasteboard generalPasteboard];
- [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: nil];
- bool result = [pb setString: cocoa_clipboard_string forType: NSStringPboardType];
-
- if (result) {
- /* Empty clipboard string */
- if (nil == cocoa_clipboard_string) {
- cocoa_clipboard_string = [[NSMutableString alloc] init];
- } else {
- [cocoa_clipboard_string setString: @""];
- }
- }
-}
-
-static struct gui_clipboard_table clipboard_table = {
- .get = gui_get_clipboard,
- .set = gui_set_clipboard,
-};
-
-struct gui_clipboard_table *cocoa_clipboard_table = &clipboard_table;
diff --git a/frontends/framebuffer/Makefile b/frontends/framebuffer/Makefile
index 6d2acb079..bdedd903b 100644
--- a/frontends/framebuffer/Makefile
+++ b/frontends/framebuffer/Makefile
@@ -130,10 +130,12 @@ define convert_font
S_FONTS += $(2)
-$(2): $(1) $(TOOLROOT)/convert_font
+$(2) $(3): $(1) $(TOOLROOT)/convert_font
$(VQ)echo " FONT: $(1) ($(4))"
$(Q)$(TOOLROOT)/convert_font -H $(3) $(1) $(2)
+frontends/framebuffer/font_internal.c: $(2)
+
endef
S_FONTS :=
@@ -146,7 +148,7 @@ $(eval $(foreach V,$(filter FB_FONT_$(NETSURF_FB_FONTLIB)_%,$(.VARIABLES)),$(cal
# S_FRONTEND are sources purely for the framebuffer build
S_FRONTEND := gui.c framebuffer.c schedule.c bitmap.c fetch.c \
- findfile.c localhistory.c clipboard.c
+ findfile.c corewindow.c local_history.c clipboard.c
# toolkit sources
S_FRAMEBUFFER_FBTK := fbtk.c event.c fill.c bitmap.c user.c window.c \
@@ -168,14 +170,15 @@ EXETARGET := nsfb
NETSURF_FRAMEBUFFER_RESOURCE_LIST := adblock.css credits.html \
default.css internal.css licence.html \
- netsurf.png quirks.css welcome.html maps.html Messages
+ netsurf.png quirks.css welcome.html maps.html
install-framebuffer:
$(Q)$(MKDIR) -p $(DESTDIR)$(NETSURF_FRAMEBUFFER_BIN)
$(Q)$(MKDIR) -p $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)
$(Q)cp -v $(EXETARGET) $(DESTDIR)/$(NETSURF_FRAMEBUFFER_BIN)netsurf-fb
$(Q)for F in $(NETSURF_FRAMEBUFFER_RESOURCE_LIST); do cp -vL $(FRONTEND_RESOURCES_DIR)/$$F $(DESTDIR)/$(NETSURF_FRAMEBUFFER_RESOURCES); done
- $(Q)$(SPLIT_MESSAGES) -l en -p fb -f messages resources/FatMessages | gzip -9n > $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages
+ $(Q)$(RM) $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages
+ $(Q)$(SPLIT_MESSAGES) -l en -p fb -f messages -o $(DESTDIR)$(NETSURF_FRAMEBUFFER_RESOURCES)messages -z resources/FatMessages
# ----------------------------------------------------------------------------
# Package target
diff --git a/frontends/framebuffer/bitmap.c b/frontends/framebuffer/bitmap.c
index 027e0122b..1fc9f46a2 100644
--- a/frontends/framebuffer/bitmap.c
+++ b/frontends/framebuffer/bitmap.c
@@ -51,7 +51,8 @@ static void *bitmap_create(int width, int height, unsigned int state)
{
nsfb_t *bm;
- LOG("width %d, height %d, state %u", width, height, state);
+ NSLOG(netsurf, INFO, "width %d, height %d, state %u", width, height,
+ state);
bm = nsfb_new(NSFB_SURFACE_RAM);
if (bm == NULL) {
@@ -69,7 +70,7 @@ static void *bitmap_create(int width, int height, unsigned int state)
return NULL;
}
- LOG("bitmap %p", bm);
+ NSLOG(netsurf, INFO, "bitmap %p", bm);
return bm;
}
@@ -197,11 +198,11 @@ static bool bitmap_test_opaque(void *bitmap)
while (tst-- > 0) {
if (bmpptr[(tst << 2) + 3] != 0xff) {
- LOG("bitmap %p has transparency", bm);
+ NSLOG(netsurf, INFO, "bitmap %p has transparency", bm);
return false;
}
}
- LOG("bitmap %p is opaque", bm);
+ NSLOG(netsurf, INFO, "bitmap %p is opaque", bm);
return true;
}
@@ -282,14 +283,14 @@ bitmap_render(struct bitmap *bitmap,
nsfb_get_geometry(tbm, &width, &height, NULL);
- LOG("width %d, height %d", width, height);
+ NSLOG(netsurf, INFO, "width %d, height %d", width, height);
/* Calculate size of buffer to render the content into */
- /* We get the width from the content width, unless it exceeds 1024,
- * in which case we use 1024. This means we never create excessively
- * large render buffers for huge contents, which would eat memory and
- * cripple performance. */
- cwidth = min(content_get_width(content), 1024);
+ /* We get the width from the largest of the bitmap width and the content
+ * width, unless it exceeds 1024, in which case we use 1024. This means
+ * we never create excessively large render buffers for huge contents,
+ * which would eat memory and cripple performance. */
+ cwidth = max(width, min(content_get_width(content), 1024));
/* The height is set in proportion with the width, according to the
* aspect ratio of the required thumbnail. */
cheight = ((cwidth * height) + (width / 2)) / width;
diff --git a/frontends/framebuffer/clipboard.c b/frontends/framebuffer/clipboard.c
index 1254c36f3..20a00e038 100644
--- a/frontends/framebuffer/clipboard.c
+++ b/frontends/framebuffer/clipboard.c
@@ -53,8 +53,8 @@ static void gui_get_clipboard(char **buffer, size_t *length)
if (gui_clipboard.length > 0) {
assert(gui_clipboard.buffer != NULL);
- LOG("Pasting %zd bytes: \"%s\"\n",
- gui_clipboard.length, gui_clipboard.buffer);
+ NSLOG(netsurf, INFO, "Pasting %zd bytes: \"%s\"\n",
+ gui_clipboard.length, gui_clipboard.buffer);
*buffer = malloc(gui_clipboard.length);
diff --git a/frontends/framebuffer/corewindow.c b/frontends/framebuffer/corewindow.c
new file mode 100644
index 000000000..93f88ff61
--- /dev/null
+++ b/frontends/framebuffer/corewindow.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * framebuffer generic core window interface.
+ *
+ * Provides interface for core renderers to the framebufefr toolkit
+ * drawable area.
+ *
+ * This module is an object that must be encapsulated. Client users
+ * should embed a struct fb_corewindow at the beginning of their
+ * context for this display surface, fill in relevant data and then
+ * call fb_corewindow_init()
+ *
+ * The fb core window structure requires the callback for draw, key and
+ * mouse operations.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_event.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/messages.h"
+#include "utils/utf8.h"
+#include "utils/nsoption.h"
+#include "netsurf/keypress.h"
+#include "netsurf/mouse.h"
+#include "netsurf/plot_style.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/corewindow.h"
+
+
+/* toolkit event handlers that do generic things and call internal callbacks */
+
+
+static int
+fb_cw_mouse_press_event(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ struct fb_corewindow *fb_cw = (struct fb_corewindow *)cbi->context;
+ browser_mouse_state state;
+
+ /** \todo frambuffer corewindow mouse event handling needs improving */
+ if (cbi->event->type != NSFB_EVENT_KEY_UP) {
+ state = BROWSER_MOUSE_HOVER;
+ } else {
+ state = BROWSER_MOUSE_PRESS_1;
+ }
+
+ fb_cw->mouse(fb_cw, state, cbi->x, cbi->y);
+
+ return 1;
+}
+
+/*
+static bool
+fb_cw_input_event(toolkit_widget *widget, void *ctx)
+{
+ struct fb_corewindow *fb_cw = (struct fb_corewindow *)ctx;
+
+ fb_cw->key(fb_cw, keycode);
+
+ return true;
+}
+*/
+
+/**
+ * handler for toolkit window redraw event
+ */
+static int fb_cw_draw_event(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ struct fb_corewindow *fb_cw;
+ nsfb_bbox_t rbox;
+ struct rect clip;
+
+ fb_cw = (struct fb_corewindow *)cbi->context;
+
+ rbox.x0 = fbtk_get_absx(widget);
+ rbox.y0 = fbtk_get_absy(widget);
+
+ rbox.x1 = rbox.x0 + fbtk_get_width(widget);
+ rbox.y1 = rbox.y0 + fbtk_get_height(widget);
+
+ nsfb_claim(fbtk_get_nsfb(widget), &rbox);
+
+ clip.x0 = fb_cw->scrollx;
+ clip.y0 = fb_cw->scrolly;
+ clip.x1 = fbtk_get_width(widget) + fb_cw->scrollx;
+ clip.y1 = fbtk_get_height(widget) + fb_cw->scrolly;
+
+ fb_cw->draw(fb_cw, &clip);
+
+ nsfb_update(fbtk_get_nsfb(widget), &rbox);
+
+ return 0;
+}
+
+
+/**
+ * callback from core to request a redraw
+ */
+static nserror
+fb_cw_invalidate(struct core_window *cw, const struct rect *r)
+{
+/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw;
+
+ toolkit_widget_queue_draw_area(fb_cw->widget,
+ r->x0, r->y0,
+ r->x1 - r->x0, r->y1 - r->y0);
+*/
+ return NSERROR_OK;
+}
+
+
+static void
+fb_cw_update_size(struct core_window *cw, int width, int height)
+{
+/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw;
+
+ toolkit_widget_set_size_request(FB_WIDGET(fb_cw->drawing_area),
+ width, height);
+*/
+}
+
+
+static void
+fb_cw_scroll_visible(struct core_window *cw, const struct rect *r)
+{
+/* struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw;
+
+ toolkit_scroll_widget(fb_cw->widget, r);
+*/
+}
+
+
+static void
+fb_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
+{
+ struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw;
+
+ *width = fbtk_get_width(fb_cw->drawable);
+ *height = fbtk_get_height(fb_cw->drawable);
+}
+
+
+static void
+fb_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
+{
+ struct fb_corewindow *fb_cw = (struct fb_corewindow *)cw;
+ fb_cw->drag_status = ds;
+}
+
+
+struct core_window_callback_table fb_cw_cb_table = {
+ .invalidate = fb_cw_invalidate,
+ .update_size = fb_cw_update_size,
+ .scroll_visible = fb_cw_scroll_visible,
+ .get_window_dimensions = fb_cw_get_window_dimensions,
+ .drag_status = fb_cw_drag_status
+};
+
+/* exported function documented fb/corewindow.h */
+nserror fb_corewindow_init(fbtk_widget_t *parent, struct fb_corewindow *fb_cw)
+{
+ int furniture_width;
+
+ furniture_width = nsoption_int(fb_furniture_size);
+
+ /* setup the core window callback table */
+ fb_cw->cb_table = &fb_cw_cb_table;
+ fb_cw->drag_status = CORE_WINDOW_DRAG_NONE;
+
+ /* container window */
+ fb_cw->wnd = fbtk_create_window(parent, 0, 0, 0, 0, 0);
+
+ fb_cw->drawable = fbtk_create_user(fb_cw->wnd,
+ 0, 0,
+ -furniture_width, -furniture_width,
+ fb_cw);
+
+ fbtk_set_handler(fb_cw->drawable,
+ FBTK_CBT_REDRAW,
+ fb_cw_draw_event,
+ fb_cw);
+
+ fbtk_set_handler(fb_cw->drawable,
+ FBTK_CBT_CLICK,
+ fb_cw_mouse_press_event,
+ fb_cw);
+/*
+ fbtk_set_handler(fb_cw->drawable,
+ FBTK_CBT_INPUT,
+ fb_cw_input_event,
+ fb_cw);
+
+ fbtk_set_handler(fb_cw->drawable,
+ FBTK_CBT_POINTERMOVE,
+ fb_cw_move_event,
+ fb_cw);
+*/
+
+ /* create horizontal scrollbar */
+ fb_cw->hscroll = fbtk_create_hscroll(fb_cw->wnd,
+ 0,
+ fbtk_get_height(fb_cw->wnd) - furniture_width,
+ fbtk_get_width(fb_cw->wnd) - furniture_width,
+ furniture_width,
+ FB_SCROLL_COLOUR,
+ FB_FRAME_COLOUR,
+ NULL,
+ NULL);
+
+ fb_cw->vscroll = fbtk_create_vscroll(fb_cw->wnd,
+ fbtk_get_width(fb_cw->wnd) - furniture_width,
+ 0,
+ furniture_width,
+ fbtk_get_height(fb_cw->wnd) - furniture_width,
+ FB_SCROLL_COLOUR,
+ FB_FRAME_COLOUR,
+ NULL,
+ NULL);
+
+ fbtk_create_fill(fb_cw->wnd,
+ fbtk_get_width(fb_cw->wnd) - furniture_width,
+ fbtk_get_height(fb_cw->wnd) - furniture_width,
+ furniture_width,
+ furniture_width,
+ FB_FRAME_COLOUR);
+
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in fb/corewindow.h */
+nserror fb_corewindow_fini(struct fb_corewindow *fb_cw)
+{
+ return NSERROR_OK;
+}
diff --git a/frontends/framebuffer/corewindow.h b/frontends/framebuffer/corewindow.h
new file mode 100644
index 000000000..5546c09b6
--- /dev/null
+++ b/frontends/framebuffer/corewindow.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FB_COREWINDOW_H
+#define FB_COREWINDOW_H
+
+#include "netsurf/core_window.h"
+
+/**
+ * fb core window state
+ */
+struct fb_corewindow {
+
+ /**
+ * framebuffer toolkit window.
+ */
+ struct fbtk_widget_s *wnd;
+ /**
+ * framebuffer toolkit horizontal scrollbar.
+ */
+ struct fbtk_widget_s *hscroll;
+ /**
+ * framebuffer toolkit vertical scrollbar.
+ */
+ struct fbtk_widget_s *vscroll;
+ /**
+ * framebuffer toolkit user drawable widget.
+ */
+ struct fbtk_widget_s *drawable;
+
+ int scrollx, scrolly; /**< scroll offsets. */
+
+
+ /** drag status set by core */
+ core_window_drag_status drag_status;
+
+ /** table of callbacks for core window operations */
+ struct core_window_callback_table *cb_table;
+
+ /**
+ * callback to draw on drawable area of fb core window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ nserror (*draw)(struct fb_corewindow *fb_cw, struct rect *r);
+
+ /**
+ * callback for keypress on fb core window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param nskey The netsurf key code.
+ * \return NSERROR_OK if key processed,
+ * NSERROR_NOT_IMPLEMENTED if key not processed
+ * otherwise apropriate error code
+ */
+ nserror (*key)(struct fb_corewindow *fb_cw, uint32_t nskey);
+
+ /**
+ * callback for mouse event on fb core window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param mouse_state mouse state
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on sucess otherwise apropriate error code.
+ */
+ nserror (*mouse)(struct fb_corewindow *fb_cw, browser_mouse_state mouse_state, int x, int y);
+};
+
+
+/**
+ * initialise elements of fb core window.
+ *
+ * As a pre-requisite the draw, key and mouse callbacks must be defined
+ *
+ * \param fb_cw A fb core window structure to initialise
+ * \return NSERROR_OK on successful initialisation otherwise error code.
+ */
+nserror fb_corewindow_init(fbtk_widget_t *parent, struct fb_corewindow *fb_cw);
+
+
+/**
+ * finalise elements of fb core window.
+ *
+ * \param fb_cw A fb core window structure to initialise
+ * \return NSERROR_OK on successful finalisation otherwise error code.
+ */
+nserror fb_corewindow_fini(struct fb_corewindow *fb_cw);
+
+#endif
diff --git a/frontends/framebuffer/fbtk.h b/frontends/framebuffer/fbtk.h
index 3cc326cef..86bdc864b 100644
--- a/frontends/framebuffer/fbtk.h
+++ b/frontends/framebuffer/fbtk.h
@@ -21,12 +21,6 @@
#include "netsurf/types.h"
-#ifdef FBTK_LOGGING
-#define FBTK_LOG(x) LOG(x)
-#else
-#define FBTK_LOG(x)
-#endif
-
#define FB_SCROLL_COLOUR 0xFFAAAAAA
#define FB_FRAME_COLOUR 0xFFDDDDDD
#define FB_COLOUR_BLACK 0xFF000000
diff --git a/frontends/framebuffer/fbtk/event.c b/frontends/framebuffer/fbtk/event.c
index a48e63809..84c6c3791 100644
--- a/frontends/framebuffer/fbtk/event.c
+++ b/frontends/framebuffer/fbtk/event.c
@@ -51,7 +51,7 @@ fbtk_input(fbtk_widget_t *root, nsfb_event_t *event)
/* obtain widget with input focus */
input = root->u.root.input;
if (input == NULL) {
- LOG("No widget has input focus.");
+ NSLOG(netsurf, INFO, "No widget has input focus.");
return; /* no widget with input */
}
@@ -84,7 +84,7 @@ fbtk_click(fbtk_widget_t *widget, nsfb_event_t *event)
x = fbtk_get_absx(clicked);
y = fbtk_get_absy(clicked);
- LOG("clicked %p at %d,%d", clicked, x, y);
+ NSLOG(netsurf, INFO, "clicked %p at %d,%d", clicked, x, y);
/* post the click */
fbtk_post_callback(clicked, FBTK_CBT_CLICK, event, cloc.x0 - x, cloc.y0 - y);
diff --git a/frontends/framebuffer/fbtk/fbtk.c b/frontends/framebuffer/fbtk/fbtk.c
index c63a6d8c9..91f6e2570 100644
--- a/frontends/framebuffer/fbtk/fbtk.c
+++ b/frontends/framebuffer/fbtk/fbtk.c
@@ -53,7 +53,7 @@ dump_tk_tree(fbtk_widget_t *widget)
int indent = 0;
while (widget != NULL) {
- LOG("%*s%p", indent, "", widget);
+ NSLOG(fbtk, DEBUG, "%*s%p", indent, "", widget);
if (widget->first_child != NULL) {
widget = widget->first_child;
indent += 6;
@@ -100,9 +100,13 @@ fbtk_request_redraw(fbtk_widget_t *widget)
widget->redraw.width = widget->width;
widget->redraw.height = widget->height;
-#ifdef FBTK_LOGGING
- LOG("redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget->redraw.y, widget->redraw.width, widget->redraw.height);
-#endif
+ NSLOG(fbtk, DEBUG,
+ "redrawing %p %d,%d %d,%d",
+ widget,
+ widget->redraw.x,
+ widget->redraw.y,
+ widget->redraw.width,
+ widget->redraw.height);
cwidget = widget->last_child;
while (cwidget != NULL) {
@@ -122,7 +126,7 @@ fbtk_request_redraw(fbtk_widget_t *widget)
int
fbtk_set_mapping(fbtk_widget_t *widget, bool map)
{
- LOG("setting mapping on %p to %d", widget, map);
+ NSLOG(netsurf, INFO, "setting mapping on %p to %d", widget, map);
widget->mapped = map;
if (map) {
fbtk_request_redraw(widget);
@@ -132,9 +136,11 @@ fbtk_set_mapping(fbtk_widget_t *widget, bool map)
return 0;
}
-/** swap the widget given with the next sibling.
- *
+
+/**
* Swap a sibling widget with the next deepest in the hierachy
+ *
+ * \param lw The widget to swap
*/
static void
swap_siblings(fbtk_widget_t *lw)
@@ -145,7 +151,7 @@ swap_siblings(fbtk_widget_t *lw)
assert(rw != NULL);
- LOG("Swapping %p with %p", lw, rw);
+ NSLOG(netsurf, INFO, "Swapping %p with %p", lw, rw);
before = lw->prev;
after = rw->next;
@@ -401,7 +407,6 @@ fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi)
}
-
/* internally exported function documented in widget.h */
fbtk_widget_t *
fbtk_get_root_widget(fbtk_widget_t *widget)
@@ -411,7 +416,8 @@ fbtk_get_root_widget(fbtk_widget_t *widget)
/* check root widget was found */
if (widget->type != FB_WIDGET_TYPE_ROOT) {
- LOG("Widget with null parent that is not the root widget!");
+ NSLOG(netsurf, INFO,
+ "Widget with null parent that is not the root widget!");
return NULL;
}
@@ -433,6 +439,7 @@ fbtk_get_absx(fbtk_widget_t *widget)
return x;
}
+
/* exported function documented in fbtk.h */
int
fbtk_get_absy(fbtk_widget_t *widget)
@@ -447,6 +454,7 @@ fbtk_get_absy(fbtk_widget_t *widget)
return y;
}
+
/* exported function documented in fbtk.h */
int
fbtk_get_height(fbtk_widget_t *widget)
@@ -551,9 +559,7 @@ fbtk_widget_new(fbtk_widget_t *parent,
if (neww == NULL)
return NULL;
-#ifdef FBTK_LOGGING
- LOG("creating %p %d,%d %d,%d", neww, x, y, width, height);
-#endif
+ NSLOG(fbtk, DEBUG, "creating %p %d,%d %d,%d", neww, x, y, width, height);
/* make new window fit inside parent */
if (width == 0) {
@@ -574,9 +580,8 @@ fbtk_widget_new(fbtk_widget_t *parent,
height = parent->height - y;
}
-#ifdef FBTK_LOGGING
- LOG("using %p %d,%d %d,%d", neww, x, y, width, height);
-#endif
+ NSLOG(fbtk, DEBUG, "using %p %d,%d %d,%d", neww, x, y, width, height);
+
/* set values */
neww->type = type;
neww->x = x;
@@ -634,9 +639,12 @@ do_redraw(nsfb_t *nsfb, fbtk_widget_t *widget)
plot_ctx.x1 = plot_ctx.x0 + widget->redraw.width;
plot_ctx.y1 = plot_ctx.y0 + widget->redraw.height;
-#ifdef FBTK_LOGGING
- LOG("clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0, plot_ctx.x1, plot_ctx.y1);
-#endif
+ NSLOG(fbtk, DEBUG,
+ "clipping %p %d,%d %d,%d",
+ widget,
+ plot_ctx.x0, plot_ctx.y0,
+ plot_ctx.x1, plot_ctx.y1);
+
if (nsfb_plot_set_clip(nsfb, &plot_ctx) == true) {
fbtk_post_callback(widget, FBTK_CBT_REDRAW);
}
diff --git a/frontends/framebuffer/fbtk/scroll.c b/frontends/framebuffer/fbtk/scroll.c
index cc98fb2dd..b056ac81f 100644
--- a/frontends/framebuffer/fbtk/scroll.c
+++ b/frontends/framebuffer/fbtk/scroll.c
@@ -334,7 +334,7 @@ hscroll_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
hpos = 0;
}
- LOG("hscroll %d", hscroll);
+ NSLOG(netsurf, INFO, "hscroll %d", hscroll);
rect.x0 = bbox.x0 + 3 + hpos;
rect.y0 = bbox.y0 + 5;
@@ -362,7 +362,7 @@ hscrolll_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
newpos = scrollw->u.scroll.minimum;
if (newpos == scrollw->u.scroll.position) {
- LOG("horiz scroll was the same %d", newpos);
+ NSLOG(netsurf, INFO, "horiz scroll was the same %d", newpos);
return 0;
}
diff --git a/frontends/framebuffer/fbtk/text.c b/frontends/framebuffer/fbtk/text.c
index 00dcba491..9c96dcef4 100644
--- a/frontends/framebuffer/fbtk/text.c
+++ b/frontends/framebuffer/fbtk/text.c
@@ -71,7 +71,7 @@ fb_text_font_style(fbtk_widget_t *widget, int *font_height, int *padding,
#endif
font_style->family = PLOT_FONT_FAMILY_SANS_SERIF;
- font_style->size = px_to_pt(*font_height * FONT_SIZE_SCALE);
+ font_style->size = px_to_pt(*font_height * PLOT_STYLE_SCALE);
font_style->weight = 400;
font_style->flags = FONTF_NONE;
font_style->background = widget->bg;
@@ -98,6 +98,11 @@ fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi )
int padding;
int scroll = 0;
bool caret = false;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &fb_plotters
+ };
fb_text_font_style(widget, &fh, &padding, &font_style);
@@ -142,8 +147,11 @@ fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi )
}
/* Call the fb text plotting, baseline is 3/4 down the font */
- fb_plotters.text(x, y, widget->u.text.text,
- widget->u.text.len, &font_style);
+ ctx.plot->text(&ctx,
+ &font_style,
+ x, y,
+ widget->u.text.text,
+ widget->u.text.len);
}
if (caret) {
@@ -209,6 +217,11 @@ fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi )
int fh;
int border;
fbtk_widget_t *root = fbtk_get_root_widget(widget);
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &fb_plotters
+ };
fb_text_font_style(widget, &fh, &border, &font_style);
@@ -256,11 +269,12 @@ fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi )
if (widget->u.text.text != NULL) {
/* Call the fb text plotting, baseline is 3/4 down the font */
- fb_plotters.text(bbox.x0 + border,
- bbox.y0 + ((fh * 3) / 4) + border,
- widget->u.text.text,
- widget->u.text.len,
- &font_style);
+ ctx.plot->text(&ctx,
+ &font_style,
+ bbox.x0 + border,
+ bbox.y0 + ((fh * 3) / 4) + border,
+ widget->u.text.text,
+ widget->u.text.len);
}
nsfb_update(root->u.root.fb, &bbox);
@@ -374,6 +388,22 @@ text_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
}
break;
+ case NSFB_KEY_HOME:
+ if (widget->u.text.idx > 0) {
+ widget->u.text.idx = 0;
+
+ caret_moved = true;
+ }
+ break;
+
+ case NSFB_KEY_END:
+ if (widget->u.text.idx < widget->u.text.len) {
+ widget->u.text.idx = widget->u.text.len;
+
+ caret_moved = true;
+ }
+ break;
+
case NSFB_KEY_PAGEUP:
case NSFB_KEY_PAGEDOWN:
case NSFB_KEY_UP:
diff --git a/frontends/framebuffer/fetch.c b/frontends/framebuffer/fetch.c
index 801b87a74..23cbb4f21 100644
--- a/frontends/framebuffer/fetch.c
+++ b/frontends/framebuffer/fetch.c
@@ -65,7 +65,7 @@ static nsurl *get_resource_url(const char *path)
static const char *fetch_filetype(const char *unix_path)
{
int l;
- LOG("unix path %s", unix_path);
+ NSLOG(netsurf, INFO, "unix path %s", unix_path);
l = strlen(unix_path);
if (2 < l && strcasecmp(unix_path + l - 3, "css") == 0)
return "text/css";
diff --git a/frontends/framebuffer/font_freetype.c b/frontends/framebuffer/font_freetype.c
index e7c07f5ff..744ac6281 100644
--- a/frontends/framebuffer/font_freetype.c
+++ b/frontends/framebuffer/font_freetype.c
@@ -90,12 +90,13 @@ ft_face_requester(FTC_FaceID face_id,
error = FT_New_Face(library, fb_face->fontfile, fb_face->index, face);
if (error) {
- LOG("Could not find font (code %d)", error);
+ NSLOG(netsurf, INFO, "Could not find font (code %d)", error);
} else {
error = FT_Select_Charmap(*face, FT_ENCODING_UNICODE);
if (error) {
- LOG("Could not select charmap (code %d)", error);
+ NSLOG(netsurf, INFO,
+ "Could not select charmap (code %d)", error);
} else {
for (cidx = 0; cidx < (*face)->num_charmaps; cidx++) {
if ((*face)->charmap == (*face)->charmaps[cidx]) {
@@ -105,7 +106,7 @@ ft_face_requester(FTC_FaceID face_id,
}
}
}
- LOG("Loaded face from %s", fb_face->fontfile);
+ NSLOG(netsurf, INFO, "Loaded face from %s", fb_face->fontfile);
return error;
}
@@ -132,7 +133,8 @@ fb_new_face(const char *option, const char *resname, const char *fontname)
error = FTC_Manager_LookupFace(ft_cmanager, (FTC_FaceID)newf, &aface);
if (error) {
- LOG("Could not find font face %s (code %d)", fontname, error);
+ NSLOG(netsurf, INFO, "Could not find font face %s (code %d)",
+ fontname, error);
free(newf->fontfile);
free(newf);
newf = NULL;
@@ -152,7 +154,8 @@ bool fb_font_init(void)
/* freetype library initialise */
error = FT_Init_FreeType( &library );
if (error) {
- LOG("Freetype could not initialised (code %d)", error);
+ NSLOG(netsurf, INFO,
+ "Freetype could not initialised (code %d)", error);
return false;
}
@@ -172,7 +175,9 @@ bool fb_font_init(void)
NULL,
&ft_cmanager);
if (error) {
- LOG("Freetype could not initialise cache manager (code %d)", error);
+ NSLOG(netsurf, INFO,
+ "Freetype could not initialise cache manager (code %d)",
+ error);
FT_Done_FreeType(library);
return false;
}
@@ -189,7 +194,7 @@ bool fb_font_init(void)
NETSURF_FB_FONT_SANS_SERIF);
if (fb_face == NULL) {
/* The sans serif font is the default and must be found. */
- LOG("Could not find the default font");
+ NSLOG(netsurf, INFO, "Could not find the default font");
FTC_Manager_Done(ft_cmanager);
FT_Done_FreeType(library);
return false;
@@ -387,7 +392,7 @@ static void fb_fill_scalar(const plot_font_style_t *fstyle, FTC_Scaler srec)
srec->face_id = (FTC_FaceID)fb_faces[selected_face];
- srec->width = srec->height = (fstyle->size * 64) / FONT_SIZE_SCALE;
+ srec->width = srec->height = (fstyle->size * 64) / PLOT_STYLE_SCALE;
srec->pixel = 0;
srec->x_res = srec->y_res = browser_get_dpi();
diff --git a/frontends/framebuffer/font_internal.c b/frontends/framebuffer/font_internal.c
index 3b8a1c43f..d755681c6 100644
--- a/frontends/framebuffer/font_internal.c
+++ b/frontends/framebuffer/font_internal.c
@@ -212,7 +212,7 @@ fb_get_font_size(const plot_font_style_t *fstyle)
{
int size = fstyle->size * 10 /
(((nsoption_int(font_min_size) * 3 +
- nsoption_int(font_size)) / 4) * FONT_SIZE_SCALE);
+ nsoption_int(font_size)) / 4) * PLOT_STYLE_SCALE);
if (size > 2)
size = 2;
else if (size <= 0)
@@ -270,6 +270,7 @@ fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
break;
}
}
+ /* Fall through. */
case FB_BOLD:
section = fb_bold_section_table[ucs4 / 256];
if (section != 0 || ucs4 / 256 == 0) {
@@ -280,6 +281,7 @@ fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
break;
}
}
+ /* Fall through. */
case FB_ITALIC:
section = fb_italic_section_table[ucs4 / 256];
if (section != 0 || ucs4 / 256 == 0) {
@@ -290,6 +292,7 @@ fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
break;
}
}
+ /* Fall through. */
case FB_REGULAR:
section = fb_regular_section_table[ucs4 / 256];
if (section != 0 || ucs4 / 256 == 0) {
@@ -300,6 +303,7 @@ fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
break;
}
}
+ /* Fall through. */
default:
glyph_data = get_codepoint(ucs4, style & FB_ITALIC);
break;
diff --git a/frontends/framebuffer/framebuffer.c b/frontends/framebuffer/framebuffer.c
index 74c72fe71..52afdbf5d 100644
--- a/frontends/framebuffer/framebuffer.c
+++ b/frontends/framebuffer/framebuffer.c
@@ -45,139 +45,274 @@
static nsfb_t *nsfb;
-static bool
-framebuffer_plot_disc(int x, int y, int radius, const plot_style_t *style)
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
{
- nsfb_bbox_t ellipse;
- ellipse.x0 = x - radius;
- ellipse.y0 = y - radius;
- ellipse.x1 = x + radius;
- ellipse.y1 = y + radius;
-
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- nsfb_plot_ellipse_fill(nsfb, &ellipse, style->fill_colour);
- }
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- nsfb_plot_ellipse(nsfb, &ellipse, style->stroke_colour);
- }
- return true;
+ nsfb_bbox_t nsfb_clip;
+ nsfb_clip.x0 = clip->x0;
+ nsfb_clip.y0 = clip->y0;
+ nsfb_clip.x1 = clip->x1;
+ nsfb_clip.y1 = clip->y1;
+
+ if (!nsfb_plot_set_clip(nsfb, &nsfb_clip)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
-static bool
-framebuffer_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
- return nsfb_plot_arc(nsfb, x, y, radius, angle1, angle2, style->fill_colour);
+ if (!nsfb_plot_arc(nsfb, x, y, radius, angle1, angle2, style->fill_colour)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
-static bool
-framebuffer_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
{
- return nsfb_plot_polygon(nsfb, p, n, style->fill_colour);
+ nsfb_bbox_t ellipse;
+ ellipse.x0 = x - radius;
+ ellipse.y0 = y - radius;
+ ellipse.x1 = x + radius;
+ ellipse.y1 = y + radius;
+
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ nsfb_plot_ellipse_fill(nsfb, &ellipse, style->fill_colour);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsfb_plot_ellipse(nsfb, &ellipse, style->stroke_colour);
+ }
+ return NSERROR_OK;
}
-#ifdef FB_USE_FREETYPE
-static bool
-framebuffer_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
- uint32_t ucs4;
- size_t nxtchr = 0;
- FT_Glyph glyph;
- FT_BitmapGlyph bglyph;
- nsfb_bbox_t loc;
-
- while (nxtchr < length) {
- ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
- nxtchr = utf8_next(text, length, nxtchr);
-
- glyph = fb_getglyph(fstyle, ucs4);
- if (glyph == NULL)
- continue;
-
- if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
- bglyph = (FT_BitmapGlyph)glyph;
-
- loc.x0 = x + bglyph->left;
- loc.y0 = y - bglyph->top;
- loc.x1 = loc.x0 + bglyph->bitmap.width;
- loc.y1 = loc.y0 + bglyph->bitmap.rows;
-
- /* now, draw to our target surface */
- if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
- nsfb_plot_glyph1(nsfb,
- &loc,
- bglyph->bitmap.buffer,
- bglyph->bitmap.pitch,
- fstyle->foreground);
- } else {
- nsfb_plot_glyph8(nsfb,
- &loc,
- bglyph->bitmap.buffer,
- bglyph->bitmap.pitch,
- fstyle->foreground);
- }
- }
- x += glyph->advance.x >> 16;
-
- }
- return true;
+ nsfb_bbox_t rect;
+ nsfb_plot_pen_t pen;
+
+ rect.x0 = line->x0;
+ rect.y0 = line->y0;
+ rect.x1 = line->x1;
+ rect.y1 = line->y1;
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+
+ if (style->stroke_type == PLOT_OP_TYPE_DOT) {
+ pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
+ pen.stroke_pattern = 0xAAAAAAAA;
+ } else if (style->stroke_type == PLOT_OP_TYPE_DASH) {
+ pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
+ pen.stroke_pattern = 0xF0F0F0F0;
+ } else {
+ pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
+ }
+
+ pen.stroke_colour = style->stroke_colour;
+ pen.stroke_width = plot_style_fixed_to_int(style->stroke_width);
+ nsfb_plot_line(nsfb, &rect, &pen);
+ }
+ return NSERROR_OK;
}
-#else
-static bool framebuffer_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param nsrect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *nsrect)
{
- enum fb_font_style style = fb_get_font_style(fstyle);
- int size = fb_get_font_size(fstyle);
- const uint8_t *chrp;
- size_t nxtchr = 0;
- nsfb_bbox_t loc;
- uint32_t ucs4;
- int p = FB_FONT_PITCH * size;
- int w = FB_FONT_WIDTH * size;
- int h = FB_FONT_HEIGHT * size;
+ nsfb_bbox_t rect;
+ bool dotted = false;
+ bool dashed = false;
- y -= ((h * 3) / 4);
- /* the coord is the bottom-left of the pixels offset by 1 to make
- * it work since fb coords are the top-left of pixels */
- y += 1;
+ rect.x0 = nsrect->x0;
+ rect.y0 = nsrect->y0;
+ rect.x1 = nsrect->x1;
+ rect.y1 = nsrect->y1;
- while (nxtchr < length) {
- ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
- nxtchr = utf8_next(text, length, nxtchr);
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ nsfb_plot_rectangle_fill(nsfb, &rect, style->fill_colour);
+ }
- if (!codepoint_displayable(ucs4))
- continue;
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ if (style->stroke_type == PLOT_OP_TYPE_DOT) {
+ dotted = true;
+ }
- loc.x0 = x;
- loc.y0 = y;
- loc.x1 = loc.x0 + w;
- loc.y1 = loc.y0 + h;
+ if (style->stroke_type == PLOT_OP_TYPE_DASH) {
+ dashed = true;
+ }
- chrp = fb_get_glyph(ucs4, style, size);
- nsfb_plot_glyph1(nsfb, &loc, chrp, p, fstyle->foreground);
+ nsfb_plot_rectangle(nsfb, &rect,
+ plot_style_fixed_to_int(style->stroke_width),
+ style->stroke_colour, dotted, dashed);
+ }
+ return NSERROR_OK;
+}
- x += w;
- }
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
+{
+ if (!nsfb_plot_polygon(nsfb, p, n, style->fill_colour)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
+}
- return true;
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
+{
+ NSLOG(netsurf, INFO, "path unimplemented");
+ return NSERROR_OK;
}
-#endif
-static bool
-framebuffer_plot_bitmap(int x, int y,
- int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
- nsfb_bbox_t loc;
- nsfb_bbox_t clipbox;
- bool repeat_x = (flags & BITMAPF_REPEAT_X);
- bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+ nsfb_bbox_t loc;
+ nsfb_bbox_t clipbox;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
int bmwidth;
int bmheight;
int bmstride;
@@ -193,15 +328,18 @@ framebuffer_plot_bitmap(int x, int y,
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just plot it */
- loc.x0 = x;
- loc.y0 = y;
- loc.x1 = loc.x0 + width;
- loc.y1 = loc.y0 + height;
+ loc.x0 = x;
+ loc.y0 = y;
+ loc.x1 = loc.x0 + width;
+ loc.y1 = loc.y0 + height;
- return nsfb_plot_copy(bm, NULL, nsfb, &loc);
+ if (!nsfb_plot_copy(bm, NULL, nsfb, &loc)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
- nsfb_plot_get_clip(nsfb, &clipbox);
+ nsfb_plot_get_clip(nsfb, &clipbox);
nsfb_get_geometry(bm, &bmwidth, &bmheight, &bmformat);
nsfb_get_buffer(bm, &bmptr, &bmstride);
@@ -209,8 +347,11 @@ framebuffer_plot_bitmap(int x, int y,
* of the area. Can only be done when image is fully opaque. */
if ((bmwidth == 1) && (bmheight == 1)) {
if ((*(nsfb_colour_t *)bmptr & 0xff000000) != 0) {
- return nsfb_plot_rectangle_fill(nsfb, &clipbox,
- *(nsfb_colour_t *)bmptr);
+ if (!nsfb_plot_rectangle_fill(nsfb, &clipbox,
+ *(nsfb_colour_t *)bmptr)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
}
@@ -221,24 +362,29 @@ framebuffer_plot_bitmap(int x, int y,
if (framebuffer_bitmap_get_opaque(bm)) {
/** TODO: Currently using top left pixel. Maybe centre
* pixel or average value would be better. */
- return nsfb_plot_rectangle_fill(nsfb, &clipbox,
- *(nsfb_colour_t *)bmptr);
+ if (!nsfb_plot_rectangle_fill(nsfb, &clipbox,
+ *(nsfb_colour_t *)bmptr)) {
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
}
/* get left most tile position */
- if (repeat_x)
+ if (repeat_x) {
for (; x > clipbox.x0; x -= width);
+ }
/* get top most tile position */
- if (repeat_y)
+ if (repeat_y) {
for (; y > clipbox.y0; y -= height);
+ }
/* set up top left tile location */
- loc.x0 = x;
- loc.y0 = y;
- loc.x1 = loc.x0 + width;
- loc.y1 = loc.y0 + height;
+ loc.x0 = x;
+ loc.y0 = y;
+ loc.x1 = loc.x0 + width;
+ loc.y1 = loc.y0 + height;
/* plot tiling across and down to extents */
nsfb_plot_bitmap_tiles(nsfb, &loc,
@@ -247,94 +393,135 @@ framebuffer_plot_bitmap(int x, int y,
(nsfb_colour_t *)bmptr, bmwidth, bmheight,
bmstride * 8 / 32, bmformat == NSFB_FMT_ABGR8888);
- return true;
+ return NSERROR_OK;
}
-static bool
-framebuffer_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- nsfb_bbox_t rect;
- bool dotted = false;
- bool dashed = false;
-
- rect.x0 = x0;
- rect.y0 = y0;
- rect.x1 = x1;
- rect.y1 = y1;
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- nsfb_plot_rectangle_fill(nsfb, &rect, style->fill_colour);
- }
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- if (style->stroke_type == PLOT_OP_TYPE_DOT)
- dotted = true;
-
- if (style->stroke_type == PLOT_OP_TYPE_DASH)
- dashed = true;
+#ifdef FB_USE_FREETYPE
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
+{
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bglyph;
+ nsfb_bbox_t loc;
+
+ while (nxtchr < length) {
+ ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(text, length, nxtchr);
+
+ glyph = fb_getglyph(fstyle, ucs4);
+ if (glyph == NULL)
+ continue;
+
+ if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+ bglyph = (FT_BitmapGlyph)glyph;
+
+ loc.x0 = x + bglyph->left;
+ loc.y0 = y - bglyph->top;
+ loc.x1 = loc.x0 + bglyph->bitmap.width;
+ loc.y1 = loc.y0 + bglyph->bitmap.rows;
+
+ /* now, draw to our target surface */
+ if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+ nsfb_plot_glyph1(nsfb,
+ &loc,
+ bglyph->bitmap.buffer,
+ bglyph->bitmap.pitch,
+ fstyle->foreground);
+ } else {
+ nsfb_plot_glyph8(nsfb,
+ &loc,
+ bglyph->bitmap.buffer,
+ bglyph->bitmap.pitch,
+ fstyle->foreground);
+ }
+ }
+ x += glyph->advance.x >> 16;
- nsfb_plot_rectangle(nsfb, &rect, style->stroke_width, style->stroke_colour, dotted, dashed);
}
+ return NSERROR_OK;
- return true;
}
-static bool
-framebuffer_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+#else
+
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+framebuffer_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- nsfb_bbox_t rect;
- nsfb_plot_pen_t pen;
+ enum fb_font_style style = fb_get_font_style(fstyle);
+ int size = fb_get_font_size(fstyle);
+ const uint8_t *chrp;
+ size_t nxtchr = 0;
+ nsfb_bbox_t loc;
+ uint32_t ucs4;
+ int p = FB_FONT_PITCH * size;
+ int w = FB_FONT_WIDTH * size;
+ int h = FB_FONT_HEIGHT * size;
- rect.x0 = x0;
- rect.y0 = y0;
- rect.x1 = x1;
- rect.y1 = y1;
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ y -= ((h * 3) / 4);
+ /* the coord is the bottom-left of the pixels offset by 1 to make
+ * it work since fb coords are the top-left of pixels */
+ y += 1;
- if (style->stroke_type == PLOT_OP_TYPE_DOT) {
- pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
- pen.stroke_pattern = 0xAAAAAAAA;
- } else if (style->stroke_type == PLOT_OP_TYPE_DASH) {
- pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
- pen.stroke_pattern = 0xF0F0F0F0;
- } else {
- pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
- }
+ while (nxtchr < length) {
+ ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(text, length, nxtchr);
- pen.stroke_colour = style->stroke_colour;
- pen.stroke_width = style->stroke_width;
- nsfb_plot_line(nsfb, &rect, &pen);
- }
+ if (!codepoint_displayable(ucs4))
+ continue;
- return true;
-}
+ loc.x0 = x;
+ loc.y0 = y;
+ loc.x1 = loc.x0 + w;
+ loc.y1 = loc.y0 + h;
+ chrp = fb_get_glyph(ucs4, style, size);
+ nsfb_plot_glyph1(nsfb, &loc, chrp, p, fstyle->foreground);
-static bool
-framebuffer_plot_path(const float *p,
- unsigned int n,
- colour fill,
- float width,
- colour c,
- const float transform[6])
-{
- LOG("path unimplemented");
- return true;
-}
+ x += w;
-static bool
-framebuffer_plot_clip(const struct rect *clip)
-{
- nsfb_bbox_t nsfb_clip;
- nsfb_clip.x0 = clip->x0;
- nsfb_clip.y0 = clip->y0;
- nsfb_clip.x1 = clip->x1;
- nsfb_clip.y1 = clip->y1;
+ }
- return nsfb_plot_set_clip(nsfb, &nsfb_clip);
+ return NSERROR_OK;
}
+#endif
+
+/** framebuffer plot operation table */
const struct plotter_table fb_plotters = {
.clip = framebuffer_plot_clip,
.arc = framebuffer_plot_arc,
@@ -345,7 +532,7 @@ const struct plotter_table fb_plotters = {
.path = framebuffer_plot_path,
.bitmap = framebuffer_plot_bitmap,
.text = framebuffer_plot_text,
- .option_knockout = true,
+ .option_knockout = true,
};
@@ -377,7 +564,7 @@ static bool framebuffer_format_from_bpp(int bpp, enum nsfb_format_e *fmt)
break;
default:
- LOG("Bad bits per pixel (%d)\n", bpp);
+ NSLOG(netsurf, INFO, "Bad bits per pixel (%d)\n", bpp);
return false;
}
@@ -394,33 +581,34 @@ framebuffer_initialise(const char *fename, int width, int height, int bpp)
/* bpp is a proxy for the framebuffer format */
if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) {
- return NULL;
+ return NULL;
}
fbtype = nsfb_type_from_name(fename);
if (fbtype == NSFB_SURFACE_NONE) {
- LOG("The %s surface is not available from libnsfb\n", fename);
- return NULL;
+ NSLOG(netsurf, INFO,
+ "The %s surface is not available from libnsfb\n", fename);
+ return NULL;
}
nsfb = nsfb_new(fbtype);
if (nsfb == NULL) {
- LOG("Unable to create %s fb surface\n", fename);
- return NULL;
+ NSLOG(netsurf, INFO, "Unable to create %s fb surface\n", fename);
+ return NULL;
}
-
+
if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) {
- LOG("Unable to set surface geometry\n");
- nsfb_free(nsfb);
- return NULL;
+ NSLOG(netsurf, INFO, "Unable to set surface geometry\n");
+ nsfb_free(nsfb);
+ return NULL;
}
nsfb_cursor_init(nsfb);
-
+
if (nsfb_init(nsfb) == -1) {
- LOG("Unable to initialise nsfb surface\n");
- nsfb_free(nsfb);
- return NULL;
+ NSLOG(netsurf, INFO, "Unable to initialise nsfb surface\n");
+ nsfb_free(nsfb);
+ return NULL;
}
return nsfb;
@@ -434,12 +622,12 @@ framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp)
/* bpp is a proxy for the framebuffer format */
if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) {
- return false;
+ return false;
}
if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) {
- LOG("Unable to change surface geometry\n");
- return false;
+ NSLOG(netsurf, INFO, "Unable to change surface geometry\n");
+ return false;
}
return true;
@@ -449,14 +637,14 @@ framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp)
void
framebuffer_finalise(void)
{
- nsfb_free(nsfb);
+ nsfb_free(nsfb);
}
bool
framebuffer_set_cursor(struct fbtk_bitmap *bm)
{
return nsfb_cursor_set(nsfb, (nsfb_colour_t *)bm->pixdata, bm->width, bm->height, bm->width, bm->hot_x, bm->hot_y);
-}
+}
nsfb_t *framebuffer_set_surface(nsfb_t *new_nsfb)
{
diff --git a/frontends/framebuffer/gui.c b/frontends/framebuffer/gui.c
index 4d4c7334f..1e27dafb6 100644
--- a/frontends/framebuffer/gui.c
+++ b/frontends/framebuffer/gui.c
@@ -54,6 +54,7 @@
#include "framebuffer/clipboard.h"
#include "framebuffer/fetch.h"
#include "framebuffer/bitmap.h"
+#include "framebuffer/local_history.h"
#define NSFB_TOOLBAR_DEFAULT_LAYOUT "blfsrutc"
@@ -119,7 +120,7 @@ static void die(const char *error)
*/
static nserror fb_warn_user(const char *warning, const char *detail)
{
- LOG("%s %s", warning, detail);
+ NSLOG(netsurf, INFO, "%s %s", warning, detail);
return NSERROR_OK;
}
@@ -152,7 +153,7 @@ widget_scroll_y(struct gui_window *gw, int y, bool abs)
int content_width, content_height;
int height;
- LOG("window scroll");
+ NSLOG(netsurf, INFO, "window scroll");
if (abs) {
bwidget->pany = y - bwidget->scrolly;
} else {
@@ -236,7 +237,7 @@ fb_pan(fbtk_widget_t *widget,
height = fbtk_get_height(widget);
width = fbtk_get_width(widget);
- LOG("panning %d, %d", bwidget->panx, bwidget->pany);
+ NSLOG(netsurf, INFO, "panning %d, %d", bwidget->panx, bwidget->pany);
x = fbtk_get_absx(widget);
y = fbtk_get_absy(widget);
@@ -412,7 +413,8 @@ fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
bwidget = fbtk_get_userpw(widget);
if (bwidget == NULL) {
- LOG("browser widget from widget %p was null", widget);
+ NSLOG(netsurf, INFO,
+ "browser widget from widget %p was null", widget);
return -1;
}
@@ -464,7 +466,7 @@ process_cmdline(int argc, char** argv)
{0, 0, 0, 0 }
}; /* no long options */
- LOG("argc %d, argv %p", argc, argv);
+ NSLOG(netsurf, INFO, "argc %d, argv %p", argc, argv);
fename = "sdl";
febpp = 32;
@@ -533,7 +535,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
if (nsoption_charp(cookie_file) == NULL ||
nsoption_charp(cookie_jar) == NULL) {
- LOG("Failed initialising cookie options");
+ NSLOG(netsurf, INFO, "Failed initialising cookie options");
return NSERROR_BAD_PARAMETER;
}
@@ -611,7 +613,7 @@ static void framebuffer_run(void)
static void gui_quit(void)
{
- LOG("gui_quit");
+ NSLOG(netsurf, INFO, "gui_quit");
urldb_save_cookies(nsoption_charp(cookie_jar));
@@ -638,7 +640,8 @@ fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
- LOG("browser window clicked at %d,%d", cbi->x, cbi->y);
+ NSLOG(netsurf, INFO, "browser window clicked at %d,%d", cbi->x,
+ cbi->y);
switch (cbi->event->type) {
case NSFB_EVENT_KEY_DOWN:
@@ -823,7 +826,7 @@ fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
int ucs4 = -1;
- LOG("got value %d", cbi->event->value.keycode);
+ NSLOG(netsurf, INFO, "got value %d", cbi->event->value.keycode);
switch (cbi->event->type) {
case NSFB_EVENT_KEY_DOWN:
@@ -948,8 +951,8 @@ fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
browser_window_key_press(gw->bw, NS_KEY_REDO);
break;
}
- /* Z or Y pressed but not undo or redo;
- * Fall through to default handling */
+ /* Z or Y pressed but not undo or redo; */
+ /* Fall through */
default:
ucs4 = fbtk_keycode_to_ucs4(cbi->event->value.keycode,
@@ -1150,7 +1153,7 @@ fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi)
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
- fb_localhistory_map(gw->localhistory);
+ fb_local_history_present(fbtk, gw->bw);
return 0;
}
@@ -1199,7 +1202,7 @@ create_toolbar(struct gui_window *gw,
toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT;
}
- LOG("Using toolbar layout %s", toolbar_layout);
+ NSLOG(netsurf, INFO, "Using toolbar layout %s", toolbar_layout);
itmtype = toolbar_layout;
@@ -1233,7 +1236,7 @@ create_toolbar(struct gui_window *gw,
(*itmtype != 0) &&
(xdir !=0)) {
- LOG("toolbar adding %c", *itmtype);
+ NSLOG(netsurf, INFO, "toolbar adding %c", *itmtype);
switch (*itmtype) {
@@ -1375,7 +1378,9 @@ create_toolbar(struct gui_window *gw,
default:
widget = NULL;
xdir = 0;
- LOG("Unknown element %c in toolbar layout", *itmtype);
+ NSLOG(netsurf, INFO,
+ "Unknown element %c in toolbar layout",
+ *itmtype);
break;
}
@@ -1384,7 +1389,7 @@ create_toolbar(struct gui_window *gw,
xpos += (xdir * (fbtk_get_width(widget) + padding));
}
- LOG("xpos is %d", xpos);
+ NSLOG(netsurf, INFO, "xpos is %d", xpos);
itmtype += xdir;
}
@@ -1583,7 +1588,7 @@ resize_browser_widget(struct gui_window *gw, int x, int y,
int width, int height)
{
fbtk_set_pos_and_size(gw->browser, x, y, width, height);
- browser_window_reformat(gw->bw, false, width, height);
+ browser_window_schedule_reformat(gw->bw);
}
static void
@@ -1594,7 +1599,7 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width)
int statusbar_width = 0;
int toolbar_height = nsoption_int(fb_toolbar_size);
- LOG("Normal window");
+ NSLOG(netsurf, INFO, "Normal window");
gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
@@ -1625,7 +1630,8 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width)
false);
fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
- LOG("status bar %p at %d,%d", gw->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->status));
+ NSLOG(netsurf, INFO, "status bar %p at %d,%d", gw->status,
+ fbtk_get_absx(gw->status), fbtk_get_absy(gw->status));
/* create horizontal scrollbar */
gw->hscroll = fbtk_create_hscroll(gw->window,
@@ -1782,7 +1788,6 @@ gui_window_create(struct browser_window *bw,
gw->bw = bw;
create_normal_browser_window(gw, nsoption_int(fb_furniture_size));
- gw->localhistory = fb_create_localhistory(bw, fbtk, nsoption_int(fb_furniture_size));
/* map and request redraw of gui window */
fbtk_set_mapping(gw->window, true);
@@ -1803,21 +1808,33 @@ gui_window_destroy(struct gui_window *gw)
free(gw);
}
-static void
-gui_window_redraw_window(struct gui_window *g)
-{
- fb_queue_redraw(g->browser, 0, 0, fbtk_get_width(g->browser), fbtk_get_height(g->browser) );
-}
-static void
-gui_window_update_box(struct gui_window *g, const struct rect *rect)
+/**
+ * Invalidates an area of a framebuffer browser window
+ *
+ * \param g The netsurf window being invalidated.
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
+ */
+static nserror
+fb_window_invalidate_area(struct gui_window *g, const struct rect *rect)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
- fb_queue_redraw(g->browser,
- rect->x0 - bwidget->scrollx,
- rect->y0 - bwidget->scrolly,
- rect->x1 - bwidget->scrollx,
- rect->y1 - bwidget->scrolly);
+
+ if (rect != NULL) {
+ fb_queue_redraw(g->browser,
+ rect->x0 - bwidget->scrollx,
+ rect->y0 - bwidget->scrolly,
+ rect->x1 - bwidget->scrollx,
+ rect->y1 - bwidget->scrolly);
+ } else {
+ fb_queue_redraw(g->browser,
+ 0,
+ 0,
+ fbtk_get_width(g->browser),
+ fbtk_get_height(g->browser));
+ }
+ return NSERROR_OK;
}
static bool
@@ -1832,34 +1849,56 @@ gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
return true;
}
-static void
-gui_window_set_scroll(struct gui_window *gw, int sx, int sy)
+/**
+ * Set the scroll position of a framebuffer browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The framebuffer implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param gw gui_window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *gw, const struct rect *rect)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
float scale = browser_window_get_scale(gw->bw);
assert(bwidget);
- widget_scroll_x(gw, sx * scale, true);
- widget_scroll_y(gw, sy * scale, true);
+ widget_scroll_x(gw, rect->x0 * scale, true);
+ widget_scroll_y(gw, rect->y0 * scale, true);
+
+ return NSERROR_OK;
}
-static void
-gui_window_get_dimensions(struct gui_window *g,
+/**
+ * Find the current dimensions of a framebuffer browser window content area.
+ *
+ * \param gw The gui window to measure content area of.
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated.
+ */
+static nserror
+gui_window_get_dimensions(struct gui_window *gw,
int *width,
int *height,
bool scaled)
{
- float scale = browser_window_get_scale(g->bw);
-
- *width = fbtk_get_width(g->browser);
- *height = fbtk_get_height(g->browser);
+ *width = fbtk_get_width(gw->browser);
+ *height = fbtk_get_height(gw->browser);
if (scaled) {
+ float scale = browser_window_get_scale(gw->bw);
*width /= scale;
*height /= scale;
}
+ return NSERROR_OK;
}
static void
@@ -2038,26 +2077,15 @@ gui_window_remove_caret(struct gui_window *g)
}
}
-static void framebuffer_window_reformat(struct gui_window *gw)
-{
- /** @todo if we ever do zooming reformat should be implemented */
- LOG("window:%p", gw);
-
- /*
- browser_window_reformat(gw->bw, false, width, height);
- */
-}
static struct gui_window_table framebuffer_window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
+ .invalidate = fb_window_invalidate_area,
.get_scroll = gui_window_get_scroll,
.set_scroll = gui_window_set_scroll,
.get_dimensions = gui_window_get_dimensions,
.update_extent = gui_window_update_extent,
- .reformat = framebuffer_window_reformat,
.set_url = gui_window_set_url,
.set_status = gui_window_set_status,
@@ -2160,7 +2188,7 @@ main(int argc, char** argv)
/* create an initial browser window */
- LOG("calling browser_window_create");
+ NSLOG(netsurf, INFO, "calling browser_window_create");
ret = nsurl_create(feurl, &url);
if (ret == NSERROR_OK) {
@@ -2182,11 +2210,14 @@ main(int argc, char** argv)
netsurf_exit();
if (fb_font_finalise() == false)
- LOG("Font finalisation failed.");
+ NSLOG(netsurf, INFO, "Font finalisation failed.");
/* finalise options */
nsoption_finalise(nsoptions, nsoptions_default);
+ /* finalise logging */
+ nslog_finalise();
+
return 0;
}
diff --git a/frontends/framebuffer/gui.h b/frontends/framebuffer/gui.h
index 0de1add69..abb27c4bb 100644
--- a/frontends/framebuffer/gui.h
+++ b/frontends/framebuffer/gui.h
@@ -27,17 +27,6 @@ typedef struct fb_cursor_s fb_cursor_t;
/* bounding box */
typedef struct nsfb_bbox_s bbox_t;
-struct gui_localhistory {
- struct browser_window *bw;
-
- struct fbtk_widget_s *window;
- struct fbtk_widget_s *hscroll;
- struct fbtk_widget_s *vscroll;
- struct fbtk_widget_s *history;
-
- int scrollx, scrolly; /**< scroll offsets. */
-};
-
struct gui_window {
struct browser_window *bw;
@@ -59,8 +48,6 @@ struct gui_window {
int throbber_index;
- struct gui_localhistory *localhistory;
-
struct gui_window *next;
struct gui_window *prev;
};
@@ -68,13 +55,8 @@ struct gui_window {
extern struct gui_window *window_list;
-struct gui_localhistory *fb_create_localhistory(struct browser_window *bw,
- struct fbtk_widget_s *parent, int furniture_width);
-void fb_localhistory_map(struct gui_localhistory * glh);
-
void gui_resize(struct fbtk_widget_s *root, int width, int height);
-
#endif /* NETSURF_FB_GUI_H */
/*
diff --git a/frontends/framebuffer/local_history.c b/frontends/framebuffer/local_history.c
new file mode 100644
index 000000000..cc45b1f29
--- /dev/null
+++ b/frontends/framebuffer/local_history.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of framebuffer local history manager.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_event.h>
+
+#include "utils/log.h"
+#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
+#include "desktop/local_history.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/framebuffer.h"
+#include "framebuffer/corewindow.h"
+#include "framebuffer/local_history.h"
+
+struct fb_local_history_window {
+ struct fb_corewindow core;
+
+ struct local_history_session *session;
+};
+
+static struct fb_local_history_window *local_history_window = NULL;
+
+
+/**
+ * callback for mouse action on local history window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+fb_local_history_mouse(struct fb_corewindow *fb_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct fb_local_history_window *lhw;
+ /* technically degenerate container of */
+ lhw = (struct fb_local_history_window *)fb_cw;
+
+ local_history_mouse_action(lhw->session, mouse_state, x, y);
+
+ if (mouse_state != BROWSER_MOUSE_HOVER) {
+ fbtk_set_mapping(lhw->core.wnd, false);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * callback for keypress on local history window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+fb_local_history_key(struct fb_corewindow *fb_cw, uint32_t nskey)
+{
+ struct fb_local_history_window *lhw;
+ /* technically degenerate container of */
+ lhw = (struct fb_local_history_window *)fb_cw;
+
+ if (local_history_keypress(lhw->session, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * callback on draw event for local history window
+ *
+ * \param fb_cw The fb core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+fb_local_history_draw(struct fb_corewindow *fb_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &fb_plotters
+ };
+ struct fb_local_history_window *lhw;
+
+ /* technically degenerate container of */
+ lhw = (struct fb_local_history_window *)fb_cw;
+
+ local_history_redraw(lhw->session, 0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Creates the window for the local history view.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror
+fb_local_history_init(fbtk_widget_t *parent,
+ struct browser_window *bw,
+ struct fb_local_history_window **win_out)
+{
+ struct fb_local_history_window *ncwin;
+ nserror res;
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ if ((*win_out) != NULL) {
+ res = local_history_set((*win_out)->session, bw);
+ return res;
+ }
+
+ ncwin = calloc(1, sizeof(*ncwin));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ ncwin->core.draw = fb_local_history_draw;
+ ncwin->core.key = fb_local_history_key;
+ ncwin->core.mouse = fb_local_history_mouse;
+
+ res = fb_corewindow_init(parent, &ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ bw,
+ &ncwin->session);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ *win_out = ncwin;
+
+ return NSERROR_OK;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror fb_local_history_present(fbtk_widget_t *parent,
+ struct browser_window *bw)
+{
+ nserror res;
+ int prnt_width, prnt_height;
+ int width, height;
+
+ res = fb_local_history_init(parent, bw, &local_history_window);
+ if (res == NSERROR_OK) {
+
+ prnt_width = fbtk_get_width(parent);
+ prnt_height = fbtk_get_height(parent);
+
+ /* resize history widget ensureing the drawing area is
+ * no larger than parent window
+ */
+ res = local_history_get_size(local_history_window->session,
+ &width,
+ &height);
+ if (width > prnt_width) {
+ width = prnt_width;
+ }
+ if (height > prnt_height) {
+ height = prnt_height;
+ }
+ /* should update scroll area with contents */
+
+ fbtk_set_zorder(local_history_window->core.wnd, INT_MIN);
+ fbtk_set_mapping(local_history_window->core.wnd, true);
+ }
+
+ return res;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror fb_local_history_hide(void)
+{
+ nserror res = NSERROR_OK;
+
+ if (local_history_window != NULL) {
+ fbtk_set_mapping(local_history_window->core.wnd, false);
+
+ res = local_history_set(local_history_window->session, NULL);
+ }
+
+ return res;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror fb_local_history_destroy(void)
+{
+ nserror res;
+
+ if (local_history_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = local_history_fini(local_history_window->session);
+ if (res == NSERROR_OK) {
+ res = fb_corewindow_fini(&local_history_window->core);
+ //gtk_widget_destroy(GTK_WIDGET(local_history_window->wnd));
+ free(local_history_window);
+ local_history_window = NULL;
+ }
+
+ return res;
+
+}
diff --git a/frontends/framebuffer/local_history.h b/frontends/framebuffer/local_history.h
new file mode 100644
index 000000000..929eeacd8
--- /dev/null
+++ b/frontends/framebuffer/local_history.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to framebuffer local history manager
+ */
+
+#ifndef FB_LOCAL_HISTORY_H
+#define FB_LOCAL_HISTORY_H
+
+struct browser_window;
+
+/**
+ * make the local history window visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror fb_local_history_present(fbtk_widget_t *parent, struct browser_window *bw);
+
+/**
+ * hide the local history window from being visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror fb_local_history_hide(void);
+
+/**
+ * Destroys the local history window and performs any other necessary cleanup
+ * actions.
+ */
+nserror fb_local_history_destroy(void);
+
+#endif
diff --git a/frontends/framebuffer/localhistory.c b/frontends/framebuffer/localhistory.c
deleted file mode 100644
index 3192f0747..000000000
--- a/frontends/framebuffer/localhistory.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include <libnsfb.h>
-#include <libnsfb_plot.h>
-#include <libnsfb_event.h>
-
-#include "desktop/browser_history.h"
-#include "netsurf/plotters.h"
-
-#include "framebuffer/gui.h"
-#include "framebuffer/fbtk.h"
-#include "framebuffer/framebuffer.h"
-
-static int
-localhistory_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
-{
- struct gui_localhistory *glh = cbi->context;
- nsfb_bbox_t rbox;
-
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &fb_plotters
- };
-
- rbox.x0 = fbtk_get_absx(widget);
- rbox.y0 = fbtk_get_absy(widget);
-
- rbox.x1 = rbox.x0 + fbtk_get_width(widget);
- rbox.y1 = rbox.y0 + fbtk_get_height(widget);
-
- nsfb_claim(fbtk_get_nsfb(widget), &rbox);
-
- nsfb_plot_rectangle_fill(fbtk_get_nsfb(widget), &rbox, 0xffffffff);
-
- browser_window_history_redraw_rectangle(glh->bw,
- glh->scrollx,
- glh->scrolly,
- fbtk_get_width(widget) + glh->scrollx,
- fbtk_get_height(widget) + glh->scrolly,
- 0, 0, &ctx);
-
- nsfb_update(fbtk_get_nsfb(widget), &rbox);
-
- return 0;
-}
-
-static int
-localhistory_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
-{
- struct gui_localhistory *glh = cbi->context;
-
- if (cbi->event->type != NSFB_EVENT_KEY_UP)
- return 0;
-
- browser_window_history_click(glh->bw, cbi->x, cbi->y, false);
-
- fbtk_set_mapping(glh->window, false);
-
- return 1;
-}
-
-struct gui_localhistory *
-fb_create_localhistory(struct browser_window *bw,
- fbtk_widget_t *parent,
- int furniture_width)
-{
- struct gui_localhistory *glh;
- glh = calloc(1, sizeof(struct gui_localhistory));
-
- if (glh == NULL)
- return NULL;
-
- glh->bw = bw;
-
- /* container window */
- glh->window = fbtk_create_window(parent, 0, 0, 0, 0, 0);
-
- glh->history = fbtk_create_user(glh->window, 0, 0, -furniture_width, -furniture_width, glh);
-
- fbtk_set_handler(glh->history, FBTK_CBT_REDRAW, localhistory_redraw, glh);
- fbtk_set_handler(glh->history, FBTK_CBT_CLICK, localhistory_click, glh);
- /*
- fbtk_set_handler(gw->localhistory, FBTK_CBT_INPUT, fb_browser_window_input, gw);
- fbtk_set_handler(gw->localhistory, FBTK_CBT_POINTERMOVE, fb_browser_window_move, bw);
- */
-
- /* create horizontal scrollbar */
- glh->hscroll = fbtk_create_hscroll(glh->window,
- 0,
- fbtk_get_height(glh->window) - furniture_width,
- fbtk_get_width(glh->window) - furniture_width,
- furniture_width,
- FB_SCROLL_COLOUR,
- FB_FRAME_COLOUR,
- NULL,
- NULL);
-
- glh->vscroll = fbtk_create_vscroll(glh->window,
- fbtk_get_width(glh->window) - furniture_width,
- 0,
- furniture_width,
- fbtk_get_height(glh->window) - furniture_width,
- FB_SCROLL_COLOUR,
- FB_FRAME_COLOUR,
- NULL,
- NULL);
-
- fbtk_create_fill(glh->window,
- fbtk_get_width(glh->window) - furniture_width,
- fbtk_get_height(glh->window) - furniture_width,
- furniture_width,
- furniture_width,
- FB_FRAME_COLOUR);
-
- return glh;
-}
-
-void
-fb_localhistory_map(struct gui_localhistory * glh)
-{
- fbtk_set_zorder(glh->window, INT_MIN);
- fbtk_set_mapping(glh->window, true);
-}
diff --git a/frontends/framebuffer/res/Messages b/frontends/framebuffer/res/Messages
deleted file mode 120000
index 72c9eff90..000000000
--- a/frontends/framebuffer/res/Messages
+++ /dev/null
@@ -1 +0,0 @@
-../../../!NetSurf/Resources/en/Messages \ No newline at end of file
diff --git a/frontends/framebuffer/res/adblock.css b/frontends/framebuffer/res/adblock.css
index ff2485622..0d12aaa7c 120000
--- a/frontends/framebuffer/res/adblock.css
+++ b/frontends/framebuffer/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
+../../../resources/adblock.css \ No newline at end of file
diff --git a/frontends/framebuffer/res/credits.html b/frontends/framebuffer/res/credits.html
index 1ba17392b..b43a1a06c 120000
--- a/frontends/framebuffer/res/credits.html
+++ b/frontends/framebuffer/res/credits.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
+../../../resources/en/credits.html \ No newline at end of file
diff --git a/frontends/framebuffer/res/default.css b/frontends/framebuffer/res/default.css
index a8579eb7c..fa3ae6c26 120000
--- a/frontends/framebuffer/res/default.css
+++ b/frontends/framebuffer/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
+../../../resources/default.css \ No newline at end of file
diff --git a/frontends/framebuffer/res/internal.css b/frontends/framebuffer/res/internal.css
index 17f9f1504..5583a9811 120000
--- a/frontends/framebuffer/res/internal.css
+++ b/frontends/framebuffer/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
+../../../resources/internal.css \ No newline at end of file
diff --git a/frontends/framebuffer/res/licence.html b/frontends/framebuffer/res/licence.html
index 147dd6db2..c0c1e6630 120000
--- a/frontends/framebuffer/res/licence.html
+++ b/frontends/framebuffer/res/licence.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
+../../../resources/en/licence.html \ No newline at end of file
diff --git a/frontends/framebuffer/res/maps.html b/frontends/framebuffer/res/maps.html
index 28362130a..05bcdc42e 120000
--- a/frontends/framebuffer/res/maps.html
+++ b/frontends/framebuffer/res/maps.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
+../../../resources/en/maps.html \ No newline at end of file
diff --git a/frontends/framebuffer/res/netsurf.png b/frontends/framebuffer/res/netsurf.png
index 905512c25..d0ab72a5e 120000
--- a/frontends/framebuffer/res/netsurf.png
+++ b/frontends/framebuffer/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
+../../../resources/netsurf.png \ No newline at end of file
diff --git a/frontends/framebuffer/res/quirks.css b/frontends/framebuffer/res/quirks.css
index 88aabe48c..1e752cb9e 120000
--- a/frontends/framebuffer/res/quirks.css
+++ b/frontends/framebuffer/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
+../../../resources/quirks.css \ No newline at end of file
diff --git a/frontends/framebuffer/res/welcome.html b/frontends/framebuffer/res/welcome.html
index 28362130a..d5220f90a 120000
--- a/frontends/framebuffer/res/welcome.html
+++ b/frontends/framebuffer/res/welcome.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
+../../../resources/en/welcome.html \ No newline at end of file
diff --git a/frontends/framebuffer/schedule.c b/frontends/framebuffer/schedule.c
index 581ad72f1..6d1711236 100644
--- a/frontends/framebuffer/schedule.c
+++ b/frontends/framebuffer/schedule.c
@@ -24,12 +24,6 @@
#include "framebuffer/schedule.h"
-#ifdef DEBUG_SCHEDULER
-#define SRLOG(x...) LOG(x)
-#else
-#define SRLOG(x...) ((void) 0)
-#endif
-
/* linked list of scheduled callbacks */
static struct nscallback *schedule_list = NULL;
@@ -63,7 +57,7 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
return NSERROR_OK;
}
- SRLOG("removing %p, %p", callback, p);
+ NSLOG(schedule, DEBUG, "removing %p, %p", callback, p);
cur_nscb = schedule_list;
prev_nscb = NULL;
@@ -73,7 +67,8 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
(cur_nscb->p == p)) {
/* item to remove */
- SRLOG("callback entry %p removing %p(%p)",
+ NSLOG(schedule, DEBUG,
+ "callback entry %p removing %p(%p)",
cur_nscb, cur_nscb->callback, cur_nscb->p);
/* remove callback */
@@ -109,7 +104,7 @@ nserror framebuffer_schedule(int tival, void (*callback)(void *p), void *p)
return ret;
}
- SRLOG("Adding %p(%p) in %d", callback, p, tival);
+ NSLOG(schedule, DEBUG, "Adding %p(%p) in %d", callback, p, tival);
tv.tv_sec = tival / 1000; /* miliseconds to seconds */
tv.tv_usec = (tival % 1000) * 1000; /* remainder to microseconds */
@@ -190,7 +185,9 @@ int schedule_run(void)
/* make rettime relative to now */
timersub(&nexttime, &tv, &rettime);
- SRLOG("returning time to next event as %ldms",(rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
+ NSLOG(schedule, DEBUG,
+ "returning time to next event as %ldms",
+ (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
/* return next event time in milliseconds (24days max wait) */
return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
@@ -203,12 +200,14 @@ void list_schedule(void)
gettimeofday(&tv, NULL);
- LOG("schedule list at %ld:%ld", tv.tv_sec, tv.tv_usec);
+ NSLOG(netsurf, INFO, "schedule list at %ld:%ld", tv.tv_sec,
+ tv.tv_usec);
cur_nscb = schedule_list;
while (cur_nscb != NULL) {
- LOG("Schedule %p at %ld:%ld", cur_nscb, cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
+ NSLOG(netsurf, INFO, "Schedule %p at %ld:%ld", cur_nscb,
+ cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
cur_nscb = cur_nscb->next;
}
}
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index afbfcd791..ec60ce70c 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -165,11 +165,11 @@ endif
# S_FRONTEND are sources purely for the GTK frontend
S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c \
- scaffolding.c gdk.c completion.c login.c throbber.c \
- selection.c global_history.c window.c fetch.c download.c menu.c \
- print.c search.c tabs.c toolbar.c gettext.c \
- compat.c cookies.c hotlist.c viewdata.c viewsource.c \
- preferences.c about.c ssl_cert.c resources.c corewindow.c
+ scaffolding.c gdk.c completion.c login.c throbber.c accelerator.c \
+ selection.c window.c fetch.c download.c menu.c print.c \
+ search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \
+ viewsource.c preferences.c about.c resources.c corewindow.c \
+ local_history.c global_history.c cookies.c hotlist.c ssl_cert.c
# This is the final source build list
# Note this is deliberately *not* expanded here as common and image
diff --git a/frontends/gtk/accelerator.c b/frontends/gtk/accelerator.c
new file mode 100644
index 000000000..11b7fb1d0
--- /dev/null
+++ b/frontends/gtk/accelerator.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK accelerator support
+ *
+ */
+
+#include <stdint.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/errors.h"
+#include "utils/hashtable.h"
+
+#include "gtk/resources.h"
+#include "gtk/accelerator.h"
+
+/** acclelerators are stored in a fixed-size hash table. */
+#define HASH_SIZE 53
+
+/** The hash table used to store the accelerators */
+static struct hash_table *accelerators_hash = NULL;
+
+nserror nsgtk_accelerator_init(char **respaths)
+{
+ nserror res;
+ const uint8_t *data;
+ size_t data_size;
+
+ if (accelerators_hash == NULL) {
+ accelerators_hash = hash_create(HASH_SIZE);
+ }
+ if (accelerators_hash == NULL) {
+ NSLOG(netsurf, INFO, "Unable to create hash table");
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_data_from_resname("accelerators", &data, &data_size);
+ if (res == NSERROR_OK) {
+ res = hash_add_inline(accelerators_hash, data, data_size);
+ } else {
+ const char *accelerators_path;
+ /* Obtain path to accelerators */
+ res = nsgtk_path_from_resname("accelerators",
+ &accelerators_path);
+ if (res == NSERROR_OK) {
+ res = hash_add_file(accelerators_hash,
+ accelerators_path);
+ }
+ }
+
+ return res;
+}
+
+const char *nsgtk_accelerator_get_desc(const char *key)
+{
+ if ((key == NULL) ||
+ (accelerators_hash == NULL)) {
+ return NULL;
+ }
+ return hash_get(accelerators_hash, key);
+}
diff --git a/frontends/gtk/accelerator.h b/frontends/gtk/accelerator.h
new file mode 100644
index 000000000..09c253eb9
--- /dev/null
+++ b/frontends/gtk/accelerator.h
@@ -0,0 +1,2 @@
+nserror nsgtk_accelerator_init(char **respaths);
+const char *nsgtk_accelerator_get_desc(const char *key);
diff --git a/frontends/gtk/bitmap.c b/frontends/gtk/bitmap.c
index b42814295..36b614cf9 100644
--- a/frontends/gtk/bitmap.c
+++ b/frontends/gtk/bitmap.c
@@ -18,9 +18,9 @@
/**
* \file
- * Generic bitmap handling (GDK / GTK+ implementation).
+ * GTK bitmap handling.
*
- * This implements the interface given by desktop/bitmap.h using GdkPixbufs.
+ * This implements the bitmap interface using cairo image surfaces
*/
#include <assert.h>
diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c
index dc77e1c4e..1f7833cca 100644
--- a/frontends/gtk/cookies.c
+++ b/frontends/gtk/cookies.c
@@ -164,8 +164,9 @@ static void nsgtk_cookies_init_menu(struct nsgtk_cookie_window *ncwin)
w = GTK_WIDGET(gtk_builder_get_object(ncwin->builder,
event->widget));
if (w == NULL) {
- LOG("Unable to connect menu widget ""%s""",
- event->widget);
+ NSLOG(netsurf, INFO,
+ "Unable to connect menu widget ""%s""",
+ event->widget);
} else {
g_signal_connect(G_OBJECT(w),
"activate",
@@ -246,14 +247,14 @@ static nserror nsgtk_cookies_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsgtk_cookie_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
res = nsgtk_builder_new_from_resname("cookies", &ncwin->builder);
if (res != NSERROR_OK) {
- LOG("Cookie UI builder init failed");
+ NSLOG(netsurf, INFO, "Cookie UI builder init failed");
free(ncwin);
return res;
}
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
index 70c3ad135..6ca5d228f 100644
--- a/frontends/gtk/corewindow.c
+++ b/frontends/gtk/corewindow.c
@@ -145,6 +145,7 @@ nsgtk_cw_button_release_event(GtkWidget *widget,
{
struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+ bool was_drag = false;
/* only button 1 clicks are considered double clicks. If the
* mouse state is PRESS then we are waiting for a release to
@@ -168,9 +169,11 @@ nsgtk_cw_button_release_event(GtkWidget *widget,
} else if (mouse->state & BROWSER_MOUSE_HOLDING_1) {
mouse->state ^= (BROWSER_MOUSE_HOLDING_1 |
BROWSER_MOUSE_DRAG_ON);
+ was_drag = true;
} else if (mouse->state & BROWSER_MOUSE_HOLDING_2) {
mouse->state ^= (BROWSER_MOUSE_HOLDING_2 |
BROWSER_MOUSE_DRAG_ON);
+ was_drag = true;
}
/* Handle modifiers being removed */
@@ -188,9 +191,10 @@ nsgtk_cw_button_release_event(GtkWidget *widget,
}
/* end drag with modifiers */
- if (mouse->state & (BROWSER_MOUSE_MOD_1 |
- BROWSER_MOUSE_MOD_2 |
- BROWSER_MOUSE_MOD_3)) {
+ if (was_drag && (mouse->state & (
+ BROWSER_MOUSE_MOD_1 |
+ BROWSER_MOUSE_MOD_2 |
+ BROWSER_MOUSE_MOD_3))) {
mouse->state = BROWSER_MOUSE_HOVER;
}
@@ -413,14 +417,14 @@ nsgtk_cw_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer g)
if (res == NSERROR_OK) {
return TRUE;
} else if (res != NSERROR_NOT_IMPLEMENTED) {
- LOG("%s", messages_get_errorcode(res));
+ NSLOG(netsurf, INFO, "%s", messages_get_errorcode(res));
return FALSE;
}
/* deal with unprocessed keypress */
res = nsgtk_cw_key(nsgtk_cw, nskey);
if (res != NSERROR_OK) {
- LOG("%s", messages_get_errorcode(res));
+ NSLOG(netsurf, INFO, "%s", messages_get_errorcode(res));
return FALSE;
}
return TRUE;
@@ -496,7 +500,6 @@ nsgtk_cw_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
double y2;
struct rect clip;
- current_widget = widget;
current_cr = cr;
cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
@@ -508,8 +511,6 @@ nsgtk_cw_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
nsgtk_cw->draw(nsgtk_cw, &clip);
- current_widget = NULL;
-
return FALSE;
}
@@ -537,12 +538,10 @@ nsgtk_cw_draw_event(GtkWidget *widget,
clip.x1 = event->area.x + event->area.width;
clip.y1 = event->area.y + event->area.height;
- current_widget = widget;
current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget));
nsgtk_cw->draw(nsgtk_cw, &clip);
- current_widget = NULL;
cairo_destroy(current_cr);
return FALSE;
@@ -552,19 +551,33 @@ nsgtk_cw_draw_event(GtkWidget *widget,
/**
- * redraw window core window callback
+ * callback from core to request an invalidation of a GTK core window area.
*
- * \param cw core window handle.
- * \param r rectangle that needs redrawing.
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] rect area to redraw or NULL for the entire window area.
+ * \return NSERROR_OK on success or appropriate error code.
*/
-static void
-nsgtk_cw_redraw_request(struct core_window *cw, const struct rect *r)
+static nserror
+nsgtk_cw_invalidate_area(struct core_window *cw, const struct rect *rect)
{
struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ if (rect == NULL) {
+ gtk_widget_queue_draw(GTK_WIDGET(nsgtk_cw->drawing_area));
+ return NSERROR_OK;
+ }
+
gtk_widget_queue_draw_area(GTK_WIDGET(nsgtk_cw->drawing_area),
- r->x0, r->y0,
- r->x1 - r->x0, r->y1 - r->y0);
+ rect->x0,
+ rect->y0,
+ rect->x1 - rect->x0,
+ rect->y1 - rect->y0);
+
+ return NSERROR_OK;
}
@@ -653,7 +666,7 @@ static void
nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
{
struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
- nsgtk_cw->drag_staus = ds;
+ nsgtk_cw->drag_status = ds;
}
@@ -661,17 +674,19 @@ nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
* core window callback table for nsgtk
*/
static struct core_window_callback_table nsgtk_cw_cb_table = {
- .redraw_request = nsgtk_cw_redraw_request,
+ .invalidate = nsgtk_cw_invalidate_area,
.update_size = nsgtk_cw_update_size,
.scroll_visible = nsgtk_cw_scroll_visible,
.get_window_dimensions = nsgtk_cw_get_window_dimensions,
.drag_status = nsgtk_cw_drag_status
};
+
/* exported function documented gtk/corewindow.h */
nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw)
{
nsgtk_cw->cb_table = &nsgtk_cw_cb_table;
+ nsgtk_cw->drag_status = CORE_WINDOW_DRAG_NONE;
/* input method setup */
nsgtk_cw->input_method = gtk_im_multicontext_new();
diff --git a/frontends/gtk/corewindow.h b/frontends/gtk/corewindow.h
index 90bfd6193..6100e67ae 100644
--- a/frontends/gtk/corewindow.h
+++ b/frontends/gtk/corewindow.h
@@ -51,7 +51,7 @@ struct nsgtk_corewindow {
/** mouse state */
struct nsgtk_corewindow_mouse mouse_state;
/** drag status set by core */
- core_window_drag_status drag_staus;
+ core_window_drag_status drag_status;
/**
* callback to draw on drawable area of nsgtk core window
diff --git a/frontends/gtk/download.c b/frontends/gtk/download.c
index 8c8161459..d11036ea8 100644
--- a/frontends/gtk/download.c
+++ b/frontends/gtk/download.c
@@ -331,6 +331,7 @@ static gboolean nsgtk_download_update(gboolean force_update)
switch (dl->status) {
case NSGTK_DOWNLOAD_WORKING:
pulse_mode = TRUE;
+ /* Fall through */
case NSGTK_DOWNLOAD_NONE:
dl->speed = dl->size_downloaded /
@@ -347,6 +348,7 @@ static gboolean nsgtk_download_update(gboolean force_update)
nsgtk_downloads_num_active++;
update = TRUE;
+ /* Fall through */
case NSGTK_DOWNLOAD_COMPLETE:
downloaded += dl->size_downloaded;
@@ -475,7 +477,7 @@ nserror nsgtk_download_init(void)
res = nsgtk_builder_new_from_resname("downloads", &builder);
if (res != NSERROR_OK) {
- LOG("Download UI builder init failed");
+ NSLOG(netsurf, INFO, "Download UI builder init failed");
return res;
}
diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c
index 154f43708..b05c1bd95 100644
--- a/frontends/gtk/fetch.c
+++ b/frontends/gtk/fetch.c
@@ -30,6 +30,7 @@
* ASCII hence not using locale dependant ctype functions for parsing.
*/
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -39,8 +40,8 @@
#include <strings.h>
#include <gtk/gtk.h>
-#include "utils/hashtable.h"
#include "utils/log.h"
+#include "utils/hashtable.h"
#include "utils/filepath.h"
#include "utils/file.h"
#include "utils/nsurl.h"
@@ -90,7 +91,8 @@ void gtk_fetch_filetype_init(const char *mimefile)
fh = fopen(mimefile, "r");
if (fh == NULL) {
- LOG("Unable to open a mime.types file, so using a minimal one for you.");
+ NSLOG(netsurf, INFO,
+ "Unable to open a mime.types file, so using a minimal one for you.");
return;
}
diff --git a/frontends/gtk/gdk.c b/frontends/gtk/gdk.c
index 9ed90bd8e..fd82af5b2 100644
--- a/frontends/gtk/gdk.c
+++ b/frontends/gtk/gdk.c
@@ -86,7 +86,7 @@ nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int scwidth, int scheigh
if (cairo_surface_status(scsurface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy(scsurface);
g_object_unref(pixbuf);
- LOG("Surface creation failed");
+ NSLOG(netsurf, INFO, "Surface creation failed");
return NULL;
}
diff --git a/frontends/gtk/global_history.c b/frontends/gtk/global_history.c
index 7d647057b..f204168d0 100644
--- a/frontends/gtk/global_history.c
+++ b/frontends/gtk/global_history.c
@@ -214,8 +214,9 @@ nsgtk_global_history_init_menu(struct nsgtk_global_history_window *ghwin)
w = GTK_WIDGET(gtk_builder_get_object(ghwin->builder,
event->widget));
if (w == NULL) {
- LOG("Unable to connect menu widget ""%s""",
- event->widget);
+ NSLOG(netsurf, INFO,
+ "Unable to connect menu widget ""%s""",
+ event->widget);
} else {
g_signal_connect(G_OBJECT(w),
"activate",
@@ -228,7 +229,7 @@ nsgtk_global_history_init_menu(struct nsgtk_global_history_window *ghwin)
/**
- * callback for mouse action on cookie window
+ * callback for mouse action on global history window
*
* \param nsgtk_cw The nsgtk core window structure.
* \param mouse_state netsurf mouse state on event
@@ -248,7 +249,7 @@ nsgtk_global_history_mouse(struct nsgtk_corewindow *nsgtk_cw,
/**
- * callback for keypress on cookie window
+ * callback for keypress on global history window
*
* \param nsgtk_cw The nsgtk core window structure.
* \param nskey The netsurf key code
@@ -265,7 +266,7 @@ nsgtk_global_history_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
/**
- * callback on draw event for cookie window
+ * callback on draw event for global history window
*
* \param nsgtk_cw The nsgtk core window structure.
* \param r The rectangle of the window that needs updating.
@@ -299,14 +300,14 @@ static nserror nsgtk_global_history_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsgtk_global_history_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
- res = nsgtk_builder_new_from_resname("history", &ncwin->builder);
+ res = nsgtk_builder_new_from_resname("globalhistory", &ncwin->builder);
if (res != NSERROR_OK) {
- LOG("History UI builder init failed");
+ NSLOG(netsurf, INFO, "History UI builder init failed");
free(ncwin);
return res;
}
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 8d6b42234..3163be16d 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -58,6 +58,7 @@
#include "gtk/download.h"
#include "gtk/fetch.h"
#include "gtk/gui.h"
+#include "gtk/local_history.h"
#include "gtk/global_history.h"
#include "gtk/hotlist.h"
#include "gtk/throbber.h"
@@ -71,6 +72,7 @@
#include "gtk/resources.h"
#include "gtk/login.h"
#include "gtk/layout_pango.h"
+#include "gtk/accelerator.h"
bool nsgtk_complete = false;
@@ -207,7 +209,8 @@ static nserror set_defaults(struct nsoption_s *defaults)
(nsoption_charp(hotlist_path) == NULL) ||
(nsoption_charp(downloads_directory) == NULL) ||
(nsoption_charp(ca_path) == NULL)) {
- LOG("Failed initialising default resource paths");
+ NSLOG(netsurf, INFO,
+ "Failed initialising default resource paths");
return NSERROR_BAD_PARAMETER;
}
@@ -225,7 +228,11 @@ static nserror set_defaults(struct nsoption_s *defaults)
/**
- * Initialize GTK interface.
+ * Initialize GTK specific parts of the browser.
+ *
+ * \param argc The number of arguments on the command line
+ * \param argv A string vector of command line arguments.
+ * \respath A string vector of the path elements of resources
*/
static nserror nsgtk_init(int argc, char** argv, char **respath)
{
@@ -233,21 +240,30 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
char *resource_filename;
char *addr = NULL;
nsurl *url;
- nserror error;
+ nserror res;
- error = nsgtk_builder_new_from_resname("warning", &warning_builder);
- if (error != NSERROR_OK) {
- LOG("Unable to initialise warning dialog");
- return error;
+ /* Initialise gtk accelerator table */
+ res = nsgtk_accelerator_init(respaths);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to load gtk accelerator configuration");
+ /* not fatal if this does not load */
+ }
+
+ /* initialise warning dialog */
+ res = nsgtk_builder_new_from_resname("warning", &warning_builder);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to initialise warning dialog");
+ return res;
}
gtk_builder_connect_signals(warning_builder, NULL);
/* set default icon if its available */
- error = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
- &win_default_icon_pixbuf);
- if (error == NSERROR_OK) {
- LOG("Seting default window icon");
+ res = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
+ &win_default_icon_pixbuf);
+ if (res == NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Seting default window icon");
gtk_window_set_default_icon(win_default_icon_pixbuf);
}
@@ -255,35 +271,43 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
resource_filename = filepath_find(respath, "SearchEngines");
search_web_init(resource_filename);
if (resource_filename != NULL) {
- LOG("Using '%s' as Search Engines file", resource_filename);
+ NSLOG(netsurf, INFO, "Using '%s' as Search Engines file",
+ resource_filename);
free(resource_filename);
}
/* Default favicon */
- error = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
- if (error != NSERROR_OK) {
+ res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
+ if (res != NSERROR_OK) {
favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
false, 8, 16, 16);
}
/* arrow down icon */
- error = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
- &arrow_down_pixbuf);
- if (error != NSERROR_OK) {
+ res = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
+ &arrow_down_pixbuf);
+ if (res != NSERROR_OK) {
arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
false, 8, 8, 32);
}
/* initialise throbber */
- error = nsgtk_throbber_init();
- if (error != NSERROR_OK) {
- LOG("Unable to initialise throbber.");
- return error;
+ res = nsgtk_throbber_init();
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to initialise throbber.");
+ return res;
}
/* Initialise completions - cannot fail */
nsgtk_completion_init();
+ /* The tree view system needs to know the screen's DPI, so we
+ * find that out here, rather than when we create a first browser
+ * window.
+ */
+ browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default()));
+ NSLOG(netsurf, INFO, "Set CSS DPI to %d", browser_get_dpi());
+
filepath_sfinddef(respath, buf, "mime.types", "/etc/");
gtk_fetch_filetype_init(buf);
@@ -291,20 +315,14 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
urldb_load(nsoption_charp(url_file));
urldb_load_cookies(nsoption_charp(cookie_file));
- hotlist_init(nsoption_charp(hotlist_path));
-
- /* The tree view system needs to know the screen's DPI, so we
- * find that out here, rather than when we create a first browser
- * window.
- */
- browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default()));
- LOG("Set CSS DPI to %d", browser_get_dpi());
+ hotlist_init(nsoption_charp(hotlist_path),
+ nsoption_charp(hotlist_path));
/* Initialise top level UI elements */
- error = nsgtk_download_init();
- if (error != NSERROR_OK) {
- LOG("Unable to initialise download window.");
- return error;
+ res = nsgtk_download_init();
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to initialise download window.");
+ return res;
}
/* If there is a url specified on the command line use it */
@@ -334,19 +352,19 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
}
/* create an initial browser window */
- error = nsurl_create(addr, &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ res = nsurl_create(addr, &url);
+ if (res == NSERROR_OK) {
+ res = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
free(addr);
- return error;
+ return res;
}
@@ -424,7 +442,7 @@ static void gui_quit(void)
{
nserror res;
- LOG("Quitting GUI");
+ NSLOG(netsurf, INFO, "Quitting GUI");
/* Ensure all scaffoldings are destroyed before we go into exit */
nsgtk_download_destroy();
@@ -433,26 +451,34 @@ static void gui_quit(void)
res = nsgtk_cookies_destroy();
if (res != NSERROR_OK) {
- LOG("Error finalising cookie viewer: %s",
- messages_get_errorcode(res));
+ NSLOG(netsurf, INFO, "Error finalising cookie viewer: %s",
+ messages_get_errorcode(res));
+ }
+
+ res = nsgtk_local_history_destroy();
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Error finalising local history viewer: %s",
+ messages_get_errorcode(res));
}
res = nsgtk_global_history_destroy();
if (res != NSERROR_OK) {
- LOG("Error finalising global history viewer: %s",
- messages_get_errorcode(res));
+ NSLOG(netsurf, INFO,
+ "Error finalising global history viewer: %s",
+ messages_get_errorcode(res));
}
res = nsgtk_hotlist_destroy();
if (res != NSERROR_OK) {
- LOG("Error finalising hotlist viewer: %s",
- messages_get_errorcode(res));
+ NSLOG(netsurf, INFO, "Error finalising hotlist viewer: %s",
+ messages_get_errorcode(res));
}
- res = hotlist_fini(nsoption_charp(hotlist_path));
+ res = hotlist_fini();
if (res != NSERROR_OK) {
- LOG("Error finalising hotlist: %s",
- messages_get_errorcode(res));
+ NSLOG(netsurf, INFO, "Error finalising hotlist: %s",
+ messages_get_errorcode(res));
}
free(nsgtk_config_home);
@@ -484,7 +510,7 @@ nserror nsgtk_warning(const char *warning, const char *detail)
static GtkWindow *nsgtk_warning_window;
GtkLabel *WarningLabel;
- LOG("%s %s", warning, detail ? detail : "");
+ NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : "");
fflush(stdout);
nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
@@ -592,7 +618,7 @@ static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
res = nsgtk_builder_new_from_resname("password", &password_builder);
if (res != NSERROR_OK) {
- LOG("Password UI builder init failed");
+ NSLOG(netsurf, INFO, "Password UI builder init failed");
return;
}
@@ -813,7 +839,7 @@ static nserror get_config_home(char **config_home_out)
if (home_dir != NULL) {
ret = check_dirname(home_dir, ".netsurf", &config_home);
if (ret == NSERROR_OK) {
- LOG("\"%s\"", config_home);
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
*config_home_out = config_home;
return ret;
}
@@ -853,7 +879,7 @@ static nserror get_config_home(char **config_home_out)
}
}
- LOG("\"%s\"", config_home);
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
*config_home_out = config_home;
return NSERROR_OK;
@@ -866,7 +892,7 @@ static nserror create_config_home(char **config_home_out)
char *xdg_config_dir;
nserror ret;
- LOG("Attempting to create configuration directory");
+ NSLOG(netsurf, INFO, "Attempting to create configuration directory");
/* $XDG_CONFIG_HOME defines the base directory
* relative to which user specific configuration files
@@ -902,7 +928,7 @@ static nserror create_config_home(char **config_home_out)
/* strip the trailing separator */
config_home[strlen(config_home) - 1] = 0;
- LOG("\"%s\"", config_home);
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
*config_home_out = config_home;
@@ -951,7 +977,7 @@ static nserror get_cache_home(char **cache_home_out)
}
}
- LOG("\"%s\"", cache_home);
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
*cache_home_out = cache_home;
return NSERROR_OK;
@@ -964,7 +990,7 @@ static nserror create_cache_home(char **cache_home_out)
char *xdg_cache_dir;
nserror ret;
- LOG("Attempting to create configuration directory");
+ NSLOG(netsurf, INFO, "Attempting to create configuration directory");
/* $XDG_CACHE_HOME defines the base directory
* relative to which user specific cache files
@@ -1000,7 +1026,7 @@ static nserror create_cache_home(char **cache_home_out)
/* strip the trailing separator */
cache_home[strlen(cache_home) - 1] = 0;
- LOG("\"%s\"", cache_home);
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
*cache_home_out = cache_home;
@@ -1107,7 +1133,8 @@ int main(int argc, char** argv)
ret = create_config_home(&nsgtk_config_home);
}
if (ret != NSERROR_OK) {
- LOG("Unable to locate a configuration directory.");
+ NSLOG(netsurf, INFO,
+ "Unable to locate a configuration directory.");
nsgtk_config_home = NULL;
}
@@ -1147,10 +1174,10 @@ int main(int argc, char** argv)
if (ret != NSERROR_OK) {
fprintf(stderr, "Unable to load translated messages (%s)\n",
messages_get_errorcode(ret));
- LOG("Unable to load translated messages");
+ NSLOG(netsurf, INFO, "Unable to load translated messages");
/** \todo decide if message load faliure should be fatal */
}
-
+
/* Locate the correct user cache directory path */
ret = get_cache_home(&cache_home);
if (ret == NSERROR_NOT_FOUND) {
@@ -1158,7 +1185,7 @@ int main(int argc, char** argv)
ret = create_cache_home(&cache_home);
}
if (ret != NSERROR_OK) {
- LOG("Unable to locate a cache directory.");
+ NSLOG(netsurf, INFO, "Unable to locate a cache directory.");
}
/* core initialisation */
@@ -1170,7 +1197,7 @@ int main(int argc, char** argv)
return 1;
}
- /* run the browser */
+ /* gtk specific initalisation and main run loop */
ret = nsgtk_init(argc, argv, respaths);
if (ret != NSERROR_OK) {
fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
@@ -1185,5 +1212,8 @@ int main(int argc, char** argv)
/* finalise options */
nsoption_finalise(nsoptions, nsoptions_default);
+ /* finalise logging */
+ nslog_finalise();
+
return 0;
}
diff --git a/frontends/gtk/hotlist.c b/frontends/gtk/hotlist.c
index 34a13772d..843e47736 100644
--- a/frontends/gtk/hotlist.c
+++ b/frontends/gtk/hotlist.c
@@ -236,8 +236,9 @@ static void nsgtk_hotlist_init_menu(struct nsgtk_hotlist_window *hlwin)
w = GTK_WIDGET(gtk_builder_get_object(hlwin->builder,
event->widget));
if (w == NULL) {
- LOG("Unable to connect menu widget ""%s""",
- event->widget);
+ NSLOG(netsurf, INFO,
+ "Unable to connect menu widget ""%s""",
+ event->widget);
} else {
g_signal_connect(G_OBJECT(w),
"activate",
@@ -319,14 +320,14 @@ static nserror nsgtk_hotlist_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsgtk_hotlist_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
res = nsgtk_builder_new_from_resname("hotlist", &ncwin->builder);
if (res != NSERROR_OK) {
- LOG("Hotlist UI builder init failed");
+ NSLOG(netsurf, INFO, "Hotlist UI builder init failed");
free(ncwin);
return res;
}
diff --git a/frontends/gtk/layout_pango.c b/frontends/gtk/layout_pango.c
index 7c7190982..9e8e94d48 100644
--- a/frontends/gtk/layout_pango.c
+++ b/frontends/gtk/layout_pango.c
@@ -30,6 +30,7 @@
#include "utils/log.h"
#include "utils/nsoption.h"
+#include "netsurf/inttypes.h"
#include "netsurf/layout.h"
#include "netsurf/plot_style.h"
@@ -42,12 +43,12 @@ static PangoLayout *nsfont_pango_layout = NULL;
static inline void nsfont_pango_check(void)
{
if (nsfont_pango_context == NULL) {
- LOG("Creating nsfont_pango_context.");
+ NSLOG(netsurf, INFO, "Creating nsfont_pango_context.");
nsfont_pango_context = gdk_pango_context_get();
}
if (nsfont_pango_layout == NULL) {
- LOG("Creating nsfont_pango_layout.");
+ NSLOG(netsurf, INFO, "Creating nsfont_pango_layout.");
nsfont_pango_layout = pango_layout_new(nsfont_pango_context);
}
}
@@ -84,9 +85,10 @@ nsfont_width(const plot_font_style_t *fstyle,
pango_layout_get_pixel_size(nsfont_pango_layout, width, 0);
- /* LOG("fstyle: %p string:\"%.*s\", length: %u, width: %dpx",
- fstyle, length, string, length, *width);
- */
+ NSLOG(netsurf, DEEPDEBUG,
+ "fstyle: %p string:\"%.*s\", length: %" PRIsizet ", width: %dpx",
+ fstyle, (int)length, string, length, *width);
+
return NSERROR_OK;
}
@@ -194,7 +196,7 @@ nsfont_split(const plot_font_style_t *fstyle,
pango_layout_set_single_paragraph_mode(layout, TRUE);
/* Obtain the second line of the layout (if there is one) */
- line = pango_layout_get_line(layout, 1);
+ line = pango_layout_get_line_readonly(layout, 1);
if (line != NULL) {
/* Pango split the text. The line's start_index indicates the
* start of the character after the line break. */
@@ -222,32 +224,29 @@ nsfont_split(const plot_font_style_t *fstyle,
* \param fstyle plot style for this text
* \return true on success, false on error and error reported
*/
-bool nsfont_paint(int x, int y, const char *string, size_t length,
+nserror nsfont_paint(int x, int y, const char *string, size_t length,
const plot_font_style_t *fstyle)
{
PangoFontDescription *desc;
- PangoLayout *layout;
PangoLayoutLine *line;
if (length == 0)
- return true;
+ return NSERROR_OK;
- layout = pango_cairo_create_layout(current_cr);
+ nsfont_pango_check();
desc = nsfont_style_to_description(fstyle);
- pango_layout_set_font_description(layout, desc);
+ pango_layout_set_font_description(nsfont_pango_layout, desc);
pango_font_description_free(desc);
- pango_layout_set_text(layout, string, length);
+ pango_layout_set_text(nsfont_pango_layout, string, length);
- line = pango_layout_get_line_readonly(layout, 0);
+ line = pango_layout_get_line_readonly(nsfont_pango_layout, 0);
cairo_move_to(current_cr, x, y);
nsgtk_set_colour(fstyle->foreground);
pango_cairo_show_layout_line(current_cr, line);
- g_object_unref(layout);
-
- return true;
+ return NSERROR_OK;
}
@@ -278,7 +277,7 @@ nsfont_style_to_description(const plot_font_style_t *fstyle)
break;
}
- size = (fstyle->size * PANGO_SCALE) / FONT_SIZE_SCALE;
+ size = (fstyle->size * PANGO_SCALE) / PLOT_STYLE_SCALE;
if (fstyle->flags & FONTF_ITALIC)
style = PANGO_STYLE_ITALIC;
diff --git a/frontends/gtk/layout_pango.h b/frontends/gtk/layout_pango.h
index 137cebe68..7ce107a5d 100644
--- a/frontends/gtk/layout_pango.h
+++ b/frontends/gtk/layout_pango.h
@@ -30,7 +30,7 @@ struct plot_font_style;
extern struct gui_layout_table *nsgtk_layout_table;
-bool nsfont_paint(int x, int y, const char *string, size_t length, const struct plot_font_style *fstyle);
+nserror nsfont_paint(int x, int y, const char *string, size_t length, const struct plot_font_style *fstyle);
/**
* Convert a plot style to a PangoFontDescription.
diff --git a/frontends/gtk/local_history.c b/frontends/gtk/local_history.c
new file mode 100644
index 000000000..35b7a4ad6
--- /dev/null
+++ b/frontends/gtk/local_history.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of GTK local history manager.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
+#include "desktop/local_history.h"
+
+#include "gtk/compat.h"
+#include "gtk/plotters.h"
+#include "gtk/resources.h"
+#include "gtk/corewindow.h"
+#include "gtk/local_history.h"
+
+struct nsgtk_local_history_window {
+ struct nsgtk_corewindow core;
+
+ GtkBuilder *builder;
+
+ GtkWindow *wnd;
+
+ struct local_history_session *session;
+};
+
+static struct nsgtk_local_history_window *local_history_window = NULL;
+
+
+
+/**
+ * callback for mouse action on local history window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_local_history_mouse(struct nsgtk_corewindow *nsgtk_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct nsgtk_local_history_window *lhw;
+ /* technically degenerate container of */
+ lhw = (struct nsgtk_local_history_window *)nsgtk_cw;
+
+ local_history_mouse_action(lhw->session, mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * callback for keypress on local history window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_local_history_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
+{
+ struct nsgtk_local_history_window *lhw;
+ /* technically degenerate container of */
+ lhw = (struct nsgtk_local_history_window *)nsgtk_cw;
+
+ if (local_history_keypress(lhw->session, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * callback on draw event for local history window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_local_history_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+ struct nsgtk_local_history_window *lhw;
+
+ /* technically degenerate container of */
+ lhw = (struct nsgtk_local_history_window *)nsgtk_cw;
+
+ ctx.plot->clip(&ctx, r);
+ local_history_redraw(lhw->session, 0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Creates the window for the local history view.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror
+nsgtk_local_history_init(struct browser_window *bw,
+ struct nsgtk_local_history_window **win_out)
+{
+ struct nsgtk_local_history_window *ncwin;
+ nserror res;
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ if ((*win_out) != NULL) {
+ res = local_history_set((*win_out)->session, bw);
+ return res;
+ }
+
+ ncwin = calloc(1, sizeof(*ncwin));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_builder_new_from_resname("localhistory", &ncwin->builder);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Local history UI builder init failed");
+ free(ncwin);
+ return res;
+ }
+
+ gtk_builder_connect_signals(ncwin->builder, NULL);
+
+ ncwin->wnd = GTK_WINDOW(gtk_builder_get_object(ncwin->builder,
+ "wndHistory"));
+
+ ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
+ gtk_builder_get_object(ncwin->builder,
+ "HistoryScrolled"));
+
+ ncwin->core.drawing_area = GTK_DRAWING_AREA(
+ gtk_builder_get_object(ncwin->builder,
+ "HistoryDrawingArea"));
+
+ /* make the delete event hide the window */
+ g_signal_connect(G_OBJECT(ncwin->wnd),
+ "delete_event",
+ G_CALLBACK(gtk_widget_hide_on_delete),
+ NULL);
+
+ ncwin->core.draw = nsgtk_local_history_draw;
+ ncwin->core.key = nsgtk_local_history_key;
+ ncwin->core.mouse = nsgtk_local_history_mouse;
+
+ res = nsgtk_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ bw,
+ &ncwin->session);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ *win_out = ncwin;
+
+ return NSERROR_OK;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror nsgtk_local_history_present(GtkWindow *parent,
+ struct browser_window *bw)
+{
+ nserror res;
+ int prnt_width, prnt_height;
+ int width, height;
+ res = nsgtk_local_history_init(bw, &local_history_window);
+ if (res == NSERROR_OK) {
+ gtk_window_set_transient_for(local_history_window->wnd, parent);
+
+ gtk_window_get_size(parent, &prnt_width, &prnt_height);
+
+ /* resize history widget ensureing the drawing area is
+ * no larger than parent window
+ */
+ res = local_history_get_size(local_history_window->session,
+ &width,
+ &height);
+ if (width > prnt_width) {
+ width = prnt_width;
+ }
+ if (height > prnt_height) {
+ height = prnt_height;
+ }
+ gtk_window_resize(local_history_window->wnd, width, height);
+
+ gtk_window_present(local_history_window->wnd);
+ }
+
+ return res;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror nsgtk_local_history_hide(void)
+{
+ nserror res = NSERROR_OK;
+
+ if (local_history_window != NULL) {
+ gtk_widget_hide(GTK_WIDGET(local_history_window->wnd));
+
+ res = local_history_set(local_history_window->session, NULL);
+ }
+
+ return res;
+}
+
+
+/* exported function documented gtk/history.h */
+nserror nsgtk_local_history_destroy(void)
+{
+ nserror res;
+
+ if (local_history_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = local_history_fini(local_history_window->session);
+ if (res == NSERROR_OK) {
+ res = nsgtk_corewindow_fini(&local_history_window->core);
+ gtk_widget_destroy(GTK_WIDGET(local_history_window->wnd));
+ g_object_unref(G_OBJECT(local_history_window->builder));
+ free(local_history_window);
+ local_history_window = NULL;
+ }
+
+ return res;
+
+}
diff --git a/frontends/gtk/local_history.h b/frontends/gtk/local_history.h
new file mode 100644
index 000000000..605405ddf
--- /dev/null
+++ b/frontends/gtk/local_history.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@kyllikki.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to GTK local history manager
+ */
+
+#ifndef NSGTK_LOCAL_HISTORY_H
+#define NSGTK_LOCAL_HISTORY_H
+
+struct browser_window;
+
+/**
+ * make the local history window visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror nsgtk_local_history_present(GtkWindow *parent, struct browser_window *bw);
+
+/**
+ * hide the local history window from being visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror nsgtk_local_history_hide(void);
+
+/**
+ * Destroys the local history window and performs any other necessary cleanup
+ * actions.
+ */
+nserror nsgtk_local_history_destroy(void);
+
+#endif
diff --git a/frontends/gtk/login.c b/frontends/gtk/login.c
index 3e29903fe..91d8b37f0 100644
--- a/frontends/gtk/login.c
+++ b/frontends/gtk/login.c
@@ -222,7 +222,7 @@ void gui_401login_open(nsurl *url,
res = create_login_window(url, host, realm, cb, cbpw);
if (res != NSERROR_OK) {
- LOG("Login init failed");
+ NSLOG(netsurf, INFO, "Login init failed");
/* creating login failed so cancel navigation */
cb(false, cbpw);
diff --git a/frontends/gtk/menu.c b/frontends/gtk/menu.c
index a93ef9385..6a6033231 100644
--- a/frontends/gtk/menu.c
+++ b/frontends/gtk/menu.c
@@ -27,6 +27,7 @@
#include "gtk/compat.h"
#include "gtk/menu.h"
#include "gtk/warn.h"
+#include "gtk/accelerator.h"
/**
* Adds image menu item to a menu.
@@ -34,28 +35,37 @@
* \param menu the menu to add the item to
* \param item_out a pointer to the item's location in the menu struct
* \param message the menu item I18n lookup value
- * \param messageAccel the menu item accelerator I18n lookup value
* \param group the 'global' in a gtk sense accelerator group
* \return true if sucessful and \a item_out updated else false.
*/
-static bool nsgtk_menu_add_image_item(GtkMenu *menu,
- GtkWidget **item_out, const char *message,
- const char *messageAccel, GtkAccelGroup *group)
+static bool
+nsgtk_menu_add_image_item(GtkMenu *menu,
+ GtkWidget **item_out,
+ const char *message,
+ GtkAccelGroup *group)
{
unsigned int key;
GdkModifierType mod;
GtkWidget *item;
-
+ const char *accelerator_desc; /* accelerator key description */
+
item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message));
if (item == NULL) {
return false;
}
-
- gtk_accelerator_parse(messages_get(messageAccel), &key, &mod);
- if (key > 0) {
- gtk_widget_add_accelerator(item, "activate", group, key, mod,
- GTK_ACCEL_VISIBLE);
+
+ accelerator_desc = nsgtk_accelerator_get_desc(message);
+ if (accelerator_desc != NULL) {
+ gtk_accelerator_parse(accelerator_desc, &key, &mod);
+ if (key > 0) {
+ gtk_widget_add_accelerator(item,
+ "activate",
+ group,
+ key,
+ mod,
+ GTK_ACCEL_VISIBLE);
+ }
}
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
@@ -73,8 +83,7 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
n->m##_menu = GTK_MENU(gtk_menu_new())
#define IMAGE_ITEM(p, q, r, s, t)\
- nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\
- #r "Accel", t)
+ nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r, t)
#define CHECK_ITEM(p, q, r, s)\
s->q##_menuitem = GTK_CHECK_MENU_ITEM(\
@@ -130,8 +139,8 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
* creates an export submenu
* \param group the 'global' in a gtk sense accelerator reference
*/
-
-static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *group)
+static struct nsgtk_export_submenu *
+nsgtk_menu_export_submenu(GtkAccelGroup *group)
{
struct nsgtk_export_submenu *ret = malloc(sizeof(struct
nsgtk_export_submenu));
@@ -157,8 +166,8 @@ static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *gro
* \param group the 'global' in a gtk sense accelerator reference
*/
-static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
- GtkAccelGroup *group)
+static struct nsgtk_scaleview_submenu *
+nsgtk_menu_scaleview_submenu(GtkAccelGroup *group)
{
struct nsgtk_scaleview_submenu *ret =
malloc(sizeof(struct nsgtk_scaleview_submenu));
@@ -185,7 +194,8 @@ static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group)
{
- struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct nsgtk_tabs_submenu));
+ struct nsgtk_tabs_submenu *ret;
+ ret = malloc(sizeof(struct nsgtk_tabs_submenu));
if (ret == NULL) {
nsgtk_warning(messages_get("NoMemory"), 0);
return NULL;
diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c
index 817b72808..4a5ef510c 100644
--- a/frontends/gtk/plotters.c
+++ b/frontends/gtk/plotters.c
@@ -39,14 +39,15 @@
#include "gtk/scaffolding.h"
#include "gtk/bitmap.h"
-GtkWidget *current_widget;
cairo_t *current_cr;
static GdkRectangle cliprect;
-struct plotter_table plot;
-
-/** Set cairo context colour to nsgtk colour. */
+/**
+ * Set cairo context colour to nsgtk colour.
+ *
+ * \param c the netsurf colour to set in cairo
+ */
void nsgtk_set_colour(colour c)
{
cairo_set_source_rgba(current_cr,
@@ -56,29 +57,61 @@ void nsgtk_set_colour(colour c)
1.0);
}
-/** Set cairo context to solid plot operation. */
+
+/**
+ * Set cairo context to solid plot operation.
+ */
static inline void nsgtk_set_solid(void)
{
double dashes = 0;
cairo_set_dash(current_cr, &dashes, 0, 0);
}
-/** Set cairo context to dotted plot operation. */
+
+/**
+ * Set cairo context to dotted plot operation.
+ */
static inline void nsgtk_set_dotted(void)
{
double cdashes[] = { 1.0, 2.0 };
cairo_set_dash(current_cr, cdashes, 2, 0);
}
-/** Set cairo context to dashed plot operation. */
+
+/**
+ * Set cairo context to dashed plot operation.
+ */
static inline void nsgtk_set_dashed(void)
{
double cdashes[] = { 8.0, 2.0 };
cairo_set_dash(current_cr, cdashes, 2, 0);
}
-/** Set clipping area for subsequent plot operations. */
-static bool nsgtk_plot_clip(const struct rect *clip)
+
+/**
+ * Set cairo context line width.
+ */
+static inline void nsgtk_set_line_width(plot_style_fixed width)
+{
+ if (width == 0) {
+ cairo_set_line_width(current_cr, 1);
+ } else {
+ cairo_set_line_width(current_cr,
+ plot_style_fixed_to_double(width));
+ }
+}
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
{
cairo_reset_clip(current_cr);
cairo_rectangle(current_cr, clip->x0, clip->y0,
@@ -90,11 +123,30 @@ static bool nsgtk_plot_clip(const struct rect *clip)
cliprect.width = clip->x1 - clip->x0;
cliprect.height = clip->y1 - clip->y0;
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
nsgtk_set_colour(style->fill_colour);
nsgtk_set_solid();
@@ -105,10 +157,26 @@ static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, con
(angle2 + 90) * (M_PI / 180));
cairo_stroke(current_cr);
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style)
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
{
if (style->fill_type != PLOT_OP_TYPE_NONE) {
nsgtk_set_colour(style->fill_colour);
@@ -123,49 +191,60 @@ static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style)
nsgtk_set_colour(style->stroke_colour);
switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ case PLOT_OP_TYPE_SOLID: /* Solid colour */
default:
nsgtk_set_solid();
break;
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ case PLOT_OP_TYPE_DOT: /* Doted plot */
nsgtk_set_dotted();
break;
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ case PLOT_OP_TYPE_DASH: /* dashed plot */
nsgtk_set_dashed();
break;
}
- if (style->stroke_width == 0)
- cairo_set_line_width(current_cr, 1);
- else
- cairo_set_line_width(current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
cairo_arc(current_cr, x, y, radius, 0, M_PI * 2);
cairo_stroke(current_cr);
}
- return true;
+ return NSERROR_OK;
}
-static bool
-nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
nsgtk_set_colour(style->stroke_colour);
switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ case PLOT_OP_TYPE_SOLID: /* Solid colour */
default:
nsgtk_set_solid();
break;
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ case PLOT_OP_TYPE_DOT: /* Doted plot */
nsgtk_set_dotted();
break;
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ case PLOT_OP_TYPE_DASH: /* dashed plot */
nsgtk_set_dashed();
break;
}
@@ -174,23 +253,25 @@ nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
nsgtk_set_colour(style->stroke_colour);
}
- if (style->stroke_width == 0)
- cairo_set_line_width(current_cr, 1);
- else
- cairo_set_line_width(current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
/* core expects horizontal and vertical lines to be on pixels, not
- * between pixels */
- cairo_move_to(current_cr, (x0 == x1) ? x0 + 0.5 : x0,
- (y0 == y1) ? y0 + 0.5 : y0);
- cairo_line_to(current_cr, (x0 == x1) ? x1 + 0.5 : x1,
- (y0 == y1) ? y1 + 0.5 : y1);
+ * between pixels
+ */
+ cairo_move_to(current_cr,
+ (line->x0 == line->x1) ? line->x0 + 0.5 : line->x0,
+ (line->y0 == line->y1) ? line->y0 + 0.5 : line->y0);
+ cairo_line_to(current_cr,
+ (line->x0 == line->x1) ? line->x1 + 0.5 : line->x1,
+ (line->y0 == line->y1) ? line->y1 + 0.5 : line->y1);
cairo_stroke(current_cr);
- return true;
+ return NSERROR_OK;
}
-/** Plot a caret.
+
+/**
+ * Plot a caret.
*
* @note It is assumed that the plotters have been set up.
*/
@@ -207,14 +288,35 @@ void nsgtk_plot_caret(int x, int y, int h)
cairo_stroke(current_cr);
}
-static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
{
if (style->fill_type != PLOT_OP_TYPE_NONE) {
nsgtk_set_colour(style->fill_colour);
nsgtk_set_solid();
cairo_set_line_width(current_cr, 0);
- cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_rectangle(current_cr,
+ rect->x0,
+ rect->y0,
+ rect->x1 - rect->x0,
+ rect->y1 - rect->y0);
cairo_fill(current_cr);
cairo_stroke(current_cr);
}
@@ -223,32 +325,52 @@ static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_styl
nsgtk_set_colour(style->stroke_colour);
switch (style->stroke_type) {
- case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ case PLOT_OP_TYPE_SOLID: /* Solid colour */
default:
nsgtk_set_solid();
break;
- case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ case PLOT_OP_TYPE_DOT: /* Doted plot */
nsgtk_set_dotted();
break;
- case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ case PLOT_OP_TYPE_DASH: /* dashed plot */
nsgtk_set_dashed();
break;
}
- if (style->stroke_width == 0)
- cairo_set_line_width(current_cr, 1);
- else
- cairo_set_line_width(current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
- cairo_rectangle(current_cr, x0 + 0.5, y0 + 0.5, x1 - x0, y1 - y0);
+ cairo_rectangle(current_cr,
+ rect->x0 + 0.5,
+ rect->y0 + 0.5,
+ rect->x1 - rect->x0,
+ rect->y1 - rect->y0);
cairo_stroke(current_cr);
}
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
unsigned int i;
@@ -263,201 +385,46 @@ static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t
cairo_fill(current_cr);
cairo_stroke(current_cr);
- return true;
-}
-
-
-
-
-static bool nsgtk_plot_text(int x, int y, const char *text, size_t length,
- const struct plot_font_style *fstyle)
-{
- return nsfont_paint(x, y, text, length, fstyle);
-}
-
-
-
-static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg)
-{
- int x0, y0, x1, y1;
- int dsrcx, dsrcy, dwidth, dheight;
- int bmwidth, bmheight;
-
- cairo_surface_t *bmsurface = bitmap->surface;
-
- /* Bail early if we can */
- if (width == 0 || height == 0)
- /* Nothing to plot */
- return true;
- if ((x > (cliprect.x + cliprect.width)) ||
- ((x + width) < cliprect.x) ||
- (y > (cliprect.y + cliprect.height)) ||
- ((y + height) < cliprect.y)) {
- /* Image completely outside clip region */
- return true;
- }
-
- /* Get clip rectangle / image rectangle edge differences */
- x0 = cliprect.x - x;
- y0 = cliprect.y - y;
- x1 = (x + width) - (cliprect.x + cliprect.width);
- y1 = (y + height) - (cliprect.y + cliprect.height);
-
- /* Set initial draw geometry */
- dsrcx = x;
- dsrcy = y;
- dwidth = width;
- dheight = height;
-
- /* Manually clip draw coordinates to area of image to be rendered */
- if (x0 > 0) {
- /* Clip left */
- dsrcx += x0;
- dwidth -= x0;
- }
- if (y0 > 0) {
- /* Clip top */
- dsrcy += y0;
- dheight -= y0;
- }
- if (x1 > 0) {
- /* Clip right */
- dwidth -= x1;
- }
- if (y1 > 0) {
- /* Clip bottom */
- dheight -= y1;
- }
-
- if (dwidth == 0 || dheight == 0)
- /* Nothing to plot */
- return true;
-
- bmwidth = cairo_image_surface_get_width(bmsurface);
- bmheight = cairo_image_surface_get_height(bmsurface);
-
- /* Render the bitmap */
- if ((bmwidth == width) && (bmheight == height)) {
- /* Bitmap is not scaled */
- /* Plot the bitmap */
- cairo_set_source_surface(current_cr, bmsurface, x, y);
- cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
- cairo_fill(current_cr);
-
- } else {
- /* Bitmap is scaled */
- if ((bitmap->scsurface != NULL) &&
- ((cairo_image_surface_get_width(bitmap->scsurface) != width) ||
- (cairo_image_surface_get_height(bitmap->scsurface) != height))){
- cairo_surface_destroy(bitmap->scsurface);
- bitmap->scsurface = NULL;
- }
-
- if (bitmap->scsurface == NULL) {
- bitmap->scsurface = cairo_surface_create_similar(bmsurface,CAIRO_CONTENT_COLOR_ALPHA, width, height);
- cairo_t *cr = cairo_create(bitmap->scsurface);
-
- /* Scale *before* setting the source surface (1) */
- cairo_scale(cr, (double)width / bmwidth, (double)height / bmheight);
- cairo_set_source_surface(cr, bmsurface, 0, 0);
-
- /* To avoid getting the edge pixels blended with 0
- * alpha, which would occur with the default
- * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer (2)
- */
- cairo_pattern_set_extend(cairo_get_source(cr),
- CAIRO_EXTEND_REFLECT);
-
- /* Replace the destination with the source instead of
- * overlaying
- */
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-
- /* Do the actual drawing */
- cairo_paint(cr);
-
- cairo_destroy(cr);
-
- }
- /* Plot the scaled bitmap */
- cairo_set_source_surface(current_cr, bitmap->scsurface, x, y);
- cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
- cairo_fill(current_cr);
-
-
- }
-
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
-{
- int doneheight = 0, donewidth = 0;
- bool repeat_x = (flags & BITMAPF_REPEAT_X);
- bool repeat_y = (flags & BITMAPF_REPEAT_Y);
-
- /* Bail early if we can */
- if (width == 0 || height == 0)
- /* Nothing to plot */
- return true;
-
- if (!(repeat_x || repeat_y)) {
- /* Not repeating at all, so just pass it on */
- return nsgtk_plot_pixbuf(x, y, width, height, bitmap, bg);
- }
-
- if (y > cliprect.y) {
- doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
- } else {
- doneheight = y;
- }
-
- while (doneheight < (cliprect.y + cliprect.height)) {
- if (x > cliprect.x) {
- donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
- } else {
- donewidth = x;
- }
-
- while (donewidth < (cliprect.x + cliprect.width)) {
- nsgtk_plot_pixbuf(donewidth, doneheight,
- width, height, bitmap, bg);
- donewidth += width;
- if (!repeat_x)
- break;
- }
- doneheight += height;
-
- if (!repeat_y)
- break;
- }
-
- return true;
-}
-static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
unsigned int i;
cairo_matrix_t old_ctm, n_ctm;
if (n == 0)
- return true;
+ return NSERROR_OK;
if (p[0] != PLOTTER_PATH_MOVE) {
- LOG("Path does not start with move");
- return false;
+ NSLOG(netsurf, INFO, "Path does not start with move");
+ return NSERROR_INVALID;
}
-
/* Save CTM */
cairo_get_matrix(current_cr, &old_ctm);
/* Set up line style and width */
- cairo_set_line_width(current_cr, 1);
+ nsgtk_set_line_width(pstyle->stroke_width);
nsgtk_set_solid();
/* Load new CTM */
@@ -487,10 +454,10 @@ static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float w
p[i+5], p[i+6]);
i += 7;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
/* Reset matrix for safety */
cairo_set_matrix(current_cr, &old_ctm);
- return false;
+ return NSERROR_INVALID;
}
}
@@ -498,27 +465,184 @@ static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float w
cairo_set_matrix(current_cr, &old_ctm);
/* Now draw path */
- if (fill != NS_TRANSPARENT) {
- nsgtk_set_colour(fill);
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ nsgtk_set_colour(pstyle->fill_colour);
- if (c != NS_TRANSPARENT) {
+ if (pstyle->stroke_colour != NS_TRANSPARENT) {
/* Fill & Stroke */
cairo_fill_preserve(current_cr);
- nsgtk_set_colour(c);
+ nsgtk_set_colour(pstyle->stroke_colour);
cairo_stroke(current_cr);
} else {
/* Fill only */
cairo_fill(current_cr);
}
- } else if (c != NS_TRANSPARENT) {
+ } else if (pstyle->stroke_colour != NS_TRANSPARENT) {
/* Stroke only */
- nsgtk_set_colour(c);
+ nsgtk_set_colour(pstyle->stroke_colour);
cairo_stroke(current_cr);
}
- return true;
+ return NSERROR_OK;
}
+
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
+{
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+ GdkRectangle cliprect_bitmap;
+ cairo_surface_t *img_surface;
+ int img_width, img_height;
+
+ /* Bail early if we can */
+ if (width <= 0 || height <= 0) {
+ /* Nothing to plot */
+ return NSERROR_OK;
+ }
+
+ /* Copy the clip rectangle into bitmap plot clip rectangle */
+ cliprect_bitmap = cliprect;
+
+ /* Constrain bitmap plot rectangle for any lack of tiling */
+ if (!repeat_x) {
+ if (cliprect_bitmap.width > width) {
+ cliprect_bitmap.width = width;
+ }
+ if (cliprect_bitmap.x < x) {
+ cliprect_bitmap.x = x;
+ cliprect_bitmap.width -= x - cliprect_bitmap.x;
+ }
+ }
+ if (!repeat_y) {
+ if (cliprect_bitmap.height > height) {
+ cliprect_bitmap.height = height;
+ }
+ if (cliprect_bitmap.y < y) {
+ cliprect_bitmap.y = y;
+ cliprect_bitmap.height -= y - cliprect_bitmap.y;
+ }
+ }
+
+ /* Bail early if we can */
+ if (cliprect_bitmap.width <= 0 || cliprect_bitmap.height <= 0) {
+ /* Nothing to plot */
+ return NSERROR_OK;
+ }
+
+ /* Get the image's surface and intrinsic dimensions */
+ img_surface = bitmap->surface;
+ img_width = cairo_image_surface_get_width(img_surface);
+ img_height = cairo_image_surface_get_height(img_surface);
+
+ /* Set the source surface */
+ if ((img_width == width) && (img_height == height)) {
+ /* Non-scaled rendering */
+ cairo_set_source_surface(current_cr, img_surface, x, y);
+
+ /* Enable tiling if we're repeating */
+ if (repeat_x || repeat_y) {
+ cairo_pattern_set_extend(
+ cairo_get_source(current_cr),
+ CAIRO_EXTEND_REPEAT);
+ }
+
+ /* Render the bitmap */
+ cairo_rectangle(current_cr,
+ cliprect_bitmap.x,
+ cliprect_bitmap.y,
+ cliprect_bitmap.width,
+ cliprect_bitmap.height);
+ cairo_fill(current_cr);
+ } else {
+ /* Scaled rendering */
+ double scale_x = (double)width / img_width;
+ double scale_y = (double)height / img_height;
+
+ /* Save cairo rendering context state before scaling */
+ cairo_save(current_cr);
+ cairo_scale(current_cr, scale_x, scale_y);
+
+ cairo_set_source_surface(current_cr, img_surface,
+ x / scale_x, y / scale_y);
+
+ /* Enable tiling if we're repeating */
+ if (repeat_x || repeat_y) {
+ cairo_pattern_set_extend(
+ cairo_get_source(current_cr),
+ CAIRO_EXTEND_REPEAT);
+ }
+
+ /* Render the bitmap */
+ cairo_rectangle(current_cr,
+ cliprect_bitmap.x / scale_x,
+ cliprect_bitmap.y / scale_y,
+ cliprect_bitmap.width / scale_x,
+ cliprect_bitmap.height / scale_y);
+ cairo_fill(current_cr);
+
+ /* Restore pre-scaling cairo rendering state */
+ cairo_restore(current_cr);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
+{
+ return nsfont_paint(x, y, text, length, fstyle);
+}
+
+
/** GTK plotter table */
const struct plotter_table nsgtk_plotters = {
.clip = nsgtk_plot_clip,
@@ -532,6 +656,3 @@ const struct plotter_table nsgtk_plotters = {
.text = nsgtk_plot_text,
.option_knockout = true
};
-
-
-
diff --git a/frontends/gtk/plotters.h b/frontends/gtk/plotters.h
index c88a8da0c..453d5ceb5 100644
--- a/frontends/gtk/plotters.h
+++ b/frontends/gtk/plotters.h
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Target independent plotting (GDK / GTK+ interface).
+/**
+ * \file
+ * Target independent plotting GTK+ interface.
*/
#ifndef NETSURF_GTK_PLOTTERS_H
@@ -30,7 +31,6 @@ struct plotter_table;
extern const struct plotter_table nsgtk_plotters;
/* make sure this is NULL if no redraw is in progress */
-extern GtkWidget *current_widget;
extern cairo_t *current_cr;
void nsgtk_set_colour(colour c);
diff --git a/frontends/gtk/preferences.c b/frontends/gtk/preferences.c
index e51e77014..dac4a559d 100644
--- a/frontends/gtk/preferences.c
+++ b/frontends/gtk/preferences.c
@@ -621,7 +621,7 @@ comboboxLanguage_add_from_file(GtkListStore *liststore,
gtk_list_store_clear(liststore);
- LOG("Used %s for languages", file_location);
+ NSLOG(netsurf, INFO, "Used %s for languages", file_location);
while (fgets(buf, sizeof(buf), fp)) {
/* Ignore blank lines */
if (buf[0] == '\0')
@@ -668,7 +668,7 @@ nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget,
const char *accept_language;
if (priv->content_language == NULL) {
- LOG("content language list store unavailable");
+ NSLOG(netsurf, INFO, "content language list store unavailable");
return;
}
@@ -697,7 +697,7 @@ nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget,
}
}
if (res != NSERROR_OK) {
- LOG("error populatiung languages combo");
+ NSLOG(netsurf, INFO, "error populatiung languages combo");
}
}
@@ -826,7 +826,7 @@ ENTRY_SIGNALS(entryHomePageURL, homepage_url)
G_MODULE_EXPORT void
nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv)
{
- const gchar *url = nsurl_access(browser_window_get_url(priv->bw));
+ const gchar *url = nsurl_access(browser_window_access_url(priv->bw));
if (priv->entryHomePageURL != NULL) {
gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url);
@@ -989,14 +989,15 @@ GtkWidget* nsgtk_preferences(struct browser_window *bw, GtkWindow *parent)
res = nsgtk_builder_new_from_resname("options", &preferences_builder);
if (res != NSERROR_OK) {
- LOG("Preferences UI builder init failed");
+ NSLOG(netsurf, INFO, "Preferences UI builder init failed");
return NULL;
}
priv->dialog = gtk_builder_get_object(preferences_builder,
"dialogPreferences");
if (priv->dialog == NULL) {
- LOG("Unable to get object for preferences dialog");
+ NSLOG(netsurf, INFO,
+ "Unable to get object for preferences dialog");
/* release builder as were done with it */
g_object_unref(G_OBJECT(preferences_builder));
return NULL;
diff --git a/frontends/gtk/print.c b/frontends/gtk/print.c
index 55dcf6390..c4f1b0f7a 100644
--- a/frontends/gtk/print.c
+++ b/frontends/gtk/print.c
@@ -17,8 +17,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- /** \file
- * GTK printing (implementation).
+
+/**
+ * \file
+ * GTK printing implementation.
* All the functions and structures necessary for printing( signal handlers,
* plotters, printer) are here.
* Most of the plotters have been copied from the gtk_plotters.c file.
@@ -71,7 +73,7 @@ static inline void nsgtk_print_set_colour(colour c)
-static bool gtk_print_font_paint(int x, int y,
+static nserror gtk_print_font_paint(int x, int y,
const char *string, size_t length,
const plot_font_style_t *fstyle)
{
@@ -81,7 +83,7 @@ static bool gtk_print_font_paint(int x, int y,
PangoLayoutLine *line;
if (length == 0)
- return true;
+ return NSERROR_OK;
desc = nsfont_style_to_description(fstyle);
size = (gint) ((double) pango_font_description_get_size(desc) *
@@ -106,7 +108,7 @@ static bool gtk_print_font_paint(int x, int y,
g_object_unref(layout);
pango_font_description_free(desc);
- return true;
+ return NSERROR_OK;
}
@@ -131,10 +133,32 @@ static inline void nsgtk_print_set_dashed(void)
cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0);
}
-/** Set clipping area for subsequent plot operations. */
-static bool nsgtk_print_plot_clip(const struct rect *clip)
+/** Set cairo context line width. */
+static inline void nsgtk_set_line_width(plot_style_fixed width)
{
- LOG("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", clip->x0, clip->y0, clip->x1, clip->y1);
+ if (width == 0) {
+ cairo_set_line_width(gtk_print_current_cr, 1);
+ } else {
+ cairo_set_line_width(gtk_print_current_cr,
+ plot_style_fixed_to_double(width));
+ }
+}
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ NSLOG(netsurf, INFO,
+ "Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", clip->x0,
+ clip->y0, clip->x1, clip->y1);
/* Normalize cllipping area - to prevent overflows.
* See comment in pdf_plot_fill. */
@@ -153,10 +177,30 @@ static bool nsgtk_print_plot_clip(const struct rect *clip)
cliprect.width = clip_x1 - clip_x0;
cliprect.height = clip_y1 - clip_y0;
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
nsgtk_print_set_colour(style->fill_colour);
nsgtk_print_set_solid();
@@ -167,10 +211,26 @@ static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle
(angle2 + 90) * (M_PI / 180));
cairo_stroke(gtk_print_current_cr);
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *style)
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
{
if (style->fill_type != PLOT_OP_TYPE_NONE) {
nsgtk_print_set_colour(style->fill_colour);
@@ -199,19 +259,31 @@ static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *
break;
}
- if (style->stroke_width == 0)
- cairo_set_line_width(gtk_print_current_cr, 1);
- else
- cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2);
cairo_stroke(gtk_print_current_cr);
}
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
nsgtk_print_set_colour(style->stroke_colour);
@@ -230,42 +302,61 @@ static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_sty
break;
}
- if (style->stroke_width == 0)
- cairo_set_line_width(gtk_print_current_cr, 1);
- else
- cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
- cairo_move_to(gtk_print_current_cr, x0 + 0.5, y0 + 0.5);
- cairo_line_to(gtk_print_current_cr, x1 + 0.5, y1 + 0.5);
+ cairo_move_to(gtk_print_current_cr, line->x0 + 0.5, line->y0 + 0.5);
+ cairo_line_to(gtk_print_current_cr, line->x1 + 0.5, line->y1 + 0.5);
cairo_stroke(gtk_print_current_cr);
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
{
- LOG("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0, y0, x1, y1);
+ NSLOG(netsurf, INFO, "x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i",
+ rect->x0, rect->y0, rect->x1, rect->y1);
if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ int x0,y0,x1,y1;
nsgtk_print_set_colour(style->fill_colour);
nsgtk_print_set_solid();
/* Normalize boundaries of the area - to prevent overflows.
* See comment in pdf_plot_fill. */
- x0 = min(max(x0, 0), settings->page_width);
- y0 = min(max(y0, 0), settings->page_height);
- x1 = min(max(x1, 0), settings->page_width);
- y1 = min(max(y1, 0), settings->page_height);
+ x0 = min(max(rect->x0, 0), settings->page_width);
+ y0 = min(max(rect->y0, 0), settings->page_height);
+ x1 = min(max(rect->x1, 0), settings->page_width);
+ y1 = min(max(rect->y1, 0), settings->page_height);
cairo_set_line_width(gtk_print_current_cr, 0);
- cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_rectangle(gtk_print_current_cr,
+ x0, y0,
+ x1 - x0, y1 - y0);
cairo_fill(gtk_print_current_cr);
cairo_stroke(gtk_print_current_cr);
}
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- nsgtk_print_set_colour(style->stroke_colour);
+
+ nsgtk_print_set_colour(style->stroke_colour);
switch (style->stroke_type) {
case PLOT_OP_TYPE_SOLID: /**< Solid colour */
@@ -282,23 +373,28 @@ static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plo
break;
}
- if (style->stroke_width == 0)
- cairo_set_line_width(gtk_print_current_cr, 1);
- else
- cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+ nsgtk_set_line_width(style->stroke_width);
+
+ cairo_rectangle(gtk_print_current_cr,
+ rect->x0, rect->y0,
+ rect->x1 - rect->x0, rect->y1 - rect->y0);
- cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0);
cairo_stroke(gtk_print_current_cr);
}
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+
+static nserror
+nsgtk_print_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
unsigned int i;
- LOG("Plotting polygon.");
+ NSLOG(netsurf, INFO, "Plotting polygon.");
nsgtk_print_set_colour(style->fill_colour);
nsgtk_print_set_solid();
@@ -306,28 +402,46 @@ static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_st
cairo_set_line_width(gtk_print_current_cr, 0);
cairo_move_to(gtk_print_current_cr, p[0], p[1]);
- LOG("Starting line at: %i\t%i", p[0], p[1]);
+ NSLOG(netsurf, INFO, "Starting line at: %i\t%i", p[0], p[1]);
for (i = 1; i != n; i++) {
cairo_line_to(gtk_print_current_cr, p[i * 2], p[i * 2 + 1]);
- LOG("Drawing line to: %i\t%i", p[i * 2], p[i * 2 + 1]);
+ NSLOG(netsurf, INFO, "Drawing line to: %i\t%i", p[i * 2],
+ p[i * 2 + 1]);
}
cairo_fill(gtk_print_current_cr);
cairo_stroke(gtk_print_current_cr);
- return true;
+ return NSERROR_OK;
}
-static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill,
- float width, colour c, const float transform[6])
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
/* Only the internal SVG renderer uses this plot call currently,
* and the GTK version uses librsvg. Thus, we ignore this complexity,
* and just return true obliviously. */
- return true;
+ return NSERROR_OK;
}
@@ -445,9 +559,37 @@ static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height,
}
-static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_print_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width, int height,
+ colour bg,
+ bitmap_flags_t flags)
{
int doneheight = 0, donewidth = 0;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
@@ -495,12 +637,19 @@ static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
return true;
}
-static bool nsgtk_print_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+
+static nserror
+nsgtk_print_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
return gtk_print_font_paint(x, y, text, length, fstyle);
}
+
/** GTK print plotter table */
static const struct plotter_table nsgtk_print_plotters = {
.clip = nsgtk_print_plot_clip,
@@ -549,7 +698,7 @@ void gtk_print_signal_begin_print (GtkPrintOperation *operation,
int page_number;
double height_on_page, height_to_print;
- LOG("Begin print");
+ NSLOG(netsurf, INFO, "Begin print");
settings = user_data;
@@ -568,7 +717,11 @@ void gtk_print_signal_begin_print (GtkPrintOperation *operation,
} else {
- LOG("page_width: %f ;page_height: %f; content height: %lf", settings->page_width, settings->page_height, height_to_print);
+ NSLOG(netsurf, INFO,
+ "page_width: %f ;page_height: %f; content height: %lf",
+ settings->page_width,
+ settings->page_height,
+ height_to_print);
height_on_page = settings->page_height;
height_on_page = height_on_page -
@@ -592,7 +745,7 @@ void gtk_print_signal_begin_print (GtkPrintOperation *operation,
void gtk_print_signal_draw_page(GtkPrintOperation *operation,
GtkPrintContext *context, gint page_nr, gpointer user_data)
{
- LOG("Draw Page");
+ NSLOG(netsurf, INFO, "Draw Page");
gtk_print_current_cr = gtk_print_context_get_cairo_context(context);
print_draw_next_page(&gtk_printer, settings);
}
@@ -604,7 +757,7 @@ void gtk_print_signal_draw_page(GtkPrintOperation *operation,
void gtk_print_signal_end_print(GtkPrintOperation *operation,
GtkPrintContext *context, gpointer user_data)
{
- LOG("End print");
+ NSLOG(netsurf, INFO, "End print");
print_cleanup(content_to_print, &gtk_printer, user_data);
}
diff --git a/frontends/gtk/res/accelerators b/frontends/gtk/res/accelerators
new file mode 100644
index 000000000..2da229aff
--- /dev/null
+++ b/frontends/gtk/res/accelerators
@@ -0,0 +1,40 @@
+# GTK accelerator keys for menu entries
+# The keys must match those in the menus to be applied
+#
+# These are passed to gtk_accelerator_parse and must not be translated
+# The key names are the same as those in the gdk/gdkkeysyms.h header file
+# but without the leading “GDK_KEY_â€.
+
+gtkNextTab:<Control>Page_Down
+gtkPrevTab:<Control>Page_Up
+gtkCloseTab:<Control>w
+gtkNewTab:<Control>t
+gtkNewWindow:<Control>n
+gtkOpenFile:<Control>o
+gtkCloseWindow:<Control><shift>w
+gtkSavePage:<Control>s
+gtkPrintPreview:<Control><shift>p
+gtkPrint:<Control>p
+gtkQuitMenu:<Control>q
+gtkCut:<Control>x
+gtkCopy:<Control>c
+gtkPaste:<Control>v
+gtkSelectAll:<Control>a
+gtkFind:<Control>f
+gtkStop:Escape
+gtkReload:F5
+gtkZoomPlus:<Control>plus
+gtkZoomMinus:<Control>minus
+gtkZoomNormal:<Control>0
+gtkFullScreen:F11
+gtkPageSource:<Control>U
+gtkDownloads:<Control>j
+gtkBack:<alt>Left
+gtkForward:<alt>Right
+gtkHome:<alt>Down
+gtkLocalHistory:<Control>h
+gtkGlobalHistory:<Control><shift>h
+gtkAddBookMarks:<Control>d
+gtkShowBookMarks:F6
+gtkShowCookies:F9
+gtkOpenLocation:<Control>l
diff --git a/frontends/gtk/res/adblock.css b/frontends/gtk/res/adblock.css
index ff2485622..0d12aaa7c 120000
--- a/frontends/gtk/res/adblock.css
+++ b/frontends/gtk/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
+../../../resources/adblock.css \ No newline at end of file
diff --git a/frontends/gtk/res/ca-bundle.txt b/frontends/gtk/res/ca-bundle.txt
index 0b0e416ad..1187fa51a 120000
--- a/frontends/gtk/res/ca-bundle.txt
+++ b/frontends/gtk/res/ca-bundle.txt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
+../../../resources/ca-bundle \ No newline at end of file
diff --git a/frontends/gtk/res/de/welcome.html b/frontends/gtk/res/de/welcome.html
index 98a53b215..b77e23743 120000
--- a/frontends/gtk/res/de/welcome.html
+++ b/frontends/gtk/res/de/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/de/welcome.html,faf \ No newline at end of file
+../../../../resources/de/welcome.html \ No newline at end of file
diff --git a/frontends/gtk/res/default.css b/frontends/gtk/res/default.css
index a8579eb7c..fa3ae6c26 120000
--- a/frontends/gtk/res/default.css
+++ b/frontends/gtk/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
+../../../resources/default.css \ No newline at end of file
diff --git a/frontends/gtk/res/en/credits.html b/frontends/gtk/res/en/credits.html
index 252516fd7..f73ecd4aa 120000
--- a/frontends/gtk/res/en/credits.html
+++ b/frontends/gtk/res/en/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
+../../../../resources/en/credits.html \ No newline at end of file
diff --git a/frontends/gtk/res/en/licence.html b/frontends/gtk/res/en/licence.html
index 79f73669b..0c3b430b7 120000
--- a/frontends/gtk/res/en/licence.html
+++ b/frontends/gtk/res/en/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
+../../../../resources/en/licence.html \ No newline at end of file
diff --git a/frontends/gtk/res/en/maps.html b/frontends/gtk/res/en/maps.html
index bb3ffcbe7..507a4b248 120000
--- a/frontends/gtk/res/en/maps.html
+++ b/frontends/gtk/res/en/maps.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/maps.html,faf \ No newline at end of file
+../../../../resources/en/maps.html \ No newline at end of file
diff --git a/frontends/gtk/res/en/welcome.html b/frontends/gtk/res/en/welcome.html
index 601099223..543f31ddd 120000
--- a/frontends/gtk/res/en/welcome.html
+++ b/frontends/gtk/res/en/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
+../../../../resources/en/welcome.html \ No newline at end of file
diff --git a/frontends/gtk/res/history.gtk2.ui b/frontends/gtk/res/globalhistory.gtk2.ui
index 2b89ecb4b..2b89ecb4b 100644
--- a/frontends/gtk/res/history.gtk2.ui
+++ b/frontends/gtk/res/globalhistory.gtk2.ui
diff --git a/frontends/gtk/res/history.gtk3.ui b/frontends/gtk/res/globalhistory.gtk3.ui
index 7fa598f1e..7fa598f1e 100644
--- a/frontends/gtk/res/history.gtk3.ui
+++ b/frontends/gtk/res/globalhistory.gtk3.ui
diff --git a/frontends/gtk/res/icons b/frontends/gtk/res/icons
index 187efd6f9..94d2dc0df 120000
--- a/frontends/gtk/res/icons
+++ b/frontends/gtk/res/icons
@@ -1 +1 @@
-../../../!NetSurf/Resources/Icons/ \ No newline at end of file
+../../../resources/icons \ No newline at end of file
diff --git a/frontends/gtk/res/internal.css b/frontends/gtk/res/internal.css
index 17f9f1504..5583a9811 120000
--- a/frontends/gtk/res/internal.css
+++ b/frontends/gtk/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
+../../../resources/internal.css \ No newline at end of file
diff --git a/frontends/gtk/res/it/credits.html b/frontends/gtk/res/it/credits.html
index 64b78982e..2b7c99542 120000
--- a/frontends/gtk/res/it/credits.html
+++ b/frontends/gtk/res/it/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/credits.html,faf \ No newline at end of file
+../../../../resources/it/credits.html \ No newline at end of file
diff --git a/frontends/gtk/res/it/licence.html b/frontends/gtk/res/it/licence.html
index 4abc825d3..92afce85b 120000
--- a/frontends/gtk/res/it/licence.html
+++ b/frontends/gtk/res/it/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/licence.html,faf \ No newline at end of file
+../../../../resources/it/licence.html \ No newline at end of file
diff --git a/frontends/gtk/res/it/welcome.html b/frontends/gtk/res/it/welcome.html
index 59cef0551..2673ba948 120000
--- a/frontends/gtk/res/it/welcome.html
+++ b/frontends/gtk/res/it/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/it/welcome.html,faf \ No newline at end of file
+../../../../resources/it/welcome.html \ No newline at end of file
diff --git a/frontends/gtk/res/ja/welcome.html b/frontends/gtk/res/ja/welcome.html
index a2556ee4e..8b603f3df 120000
--- a/frontends/gtk/res/ja/welcome.html
+++ b/frontends/gtk/res/ja/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/ja/welcome.html,faf \ No newline at end of file
+../../../../resources/ja/welcome.html \ No newline at end of file
diff --git a/frontends/gtk/res/localhistory.gtk2.ui b/frontends/gtk/res/localhistory.gtk2.ui
new file mode 100644
index 000000000..9512b6289
--- /dev/null
+++ b/frontends/gtk/res/localhistory.gtk2.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndHistory">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Local History</property>
+ <property name="window_position">center</property>
+ <property name="default_width">20</property>
+ <property name="default_height">20</property>
+ <property name="type_hint">utility</property>
+ <property name="decorated">False</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkScrolledWindow" id="HistoryScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="HistoryViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <object class="GtkDrawingArea" id="HistoryDrawingArea">
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/localhistory.gtk3.ui b/frontends/gtk/res/localhistory.gtk3.ui
new file mode 100644
index 000000000..1a4b9004d
--- /dev/null
+++ b/frontends/gtk/res/localhistory.gtk3.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndHistory">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Local History</property>
+ <property name="window_position">center</property>
+ <property name="default_width">20</property>
+ <property name="default_height">20</property>
+ <property name="type_hint">utility</property>
+ <property name="decorated">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow" id="HistoryScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport" id="HistoryViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="HistoryDrawingArea">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/netsurf.gresource.xml b/frontends/gtk/res/netsurf.gresource.xml
index c7626b053..e8243254a 100644
--- a/frontends/gtk/res/netsurf.gresource.xml
+++ b/frontends/gtk/res/netsurf.gresource.xml
@@ -2,30 +2,32 @@
<gresources>
<gresource prefix="/org/netsurf">
<file>cookies.gtk2.ui</file>
- <file>history.gtk3.ui</file>
- <file>netsurf.gtk2.ui</file>
- <file>password.gtk3.ui</file>
- <file>toolbar.gtk2.ui</file>
+ <file>globalhistory.gtk3.ui</file>
+ <file>localhistory.gtk3.ui</file>
+ <file>netsurf.gtk2.ui</file>
+ <file>password.gtk3.ui</file>
+ <file>toolbar.gtk2.ui</file>
<file>warning.gtk3.ui</file>
- <file>cookies.gtk3.ui</file>
- <file>hotlist.gtk2.ui</file>
- <file>netsurf.gtk3.ui</file>
- <file>ssl.gtk2.ui</file>
+ <file>cookies.gtk3.ui</file>
+ <file>hotlist.gtk2.ui</file>
+ <file>netsurf.gtk3.ui</file>
+ <file>ssl.gtk2.ui</file>
<file>toolbar.gtk3.ui</file>
- <file>downloads.gtk2.ui</file>
- <file>hotlist.gtk3.ui</file>
- <file>options.gtk2.ui</file>
- <file>ssl.gtk3.ui</file>
+ <file>downloads.gtk2.ui</file>
+ <file>hotlist.gtk3.ui</file>
+ <file>options.gtk2.ui</file>
+ <file>ssl.gtk3.ui</file>
<file>viewdata.gtk2.ui</file>
- <file>downloads.gtk3.ui</file>
- <file>login.gtk2.ui</file>
- <file>options.gtk3.ui</file>
- <file>tabcontents.gtk2.ui</file>
+ <file>downloads.gtk3.ui</file>
+ <file>login.gtk2.ui</file>
+ <file>options.gtk3.ui</file>
+ <file>tabcontents.gtk2.ui</file>
<file>viewdata.gtk3.ui</file>
- <file>history.gtk2.ui</file>
- <file>login.gtk3.ui</file>
- <file>password.gtk2.ui</file>
- <file>tabcontents.gtk3.ui</file>
+ <file>localhistory.gtk2.ui</file>
+ <file>globalhistory.gtk2.ui</file>
+ <file>login.gtk3.ui</file>
+ <file>password.gtk2.ui</file>
+ <file>tabcontents.gtk3.ui</file>
<file>warning.gtk2.ui</file>
<file preprocess="to-pixdata">favicon.png</file>
<file preprocess="to-pixdata">netsurf.xpm</file>
@@ -66,5 +68,6 @@
<file>icons/hotlist-rmv.png</file>
<file>icons/search.png</file>
<file>languages</file>
+ <file>accelerators</file>
</gresource>
</gresources>
diff --git a/frontends/gtk/res/netsurf.png b/frontends/gtk/res/netsurf.png
index 905512c25..d0ab72a5e 120000
--- a/frontends/gtk/res/netsurf.png
+++ b/frontends/gtk/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
+../../../resources/netsurf.png \ No newline at end of file
diff --git a/frontends/gtk/res/nl/credits.html b/frontends/gtk/res/nl/credits.html
index 9c983987a..71b27e40a 120000
--- a/frontends/gtk/res/nl/credits.html
+++ b/frontends/gtk/res/nl/credits.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/credits.html,faf \ No newline at end of file
+../../../../resources/nl/credits.html \ No newline at end of file
diff --git a/frontends/gtk/res/nl/licence.html b/frontends/gtk/res/nl/licence.html
index 8a10d2073..5aaf1cb44 120000
--- a/frontends/gtk/res/nl/licence.html
+++ b/frontends/gtk/res/nl/licence.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/licence.html,faf \ No newline at end of file
+../../../../resources/nl/licence.html \ No newline at end of file
diff --git a/frontends/gtk/res/nl/welcome.html b/frontends/gtk/res/nl/welcome.html
index 6b2ba7742..ef7a97cc9 120000
--- a/frontends/gtk/res/nl/welcome.html
+++ b/frontends/gtk/res/nl/welcome.html
@@ -1 +1 @@
-../../../../!NetSurf/Resources/nl/welcome.html,faf \ No newline at end of file
+../../../../resources/nl/welcome.html \ No newline at end of file
diff --git a/frontends/gtk/res/options.gtk2.ui b/frontends/gtk/res/options.gtk2.ui
index d5542ba5d..a1162585d 100644
--- a/frontends/gtk/res/options.gtk2.ui
+++ b/frontends/gtk/res/options.gtk2.ui
@@ -2,6 +2,297 @@
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
+ <object class="GtkAdjustment" id="adjustment_animation_time">
+ <property name="lower">0.10000000000000001</property>
+ <property name="upper">10</property>
+ <property name="value">0.10000000000000001</property>
+ <property name="step_increment">0.10000000000000001</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_cache_disc_size">
+ <property name="upper">4096</property>
+ <property name="value">1024</property>
+ <property name="step_increment">32</property>
+ <property name="page_increment">256</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_cache_memory_size">
+ <property name="upper">2048</property>
+ <property name="value">16</property>
+ <property name="step_increment">4</property>
+ <property name="page_increment">16</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_disc_cache_age">
+ <property name="upper">999</property>
+ <property name="value">28</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_fetching_cached">
+ <property name="upper">100</property>
+ <property name="value">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_fetching_max">
+ <property name="lower">1</property>
+ <property name="upper">100</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_fetching_perhost">
+ <property name="lower">1</property>
+ <property name="upper">100</property>
+ <property name="value">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_font_default_size">
+ <property name="lower">1</property>
+ <property name="upper">99.900000000000006</property>
+ <property name="value">16</property>
+ <property name="step_increment">0.10000000000000001</property>
+ <property name="page_increment">2</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_history_age">
+ <property name="upper">999</property>
+ <property name="value">28</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">28</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_pdf_lmargin">
+ <property name="upper">999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_pdf_scale">
+ <property name="lower">1</property>
+ <property name="upper">1000</property>
+ <property name="value">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment_proxy_port">
+ <property name="lower">1</property>
+ <property name="upper">65535</property>
+ <property name="value">3128</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xpad">3</property>
+ <property name="stock">gtk-apply</property>
+ </object>
+ <object class="GtkListStore" id="liststore_content_language">
+ <columns>
+ <!-- column-name Code -->
+ <column type="gchararray"/>
+ <!-- column-name Description -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">en</col>
+ <col id="1" translatable="yes">English</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_defaultfont">
+ <columns>
+ <!-- column-name Type -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesFonttypeSans</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesFonttypeSerif</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesFonttypeMonospace</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesFonttypeCursive</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesFonttypeFantasy</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_developer_view">
+ <columns>
+ <!-- column-name Type -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesDeveloperViewWindow</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesDeveloperViewTab</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesDeveloperViewEditor</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_image_loading">
+ <columns>
+ <!-- column-name Type -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesImageLoadBoth</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesImageLoadFore</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesImageLoadBack</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesImageLoadNone</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_proxy_type">
+ <columns>
+ <!-- column-name Type -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesProxyTypeDirect</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesProxyTypeManual</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesProxyTypeBasic</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesProxyTypeNLTM</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesProxyTypeSystem</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_search_provider">
+ <columns>
+ <!-- column-name Provider -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0">Google</col>
+ </row>
+ <row>
+ <col id="0">Yahoo!</col>
+ </row>
+ <row>
+ <col id="0">Microsoft Live</col>
+ </row>
+ <row>
+ <col id="0">Buisiness.com</col>
+ </row>
+ <row>
+ <col id="0">Omgili</col>
+ </row>
+ <row>
+ <col id="0">BBC News</col>
+ </row>
+ <row>
+ <col id="0">Ubuntu Packages</col>
+ </row>
+ <row>
+ <col id="0">Creative Commons</col>
+ </row>
+ <row>
+ <col id="0">Ask</col>
+ </row>
+ <row>
+ <col id="0">Answers</col>
+ </row>
+ <row>
+ <col id="0">Dictionary.com</col>
+ </row>
+ <row>
+ <col id="0">YouTube</col>
+ </row>
+ <row>
+ <col id="0">AeroMP3</col>
+ </row>
+ <row>
+ <col id="0">AOL</col>
+ </row>
+ <row>
+ <col id="0">Baidu</col>
+ </row>
+ <row>
+ <col id="0">Amazon</col>
+ </row>
+ <row>
+ <col id="0">Ebay</col>
+ </row>
+ <row>
+ <col id="0">IMBD</col>
+ </row>
+ <row>
+ <col id="0">ESPN</col>
+ </row>
+ <row>
+ <col id="0">Wikipedia</col>
+ </row>
+ <row>
+ <col id="0">DuckDuckGo</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_tab_position">
+ <columns>
+ <!-- column-name Position -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesTabLocTop</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesTabLocLeft</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesTabLocRight</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesTabLocBottom</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="liststore_toolbar_buttontype">
+ <columns>
+ <!-- column-name Type -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">preferencesButtonTypeSmall</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesButtonTypeLarge</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesButtonTypeLargeText</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">preferencesButtonTypeText</col>
+ </row>
+ </data>
+ </object>
<object class="GtkDialog" id="dialogPreferences">
<property name="can_focus">False</property>
<property name="border_width">5</property>
@@ -2178,7 +2469,6 @@
</child>
<child>
<object class="GtkVBox" id="vbox_pdfexport">
- <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
@@ -2583,6 +2873,12 @@
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="expand">True</property>
@@ -2710,295 +3006,4 @@
<action-widget response="-7">close</action-widget>
</action-widgets>
</object>
- <object class="GtkListStore" id="liststore_search_provider">
- <columns>
- <!-- column-name Provider -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0">Google</col>
- </row>
- <row>
- <col id="0">Yahoo!</col>
- </row>
- <row>
- <col id="0">Microsoft Live</col>
- </row>
- <row>
- <col id="0">Buisiness.com</col>
- </row>
- <row>
- <col id="0">Omgili</col>
- </row>
- <row>
- <col id="0">BBC News</col>
- </row>
- <row>
- <col id="0">Ubuntu Packages</col>
- </row>
- <row>
- <col id="0">Creative Commons</col>
- </row>
- <row>
- <col id="0">Ask</col>
- </row>
- <row>
- <col id="0">Answers</col>
- </row>
- <row>
- <col id="0">Dictionary.com</col>
- </row>
- <row>
- <col id="0">YouTube</col>
- </row>
- <row>
- <col id="0">AeroMP3</col>
- </row>
- <row>
- <col id="0">AOL</col>
- </row>
- <row>
- <col id="0">Baidu</col>
- </row>
- <row>
- <col id="0">Amazon</col>
- </row>
- <row>
- <col id="0">Ebay</col>
- </row>
- <row>
- <col id="0">IMBD</col>
- </row>
- <row>
- <col id="0">ESPN</col>
- </row>
- <row>
- <col id="0">Wikipedia</col>
- </row>
- <row>
- <col id="0">DuckDuckGo</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_tab_position">
- <columns>
- <!-- column-name Position -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesTabLocTop</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesTabLocLeft</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesTabLocRight</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesTabLocBottom</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_toolbar_buttontype">
- <columns>
- <!-- column-name Type -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesButtonTypeSmall</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesButtonTypeLarge</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesButtonTypeLargeText</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesButtonTypeText</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_image_loading">
- <columns>
- <!-- column-name Type -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesImageLoadBoth</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesImageLoadFore</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesImageLoadBack</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesImageLoadNone</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_defaultfont">
- <columns>
- <!-- column-name Type -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesFonttypeSans</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesFonttypeSerif</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesFonttypeMonospace</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesFonttypeCursive</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesFonttypeFantasy</col>
- </row>
- </data>
- </object>
- <object class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xpad">3</property>
- <property name="stock">gtk-apply</property>
- </object>
- <object class="GtkListStore" id="liststore_proxy_type">
- <columns>
- <!-- column-name Type -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesProxyTypeDirect</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesProxyTypeManual</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesProxyTypeBasic</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesProxyTypeNLTM</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesProxyTypeSystem</col>
- </row>
- </data>
- </object>
- <object class="GtkAdjustment" id="adjustment_animation_time">
- <property name="value">0.10000000000000001</property>
- <property name="lower">0.10000000000000001</property>
- <property name="upper">10</property>
- <property name="step_increment">0.10000000000000001</property>
- <property name="page_increment">1</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_font_default_size">
- <property name="value">16</property>
- <property name="lower">1</property>
- <property name="upper">99.900000000000006</property>
- <property name="step_increment">0.10000000000000001</property>
- <property name="page_increment">2</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_history_age">
- <property name="value">28</property>
- <property name="upper">999</property>
- <property name="step_increment">1</property>
- <property name="page_increment">28</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_cache_memory_size">
- <property name="value">16</property>
- <property name="upper">2048</property>
- <property name="step_increment">4</property>
- <property name="page_increment">16</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_cache_disc_size">
- <property name="value">1024</property>
- <property name="upper">4096</property>
- <property name="step_increment">32</property>
- <property name="page_increment">256</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_disc_cache_age">
- <property name="value">28</property>
- <property name="upper">999</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_proxy_port">
- <property name="value">3128</property>
- <property name="lower">1</property>
- <property name="upper">65535</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_fetching_max">
- <property name="value">10</property>
- <property name="lower">1</property>
- <property name="upper">100</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_fetching_perhost">
- <property name="value">1</property>
- <property name="lower">1</property>
- <property name="upper">100</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_fetching_cached">
- <property name="value">1</property>
- <property name="upper">100</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_pdf_scale">
- <property name="value">100</property>
- <property name="lower">1</property>
- <property name="upper">1000</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkAdjustment" id="adjustment_pdf_lmargin">
- <property name="upper">999</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
- <object class="GtkListStore" id="liststore_content_language">
- <columns>
- <!-- column-name Code -->
- <column type="gchararray"/>
- <!-- column-name Description -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">en</col>
- <col id="1" translatable="yes">English</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_developer_view">
- <columns>
- <!-- column-name Type -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0" translatable="yes">preferencesDeveloperViewWindow</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesDeveloperViewTab</col>
- </row>
- <row>
- <col id="0" translatable="yes">preferencesDeveloperViewEditor</col>
- </row>
- </data>
- </object>
</interface>
diff --git a/frontends/gtk/res/quirks.css b/frontends/gtk/res/quirks.css
index 88aabe48c..1e752cb9e 120000
--- a/frontends/gtk/res/quirks.css
+++ b/frontends/gtk/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
+../../../resources/quirks.css \ No newline at end of file
diff --git a/frontends/gtk/res/toolbar.gtk2.ui b/frontends/gtk/res/toolbar.gtk2.ui
index d84db5c8c..4e8805a6f 100644
--- a/frontends/gtk/res/toolbar.gtk2.ui
+++ b/frontends/gtk/res/toolbar.gtk2.ui
@@ -1,67 +1,84 @@
-<?xml version="1.0"?>
-<!--*- mode: xml -*-->
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <object class="GtkWindow" id="toolbarwindow">
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="dialogToolbar">
<property name="width_request">700</property>
<property name="height_request">450</property>
- <property name="title" translatable="yes"/>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="focus_on_map">True</property>
- <property name="urgency_hint">False</property>
- <child>
- <object class="GtkVBox" id="windowvbox">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">gtkToolBarTitle</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">2</property>
<child>
- <object class="GtkLabel" id="toolbarlabel">
+ <object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
- <property name="label" translatable="yes">Move items from store to toolbar Rearrange items in toolbar Move items from toolbar to store</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="can_focus">False</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Move items from store to toolbar</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Rearrange items in toolbar</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Move items from toolbar to store</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="padding">2</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <property name="can_focus">False</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkVBox" id="widgetvbox">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="can_focus">False</property>
<child>
<placeholder/>
</child>
@@ -71,119 +88,85 @@
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="position">1</property>
</packing>
</child>
- <child>
- <object class="GtkHBox" id="buttonhbox">
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
<child>
- <object class="GtkButton" id="resetbutton">
+ <object class="GtkButton" id="reset">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
+ <property name="receives_default">False</property>
<child>
<object class="GtkHBox" id="button1hbox">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-refresh</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="refreshbuttonlabel">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Reset to defaults</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
- <property name="padding">10</property>
<property name="expand">False</property>
<property name="fill">True</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkButton" id="okbutton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="label">gtk-apply</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </object>
- <packing>
<property name="padding">10</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="cancelbutton">
+ <object class="GtkButton" id="close">
+ <property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
+ <property name="receives_default">True</property>
<property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
</child>
+ <action-widgets>
+ <action-widget response="0">reset</action-widget>
+ <action-widget response="0">close</action-widget>
+ </action-widgets>
</object>
</interface>
diff --git a/frontends/gtk/res/toolbar.gtk3.ui b/frontends/gtk/res/toolbar.gtk3.ui
index d84db5c8c..1f1148703 100644
--- a/frontends/gtk/res/toolbar.gtk3.ui
+++ b/frontends/gtk/res/toolbar.gtk3.ui
@@ -1,186 +1,134 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
<!--*- mode: xml -*-->
<interface>
- <object class="GtkWindow" id="toolbarwindow">
+ <requires lib="gtk+" version="3.0"/>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-refresh</property>
+ </object>
+ <object class="GtkDialog" id="dialogToolbar">
<property name="width_request">700</property>
<property name="height_request">450</property>
- <property name="title" translatable="yes"/>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_NONE</property>
- <property name="modal">False</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="focus_on_map">True</property>
- <property name="urgency_hint">False</property>
- <child>
- <object class="GtkVBox" id="windowvbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
- <child>
- <object class="GtkLabel" id="toolbarlabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Move items from store to toolbar Rearrange items in toolbar Move items from toolbar to store</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </object>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_NONE</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">gtkToolBarTitle</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
<child>
- <object class="GtkViewport" id="viewport1">
+ <object class="GtkButton" id="reset">
+ <property name="label" translatable="yes">Reset To Defaults</property>
<property name="visible">True</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <child>
- <object class="GtkVBox" id="widgetvbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
- <child>
- <placeholder/>
- </child>
- </object>
- </child>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image2</property>
+ <property name="yalign">0.52999997138977051</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
- <object class="GtkHBox" id="buttonhbox">
+ <object class="GtkGrid" id="grid1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="can_focus">False</property>
+ <property name="column_homogeneous">True</property>
<child>
- <object class="GtkButton" id="resetbutton">
+ <object class="GtkLabel" id="label1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <child>
- <object class="GtkHBox" id="button1hbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
- <child>
- <object class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="stock">gtk-refresh</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </object>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="refreshbuttonlabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Reset to defaults</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </object>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </object>
- </child>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Move items from store to toolbar</property>
</object>
<packing>
- <property name="padding">10</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
</packing>
</child>
<child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkButton" id="okbutton">
+ <object class="GtkLabel" id="label2">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="label">gtk-apply</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Rearrange items in toolbar</property>
</object>
<packing>
- <property name="padding">10</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="cancelbutton">
+ <object class="GtkLabel" id="label3">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Move items from toolbar to store</property>
</object>
<packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkVBox" id="widgetvbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
diff --git a/frontends/gtk/resources.c b/frontends/gtk/resources.c
index dfe3d3dad..fc3ac6ff3 100644
--- a/frontends/gtk/resources.c
+++ b/frontends/gtk/resources.c
@@ -81,7 +81,8 @@ static struct nsgtk_resource_s ui_resource[] = {
RES_ENTRY("ssl"),
RES_ENTRY("toolbar"),
RES_ENTRY("downloads"),
- RES_ENTRY("history"),
+ RES_ENTRY("globalhistory"),
+ RES_ENTRY("localhistory"),
RES_ENTRY("options"),
RES_ENTRY("hotlist"),
RES_ENTRY("cookies"),
@@ -128,6 +129,7 @@ static struct nsgtk_resource_s direct_resource[] = {
RES_ENTRY("icons/hotlist-rmv.png"),
RES_ENTRY("icons/search.png"),
RES_ENTRY("languages"),
+ RES_ENTRY("accelerators"),
RES_ENTRY("Messages"),
{ NULL, 0, NSGTK_RESOURCE_FILE, NULL },
};
@@ -177,11 +179,12 @@ init_resource(char **respath, struct nsgtk_resource_s *resource)
langv = g_get_language_names();
+ /* look for resource under per language paths */
while (langv[langc] != NULL) {
+ /* allocate and fill a full resource name path buffer */
resnamelen = snprintf(NULL, 0,
"/org/netsurf/%s/%s",
langv[langc], resource->name);
-
resname = malloc(resnamelen + 1);
if (resname == NULL) {
return NSERROR_NOMEM;
@@ -190,6 +193,7 @@ init_resource(char **respath, struct nsgtk_resource_s *resource)
"/org/netsurf/%s/%s",
langv[langc], resource->name);
+ /* check if resource is present */
present = g_resources_get_info(resname,
G_RESOURCE_LOOKUP_FLAGS_NONE,
NULL, NULL, NULL);
@@ -197,16 +201,19 @@ init_resource(char **respath, struct nsgtk_resource_s *resource)
/* found an entry in the resources */
resource->path = resname;
resource->type = NSGTK_RESOURCE_GLIB;
- LOG("Found gresource path %s", resource->path);
+ NSLOG(netsurf, INFO, "Found gresource path %s",
+ resource->path);
return NSERROR_OK;
}
- /*LOG("gresource \"%s\" not found", resname);*/
+ NSLOG(netsurf, DEEPDEBUG,
+ "gresource \"%s\" not found", resname);
free(resname);
langc++;
}
- resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
+ /* allocate and fill a full resource name path buffer with no language*/
+ resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
resname = malloc(resnamelen + 1);
if (resname == NULL) {
return NSERROR_NOMEM;
@@ -220,27 +227,31 @@ init_resource(char **respath, struct nsgtk_resource_s *resource)
/* found an entry in the resources */
resource->path = resname;
resource->type = NSGTK_RESOURCE_GLIB;
- LOG("Found gresource path %s", resource->path);
+ NSLOG(netsurf, INFO, "Found gresource path %s",
+ resource->path);
return NSERROR_OK;
}
- /*LOG("gresource \"%s\" not found", resname);*/
+ NSLOG(netsurf, DEEPDEBUG, "gresource \"%s\" not found", resname);
free(resname);
#endif
+ /* look for file on disc */
resname = filepath_find(respath, resource->name);
- if (resname == NULL) {
- LOG("Unable to find resource %s on resource path",
- resource->name);
- return NSERROR_NOT_FOUND;
+ if (resname != NULL) {
+ /* found an entry on the path */
+ resource->path = resname;
+ resource->type = NSGTK_RESOURCE_FILE;
+
+ NSLOG(netsurf, INFO,
+ "Found file resource path %s", resource->path);
+ return NSERROR_OK;
}
- /* found an entry on the path */
- resource->path = resname;
- resource->type = NSGTK_RESOURCE_FILE;
+ NSLOG(netsurf, INFO, "Unable to find resource %s on resource path",
+ resource->name);
- LOG("Found file resource path %s", resource->path);
- return NSERROR_OK;
+ return NSERROR_NOT_FOUND;
}
/**
@@ -294,21 +305,21 @@ init_pixbuf_resource(char **respath, struct nsgtk_resource_s *resource)
if (strncmp(resource->name, "menu_cursor.png", resource->len) == 0) {
resource->path = (char *)&menu_cursor_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
- LOG("Found builtin for %s", resource->name);
+ NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
return NSERROR_OK;
}
if (strncmp(resource->name, "netsurf.xpm", resource->len) == 0) {
resource->path = (char *)&netsurf_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
- LOG("Found builtin for %s", resource->name);
+ NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
return NSERROR_OK;
}
if (strncmp(resource->name, "favicon.png", resource->len) == 0) {
resource->path = (char *)&favicon_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
- LOG("Found builtin for %s", resource->name);
+ NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
return NSERROR_OK;
}
#endif
@@ -376,7 +387,7 @@ find_resource_from_name(const char *resname, struct nsgtk_resource_s *resource)
#ifdef SHOW_GRESOURCE
/**
- * Debug dump of all resources compile din via GResource.
+ * Debug dump of all resources compiled in via GResource.
*/
static void list_gresource(void)
{
@@ -388,13 +399,13 @@ static void list_gresource(void)
G_RESOURCE_LOOKUP_FLAGS_NONE,
&gerror);
if (gerror) {
- LOG("gerror %s", gerror->message);
+ NSLOG(netsurf, INFO, "gerror %s", gerror->message);
g_error_free(gerror);
} else {
cur = reslist;
while (cur != NULL && *cur != NULL) {
- LOG("gres %s", *cur);
+ NSLOG(netsurf, INFO, "gres %s", *cur);
cur++;
}
g_strfreev(reslist);
@@ -487,12 +498,17 @@ nsgdk_pixbuf_new_from_resname(const char *resname, GdkPixbuf **pixbuf_out)
if (new_pixbuf == NULL) {
if (error != NULL) {
- LOG("Unable to create pixbuf from file for %s with path %s \"%s\"",
- resource->name, resource->path, error->message);
+ NSLOG(netsurf, INFO,
+ "Unable to create pixbuf from file for %s with path %s \"%s\"",
+ resource->name,
+ resource->path,
+ error->message);
g_error_free(error);
} else {
- LOG("Unable to create pixbuf from file for %s with path %s",
- resource->name, resource->path);
+ NSLOG(netsurf, INFO,
+ "Unable to create pixbuf from file for %s with path %s",
+ resource->name,
+ resource->path);
}
return NSERROR_INIT_FAILED;
}
@@ -520,8 +536,11 @@ nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
if (!gtk_builder_add_from_file(new_builder,
ui_res->path,
&error)) {
- LOG("Unable to add UI builder from file for %s with path %s \"%s\"",
- ui_res->name, ui_res->path, error->message);
+ NSLOG(netsurf, INFO,
+ "Unable to add UI builder from file for %s with path %s \"%s\"",
+ ui_res->name,
+ ui_res->path,
+ error->message);
g_error_free(error);
g_object_unref(G_OBJECT(new_builder));
return NSERROR_INIT_FAILED;
@@ -530,8 +549,11 @@ nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
if (!nsgtk_builder_add_from_resource(new_builder,
ui_res->path,
&error)) {
- LOG("Unable to add UI builder from resource for %s with path %s \"%s\"",
- ui_res->name, ui_res->path, error->message);
+ NSLOG(netsurf, INFO,
+ "Unable to add UI builder from resource for %s with path %s \"%s\"",
+ ui_res->name,
+ ui_res->path,
+ error->message);
g_error_free(error);
g_object_unref(G_OBJECT(new_builder));
return NSERROR_INIT_FAILED;
diff --git a/frontends/gtk/scaffolding.c b/frontends/gtk/scaffolding.c
index bbc568e15..bedad9140 100644
--- a/frontends/gtk/scaffolding.c
+++ b/frontends/gtk/scaffolding.c
@@ -61,6 +61,7 @@
#include "gtk/bitmap.h"
#include "gtk/gui.h"
#include "gtk/global_history.h"
+#include "gtk/local_history.h"
#include "gtk/hotlist.h"
#include "gtk/download.h"
#include "gtk/menu.h"
@@ -103,15 +104,12 @@ static gboolean nsgtk_on_##q##_activate(GtkButton *widget, gpointer data)
/** Core scaffolding structure. */
struct nsgtk_scaffolding {
- /** global linked list of scaffoldings for gui interface adjustments */
+ /** global linked list of scaffolding for gui interface adjustments */
struct nsgtk_scaffolding *next, *prev;
/** currently active gui browsing context */
struct gui_window *top_level;
- /** local history window */
- struct gtk_history_window *history_window;
-
/** Builder object scaffold was created from */
GtkBuilder *builder;
@@ -150,7 +148,6 @@ struct nsgtk_scaffolding {
/** link popup menu */
struct nsgtk_link_menu *link_menu;
-
};
/** current scaffold for model dialogue use */
@@ -159,19 +156,30 @@ static struct nsgtk_scaffolding *scaf_current;
/** global list for interface changes */
static struct nsgtk_scaffolding *scaf_list = NULL;
-/** holds the context data for what's under the pointer, when the contextual
- * menu is opened.
+/**
+ * holds the context data for what's under the pointer, when the
+ * contextual menu is opened.
*/
static struct browser_window_features current_menu_features;
/**
- * Helper to hide popup menu entries by grouping
+ * Helper to hide popup menu entries by grouping.
+ *
+ * \param menu The popup menu to modify.
+ * \param submenu flag to indicate if submenus should be hidden.
+ * \param nav flag to indicate if navigation entries should be hidden.
+ * \param cnp flag to indicate if cut and paste entries should be hidden.
+ * \param custom flag to indicate if menu customisation is hidden.
*/
-static void popup_menu_hide(struct nsgtk_popup_menu *menu, bool submenu,
- bool nav, bool cnp, bool custom)
+static void
+popup_menu_hide(struct nsgtk_popup_menu *menu,
+ bool submenu,
+ bool nav,
+ bool cnp,
+ bool custom)
{
- if (submenu){
+ if (submenu) {
gtk_widget_hide(GTK_WIDGET(menu->file_menuitem));
gtk_widget_hide(GTK_WIDGET(menu->edit_menuitem));
gtk_widget_hide(GTK_WIDGET(menu->view_menuitem));
@@ -200,13 +208,24 @@ static void popup_menu_hide(struct nsgtk_popup_menu *menu, bool submenu,
}
+
/**
- * Helper to show popup menu entries by grouping
+ * Helper to show popup menu entries by grouping.
+ *
+ * \param menu The popup menu to modify.
+ * \param submenu flag to indicate if submenus should be visible.
+ * \param nav flag to indicate if navigation entries should be visible.
+ * \param cnp flag to indicate if cut and paste entries should be visible.
+ * \param custom flag to indicate if menu customisation is visible.
*/
-static void popup_menu_show(struct nsgtk_popup_menu *menu, bool submenu,
- bool nav, bool cnp, bool custom)
+static void
+popup_menu_show(struct nsgtk_popup_menu *menu,
+ bool submenu,
+ bool nav,
+ bool cnp,
+ bool custom)
{
- if (submenu){
+ if (submenu) {
gtk_widget_show(GTK_WIDGET(menu->file_menuitem));
gtk_widget_show(GTK_WIDGET(menu->edit_menuitem));
gtk_widget_show(GTK_WIDGET(menu->view_menuitem));
@@ -232,7 +251,6 @@ static void popup_menu_show(struct nsgtk_popup_menu *menu, bool submenu,
if (custom) {
gtk_widget_show(GTK_WIDGET(menu->customize_menuitem));
}
-
}
@@ -240,16 +258,20 @@ static void popup_menu_show(struct nsgtk_popup_menu *menu, bool submenu,
/**
* resource cleanup function for window destruction.
+ *
+ * gtk event called when window is being destroyed. Need to free any
+ * resources associated with this scaffold,
+ *
+ * \param widget the widget being destroyed
+ * \param data The context pointer passed when the connection was made.
*/
static void scaffolding_window_destroy(GtkWidget *widget, gpointer data)
{
struct nsgtk_scaffolding *gs = data;
- LOG("scaffold:%p", gs);
+ NSLOG(netsurf, INFO, "scaffold:%p", gs);
- if ((gs->history_window) && (gs->history_window->window)) {
- gtk_widget_destroy(GTK_WIDGET(gs->history_window->window));
- }
+ nsgtk_local_history_hide();
if (gs->prev != NULL) {
gs->prev->next = gs->next;
@@ -260,7 +282,7 @@ static void scaffolding_window_destroy(GtkWidget *widget, gpointer data)
gs->next->prev = gs->prev;
}
- LOG("scaffold list head: %p", scaf_list);
+ NSLOG(netsurf, INFO, "scaffold list head: %p", scaf_list);
if (scaf_list == NULL) {
/* no more open windows - stop the browser */
@@ -268,11 +290,21 @@ static void scaffolding_window_destroy(GtkWidget *widget, gpointer data)
}
}
-/* signal delivered on window delete event, allowing to halt close if
- * download is in progress
+
+/**
+ * gtk event callback on window delete event.
+ *
+ * prevent window close if download is in progress
+ *
+ * \param widget The widget receiving the delete event
+ * \param event The event
+ * \param data The context pointer passed when the connection was made.
+ * \return TRUE to indicate message handled.
*/
-static gboolean scaffolding_window_delete_event(GtkWidget *widget,
- GdkEvent *event, gpointer data)
+static gboolean
+scaffolding_window_delete_event(GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
{
struct nsgtk_scaffolding *g = data;
@@ -282,12 +314,16 @@ static gboolean scaffolding_window_delete_event(GtkWidget *widget,
return TRUE;
}
+
/**
- * Update the scaffoling button sensitivity, url bar and local history size
+ * Update the scaffolding controls
+ *
+ * The button sensitivity, url bar and local history visibility are updated
+ *
+ * \param g The scaffolding context to update
*/
static void scaffolding_update_context(struct nsgtk_scaffolding *g)
{
- int width, height;
struct browser_window *bw = nsgtk_get_browser_window(g->top_level);
g->buttons[BACK_BUTTON]->sensitivity =
@@ -300,34 +336,41 @@ static void scaffolding_update_context(struct nsgtk_scaffolding *g)
/* update the url bar, particularly necessary when tabbing */
browser_window_refresh_url_bar(bw);
- /* update the local history window, as well as queuing a redraw
- * for it.
- */
- browser_window_history_size(bw, &width, &height);
- gtk_widget_set_size_request(GTK_WIDGET(g->history_window->drawing_area),
- width, height);
- gtk_widget_queue_draw(GTK_WIDGET(g->history_window->drawing_area));
+ nsgtk_local_history_hide();
}
+
/**
* Make the throbber run.
+ *
+ * scheduled callback to update the throbber
+ *
+ * \param p The context passed when scheduled.
*/
static void nsgtk_throb(void *p)
{
struct nsgtk_scaffolding *g = p;
- if (g->throb_frame >= (nsgtk_throbber->nframes - 1))
+ if (g->throb_frame >= (nsgtk_throbber->nframes - 1)) {
g->throb_frame = 1;
- else
+ } else {
g->throb_frame++;
+ }
- gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[
- g->throb_frame]);
+ gtk_image_set_from_pixbuf(g->throbber,
+ nsgtk_throbber->framedata[g->throb_frame]);
nsgtk_schedule(100, nsgtk_throb, p);
}
-static guint nsgtk_scaffolding_update_edit_actions_sensitivity(
+
+/**
+ * edit the sensitivity of focused widget
+ *
+ * \param g The scaffolding context.
+ */
+static guint
+nsgtk_scaffolding_update_edit_actions_sensitivity(
struct nsgtk_scaffolding *g)
{
GtkWidget *widget = gtk_window_get_focus(g->window);
@@ -361,7 +404,13 @@ static guint nsgtk_scaffolding_update_edit_actions_sensitivity(
}
-static void nsgtk_scaffolding_enable_edit_actions_sensitivity(
+/**
+ * make edit actions sensitive
+ *
+ * \param g The scaffolding context.
+ */
+static void
+nsgtk_scaffolding_enable_edit_actions_sensitivity(
struct nsgtk_scaffolding *g)
{
@@ -374,22 +423,46 @@ static void nsgtk_scaffolding_enable_edit_actions_sensitivity(
}
/* signal handling functions for the toolbar, URL bar, and menu bar */
-static gboolean nsgtk_window_edit_menu_clicked(GtkWidget *widget,
- struct nsgtk_scaffolding *g)
+
+/**
+ * gtk event for edit menu being show
+ *
+ * \param widget The menu widget
+ * \param g scaffolding handle
+ * \return TRUE to indicate event handled
+ */
+static gboolean
+nsgtk_window_edit_menu_shown(GtkWidget *widget,
+ struct nsgtk_scaffolding *g)
{
nsgtk_scaffolding_update_edit_actions_sensitivity(g);
return TRUE;
}
-static gboolean nsgtk_window_edit_menu_hidden(GtkWidget *widget,
- struct nsgtk_scaffolding *g)
+/**
+ * gtk event handler for edit menu being hidden
+ *
+ * \param widget The menu widget
+ * \param g scaffolding handle
+ * \return TRUE to indicate event handled
+ */
+static gboolean
+nsgtk_window_edit_menu_hidden(GtkWidget *widget,
+ struct nsgtk_scaffolding *g)
{
nsgtk_scaffolding_enable_edit_actions_sensitivity(g);
return TRUE;
}
+/**
+ * gtk event handler for popup menu being hidden.
+ *
+ * \param widget The menu widget
+ * \param g scaffolding handle
+ * \return TRUE to indicate event handled
+ */
static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget,
struct nsgtk_scaffolding *g)
{
@@ -397,6 +470,7 @@ static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget,
return TRUE;
}
+/* exported interface documented in gtk/scaffolding.h */
gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data)
{
struct nsgtk_scaffolding *g = data;
@@ -419,8 +493,14 @@ gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data)
return TRUE;
}
+
/**
* update handler for URL entry widget
+ *
+ * \param widget The widget receiving the delete event
+ * \param event The event
+ * \param data The context pointer passed when the connection was made.
+ * \return TRUE to indicate signal handled.
*/
gboolean
nsgtk_window_url_changed(GtkWidget *widget,
@@ -430,11 +510,23 @@ nsgtk_window_url_changed(GtkWidget *widget,
return nsgtk_completion_update(GTK_ENTRY(widget));
}
+
/**
* Event handler for popup menu on toolbar.
+ *
+ * \param toolbar The toolbar being clicked
+ * \param x The x coordinate where the click happened
+ * \param y The x coordinate where the click happened
+ * \param button the buttons being pressed
+ * \param data The context pointer passed when the connection was made.
+ * \return TRUE to indicate event handled.
*/
-static gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar,
- gint x, gint y, gint button, gpointer data)
+static gboolean
+nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar,
+ gint x,
+ gint y,
+ gint button,
+ gpointer data)
{
struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
@@ -448,23 +540,40 @@ static gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar,
return TRUE;
}
+
/**
* Update the menus when the number of tabs changes.
+ *
+ * \param notebook The notebook all the tabs are in
+ * \param page The newly added page container widget
+ * \param page_num The index of the newly added page
+ * \param g The scaffolding context containing the notebook
*/
-static void nsgtk_window_tabs_add(GtkNotebook *notebook,
- GtkWidget *page, guint page_num, struct nsgtk_scaffolding *g)
+static void
+nsgtk_window_tabs_add(GtkNotebook *notebook,
+ GtkWidget *page,
+ guint page_num,
+ struct nsgtk_scaffolding *g)
{
gboolean visible = gtk_notebook_get_show_tabs(g->notebook);
- g_object_set(g->menu_bar->view_submenu->tabs_menuitem, "visible", visible, NULL);
- g_object_set(g->menu_popup->view_submenu->tabs_menuitem, "visible", visible, NULL);
+ g_object_set(g->menu_bar->view_submenu->tabs_menuitem,
+ "visible", visible, NULL);
+ g_object_set(g->menu_popup->view_submenu->tabs_menuitem,
+ "visible", visible, NULL);
g->buttons[NEXTTAB_BUTTON]->sensitivity = visible;
g->buttons[PREVTAB_BUTTON]->sensitivity = visible;
g->buttons[CLOSETAB_BUTTON]->sensitivity = visible;
nsgtk_scaffolding_set_sensitivity(g);
}
+
/**
* Update the menus when the number of tabs changes.
+ *
+ * \param notebook The notebook all the tabs are in
+ * \param page The page container widget being removed
+ * \param page_num The index of the removed page
+ * \param gs The scaffolding context containing the notebook
*/
static void
nsgtk_window_tabs_remove(GtkNotebook *notebook,
@@ -473,7 +582,7 @@ nsgtk_window_tabs_remove(GtkNotebook *notebook,
struct nsgtk_scaffolding *gs)
{
/* if the scaffold is being destroyed it is not useful to
- * update the state, futher many of the widgets may have
+ * update the state, further many of the widgets may have
* already been destroyed.
*/
if (gtk_widget_in_destruction(GTK_WIDGET(gs->window)) == TRUE) {
@@ -497,6 +606,8 @@ nsgtk_window_tabs_remove(GtkNotebook *notebook,
/**
* Handle opening a file path.
+ *
+ * \param filename The filename to open.
*/
static void nsgtk_openfile_open(const char *filename)
{
@@ -560,6 +671,7 @@ MULTIHANDLER(newwindow)
return TRUE;
}
+/* exported interface documented in gtk/scaffolding.h */
nserror nsgtk_scaffolding_new_tab(struct gui_window *gw)
{
struct browser_window *bw = nsgtk_get_browser_window(gw);
@@ -629,8 +741,16 @@ MULTIHANDLER(openfile)
return TRUE;
}
-static gboolean nsgtk_filter_directory(const GtkFileFilterInfo *info,
- gpointer data)
+/**
+ * callback to determine if a path is a directory.
+ *
+ * \param info The path information
+ * \param data context pointer set to NULL
+ * \return TRUE if path is a directory else false
+ */
+static gboolean
+nsgtk_filter_directory(const GtkFileFilterInfo *info,
+ gpointer data)
{
DIR *d = opendir(info->filename);
if (d == NULL)
@@ -660,7 +780,7 @@ MULTIHANDLER(savepage)
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter);
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fc), filter);
- res = nsurl_nice(browser_window_get_url(
+ res = nsurl_nice(browser_window_access_url(
nsgtk_get_browser_window(g->top_level)), &path, false);
if (res != NSERROR_OK) {
path = strdup(messages_get("SaveText"));
@@ -685,7 +805,10 @@ MULTIHANDLER(savepage)
path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
d = opendir(path);
if (d == NULL) {
- LOG("Unable to open directory %s for complete save: %s", path, strerror(errno));
+ NSLOG(netsurf, INFO,
+ "Unable to open directory %s for complete save: %s",
+ path,
+ strerror(errno));
if (errno == ENOTDIR)
nsgtk_warning("NoDirError", path);
else
@@ -717,9 +840,9 @@ MULTIHANDLER(pdf)
char *url_name;
nserror res;
- LOG("Print preview (generating PDF) started.");
+ NSLOG(netsurf, INFO, "Print preview (generating PDF) started.");
- res = nsurl_nice(browser_window_get_url(bw), &url_name, true);
+ res = nsurl_nice(browser_window_access_url(bw), &url_name, true);
if (res != NSERROR_OK) {
nsgtk_warning(messages_get_errorcode(res), 0);
return TRUE;
@@ -735,7 +858,7 @@ MULTIHANDLER(pdf)
strncat(dirname, "/", PATH_MAX - strlen(dirname));
dirname[PATH_MAX - 1] = '\0';
- /* this way the scale used by PDF functions is synchronized with that
+ /* this way the scale used by PDF functions is synchronised with that
* used by the all-purpose print interface
*/
haru_nsfont_set_scale((float)option_export_scale / 100);
@@ -792,7 +915,7 @@ MULTIHANDLER(plaintext)
char *filename;
nserror res;
- res = nsurl_nice(browser_window_get_url(
+ res = nsurl_nice(browser_window_access_url(
nsgtk_get_browser_window(g->top_level)),
&filename, false);
if (res != NSERROR_OK) {
@@ -891,7 +1014,7 @@ MULTIHANDLER(print)
CONTENT_TEXTPLAIN) {
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
- g->window,
+ g->window,
NULL);
}
@@ -1101,10 +1224,10 @@ MULTIHANDLER(selectall)
struct browser_window *bw = nsgtk_get_browser_window(g->top_level);
if (nsgtk_widget_has_focus(GTK_WIDGET(g->url_bar))) {
- LOG("Selecting all URL bar text");
+ NSLOG(netsurf, INFO, "Selecting all URL bar text");
gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1);
} else {
- LOG("Selecting all document text");
+ NSLOG(netsurf, INFO, "Selecting all document text");
browser_window_key_press(bw, NS_KEY_SELECT_ALL);
}
@@ -1466,31 +1589,13 @@ MULTIHANDLER(home)
MULTIHANDLER(localhistory)
{
struct browser_window *bw = nsgtk_get_browser_window(g->top_level);
+ nserror res;
- int x,y, width, height, mainwidth, mainheight, margin = 20;
- /* if entries of the same url but different frag_ids have been added
- * the history needs redrawing (what throbber code normally does)
- */
-
- scaffolding_update_context(g);
- gtk_window_get_position(g->window, &x, &y);
- gtk_window_get_size(g->window, &mainwidth, &mainheight);
- browser_window_history_size(bw, &width, &height);
- width = (width + g->historybase + margin > mainwidth) ?
- mainwidth - g->historybase : width + margin;
- height = (height + g->toolbarbase + margin > mainheight) ?
- mainheight - g->toolbarbase : height + margin;
- gtk_window_set_default_size(g->history_window->window, width, height);
- gtk_widget_set_size_request(GTK_WIDGET(g->history_window->window),
- -1, -1);
- gtk_window_resize(g->history_window->window, width, height);
- gtk_window_set_transient_for(g->history_window->window, g->window);
- nsgtk_window_set_opacity(g->history_window->window, 0.9);
- gtk_widget_show(GTK_WIDGET(g->history_window->window));
- gtk_window_move(g->history_window->window, x + g->historybase, y +
- g->toolbarbase);
- gdk_window_raise(nsgtk_widget_get_window(GTK_WIDGET(g->history_window->window)));
-
+ res = nsgtk_local_history_present(g->window, bw);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to initialise local history window.");
+ }
return TRUE;
}
@@ -1499,7 +1604,8 @@ MULTIHANDLER(globalhistory)
nserror res;
res = nsgtk_global_history_present();
if (res != NSERROR_OK) {
- LOG("Unable to initialise global history window.");
+ NSLOG(netsurf, INFO,
+ "Unable to initialise global history window.");
}
return TRUE;
}
@@ -1510,7 +1616,7 @@ MULTIHANDLER(addbookmarks)
if (bw == NULL || !browser_window_has_content(bw))
return TRUE;
- hotlist_add_url(browser_window_get_url(bw));
+ hotlist_add_url(browser_window_access_url(bw));
return TRUE;
}
@@ -1519,7 +1625,7 @@ MULTIHANDLER(showbookmarks)
nserror res;
res = nsgtk_hotlist_present();
if (res != NSERROR_OK) {
- LOG("Unable to initialise bookmark window.");
+ NSLOG(netsurf, INFO, "Unable to initialise bookmark window.");
}
return TRUE;
}
@@ -1529,7 +1635,7 @@ MULTIHANDLER(showcookies)
nserror res;
res = nsgtk_cookies_present();
if (res != NSERROR_OK) {
- LOG("Unable to initialise cookies window.");
+ NSLOG(netsurf, INFO, "Unable to initialise cookies window.");
}
return TRUE;
}
@@ -1643,98 +1749,6 @@ BUTTONHANDLER(history)
#undef CHECKHANDLER
#undef BUTTONHANDLER
-#if GTK_CHECK_VERSION(3,0,0)
-
-static gboolean
-nsgtk_history_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
-{
- struct rect clip;
- struct gtk_history_window *hw = (struct gtk_history_window *)data;
- struct browser_window *bw =
- nsgtk_get_browser_window(hw->g->top_level);
-
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &nsgtk_plotters
- };
- double x1;
- double y1;
- double x2;
- double y2;
-
- current_widget = widget;
- current_cr = cr;
-
- cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
-
- clip.x0 = x1;
- clip.y0 = y1;
- clip.x1 = x2;
- clip.y1 = y2;
-
- ctx.plot->clip(&clip);
-
- browser_window_history_redraw(bw, &ctx);
-
- current_widget = NULL;
-
- return FALSE;
-}
-#else
-
-/* signal handler functions for the local history window */
-static gboolean
-nsgtk_history_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer g)
-{
- struct rect clip;
- struct gtk_history_window *hw = (struct gtk_history_window *)g;
- struct browser_window *bw =
- nsgtk_get_browser_window(hw->g->top_level);
-
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &nsgtk_plotters
- };
-
- current_widget = widget;
-
- current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget));
-
- clip.x0 = event->area.x;
- clip.y0 = event->area.y;
- clip.x1 = event->area.x + event->area.width;
- clip.y1 = event->area.y + event->area.height;
- ctx.plot->clip(&clip);
-
- browser_window_history_redraw(bw, &ctx);
-
- cairo_destroy(current_cr);
-
- current_widget = NULL;
-
- return FALSE;
-}
-
-#endif /* GTK_CHECK_VERSION(3,0,0) */
-
-static gboolean nsgtk_history_button_press_event(GtkWidget *widget,
- GdkEventButton *event, gpointer g)
-{
- struct gtk_history_window *hw = (struct gtk_history_window *)g;
- struct browser_window *bw =
- nsgtk_get_browser_window(hw->g->top_level);
-
- LOG("X=%g, Y=%g", event->x, event->y);
-
- browser_window_history_click(bw, event->x, event->y, false);
-
- return TRUE;
-}
-
-
-
static void nsgtk_attach_menu_handlers(struct nsgtk_scaffolding *g)
{
for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
@@ -2059,12 +2073,13 @@ struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
int i;
GtkAccelGroup *group;
- gs = malloc(sizeof(*gs));
+ gs = calloc(1, sizeof(*gs));
if (gs == NULL) {
return NULL;
}
- LOG("Constructing a scaffold of %p for gui_window %p", gs, toplevel);
+ NSLOG(netsurf, INFO,
+ "Constructing a scaffold of %p for gui_window %p", gs, toplevel);
gs->top_level = toplevel;
@@ -2188,35 +2203,6 @@ struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
gtk_widget_set_size_request(GTK_WIDGET(
gs->buttons[HISTORY_BUTTON]->button), 20, -1);
- /* create the local history window to be associated with this scaffold */
- gs->history_window = malloc(sizeof(struct gtk_history_window));
- gs->history_window->g = gs;
- gs->history_window->window =
- GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
- gtk_window_set_transient_for(gs->history_window->window, gs->window);
- gtk_window_set_title(gs->history_window->window, "NetSurf History");
- gtk_window_set_type_hint(gs->history_window->window,
- GDK_WINDOW_TYPE_HINT_UTILITY);
- gs->history_window->scrolled =
- GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(0, 0));
- gtk_container_add(GTK_CONTAINER(gs->history_window->window),
- GTK_WIDGET(gs->history_window->scrolled));
-
- gtk_widget_show(GTK_WIDGET(gs->history_window->scrolled));
- gs->history_window->drawing_area =
- GTK_DRAWING_AREA(gtk_drawing_area_new());
-
- gtk_widget_set_events(GTK_WIDGET(gs->history_window->drawing_area),
- GDK_EXPOSURE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK);
- nsgtk_widget_override_background_color(GTK_WIDGET(gs->history_window->drawing_area),
- GTK_STATE_NORMAL,
- 0, 0xffff, 0xffff, 0xffff);
- nsgtk_scrolled_window_add_with_viewport(gs->history_window->scrolled,
- GTK_WIDGET(gs->history_window->drawing_area));
- gtk_widget_show(GTK_WIDGET(gs->history_window->drawing_area));
-
/* set up URL bar completion */
gs->url_bar_completion = nsgtk_url_entry_completion_new(gs);
@@ -2228,17 +2214,6 @@ struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
#define CONNECT(obj, sig, callback, ptr) \
g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
- /* connect history window signals to their handlers */
- nsgtk_connect_draw_event(GTK_WIDGET(gs->history_window->drawing_area),
- G_CALLBACK(nsgtk_history_draw_event),
- gs->history_window);
- /*CONNECT(gs->history_window->drawing_area, "motion_notify_event",
- nsgtk_history_motion_notify_event, gs->history_window);*/
- CONNECT(gs->history_window->drawing_area, "button_press_event",
- nsgtk_history_button_press_event, gs->history_window);
- CONNECT(gs->history_window->window, "delete_event",
- gtk_widget_hide_on_delete, NULL);
-
g_signal_connect_after(gs->notebook, "page-added",
G_CALLBACK(nsgtk_window_tabs_add), gs);
g_signal_connect_after(gs->notebook, "page-removed",
@@ -2252,7 +2227,7 @@ struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* toolbar URL bar menu bar search bar signal handlers */
CONNECT(gs->menu_bar->edit_submenu->edit, "show",
- nsgtk_window_edit_menu_clicked, gs);
+ nsgtk_window_edit_menu_shown, gs);
CONNECT(gs->menu_bar->edit_submenu->edit, "hide",
nsgtk_window_edit_menu_hidden, gs);
@@ -2309,7 +2284,7 @@ struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* finally, show the window. */
gtk_widget_show(GTK_WIDGET(gs->window));
- LOG("creation complete");
+ NSLOG(netsurf, INFO, "creation complete");
return gs;
}
@@ -2497,7 +2472,8 @@ gui_search_web_provider_update(const char *provider_name,
GdkPixbuf *srch_pixbuf = NULL;
char *searchcontent;
- LOG("name:%s bitmap %p", provider_name, provider_bitmap);
+ NSLOG(netsurf, INFO, "name:%s bitmap %p", provider_name,
+ provider_bitmap);
if (provider_bitmap != NULL) {
srch_pixbuf = nsgdk_pixbuf_get_from_surface(provider_bitmap->surface, 16, 16);
@@ -2515,7 +2491,11 @@ gui_search_web_provider_update(const char *provider_name,
/* set the search provider parameters up in each scaffold */
for (current = scaf_list; current != NULL; current = current->next) {
- /* add ico to each window's toolbar */
+ if (current->webSearchEntry == NULL) {
+ continue;
+ }
+
+ /* add ico to each window's toolbar */
if (srch_pixbuf != NULL) {
nsgtk_entry_set_icon_from_pixbuf(current->webSearchEntry,
GTK_ENTRY_ICON_PRIMARY,
@@ -2599,13 +2579,6 @@ GtkMenuBar *nsgtk_scaffolding_menu_bar(struct nsgtk_scaffolding *g)
}
/* exported interface documented in gtk/scaffolding.h */
-struct gtk_history_window *
-nsgtk_scaffolding_history_window(struct nsgtk_scaffolding *g)
-{
- return g->history_window;
-}
-
-/* exported interface documented in gtk/scaffolding.h */
struct nsgtk_scaffolding *nsgtk_scaffolding_iterate(struct nsgtk_scaffolding *g)
{
if (g == NULL) {
@@ -2774,7 +2747,7 @@ void nsgtk_scaffolding_context_menu(struct nsgtk_scaffolding *g,
gtk_widget_show(GTK_WIDGET(g->menu_popup->paste_menuitem));
}
- /* hide customize */
+ /* hide customise */
popup_menu_hide(g->menu_popup, false, false, false, true);
}
diff --git a/frontends/gtk/schedule.c b/frontends/gtk/schedule.c
index cf0333388..d5b45674b 100644
--- a/frontends/gtk/schedule.c
+++ b/frontends/gtk/schedule.c
@@ -21,14 +21,10 @@
#include <stdbool.h>
#include "utils/errors.h"
+#include "utils/log.h"
#include "gtk/schedule.h"
-#ifdef DEBUG_GTK_SCHEDULE
-#include "utils/log.h"
-#else
-#define LOG(format, args...) ((void) 0)
-#endif
/** Killable callback closure embodiment. */
typedef struct {
@@ -50,7 +46,7 @@ nsgtk_schedule_generic_callback(gpointer data)
_nsgtk_callback_t *cb = (_nsgtk_callback_t *)(data);
if (cb->callback_killed) {
/* This callback instance has been killed. */
- LOG("CB at %p already dead.", cb);
+ NSLOG(schedule, DEBUG, "CB at %p already dead.", cb);
}
queued_callbacks = g_list_remove(queued_callbacks, cb);
pending_callbacks = g_list_append(pending_callbacks, cb);
@@ -64,7 +60,9 @@ nsgtk_schedule_kill_callback(void *_target, void *_match)
_nsgtk_callback_t *match = (_nsgtk_callback_t *)_match;
if ((target->callback == match->callback) &&
(target->context == match->context)) {
- LOG("Found match for %p(%p), killing.", target->callback, target->context);
+ NSLOG(schedule, DEBUG,
+ "Found match for %p(%p), killing.",
+ target->callback, target->context);
target->callback = NULL;
target->context = NULL;
target->callback_killed = true;
@@ -122,7 +120,9 @@ schedule_run(void)
/* Clear the pending list. */
pending_callbacks = NULL;
- LOG("Captured a run of %d callbacks to fire.", g_list_length(this_run));
+ NSLOG(schedule, DEBUG,
+ "Captured a run of %d callbacks to fire.",
+ g_list_length(this_run));
/* Run all the callbacks which made it this far. */
while (this_run != NULL) {
diff --git a/frontends/gtk/ssl_cert.c b/frontends/gtk/ssl_cert.c
index 5388f0194..9d98db1f6 100644
--- a/frontends/gtk/ssl_cert.c
+++ b/frontends/gtk/ssl_cert.c
@@ -183,7 +183,7 @@ nserror gtk_cert_verify(struct nsurl *url,
res = nsgtk_builder_new_from_resname("ssl", &ncwin->builder);
if (res != NSERROR_OK) {
- LOG("SSL UI builder init failed");
+ NSLOG(netsurf, INFO, "SSL UI builder init failed");
free(ncwin);
return res;
}
diff --git a/frontends/gtk/tabs.c b/frontends/gtk/tabs.c
index 6adce3a06..dbe9d405b 100644
--- a/frontends/gtk/tabs.c
+++ b/frontends/gtk/tabs.c
@@ -147,18 +147,20 @@ nsgtk_tab_switch_page_after(GtkNotebook *notebook,
if ((srcpagenum != -1) &&
(srcpagenum != (gint)selpagenum)) {
/* ensure the add tab is not actually selected */
- LOG("src %d sel %d", srcpagenum, selpagenum);
+ NSLOG(netsurf, INFO, "src %d sel %d", srcpagenum,
+ selpagenum);
srcpage = gtk_notebook_get_nth_page(notebook, srcpagenum);
gw = g_object_get_data(G_OBJECT(srcpage), "gui_window");
if ((gw != NULL) && (nsgtk_get_scaffold(gw) != NULL)) {
error = nsgtk_scaffolding_new_tab(gw);
if (error != NSERROR_OK) {
- LOG("Failed to open new tab.");
+ NSLOG(netsurf, INFO,
+ "Failed to open new tab.");
}
}
}
} else {
- LOG("sel %d", selpagenum);
+ NSLOG(netsurf, INFO, "sel %d", selpagenum);
/* tab with page in it */
gw = g_object_get_data(G_OBJECT(selpage), "gui_window");
if (gw != NULL) {
diff --git a/frontends/gtk/throbber.c b/frontends/gtk/throbber.c
index 9392c3909..b8efceca1 100644
--- a/frontends/gtk/throbber.c
+++ b/frontends/gtk/throbber.c
@@ -59,12 +59,14 @@ nserror nsgtk_throbber_init(void)
if (res != NSERROR_OK) {
break;
}
- LOG("%s",resname);
+ NSLOG(netsurf, INFO, "%s", resname);
}
if (frame < 1) {
/* we need at least two frames - one for idle, one for active */
- LOG("Insufficent number of frames (%d) in throbber animation.", frame);
+ NSLOG(netsurf, INFO,
+ "Insufficent number of frames (%d) in throbber animation.",
+ frame);
res = NSERROR_INIT_FAILED;
}
diff --git a/frontends/gtk/toolbar.c b/frontends/gtk/toolbar.c
index ac24a78ca..e93bd49f9 100644
--- a/frontends/gtk/toolbar.c
+++ b/frontends/gtk/toolbar.c
@@ -26,6 +26,7 @@
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsoption.h"
+#include "utils/file.h"
#include "gtk/gui.h"
#include "gtk/warn.h"
@@ -44,7 +45,7 @@ static bool edit_mode = false;
struct nsgtk_toolbar_custom_store {
GtkWidget *window;
- GtkWidget *store_buttons[PLACEHOLDER_BUTTON];
+ GtkWidget *store_buttons[PLACEHOLDER_BUTTON];
GtkWidget *widgetvbox;
GtkWidget *currentbar;
char numberh; /* current horizontal location while adding */
@@ -107,13 +108,13 @@ static char *remove_underscores(const char *s, bool replacespace)
ret = malloc(len + 1);
if (ret == NULL) {
return NULL;
- }
+ }
for (i = 0, ii = 0; i < len; i++) {
if (s[i] != '_') {
ret[ii++] = s[i];
- } else if (replacespace) {
+ } else if (replacespace) {
ret[ii++] = ' ';
- }
+ }
}
ret[ii] = '\0';
return ret;
@@ -125,6 +126,7 @@ static char *remove_underscores(const char *s, bool replacespace)
*
* \param tbbutton button reference
* \param iconsize The size of icons to select.
+ * \param usedef Use the default image if not found.
* \return default images.
*/
static GtkImage *
@@ -193,6 +195,7 @@ nsgtk_theme_image_default(nsgtk_toolbar_button tbbutton,
*
* \param tbbutton search button reference
* \param iconsize The size of icons to select.
+ * \param usedef Use the default image if not found.
* \return default search image.
*/
@@ -206,18 +209,18 @@ nsgtk_theme_searchimage_default(nsgtk_search_buttons tbbutton,
switch (tbbutton) {
case (SEARCH_BACK_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_GO_BACK,
- iconsize));
+ image = GTK_IMAGE(nsgtk_image_new_from_stock(
+ NSGTK_STOCK_GO_BACK, iconsize));
break;
case (SEARCH_FORWARD_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_GO_FORWARD,
- iconsize));
+ image = GTK_IMAGE(nsgtk_image_new_from_stock(
+ NSGTK_STOCK_GO_FORWARD, iconsize));
break;
case (SEARCH_CLOSE_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_CLOSE,
- iconsize));
+ image = GTK_IMAGE(nsgtk_image_new_from_stock(
+ NSGTK_STOCK_CLOSE, iconsize));
break;
default:
@@ -225,7 +228,8 @@ nsgtk_theme_searchimage_default(nsgtk_search_buttons tbbutton,
}
if (usedef && (image == NULL)) {
- image = GTK_IMAGE(nsgtk_image_new_from_stock("gtk-missing-image", iconsize));
+ image = GTK_IMAGE(nsgtk_image_new_from_stock(
+ "gtk-missing-image", iconsize));
}
return image;
@@ -253,7 +257,6 @@ static struct nsgtk_theme *nsgtk_theme_load(GtkIconSize iconsize, bool usedef)
theme->image[btnloop] = nsgtk_theme_image_default(btnloop,
iconsize,
usedef);
-
}
for (btnloop = SEARCH_BACK_BUTTON;
@@ -821,8 +824,9 @@ static void nsgtk_toolbar_close(struct nsgtk_scaffolding *g)
*/
static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data)
{
- edit_mode = false;
struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
+
+ edit_mode = false;
/* reset g->buttons->location */
for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
nsgtk_scaffolding_button(g, i)->location =
@@ -948,6 +952,7 @@ void nsgtk_toolbar_customization_load(struct nsgtk_scaffolding *g)
*/
static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g)
{
+ char *choices = NULL;
char *order;
int order_len = PLACEHOLDER_BUTTON * 12; /* length of order buffer */
int tbidx;
@@ -969,7 +974,8 @@ static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g)
nsgtk_scaffolding_button(g, tbidx)->location);
if (plen == order_len) {
/* ran out of space, bail early */
- LOG("toolbar ordering exceeded available space");
+ NSLOG(netsurf, INFO,
+ "toolbar ordering exceeded available space");
break;
}
cur += plen;
@@ -978,6 +984,13 @@ static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g)
nsoption_set_charp(toolbar_order, order);
+ /* ensure choices are saved */
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
return NSERROR_OK;
}
@@ -987,8 +1000,9 @@ static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g)
*/
static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data)
{
- edit_mode = false;
struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
+
+ edit_mode = false;
/* save state to file, update toolbars for all windows */
nsgtk_toolbar_customization_save(g);
nsgtk_toolbar_cast(g);
@@ -1095,7 +1109,6 @@ nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
*/
static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
{
- int x = 0, y = 0;
struct nsgtk_theme *theme;
nserror res;
@@ -1108,8 +1121,8 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
res = nsgtk_builder_new_from_resname("toolbar", &window->builder);
if (res != NSERROR_OK) {
- LOG("Toolbar UI builder init failed");
- nsgtk_warning(messages_get("NoMemory"), 0);
+ NSLOG(netsurf, INFO, "Toolbar UI builder init failed");
+ nsgtk_warning("Toolbar UI builder init failed", 0);
nsgtk_toolbar_cancel_clicked(NULL, g);
free(theme);
return;
@@ -1117,8 +1130,8 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
gtk_builder_connect_signals(window->builder, NULL);
- window->window = GTK_WIDGET(gtk_builder_get_object(window->builder,
- "toolbarwindow"));
+ window->window = GTK_WIDGET(gtk_builder_get_object(
+ window->builder, "dialogToolbar"));
if (window->window == NULL) {
nsgtk_warning(messages_get("NoMemory"), 0);
nsgtk_toolbar_cancel_clicked(NULL, g);
@@ -1126,8 +1139,11 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
return;
}
- window->widgetvbox = GTK_WIDGET(gtk_builder_get_object(window->builder,
- "widgetvbox"));
+ gtk_window_set_transient_for(GTK_WINDOW(window->window),
+ nsgtk_scaffolding_window(g));
+
+ window->widgetvbox = GTK_WIDGET(gtk_builder_get_object(
+ window->builder, "widgetvbox"));
if (window->widgetvbox == NULL) {
nsgtk_warning(messages_get("NoMemory"), 0);
nsgtk_toolbar_cancel_clicked(NULL, g);
@@ -1135,9 +1151,12 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
return;
}
- window->numberh = NSGTK_STORE_WIDTH; /* preset to width [in buttons] of */
+ /* preset to width [in buttons] of */
+ window->numberh = NSGTK_STORE_WIDTH;
+
/* store to cause creation of a new toolbar */
window->currentbutton = -1;
+
/* load toolbuttons */
/* add toolbuttons to window */
/* set event handlers */
@@ -1157,33 +1176,20 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
}
free(theme);
- gtk_window_set_transient_for(GTK_WINDOW(window->window),
- nsgtk_scaffolding_window(g));
- gtk_window_set_title(GTK_WINDOW(window->window), messages_get(
- "gtkToolBarTitle"));
+
gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE);
+
gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY);
- gtk_widget_show_all(window->window);
- gtk_window_set_position(GTK_WINDOW(window->window),
- GTK_WIN_POS_CENTER_ON_PARENT);
- gtk_window_get_position(nsgtk_scaffolding_window(g), &x, &y);
- gtk_window_move(GTK_WINDOW(window->window), x, y + 100);
-
- g_signal_connect(GTK_WIDGET(gtk_builder_get_object(window->builder,
- "cancelbutton")),
- "clicked",
- G_CALLBACK(nsgtk_toolbar_cancel_clicked),
- g);
- g_signal_connect(GTK_WIDGET(gtk_builder_get_object(window->builder,
- "okbutton")),
+ g_signal_connect(GTK_WIDGET(gtk_builder_get_object(
+ window->builder, "close")),
"clicked",
G_CALLBACK(nsgtk_toolbar_persist),
g);
- g_signal_connect(GTK_WIDGET(gtk_builder_get_object(window->builder,
- "resetbutton")),
+ g_signal_connect(GTK_WIDGET(gtk_builder_get_object(
+ window->builder, "reset")),
"clicked",
G_CALLBACK(nsgtk_toolbar_reset),
g);
@@ -1196,6 +1202,8 @@ static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
g_signal_connect(window->window, "drag-motion",
G_CALLBACK(nsgtk_toolbar_store_action), g);
+
+ gtk_widget_show_all(window->window);
}
/**
@@ -1339,33 +1347,37 @@ nsgtk_toolbar_set_handler(struct nsgtk_scaffolding *g, nsgtk_toolbar_button i)
case URL_BAR_ITEM:
nsgtk_scaffolding_update_url_bar_ref(g);
g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
- "activate", G_CALLBACK(
- nsgtk_window_url_activate_event), g);
+ "activate", G_CALLBACK(
+ nsgtk_window_url_activate_event), g);
g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
- "changed", G_CALLBACK(
- nsgtk_window_url_changed), g);
+ "changed", G_CALLBACK(
+ nsgtk_window_url_changed), g);
break;
+
case THROBBER_ITEM:
nsgtk_scaffolding_update_throbber_ref(g);
break;
+
case WEBSEARCH_ITEM:
nsgtk_scaffolding_update_websearch_ref(g);
g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
- "activate", G_CALLBACK(
- nsgtk_websearch_activate), g);
+ "activate", G_CALLBACK(
+ nsgtk_websearch_activate), g);
g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
- "button-press-event", G_CALLBACK(
- nsgtk_websearch_clear), g);
+ "button-press-event", G_CALLBACK(
+ nsgtk_websearch_clear), g);
break;
+
default:
if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) &&
- (nsgtk_scaffolding_button(g, i)->button
- != NULL))
- g_signal_connect(nsgtk_scaffolding_button(g, i)->
- button, "clicked",
- G_CALLBACK(nsgtk_scaffolding_button(g,
- i)->bhandler), g);
- break;
+ (nsgtk_scaffolding_button(g, i)->button != NULL)) {
+ g_signal_connect(
+ nsgtk_scaffolding_button(g, i)->button,
+ "clicked",
+ G_CALLBACK(nsgtk_scaffolding_button(
+ g, i)->bhandler), g);
+ }
+ break;
}
}
@@ -1457,7 +1469,8 @@ DATAHANDLER(prevtab, PREVTAB, window)
DATAHANDLER(guide, GUIDE, window)
DATAHANDLER(info, INFO, window)
#undef DATAHANDLER
-#define DATAHANDLER(p, q, r)\
+
+#define DATAHANDLER(p, q, r) \
gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\
*cont, GtkSelectionData *selection, guint info, guint time,\
gpointer data)\
@@ -1478,5 +1491,3 @@ gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\
DATAHANDLER(throbber, THROBBER, window)
DATAHANDLER(websearch, WEBSEARCH, window)
#undef DATAHANDLER
-
-
diff --git a/frontends/gtk/viewdata.c b/frontends/gtk/viewdata.c
index 6ed9dd9ac..d633238d0 100644
--- a/frontends/gtk/viewdata.c
+++ b/frontends/gtk/viewdata.c
@@ -371,7 +371,7 @@ window_init(const char *title,
res = nsgtk_builder_new_from_resname("viewdata", &newctx->builder);
if (res != NSERROR_OK) {
- LOG("Viewdata UI builder init failed");
+ NSLOG(netsurf, INFO, "Viewdata UI builder init failed");
free(newctx);
return res;
}
@@ -381,7 +381,7 @@ window_init(const char *title,
window = GTK_WINDOW(gtk_builder_get_object(newctx->builder,
"ViewDataWindow"));
if (window == NULL) {
- LOG("Unable to find window in builder ");
+ NSLOG(netsurf, INFO, "Unable to find window in builder ");
/* free the builder */
g_object_unref(G_OBJECT(newctx->builder));
@@ -616,7 +616,7 @@ static char** xdg_data_strvec(void)
xdg_data_home, xdg_data_dirs);
}
- LOG("%s", xdg_data_path);
+ NSLOG(netsurf, INFO, "%s", xdg_data_path);
svec = filepath_path_to_strvec(xdg_data_path);
free(xdg_data_path);
@@ -651,7 +651,7 @@ static char *xdg_get_default_app(const char *path, const char *mimetype)
fname = malloc(fname_len);
snprintf(fname, fname_len, "%s/applications/defaults.list", path);
- LOG("Checking %s", fname);
+ NSLOG(netsurf, INFO, "Checking %s", fname);
fp = fopen(fname, "r");
free(fname);
@@ -674,8 +674,11 @@ static char *xdg_get_default_app(const char *path, const char *mimetype)
ret = strdup(line + mimetype_len + 1);
- LOG("Found line match for %s length %zu\n", mimetype, rd);
- LOG("Result %s", ret);
+ NSLOG(netsurf, INFO,
+ "Found line match for %s length %zu\n",
+ mimetype,
+ rd);
+ NSLOG(netsurf, INFO, "Result %s", ret);
break;
}
@@ -714,7 +717,7 @@ static char *xdg_get_exec_cmd(const char *path, const char *desktop)
fname = malloc(fname_len);
snprintf(fname, fname_len, "%s/applications/%s", path, desktop);
- LOG("Checking %s", fname);
+ NSLOG(netsurf, INFO, "Checking %s", fname);
fp = fopen(fname, "r");
free(fname);
@@ -735,8 +738,8 @@ static char *xdg_get_exec_cmd(const char *path, const char *desktop)
ret = strdup(line + SLEN("Exec="));
- LOG("Found Exec length %zu", rd);
- LOG("Result %s", ret);
+ NSLOG(netsurf, INFO, "Found Exec length %zu", rd);
+ NSLOG(netsurf, INFO, "Result %s", ret);
break;
}
@@ -801,7 +804,7 @@ static char **build_exec_argv(const char *fname, const char *exec_cmd)
argv[aidx] = exec_arg(start, cur - start, fname);
if (argv[aidx] != NULL) {
- LOG("adding \"%s\"", argv[aidx]);
+ NSLOG(netsurf, INFO, "adding \"%s\"", argv[aidx]);
aidx++;
}
}
diff --git a/frontends/gtk/viewsource.c b/frontends/gtk/viewsource.c
index acf81018d..87ff6976a 100644
--- a/frontends/gtk/viewsource.c
+++ b/frontends/gtk/viewsource.c
@@ -52,7 +52,7 @@ nserror nsgtk_viewsource(GtkWindow *parent, struct browser_window *bw)
source_data = content_get_source_data(hlcontent, &source_size);
- ret = nsurl_nice(browser_window_get_url(bw), &filename, false);
+ ret = nsurl_nice(browser_window_access_url(bw), &filename, false);
if (ret != NSERROR_OK) {
filename = strdup(messages_get("SaveSource"));
if (filename == NULL) {
@@ -60,12 +60,12 @@ nserror nsgtk_viewsource(GtkWindow *parent, struct browser_window *bw)
}
}
- title = malloc(strlen(nsurl_access(browser_window_get_url(bw))) + SLEN("Source of - NetSurf") + 1);
+ title = malloc(strlen(nsurl_access(browser_window_access_url(bw))) + SLEN("Source of - NetSurf") + 1);
if (title == NULL) {
free(filename);
return NSERROR_NOMEM;
}
- sprintf(title, "Source of %s - NetSurf", nsurl_access(browser_window_get_url(bw)));
+ sprintf(title, "Source of %s - NetSurf", nsurl_access(browser_window_access_url(bw)));
ret = utf8_from_enc(source_data,
content_get_encoding(hlcontent, CONTENT_ENCODING_NORMAL),
diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c
index 326e57395..7f24d40ac 100644
--- a/frontends/gtk/window.c
+++ b/frontends/gtk/window.c
@@ -42,7 +42,6 @@
#include "netsurf/plotters.h"
#include "netsurf/form.h"
#include "netsurf/keypress.h"
-#include "desktop/textarea.h"
#include "desktop/searchweb.h"
#include "desktop/textinput.h"
@@ -52,6 +51,7 @@
#include "gtk/compat.h"
#include "gtk/gui.h"
#include "gtk/scaffolding.h"
+#include "gtk/local_history.h"
#include "gtk/plotters.h"
#include "gtk/schedule.h"
#include "gtk/tabs.h"
@@ -211,7 +211,6 @@ nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
assert(z);
assert(GTK_WIDGET(gw->layout) == widget);
- current_widget = (GtkWidget *)gw->layout;
current_cr = cr;
GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(gw->layout);
@@ -234,8 +233,6 @@ nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth);
}
- current_widget = NULL;
-
return FALSE;
}
@@ -261,7 +258,6 @@ nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
assert(z);
assert(GTK_WIDGET(gw->layout) == widget);
- current_widget = (GtkWidget *)gw->layout;
current_cr = gdk_cairo_create(nsgtk_layout_get_bin_window(gw->layout));
clip.x0 = event->area.x;
@@ -277,8 +273,6 @@ nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
cairo_destroy(current_cr);
- current_widget = NULL;
-
return FALSE;
}
@@ -345,8 +339,7 @@ static gboolean nsgtk_window_button_press_event(GtkWidget *widget,
gtk_im_context_reset(g->input_method);
gtk_widget_grab_focus(GTK_WIDGET(g->layout));
- gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window(
- g->scaffold)->window));
+ nsgtk_local_history_hide();
g->mouse.pressed_x = event->x / browser_window_get_scale(g->bw);
g->mouse.pressed_y = event->y / browser_window_get_scale(g->bw);
@@ -361,6 +354,7 @@ static gboolean nsgtk_window_button_press_event(GtkWidget *widget,
break;
case 3: /* Right button, usually. Action button, context menu. */
+ /** \todo determine if hiding the caret here is necessary */
browser_window_remove_caret(g->bw, true);
nsgtk_scaffolding_context_menu(g->scaffold,
g->mouse.pressed_x,
@@ -464,7 +458,7 @@ nsgtk_window_scroll_event(GtkWidget *widget,
break;
#endif
default:
- LOG("Unhandled mouse scroll direction");
+ NSLOG(netsurf, INFO, "Unhandled mouse scroll direction");
return TRUE;
}
@@ -747,7 +741,7 @@ gui_window_create(struct browser_window *bw,
res = nsgtk_builder_new_from_resname("tabcontents", &tab_builder);
if (res != NSERROR_OK) {
- LOG("Tab contents UI builder init failed");
+ NSLOG(netsurf, INFO, "Tab contents UI builder init failed");
return NULL;
}
@@ -760,7 +754,8 @@ gui_window_create(struct browser_window *bw,
return NULL;
}
- LOG("Creating gui window %p for browser window %p", g, bw);
+ NSLOG(netsurf, INFO, "Creating gui window %p for browser window %p",
+ g, bw);
g->bw = bw;
g->mouse.state = 0;
@@ -901,21 +896,6 @@ void nsgtk_reflow_all_windows(void)
}
-/**
- * callback from core to reformat a window.
- */
-static void nsgtk_window_reformat(struct gui_window *gw)
-{
- GtkAllocation alloc;
-
- if (gw != NULL) {
- /** @todo consider gtk_widget_get_allocated_width() */
- nsgtk_widget_get_allocation(GTK_WIDGET(gw->layout), &alloc);
-
- browser_window_reformat(gw->bw, false, alloc.width, alloc.height);
- }
-}
-
void nsgtk_window_destroy_browser(struct gui_window *gw)
{
/* remove tab */
@@ -924,10 +904,10 @@ void nsgtk_window_destroy_browser(struct gui_window *gw)
static void gui_window_destroy(struct gui_window *g)
{
- LOG("gui_window: %p", g);
+ NSLOG(netsurf, INFO, "gui_window: %p", g);
assert(g != NULL);
assert(g->bw != NULL);
- LOG("scaffolding: %p", g->scaffold);
+ NSLOG(netsurf, INFO, "scaffolding: %p", g->scaffold);
if (g->prev) {
g->prev->next = g->next;
@@ -939,7 +919,7 @@ static void gui_window_destroy(struct gui_window *g)
g->next->prev = g->prev;
}
- LOG("window list head: %p", window_list);
+ NSLOG(netsurf, INFO, "window list head: %p", window_list);
}
/**
@@ -961,13 +941,13 @@ static void gui_window_set_icon(struct gui_window *gw, struct hlcache_handle *ic
if (icon != NULL) {
icon_bitmap = content_get_bitmap(icon);
if (icon_bitmap != NULL) {
- LOG("Using %p bitmap", icon_bitmap);
+ NSLOG(netsurf, INFO, "Using %p bitmap", icon_bitmap);
gw->icon = nsgdk_pixbuf_get_from_surface(icon_bitmap->surface, 16, 16);
}
}
if (gw->icon == NULL) {
- LOG("Using default favicon");
+ NSLOG(netsurf, INFO, "Using default favicon");
g_object_ref(favicon_pixbuf);
gw->icon = favicon_pixbuf;
}
@@ -1020,27 +1000,38 @@ static void gui_window_remove_caret(struct gui_window *g)
}
-static void gui_window_redraw_window(struct gui_window *g)
-{
- gtk_widget_queue_draw(GTK_WIDGET(g->layout));
-}
-
-static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
+/**
+ * Invalidates an area of a GTK browser window
+ *
+ * \param g gui_window
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
+ */
+static nserror
+nsgtk_window_invalidate_area(struct gui_window *g, const struct rect *rect)
{
int sx, sy;
float scale;
- if (!browser_window_has_content(g->bw))
- return;
+ if (rect == NULL) {
+ gtk_widget_queue_draw(GTK_WIDGET(g->layout));
+ return NSERROR_OK;
+ }
+
+ if (!browser_window_has_content(g->bw)) {
+ return NSERROR_OK;
+ }
gui_window_get_scroll(g, &sx, &sy);
scale = browser_window_get_scale(g->bw);
gtk_widget_queue_draw_area(GTK_WIDGET(g->layout),
- rect->x0 * scale - sx,
- rect->y0 * scale - sy,
- (rect->x1 - rect->x0) * scale,
- (rect->y1 - rect->y0) * scale);
+ rect->x0 * scale - sx,
+ rect->y0 * scale - sy,
+ (rect->x1 - rect->x0) * scale,
+ (rect->y1 - rect->y0) * scale);
+
+ return NSERROR_OK;
}
static void gui_window_set_status(struct gui_window *g, const char *text)
@@ -1051,11 +1042,25 @@ static void gui_window_set_status(struct gui_window *g, const char *text)
}
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+/**
+ * Set the scroll position of a gtk browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The GTK implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param g gui window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *g, const struct rect *rect)
{
GtkAdjustment *vadj = nsgtk_layout_get_vadjustment(g->layout);
GtkAdjustment *hadj = nsgtk_layout_get_hadjustment(g->layout);
- gdouble vlower, vpage, vupper, hlower, hpage, hupper, x = (double)sx, y = (double)sy;
+ gdouble vlower, vpage, vupper, hlower, hpage, hupper;
+ gdouble x = (gdouble)rect->x0;
+ gdouble y = (gdouble)rect->y0;
assert(vadj);
assert(hadj);
@@ -1063,17 +1068,23 @@ static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
g_object_get(vadj, "page-size", &vpage, "lower", &vlower, "upper", &vupper, NULL);
g_object_get(hadj, "page-size", &hpage, "lower", &hlower, "upper", &hupper, NULL);
- if (x < hlower)
+ if (x < hlower) {
x = hlower;
- if (x > (hupper - hpage))
+ }
+ if (x > (hupper - hpage)) {
x = hupper - hpage;
- if (y < vlower)
+ }
+ if (y < vlower) {
y = vlower;
- if (y > (vupper - vpage))
+ }
+ if (y > (vupper - vpage)) {
y = vupper - vpage;
+ }
gtk_adjustment_set_value(vadj, y);
gtk_adjustment_set_value(hadj, x);
+
+ return NSERROR_OK;
}
static void gui_window_update_extent(struct gui_window *g)
@@ -1198,24 +1209,37 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh
}
-static void gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
- bool scaled)
+/**
+ * Find the current dimensions of a GTK browser window content area.
+ *
+ * \param gw The gui window to measure content area of.
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated
+ * else error code.
+ */
+static nserror
+gui_window_get_dimensions(struct gui_window *gw,
+ int *width, int *height,
+ bool scaled)
{
GtkAllocation alloc;
- /* @todo consider gtk_widget_get_allocated_width() */
- nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc);
+ /** @todo consider gtk_widget_get_allocated_width() */
+ nsgtk_widget_get_allocation(GTK_WIDGET(gw->layout), &alloc);
*width = alloc.width;
*height = alloc.height;
if (scaled) {
- float scale = browser_window_get_scale(g->bw);
+ float scale = browser_window_get_scale(gw->bw);
*width /= scale;
*height /= scale;
}
- LOG("width: %i", *width);
- LOG("height: %i", *height);
+ NSLOG(netsurf, INFO, "gw:%p width:%i height:%i", gw, *width, *height);
+
+ return NSERROR_OK;
}
static void gui_window_start_selection(struct gui_window *g)
@@ -1246,8 +1270,8 @@ static void gui_window_create_form_select_menu(struct gui_window *g,
item = 0;
option = form_select_get_option(control, item);
while (option != NULL) {
- LOG("Item %"PRIdPTR" option %p text %s",
- item, option, option->text);
+ NSLOG(netsurf, INFO, "Item %"PRIdPTR" option %p text %s",
+ item, option, option->text);
menu_item = gtk_check_menu_item_new_with_label(option->text);
if (option->selected) {
gtk_check_menu_item_set_active(
@@ -1290,10 +1314,10 @@ gui_window_file_gadget_open(struct gui_window *g,
NSGTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
- LOG("*** open dialog: %p", dialog);
+ NSLOG(netsurf, INFO, "*** open dialog: %p", dialog);
int ret = gtk_dialog_run(GTK_DIALOG(dialog));
- LOG("*** return value: %d", ret);
+ NSLOG(netsurf, INFO, "*** return value: %d", ret);
if (ret == GTK_RESPONSE_ACCEPT) {
char *filename;
@@ -1301,7 +1325,7 @@ gui_window_file_gadget_open(struct gui_window *g,
GTK_FILE_CHOOSER(dialog));
browser_window_set_gadget_filename(g->bw, gadget, filename);
-
+
g_free(filename);
}
@@ -1311,13 +1335,11 @@ gui_window_file_gadget_open(struct gui_window *g,
static struct gui_window_table window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
+ .invalidate = nsgtk_window_invalidate_area,
.get_scroll = gui_window_get_scroll,
.set_scroll = gui_window_set_scroll,
.get_dimensions = gui_window_get_dimensions,
.update_extent = gui_window_update_extent,
- .reformat = nsgtk_window_reformat,
.set_icon = gui_window_set_icon,
.set_status = gui_window_set_status,
diff --git a/frontends/monkey/401login.c b/frontends/monkey/401login.c
index 8b4d33d7d..090f18984 100644
--- a/frontends/monkey/401login.c
+++ b/frontends/monkey/401login.c
@@ -24,11 +24,11 @@
#include "monkey/401login.h"
typedef struct monkey401 {
- struct monkey401 *r_next, *r_prev;
- uint32_t num;
- lwc_string *host; /* Ignore */
- nserror (*cb)(bool,void*);
- void *pw;
+ struct monkey401 *r_next, *r_prev;
+ uint32_t num;
+ lwc_string *host; /* Ignore */
+ nserror (*cb)(bool,void*);
+ void *pw;
} monkey401_t;
static monkey401_t *m4_ring = NULL;
@@ -37,19 +37,19 @@ static uint32_t m4_ctr = 0;
void gui_401login_open(nsurl *url, const char *realm,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
- monkey401_t *m4t = calloc(sizeof(*m4t), 1);
- if (m4t == NULL) {
- cb(false, cbpw);
- return;
- }
- m4t->cb = cb;
- m4t->pw = cbpw;
- m4t->num = m4_ctr++;
+ monkey401_t *m4t = calloc(sizeof(*m4t), 1);
+ if (m4t == NULL) {
+ cb(false, cbpw);
+ return;
+ }
+ m4t->cb = cb;
+ m4t->pw = cbpw;
+ m4t->num = m4_ctr++;
- RING_INSERT(m4_ring, m4t);
+ RING_INSERT(m4_ring, m4t);
- fprintf(stdout, "401LOGIN OPEN M4 %u URL %s REALM %s\n",
- m4t->num, nsurl_access(url), realm);
+ fprintf(stdout, "401LOGIN OPEN M4 %u URL %s REALM %s\n",
+ m4t->num, nsurl_access(url), realm);
}
diff --git a/frontends/monkey/bitmap.c b/frontends/monkey/bitmap.c
index 3313e1123..83b8566b6 100644
--- a/frontends/monkey/bitmap.c
+++ b/frontends/monkey/bitmap.c
@@ -26,125 +26,125 @@
#include "monkey/bitmap.h"
struct bitmap {
- void *ptr;
- size_t rowstride;
- int width;
- int height;
- unsigned int state;
+ void *ptr;
+ size_t rowstride;
+ int width;
+ int height;
+ unsigned int state;
};
static void *bitmap_create(int width, int height, unsigned int state)
{
- struct bitmap *ret = calloc(sizeof(*ret), 1);
- if (ret == NULL)
- return NULL;
+ struct bitmap *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NULL;
- ret->width = width;
- ret->height = height;
- ret->state = state;
+ ret->width = width;
+ ret->height = height;
+ ret->state = state;
- ret->ptr = calloc(width, height * 4);
+ ret->ptr = calloc(width, height * 4);
- if (ret->ptr == NULL) {
- free(ret);
- return NULL;
- }
+ if (ret->ptr == NULL) {
+ free(ret);
+ return NULL;
+ }
- return ret;
+ return ret;
}
static void bitmap_destroy(void *bitmap)
{
- struct bitmap *bmap = bitmap;
- free(bmap->ptr);
- free(bmap);
+ struct bitmap *bmap = bitmap;
+ free(bmap->ptr);
+ free(bmap);
}
static void bitmap_set_opaque(void *bitmap, bool opaque)
{
- struct bitmap *bmap = bitmap;
+ struct bitmap *bmap = bitmap;
- if (opaque)
- bmap->state |= (BITMAP_OPAQUE);
- else
- bmap->state &= ~(BITMAP_OPAQUE);
+ if (opaque)
+ bmap->state |= (BITMAP_OPAQUE);
+ else
+ bmap->state &= ~(BITMAP_OPAQUE);
}
static bool bitmap_test_opaque(void *bitmap)
{
- return false;
+ return false;
}
static bool bitmap_get_opaque(void *bitmap)
{
- struct bitmap *bmap = bitmap;
+ struct bitmap *bmap = bitmap;
- return (bmap->state & BITMAP_OPAQUE) == BITMAP_OPAQUE;
+ return (bmap->state & BITMAP_OPAQUE) == BITMAP_OPAQUE;
}
static unsigned char *bitmap_get_buffer(void *bitmap)
{
- struct bitmap *bmap = bitmap;
+ struct bitmap *bmap = bitmap;
- return (unsigned char *)(bmap->ptr);
+ return (unsigned char *)(bmap->ptr);
}
static size_t bitmap_get_rowstride(void *bitmap)
{
- struct bitmap *bmap = bitmap;
- return bmap->width * 4;
+ struct bitmap *bmap = bitmap;
+ return bmap->width * 4;
}
static size_t bitmap_get_bpp(void *bitmap)
{
- /* OMG?! */
- return 4;
+ /* OMG?! */
+ return 4;
}
static bool bitmap_save(void *bitmap, const char *path, unsigned flags)
{
- return true;
+ return true;
}
static void bitmap_modified(void *bitmap)
{
- struct bitmap *bmap = bitmap;
- bmap->state |= BITMAP_MODIFIED;
+ struct bitmap *bmap = bitmap;
+ bmap->state |= BITMAP_MODIFIED;
}
static int bitmap_get_width(void *bitmap)
{
- struct bitmap *bmap = bitmap;
- return bmap->width;
+ struct bitmap *bmap = bitmap;
+ return bmap->width;
}
static int bitmap_get_height(void *bitmap)
{
- struct bitmap *bmap = bitmap;
- return bmap->height;
+ struct bitmap *bmap = bitmap;
+ return bmap->height;
}
static nserror bitmap_render(struct bitmap *bitmap,
struct hlcache_handle *content)
{
- fprintf(stdout, "GENERIC BITMAP RENDER\n");
- return NSERROR_OK;
+ fprintf(stdout, "GENERIC BITMAP RENDER\n");
+ return NSERROR_OK;
}
static struct gui_bitmap_table bitmap_table = {
- .create = bitmap_create,
- .destroy = bitmap_destroy,
- .set_opaque = bitmap_set_opaque,
- .get_opaque = bitmap_get_opaque,
- .test_opaque = bitmap_test_opaque,
- .get_buffer = bitmap_get_buffer,
- .get_rowstride = bitmap_get_rowstride,
- .get_width = bitmap_get_width,
- .get_height = bitmap_get_height,
- .get_bpp = bitmap_get_bpp,
- .save = bitmap_save,
- .modified = bitmap_modified,
- .render = bitmap_render,
+ .create = bitmap_create,
+ .destroy = bitmap_destroy,
+ .set_opaque = bitmap_set_opaque,
+ .get_opaque = bitmap_get_opaque,
+ .test_opaque = bitmap_test_opaque,
+ .get_buffer = bitmap_get_buffer,
+ .get_rowstride = bitmap_get_rowstride,
+ .get_width = bitmap_get_width,
+ .get_height = bitmap_get_height,
+ .get_bpp = bitmap_get_bpp,
+ .save = bitmap_save,
+ .modified = bitmap_modified,
+ .render = bitmap_render,
};
struct gui_bitmap_table *monkey_bitmap_table = &bitmap_table;
diff --git a/frontends/monkey/browser.c b/frontends/monkey/browser.c
index 3bf0dd036..1fbbbf0b1 100644
--- a/frontends/monkey/browser.c
+++ b/frontends/monkey/browser.c
@@ -42,287 +42,306 @@ static struct gui_window *gw_ring = NULL;
/* exported function documented in monkey/browser.h */
nserror monkey_warn_user(const char *warning, const char *detail)
{
- fprintf(stderr, "WARN %s %s\n", warning, detail);
- return NSERROR_OK;
+ fprintf(stderr, "WARN %s %s\n", warning, detail);
+ return NSERROR_OK;
}
struct gui_window *
monkey_find_window_by_num(uint32_t win_num)
{
- struct gui_window *ret = NULL;
+ struct gui_window *ret = NULL;
- RING_ITERATE_START(struct gui_window, gw_ring, c_ring) {
- if (c_ring->win_num == win_num) {
- ret = c_ring;
- RING_ITERATE_STOP(gw_ring, c_ring);
- }
- } RING_ITERATE_END(gw_ring, c_ring);
+ RING_ITERATE_START(struct gui_window, gw_ring, c_ring) {
+ if (c_ring->win_num == win_num) {
+ ret = c_ring;
+ RING_ITERATE_STOP(gw_ring, c_ring);
+ }
+ } RING_ITERATE_END(gw_ring, c_ring);
- return ret;
-}
-
-
-/**
- * callback from core to reformat a window.
- */
-static void monkey_window_reformat(struct gui_window *gw)
-{
- browser_window_reformat(gw->bw, false, gw->width, gw->height);
+ return ret;
}
void
monkey_kill_browser_windows(void)
{
- while (gw_ring != NULL) {
- browser_window_destroy(gw_ring->bw);
- }
+ while (gw_ring != NULL) {
+ browser_window_destroy(gw_ring->bw);
+ }
}
static struct gui_window *
gui_window_create(struct browser_window *bw,
- struct gui_window *existing,
- gui_window_create_flags flags)
+ struct gui_window *existing,
+ gui_window_create_flags flags)
{
- struct gui_window *ret = calloc(sizeof(*ret), 1);
- if (ret == NULL)
- return NULL;
+ struct gui_window *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NULL;
- ret->win_num = win_ctr++;
- ret->bw = bw;
+ ret->win_num = win_ctr++;
+ ret->bw = bw;
- ret->width = 800;
- ret->height = 600;
+ ret->width = 800;
+ ret->height = 600;
- fprintf(stdout, "WINDOW NEW WIN %u FOR %p EXISTING %p NEWTAB %s CLONE %s\n",
- ret->win_num, bw, existing, flags & GW_CREATE_TAB ? "TRUE" : "FALSE",
- flags & GW_CREATE_CLONE ? "TRUE" : "FALSE");
- fprintf(stdout, "WINDOW SIZE WIN %u WIDTH %d HEIGHT %d\n",
- ret->win_num, ret->width, ret->height);
+ fprintf(stdout, "WINDOW NEW WIN %u FOR %p EXISTING %p NEWTAB %s CLONE %s\n",
+ ret->win_num, bw, existing, flags & GW_CREATE_TAB ? "TRUE" : "FALSE",
+ flags & GW_CREATE_CLONE ? "TRUE" : "FALSE");
+ fprintf(stdout, "WINDOW SIZE WIN %u WIDTH %d HEIGHT %d\n",
+ ret->win_num, ret->width, ret->height);
- RING_INSERT(gw_ring, ret);
+ RING_INSERT(gw_ring, ret);
- return ret;
+ return ret;
}
static void
gui_window_destroy(struct gui_window *g)
{
- fprintf(stdout, "WINDOW DESTROY WIN %u\n", g->win_num);
- RING_REMOVE(gw_ring, g);
- free(g);
+ fprintf(stdout, "WINDOW DESTROY WIN %u\n", g->win_num);
+ RING_REMOVE(gw_ring, g);
+ free(g);
}
static void
gui_window_set_title(struct gui_window *g, const char *title)
{
- fprintf(stdout, "WINDOW TITLE WIN %u STR %s\n", g->win_num, title);
-}
-
-static void
-gui_window_redraw_window(struct gui_window *g)
-{
- fprintf(stdout, "WINDOW REDRAW WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW TITLE WIN %u STR %s\n", g->win_num, title);
}
-static void
+/**
+ * Find the current dimensions of a monkey browser window content area.
+ *
+ * \param g The gui window to measure content area of.
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ * \return NSERROR_OK on sucess and width and height updated.
+ */
+static nserror
gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
bool scaled)
{
- fprintf(stdout, "WINDOW GET_DIMENSIONS WIN %u WIDTH %d HEIGHT %d\n",
- g->win_num, g->width, g->height);
- *width = g->width;
- *height = g->height;
+ fprintf(stdout, "WINDOW GET_DIMENSIONS WIN %u WIDTH %d HEIGHT %d\n",
+ g->win_num, g->width, g->height);
+ *width = g->width;
+ *height = g->height;
+
+ return NSERROR_OK;
}
static void
gui_window_new_content(struct gui_window *g)
{
- fprintf(stdout, "WINDOW NEW_CONTENT WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW NEW_CONTENT WIN %u\n", g->win_num);
}
static void
gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon)
{
- fprintf(stdout, "WINDOW NEW_ICON WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW NEW_ICON WIN %u\n", g->win_num);
}
static void
gui_window_start_throbber(struct gui_window *g)
{
- fprintf(stdout, "WINDOW START_THROBBER WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW START_THROBBER WIN %u\n", g->win_num);
}
static void
gui_window_stop_throbber(struct gui_window *g)
{
- fprintf(stdout, "WINDOW STOP_THROBBER WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW STOP_THROBBER WIN %u\n", g->win_num);
}
-static void
-gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+
+/**
+ * Set the scroll position of a monkey browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown.
+ *
+ * \param gw gui window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *gw, const struct rect *rect)
{
- g->scrollx = sx;
- g->scrolly = sy;
- fprintf(stdout, "WINDOW SET_SCROLL WIN %u X %d Y %d\n", g->win_num, sx, sy);
+ gw->scrollx = rect->x0;
+ gw->scrolly = rect->y0;
+
+ fprintf(stdout, "WINDOW SET_SCROLL WIN %u X %d Y %d\n",
+ gw->win_num, rect->x0, rect->y0);
+ return NSERROR_OK;
}
-static void
-gui_window_update_box(struct gui_window *g, const struct rect *rect)
+
+/**
+ * Invalidates an area of a monkey browser window
+ *
+ * \param gw gui_window
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
+ */
+static nserror
+monkey_window_invalidate_area(struct gui_window *gw, const struct rect *rect)
{
- fprintf(stdout, "WINDOW UPDATE_BOX WIN %u X %d Y %d WIDTH %d HEIGHT %d\n",
- g->win_num, rect->x0, rect->y0,
- (rect->x1 - rect->x0), (rect->y1 - rect->y0));
-
+ fprintf(stdout, "WINDOW INVALIDATE_AREA WIN %u", gw->win_num);
+
+ if (rect != NULL) {
+ fprintf(stdout,
+ " X %d Y %d WIDTH %d HEIGHT %d\n",
+ rect->x0, rect->y0,
+ (rect->x1 - rect->x0), (rect->y1 - rect->y0));
+ } else {
+ fprintf(stdout," ALL\n");
+ }
+
+ return NSERROR_OK;
}
static void
gui_window_update_extent(struct gui_window *g)
{
- int width, height;
+ int width, height;
- if (browser_window_get_extents(g->bw, false, &width, &height) != NSERROR_OK)
- return;
+ if (browser_window_get_extents(g->bw, false, &width, &height) != NSERROR_OK)
+ return;
- fprintf(stdout, "WINDOW UPDATE_EXTENT WIN %u WIDTH %d HEIGHT %d\n",
- g->win_num, width, height);
+ fprintf(stdout, "WINDOW UPDATE_EXTENT WIN %u WIDTH %d HEIGHT %d\n",
+ g->win_num, width, height);
}
static void
gui_window_set_status(struct gui_window *g, const char *text)
{
- fprintf(stdout, "WINDOW SET_STATUS WIN %u STR %s\n", g->win_num, text);
+ fprintf(stdout, "WINDOW SET_STATUS WIN %u STR %s\n", g->win_num, text);
}
static void
gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
{
- const char *ptr_name = "UNKNOWN";
+ const char *ptr_name = "UNKNOWN";
- switch (shape) {
- case GUI_POINTER_POINT:
- ptr_name = "POINT";
- break;
- case GUI_POINTER_CARET:
- ptr_name = "CARET";
- break;
- case GUI_POINTER_UP:
- ptr_name = "UP";
- break;
- case GUI_POINTER_DOWN:
- ptr_name = "DOWN";
- break;
- case GUI_POINTER_LEFT:
- ptr_name = "LEFT";
- break;
- case GUI_POINTER_RIGHT:
- ptr_name = "RIGHT";
- break;
- case GUI_POINTER_LD:
- ptr_name = "LD";
- break;
- case GUI_POINTER_RD:
- ptr_name = "RD";
- break;
- case GUI_POINTER_LU:
- ptr_name = "LU";
- break;
- case GUI_POINTER_RU:
- ptr_name = "RU";
- break;
- case GUI_POINTER_CROSS:
- ptr_name = "CROSS";
- break;
- case GUI_POINTER_MOVE:
- ptr_name = "MOVE";
- break;
- case GUI_POINTER_WAIT:
- ptr_name = "WAIT";
- break;
- case GUI_POINTER_HELP:
- ptr_name = "HELP";
- break;
- case GUI_POINTER_MENU:
- ptr_name = "MENU";
- break;
- case GUI_POINTER_PROGRESS:
- ptr_name = "PROGRESS";
- break;
- case GUI_POINTER_NO_DROP:
- ptr_name = "NO_DROP";
- break;
- case GUI_POINTER_NOT_ALLOWED:
- ptr_name = "NOT_ALLOWED";
- break;
- case GUI_POINTER_DEFAULT:
- ptr_name = "DEFAULT";
- break;
- default:
- break;
- }
- fprintf(stdout, "WINDOW SET_POINTER WIN %u POINTER %s\n", g->win_num, ptr_name);
+ switch (shape) {
+ case GUI_POINTER_POINT:
+ ptr_name = "POINT";
+ break;
+ case GUI_POINTER_CARET:
+ ptr_name = "CARET";
+ break;
+ case GUI_POINTER_UP:
+ ptr_name = "UP";
+ break;
+ case GUI_POINTER_DOWN:
+ ptr_name = "DOWN";
+ break;
+ case GUI_POINTER_LEFT:
+ ptr_name = "LEFT";
+ break;
+ case GUI_POINTER_RIGHT:
+ ptr_name = "RIGHT";
+ break;
+ case GUI_POINTER_LD:
+ ptr_name = "LD";
+ break;
+ case GUI_POINTER_RD:
+ ptr_name = "RD";
+ break;
+ case GUI_POINTER_LU:
+ ptr_name = "LU";
+ break;
+ case GUI_POINTER_RU:
+ ptr_name = "RU";
+ break;
+ case GUI_POINTER_CROSS:
+ ptr_name = "CROSS";
+ break;
+ case GUI_POINTER_MOVE:
+ ptr_name = "MOVE";
+ break;
+ case GUI_POINTER_WAIT:
+ ptr_name = "WAIT";
+ break;
+ case GUI_POINTER_HELP:
+ ptr_name = "HELP";
+ break;
+ case GUI_POINTER_MENU:
+ ptr_name = "MENU";
+ break;
+ case GUI_POINTER_PROGRESS:
+ ptr_name = "PROGRESS";
+ break;
+ case GUI_POINTER_NO_DROP:
+ ptr_name = "NO_DROP";
+ break;
+ case GUI_POINTER_NOT_ALLOWED:
+ ptr_name = "NOT_ALLOWED";
+ break;
+ case GUI_POINTER_DEFAULT:
+ ptr_name = "DEFAULT";
+ break;
+ default:
+ break;
+ }
+ fprintf(stdout, "WINDOW SET_POINTER WIN %u POINTER %s\n", g->win_num, ptr_name);
}
static nserror
gui_window_set_url(struct gui_window *g, nsurl *url)
{
- fprintf(stdout, "WINDOW SET_URL WIN %u URL %s\n", g->win_num, nsurl_access(url));
- return NSERROR_OK;
+ fprintf(stdout, "WINDOW SET_URL WIN %u URL %s\n", g->win_num, nsurl_access(url));
+ return NSERROR_OK;
}
static bool
gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
{
- fprintf(stdout, "WINDOW GET_SCROLL WIN %u X %d Y %d\n",
- g->win_num, g->scrollx, g->scrolly);
- *sx = g->scrollx;
- *sy = g->scrolly;
- return true;
+ fprintf(stdout, "WINDOW GET_SCROLL WIN %u X %d Y %d\n",
+ g->win_num, g->scrollx, g->scrolly);
+ *sx = g->scrollx;
+ *sy = g->scrolly;
+ return true;
}
static bool
gui_window_scroll_start(struct gui_window *g)
{
- fprintf(stdout, "WINDOW SCROLL_START WIN %u\n", g->win_num);
- g->scrollx = g->scrolly = 0;
- return true;
+ fprintf(stdout, "WINDOW SCROLL_START WIN %u\n", g->win_num);
+ g->scrollx = g->scrolly = 0;
+ return true;
}
-static void
-gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
- int x1, int y1)
-{
- fprintf(stdout, "WINDOW SCROLL_VISIBLE WIN %u X0 %d Y0 %d X1 %d Y1 %d\n",
- g->win_num, x0, y0, x1, y1);
-}
static void
gui_window_place_caret(struct gui_window *g, int x, int y, int height,
- const struct rect *clip)
+ const struct rect *clip)
{
- fprintf(stdout, "WINDOW PLACE_CARET WIN %u X %d Y %d HEIGHT %d\n",
- g->win_num, x, y, height);
+ fprintf(stdout, "WINDOW PLACE_CARET WIN %u X %d Y %d HEIGHT %d\n",
+ g->win_num, x, y, height);
}
static void
gui_window_remove_caret(struct gui_window *g)
{
- fprintf(stdout, "WINDOW REMOVE_CARET WIN %u\n", g->win_num);
+ fprintf(stdout, "WINDOW REMOVE_CARET WIN %u\n", g->win_num);
}
static bool
gui_window_drag_start(struct gui_window *g, gui_drag_type type,
const struct rect *rect)
{
- fprintf(stdout, "WINDOW SCROLL_START WIN %u TYPE %i\n", g->win_num, type);
- return false;
+ fprintf(stdout, "WINDOW SCROLL_START WIN %u TYPE %i\n", g->win_num, type);
+ return false;
}
static nserror
gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
{
- fprintf(stdout, "WINDOW SAVE_LINK WIN %u URL %s TITLE %s\n",
- g->win_num, nsurl_access(url), title);
- return NSERROR_OK;
+ fprintf(stdout, "WINDOW SAVE_LINK WIN %u URL %s TITLE %s\n",
+ g->win_num, nsurl_access(url), title);
+ return NSERROR_OK;
}
@@ -332,182 +351,180 @@ gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
static void
monkey_window_handle_new(int argc, char **argv)
{
- nsurl *url = NULL;
- nserror error = NSERROR_OK;
-
- if (argc > 3)
- return;
-
- if (argc == 3) {
- error = nsurl_create(argv[2], &url);
- }
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- if (url != NULL) {
- nsurl_unref(url);
- }
- }
- if (error != NSERROR_OK) {
- monkey_warn_user(messages_get_errorcode(error), 0);
- }
+ nsurl *url = NULL;
+ nserror error = NSERROR_OK;
+
+ if (argc > 3)
+ return;
+
+ if (argc == 3) {
+ error = nsurl_create(argv[2], &url);
+ }
+ if (error == NSERROR_OK) {
+ error = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ if (url != NULL) {
+ nsurl_unref(url);
+ }
+ }
+ if (error != NSERROR_OK) {
+ monkey_warn_user(messages_get_errorcode(error), 0);
+ }
}
static void
monkey_window_handle_destroy(int argc, char **argv)
{
- struct gui_window *gw;
- uint32_t nr = atoi((argc > 2) ? argv[2] : "-1");
+ struct gui_window *gw;
+ uint32_t nr = atoi((argc > 2) ? argv[2] : "-1");
- gw = monkey_find_window_by_num(nr);
+ gw = monkey_find_window_by_num(nr);
- if (gw == NULL) {
- fprintf(stdout, "ERROR WINDOW NUM BAD\n");
- } else {
- browser_window_destroy(gw->bw);
- }
+ if (gw == NULL) {
+ fprintf(stdout, "ERROR WINDOW NUM BAD\n");
+ } else {
+ browser_window_destroy(gw->bw);
+ }
}
static void
monkey_window_handle_go(int argc, char **argv)
{
- struct gui_window *gw;
- nsurl *url;
- nsurl *ref_url = NULL;
- nserror error;
+ struct gui_window *gw;
+ nsurl *url;
+ nsurl *ref_url = NULL;
+ nserror error;
- if (argc < 4 || argc > 5) {
- fprintf(stdout, "ERROR WINDOW GO ARGS BAD\n");
- return;
- }
+ if (argc < 4 || argc > 5) {
+ fprintf(stdout, "ERROR WINDOW GO ARGS BAD\n");
+ return;
+ }
- gw = monkey_find_window_by_num(atoi(argv[2]));
+ gw = monkey_find_window_by_num(atoi(argv[2]));
- if (gw == NULL) {
- fprintf(stdout, "ERROR WINDOW NUM BAD\n");
- return;
- }
-
- error = nsurl_create(argv[3], &url);
- if (error == NSERROR_OK) {
- if (argc == 5) {
- error = nsurl_create(argv[4], &ref_url);
- }
-
- if (error == NSERROR_OK) {
- error = browser_window_navigate(gw->bw,
- url,
- ref_url,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- if (ref_url != NULL) {
- nsurl_unref(ref_url);
- }
- }
- nsurl_unref(url);
- }
-
- if (error != NSERROR_OK) {
- monkey_warn_user(messages_get_errorcode(error), 0);
- }
+ if (gw == NULL) {
+ fprintf(stdout, "ERROR WINDOW NUM BAD\n");
+ return;
+ }
+
+ error = nsurl_create(argv[3], &url);
+ if (error == NSERROR_OK) {
+ if (argc == 5) {
+ error = nsurl_create(argv[4], &ref_url);
+ }
+
+ if (error == NSERROR_OK) {
+ error = browser_window_navigate(gw->bw,
+ url,
+ ref_url,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ if (ref_url != NULL) {
+ nsurl_unref(ref_url);
+ }
+ }
+ nsurl_unref(url);
+ }
+
+ if (error != NSERROR_OK) {
+ monkey_warn_user(messages_get_errorcode(error), 0);
+ }
}
static void
monkey_window_handle_redraw(int argc, char **argv)
{
- struct gui_window *gw;
- struct rect clip;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = monkey_plotters
- };
+ struct gui_window *gw;
+ struct rect clip;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = monkey_plotters
+ };
- if (argc != 3 && argc != 7) {
- fprintf(stdout, "ERROR WINDOW REDRAW ARGS BAD\n");
- return;
- }
+ if (argc != 3 && argc != 7) {
+ fprintf(stdout, "ERROR WINDOW REDRAW ARGS BAD\n");
+ return;
+ }
- gw = monkey_find_window_by_num(atoi(argv[2]));
+ gw = monkey_find_window_by_num(atoi(argv[2]));
- if (gw == NULL) {
- fprintf(stdout, "ERROR WINDOW NUM BAD\n");
- return;
- }
+ if (gw == NULL) {
+ fprintf(stdout, "ERROR WINDOW NUM BAD\n");
+ return;
+ }
- clip.x0 = 0;
- clip.y0 = 0;
- clip.x1 = gw->width;
- clip.y1 = gw->height;
+ clip.x0 = 0;
+ clip.y0 = 0;
+ clip.x1 = gw->width;
+ clip.y1 = gw->height;
- if (argc == 7) {
- clip.x0 = atoi(argv[3]);
- clip.y0 = atoi(argv[4]);
- clip.x1 = atoi(argv[5]);
- clip.y1 = atoi(argv[6]);
- }
+ if (argc == 7) {
+ clip.x0 = atoi(argv[3]);
+ clip.y0 = atoi(argv[4]);
+ clip.x1 = atoi(argv[5]);
+ clip.y1 = atoi(argv[6]);
+ }
- LOG("Issue redraw");
- fprintf(stdout, "WINDOW REDRAW WIN %d START\n", atoi(argv[2]));
- browser_window_redraw(gw->bw, gw->scrollx, gw->scrolly, &clip, &ctx);
- fprintf(stdout, "WINDOW REDRAW WIN %d STOP\n", atoi(argv[2]));
+ NSLOG(netsurf, INFO, "Issue redraw");
+ fprintf(stdout, "WINDOW REDRAW WIN %d START\n", atoi(argv[2]));
+ browser_window_redraw(gw->bw, gw->scrollx, gw->scrolly, &clip, &ctx);
+ fprintf(stdout, "WINDOW REDRAW WIN %d STOP\n", atoi(argv[2]));
}
static void
monkey_window_handle_reload(int argc, char **argv)
{
- struct gui_window *gw;
- if (argc != 3 && argc != 4) {
- fprintf(stdout, "ERROR WINDOW RELOAD ARGS BAD\n");
- }
+ struct gui_window *gw;
+ if (argc != 3 && argc != 4) {
+ fprintf(stdout, "ERROR WINDOW RELOAD ARGS BAD\n");
+ }
- gw = monkey_find_window_by_num(atoi(argv[2]));
+ gw = monkey_find_window_by_num(atoi(argv[2]));
- if (gw == NULL) {
- fprintf(stdout, "ERROR WINDOW NUM BAD\n");
- } else {
- browser_window_reload(gw->bw, argc == 4);
- }
+ if (gw == NULL) {
+ fprintf(stdout, "ERROR WINDOW NUM BAD\n");
+ } else {
+ browser_window_reload(gw->bw, argc == 4);
+ }
}
void
monkey_window_handle_command(int argc, char **argv)
{
- if (argc == 1)
- return;
+ if (argc == 1)
+ return;
- if (strcmp(argv[1], "NEW") == 0) {
- monkey_window_handle_new(argc, argv);
- } else if (strcmp(argv[1], "DESTROY") == 0) {
- monkey_window_handle_destroy(argc, argv);
- } else if (strcmp(argv[1], "GO") == 0) {
- monkey_window_handle_go(argc, argv);
- } else if (strcmp(argv[1], "REDRAW") == 0) {
- monkey_window_handle_redraw(argc, argv);
- } else if (strcmp(argv[1], "RELOAD") == 0) {
- monkey_window_handle_reload(argc, argv);
- } else {
- fprintf(stdout, "ERROR WINDOW COMMAND UNKNOWN %s\n", argv[1]);
- }
+ if (strcmp(argv[1], "NEW") == 0) {
+ monkey_window_handle_new(argc, argv);
+ } else if (strcmp(argv[1], "DESTROY") == 0) {
+ monkey_window_handle_destroy(argc, argv);
+ } else if (strcmp(argv[1], "GO") == 0) {
+ monkey_window_handle_go(argc, argv);
+ } else if (strcmp(argv[1], "REDRAW") == 0) {
+ monkey_window_handle_redraw(argc, argv);
+ } else if (strcmp(argv[1], "RELOAD") == 0) {
+ monkey_window_handle_reload(argc, argv);
+ } else {
+ fprintf(stdout, "ERROR WINDOW COMMAND UNKNOWN %s\n", argv[1]);
+ }
}
static struct gui_window_table window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
+ .invalidate = monkey_window_invalidate_area,
.get_scroll = gui_window_get_scroll,
.set_scroll = gui_window_set_scroll,
.get_dimensions = gui_window_get_dimensions,
.update_extent = gui_window_update_extent,
- .reformat = monkey_window_reformat,
.set_title = gui_window_set_title,
.set_url = gui_window_set_url,
@@ -518,7 +535,6 @@ static struct gui_window_table window_table = {
.remove_caret = gui_window_remove_caret,
.drag_start = gui_window_drag_start,
.save_link = gui_window_save_link,
- .scroll_visible = gui_window_scroll_visible,
.scroll_start = gui_window_scroll_start,
.new_content = gui_window_new_content,
.start_throbber = gui_window_start_throbber,
diff --git a/frontends/monkey/browser.h b/frontends/monkey/browser.h
index 2b0340211..8cbbb947d 100644
--- a/frontends/monkey/browser.h
+++ b/frontends/monkey/browser.h
@@ -25,16 +25,16 @@ extern struct gui_window_table *monkey_window_table;
extern struct gui_download_table *monkey_download_table;
struct gui_window {
- struct gui_window *r_next;
- struct gui_window *r_prev;
+ struct gui_window *r_next;
+ struct gui_window *r_prev;
- uint32_t win_num;
- struct browser_window *bw;
+ uint32_t win_num;
+ struct browser_window *bw;
- int width, height;
- int scrollx, scrolly;
+ int width, height;
+ int scrollx, scrolly;
- char *host; /* Ignore this, it's in case RING*() gets debugging for fetchers */
+ char *host; /* Ignore this, it's in case RING*() gets debugging for fetchers */
};
diff --git a/frontends/monkey/cert.c b/frontends/monkey/cert.c
index 710e71098..a19975527 100644
--- a/frontends/monkey/cert.c
+++ b/frontends/monkey/cert.c
@@ -25,11 +25,11 @@
#include "monkey/cert.h"
typedef struct monkey_cert {
- struct monkey_cert *r_next, *r_prev;
- uint32_t num;
- char *host; /* Ignore */
- nserror (*cb)(bool,void*);
- void *pw;
+ struct monkey_cert *r_next, *r_prev;
+ uint32_t num;
+ char *host; /* Ignore */
+ nserror (*cb)(bool,void*);
+ void *pw;
} monkey_cert_t;
static monkey_cert_t *cert_ring = NULL;
@@ -40,20 +40,20 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
- monkey_cert_t *m4t = calloc(sizeof(*m4t), 1);
- if (m4t == NULL) {
- return NSERROR_NOMEM;
- }
- m4t->cb = cb;
- m4t->pw = cbpw;
- m4t->num = cert_ctr++;
+ monkey_cert_t *m4t = calloc(sizeof(*m4t), 1);
+ if (m4t == NULL) {
+ return NSERROR_NOMEM;
+ }
+ m4t->cb = cb;
+ m4t->pw = cbpw;
+ m4t->num = cert_ctr++;
- RING_INSERT(cert_ring, m4t);
+ RING_INSERT(cert_ring, m4t);
- fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n",
- m4t->num, nsurl_access(url));
+ fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n",
+ m4t->num, nsurl_access(url));
- return NSERROR_OK;
+ return NSERROR_OK;
}
diff --git a/frontends/monkey/dispatch.c b/frontends/monkey/dispatch.c
index 563534d64..e60325cf1 100644
--- a/frontends/monkey/dispatch.c
+++ b/frontends/monkey/dispatch.c
@@ -28,9 +28,9 @@
#include "monkey/dispatch.h"
typedef struct cmdhandler {
- struct cmdhandler *r_next, *r_prev;
- const char *cmd;
- handle_command_fn fn;
+ struct cmdhandler *r_next, *r_prev;
+ const char *cmd;
+ handle_command_fn fn;
} monkey_cmdhandler_t;
static monkey_cmdhandler_t *handler_ring = NULL;
@@ -38,68 +38,68 @@ static monkey_cmdhandler_t *handler_ring = NULL;
nserror
monkey_register_handler(const char *cmd, handle_command_fn fn)
{
- monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1);
- if (ret == NULL) {
- LOG("Unable to allocate handler");
- return NSERROR_NOMEM;
- }
- ret->cmd = strdup(cmd);
- ret->fn = fn;
- RING_INSERT(handler_ring, ret);
- return NSERROR_OK;
+ monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL) {
+ NSLOG(netsurf, INFO, "Unable to allocate handler");
+ return NSERROR_NOMEM;
+ }
+ ret->cmd = strdup(cmd);
+ ret->fn = fn;
+ RING_INSERT(handler_ring, ret);
+ return NSERROR_OK;
}
void
monkey_process_command(void)
{
- char buffer[PATH_MAX];
- int argc = 0;
- char **argv = NULL;
- char *p, *r = NULL;
- handle_command_fn fn = NULL;
- char **nargv;
+ char buffer[PATH_MAX];
+ int argc = 0;
+ char **argv = NULL;
+ char *p, *r = NULL;
+ handle_command_fn fn = NULL;
+ char **nargv;
- if (fgets(buffer, PATH_MAX, stdin) == NULL) {
- /* end of input or read error so issue QUIT */
- sprintf(buffer, "QUIT\n");
- }
+ if (fgets(buffer, PATH_MAX, stdin) == NULL) {
+ /* end of input or read error so issue QUIT */
+ sprintf(buffer, "QUIT\n");
+ }
- /* remove newline */
- buffer[strlen(buffer) - 1] = '\0';
+ /* remove newline */
+ buffer[strlen(buffer) - 1] = '\0';
- argv = malloc(sizeof *argv);
- if (argv == NULL) {
- return;
- }
- argc = 1;
- *argv = buffer;
+ argv = malloc(sizeof *argv);
+ if (argv == NULL) {
+ return;
+ }
+ argc = 1;
+ *argv = buffer;
- for (p = r = buffer; *p != '\0'; p++) {
- if (*p == ' ') {
- nargv = realloc(argv, sizeof(*argv) * (argc + 1));
- if (nargv == NULL) {
- /* reallocation of argument vector failed, try using what is
- * already processed.
- */
- break;
- } else {
- argv = nargv;
- }
- argv[argc++] = r = p + 1;
- *p = '\0';
- }
- }
+ for (p = r = buffer; *p != '\0'; p++) {
+ if (*p == ' ') {
+ nargv = realloc(argv, sizeof(*argv) * (argc + 1));
+ if (nargv == NULL) {
+ /* reallocation of argument vector failed, try using what is
+ * already processed.
+ */
+ break;
+ } else {
+ argv = nargv;
+ }
+ argv[argc++] = r = p + 1;
+ *p = '\0';
+ }
+ }
- RING_ITERATE_START(monkey_cmdhandler_t, handler_ring, handler) {
- if (strcmp(argv[0], handler->cmd) == 0) {
- fn = handler->fn;
- RING_ITERATE_STOP(handler_ring, handler);
- }
- } RING_ITERATE_END(handler_ring, handler);
+ RING_ITERATE_START(monkey_cmdhandler_t, handler_ring, handler) {
+ if (strcmp(argv[0], handler->cmd) == 0) {
+ fn = handler->fn;
+ RING_ITERATE_STOP(handler_ring, handler);
+ }
+ } RING_ITERATE_END(handler_ring, handler);
- if (fn != NULL) {
- fn(argc, argv);
- }
+ if (fn != NULL) {
+ fn(argc, argv);
+ }
- free(argv);
+ free(argv);
}
diff --git a/frontends/monkey/download.c b/frontends/monkey/download.c
index f2e1cbfbf..5c9ce1b53 100644
--- a/frontends/monkey/download.c
+++ b/frontends/monkey/download.c
@@ -30,11 +30,11 @@
static uint32_t dwin_ctr = 0;
struct gui_download_window {
- struct gui_download_window *r_next;
- struct gui_download_window *r_prev;
- struct gui_window *g;
- uint32_t dwin_num;
- char *host; /* ignore */
+ struct gui_download_window *r_next;
+ struct gui_download_window *r_prev;
+ struct gui_window *g;
+ uint32_t dwin_num;
+ char *host; /* ignore */
};
static struct gui_download_window *dw_ring = NULL;
@@ -43,44 +43,44 @@ static struct gui_download_window *
gui_download_window_create(download_context *ctx,
struct gui_window *parent)
{
- struct gui_download_window *ret = calloc(sizeof(*ret), 1);
- if (ret == NULL)
- return NULL;
- ret->g = parent;
- ret->dwin_num = dwin_ctr++;
+ struct gui_download_window *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NULL;
+ ret->g = parent;
+ ret->dwin_num = dwin_ctr++;
- RING_INSERT(dw_ring, ret);
+ RING_INSERT(dw_ring, ret);
- fprintf(stdout, "DOWNLOAD_WINDOW CREATE DWIN %u WIN %u\n",
- ret->dwin_num, parent->win_num);
+ fprintf(stdout, "DOWNLOAD_WINDOW CREATE DWIN %u WIN %u\n",
+ ret->dwin_num, parent->win_num);
- return ret;
+ return ret;
}
static nserror
gui_download_window_data(struct gui_download_window *dw,
const char *data, unsigned int size)
{
- fprintf(stdout, "DOWNLOAD_WINDOW DATA DWIN %u SIZE %u DATA %s\n",
- dw->dwin_num, size, data);
- return NSERROR_OK;
+ fprintf(stdout, "DOWNLOAD_WINDOW DATA DWIN %u SIZE %u DATA %s\n",
+ dw->dwin_num, size, data);
+ return NSERROR_OK;
}
static void
gui_download_window_error(struct gui_download_window *dw,
const char *error_msg)
{
- fprintf(stdout, "DOWNLOAD_WINDOW ERROR DWIN %u ERROR %s\n",
- dw->dwin_num, error_msg);
+ fprintf(stdout, "DOWNLOAD_WINDOW ERROR DWIN %u ERROR %s\n",
+ dw->dwin_num, error_msg);
}
static void
gui_download_window_done(struct gui_download_window *dw)
{
- fprintf(stdout, "DOWNLOAD_WINDOW DONE DWIN %u\n",
- dw->dwin_num);
- RING_REMOVE(dw_ring, dw);
- free(dw);
+ fprintf(stdout, "DOWNLOAD_WINDOW DONE DWIN %u\n",
+ dw->dwin_num);
+ RING_REMOVE(dw_ring, dw);
+ free(dw);
}
static struct gui_download_table download_table = {
diff --git a/frontends/monkey/farmer.py b/frontends/monkey/farmer.py
new file mode 100644
index 000000000..d4b4b1e21
--- /dev/null
+++ b/frontends/monkey/farmer.py
@@ -0,0 +1,363 @@
+#!/usr/bin/python
+
+# Copyright 2017 Daniel Silverstone <dsilvers@digital-scurf.org>
+#
+# This file is part of NetSurf, http://www.netsurf-browser.org/
+#
+# NetSurf is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# NetSurf is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Monkey Farmer
+
+The monkey farmer is a wrapper around `nsmonkey` which can be used to simplify
+access to the monkey behaviours and ultimately to write useful tests in an
+expressive but not overcomplicated DSLish way. Tests are, ultimately, still
+Python code.
+
+"""
+
+import asyncore
+import os
+import socket
+import subprocess
+import time
+
+#monkey_cmd = ['./nsmonkey', '--accept_language=fr']
+monkey_cmd = ['./nsmonkey']
+
+class MonkeyFarmer(asyncore.dispatcher):
+ def __init__(self, online, quiet=False):
+ (mine, monkeys) = socket.socketpair()
+
+ asyncore.dispatcher.__init__(self, sock=mine)
+
+ self.monkey = subprocess.Popen(
+ monkey_cmd,
+ stdin=monkeys,
+ stdout=monkeys,
+ close_fds=[mine])
+
+ monkeys.close()
+
+ self.buffer = ""
+ self.incoming = ""
+ self.lines = []
+ self.scheduled = []
+ self.deadmonkey = False
+ self.online = online
+ self.quiet = quiet
+
+ def handle_connect(self):
+ pass
+
+ def handle_read(self):
+ got = self.recv(8192)
+ if got == "" or got is None:
+ self.deadmonkey = True
+ return
+ self.incoming += got
+ if "\n" in self.incoming:
+ lines = self.incoming.split("\n")
+ self.incoming = lines.pop()
+ self.lines = lines
+
+ def writable(self):
+ return (len(self.buffer) > 0)
+
+ def handle_write(self):
+ sent = self.send(self.buffer)
+ self.buffer = self.buffer[sent:]
+
+ def tell_monkey(self, *args):
+ cmd = (" ".join(args))
+ if not self.quiet:
+ print ">>> %s" % cmd
+ self.buffer += "%s\n" % cmd
+
+ def monkey_says(self, line):
+ if not self.quiet:
+ print "<<< %s" % line
+ self.online(line)
+
+ def schedule_event(self, event, secs=None, when=None):
+ assert(secs is not None or when is not None)
+ if when is None:
+ when = time.time() + secs
+ self.scheduled.append((when, event))
+ self.scheduled.sort(lambda a,b: cmp(a[0],b[0]))
+
+ def unschedule_event(self, event):
+ self.scheduled = [x for x in self.scheduled if x[1] != event]
+
+ def loop(self, once=False):
+ if len(self.lines) > 0:
+ self.monkey_says(self.lines.pop(0))
+ if once:
+ return
+ while not self.deadmonkey:
+ now = time.time()
+ while len(self.scheduled) > 0 and now >= self.scheduled[0][0]:
+ func = self.scheduled[0][1]
+ self.scheduled.pop(0)
+ func(self)
+ now = time.time()
+ if len(self.scheduled) > 0:
+ next = self.scheduled[0][0]
+ asyncore.loop(timeout=next-now, count=1)
+ else:
+ asyncore.loop(count=1)
+ if len(self.lines) > 0:
+ self.monkey_says(self.lines.pop(0))
+ if once:
+ break
+
+class Browser:
+ def __init__(self, quiet=False):
+ self.farmer = MonkeyFarmer(online=self.on_monkey_line, quiet=quiet)
+ self.windows = {}
+ self.current_draw_target = None
+
+ def pass_options(self, *opts):
+ if len(opts) > 0:
+ self.farmer.tell_monkey("OPTIONS " + (" ".join(opts)))
+
+ def on_monkey_line(self, line):
+ parts = line.split(" ")
+ handler = getattr(self, "handle_" + parts[0], None)
+ if handler is not None:
+ handler(*parts[1:])
+
+ def quit(self):
+ self.farmer.tell_monkey("QUIT")
+
+ def quit_and_wait(self):
+ self.quit()
+ self.farmer.loop()
+
+ def handle_GENERIC(self, what, *args):
+ pass
+
+ def handle_WINDOW(self, action, _win, winid, *args):
+ if action == "NEW":
+ new_win = BrowserWindow(self, winid, *args)
+ self.windows[winid] = new_win
+ else:
+ win = self.windows.get(winid, None)
+ if win is None:
+ print " Unknown window id %s" % winid
+ else:
+ win.handle(action, *args)
+
+ def handle_PLOT(self, *args):
+ if self.current_draw_target is not None:
+ self.current_draw_target.handle_plot(*args)
+
+ def new_window(self, url=None):
+ if url is None:
+ self.farmer.tell_monkey("WINDOW NEW")
+ else:
+ self.farmer.tell_monkey("WINDOW NEW %s" % url)
+ wins_known = set(self.windows.keys())
+ while len(set(self.windows.keys()).difference(wins_known)) == 0:
+ self.farmer.loop(once=True)
+ poss_wins = set(self.windows.keys()).difference(wins_known)
+ return self.windows[poss_wins.pop()]
+
+
+class BrowserWindow:
+ def __init__(self, browser, winid, _for, coreid, _existing, otherid, _newtab, newtab, _clone, clone):
+ self.alive = True
+ self.browser = browser
+ self.winid = winid
+ self.coreid = coreid
+ self.existing = browser.windows.get(otherid, None)
+ self.newtab = newtab == "TRUE"
+ self.clone = clone == "TRUE"
+ self.width = 0
+ self.height = 0
+ self.title = ""
+ self.throbbing = False
+ self.scrollx = 0
+ self.scrolly = 0
+ self.content_width = 0
+ self.content_height = 0
+ self.status = ""
+ self.pointer = ""
+ self.scale = 1.0
+ self.url = ""
+ self.plotted = []
+ self.plotting = False
+
+ def kill(self):
+ self.browser.farmer.tell_monkey("WINDOW DESTROY %s" % self.winid)
+
+ def go(self, url, referer = None):
+ if referer is None:
+ self.browser.farmer.tell_monkey("WINDOW GO %s %s" % (
+ self.winid, url))
+ else:
+ self.browser.farmer.tell_monkey("WINDOW GO %s %s %s" % (
+ self.winid, url, referer))
+
+ def reload(self):
+ self.browser.farmer.tell_monkey("WINDOW RELOAD %s" % self.winid)
+
+ def redraw(self, coords=None):
+ if coords is None:
+ self.browser.farmer.tell_monkey("WINDOW REDRAW %s" % self.winid)
+ else:
+ self.browser.farmer.tell_monkey("WINDOW REDRAW %s %s" % (
+ self.winid, (" ".join(coords))))
+
+ def handle(self, action, *args):
+ handler = getattr(self, "handle_window_" + action, None)
+ if handler is not None:
+ handler(*args)
+
+ def handle_window_SIZE(self, _width, width, _height, height):
+ self.width = int(width)
+ self.height = int(height)
+
+ def handle_window_DESTROY(self):
+ self.alive = False
+
+ def handle_window_TITLE(self, _str, *title):
+ self.title = " ".join(title)
+
+ def handle_window_REDRAW(self):
+ pass
+
+ def handle_window_GET_DIMENSIONS(self, _width, width, _height, height):
+ self.width = width
+ self.height = height
+
+ def handle_window_NEW_CONTENT(self):
+ pass
+
+ def handle_window_NEW_ICON(self):
+ pass
+
+ def handle_window_START_THROBBER(self):
+ self.throbbing = True
+
+ def handle_window_STOP_THROBBER(self):
+ self.throbbing = False
+
+ def handle_window_SET_SCROLL(self, _x, x, _y, y):
+ self.scrollx = int(x)
+ self.scrolly = int(y)
+
+ def handle_window_UPDATE_BOX(self, _x, x, _y, y, _width, width, _height, height):
+ x = int(x)
+ y = int(y)
+ width = int(width)
+ height = int(height)
+ pass
+
+ def handle_window_UPDATE_EXTENT(self, _width, width, _height, height):
+ self.content_width = int(width)
+ self.content_height = int(height)
+
+ def handle_window_SET_STATUS(self, _str, *status):
+ self.status = (" ".join(status))
+
+ def handle_window_SET_POINTER(self, _ptr, ptr):
+ self.pointer = ptr
+
+ def handle_window_SET_SCALE(self, _scale, scale):
+ self.scale = float(scale)
+
+ def handle_window_SET_URL(self, _url, url):
+ self.url = url
+
+ def handle_window_GET_SCROLL(self, _x, x, _y, y):
+ self.scrollx = int(x)
+ self.scrolly = int(y)
+
+ def handle_window_SCROLL_START(self):
+ self.scrollx = 0
+ self.scrolly = 0
+
+ def handle_window_REDRAW(self, act):
+ if act == "START":
+ self.browser.current_draw_target = self
+ self.plotted = []
+ self.plotting = True
+ else:
+ self.browser.current_draw_target = None
+ self.plotting = False
+
+ def load_page(self, url=None, referer=None):
+ if url is not None:
+ self.go(url, referer)
+ self.wait_loaded()
+
+ def reload(self):
+ self.browser.farmer.tell_monkey("WINDOW RELOAD %s" % self.winid)
+ self.wait_loaded()
+
+ def wait_loaded(self):
+ while not self.throbbing:
+ self.browser.farmer.loop(once=True)
+ while self.throbbing:
+ self.browser.farmer.loop(once=True)
+
+ def handle_plot(self, *args):
+ self.plotted.append(args)
+
+ def redraw(self, coords=None):
+ if coords is None:
+ self.browser.farmer.tell_monkey("WINDOW REDRAW %s" % self.winid)
+ else:
+ self.browser.farmer.tell_monkey("WINDOW REDRAW %s %s" % (
+ self.winid, (" ".join(coords))))
+ while not self.plotting:
+ self.browser.farmer.loop(once=True)
+ while self.plotting:
+ self.browser.farmer.loop(once=True)
+ return self.plotted
+
+
+# Simple test is as follows...
+
+browser = Browser(quiet=True)
+
+win = browser.new_window()
+
+fname = "test/js/inline-doc-write-simple.html"
+full_fname = os.path.join(os.getcwd(), fname)
+
+browser.pass_options("--enable_javascript=0")
+win.load_page("file://" + full_fname)
+
+print("Loaded, URL is %s" % win.url)
+
+cmds = win.redraw()
+print("Received %d plot commands" % len(cmds))
+for cmd in cmds:
+ if cmd[0] == "TEXT":
+ print "%s %s -> %s" % (cmd[2], cmd[4], (" ".join(cmd[6:])))
+
+
+browser.pass_options("--enable_javascript=1")
+win.load_page("file://" + full_fname)
+
+print("Loaded, URL is %s" % win.url)
+
+cmds = win.redraw()
+print("Received %d plot commands" % len(cmds))
+for cmd in cmds:
+ if cmd[0] == "TEXT":
+ print "%s %s -> %s" % (cmd[2], cmd[4], (" ".join(cmd[6:])))
+
+browser.quit_and_wait()
diff --git a/frontends/monkey/fetch.c b/frontends/monkey/fetch.c
index 4985329db..256d79b59 100644
--- a/frontends/monkey/fetch.c
+++ b/frontends/monkey/fetch.c
@@ -36,18 +36,18 @@ extern char **respaths;
static nsurl *gui_get_resource_url(const char *path)
{
- char buf[PATH_MAX];
- nsurl *url = NULL;
+ char buf[PATH_MAX];
+ nsurl *url = NULL;
- netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url);
+ netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url);
- return url;
+ return url;
}
static struct gui_fetch_table fetch_table = {
- .filetype = monkey_fetch_filetype,
+ .filetype = monkey_fetch_filetype,
- .get_resource_url = gui_get_resource_url,
+ .get_resource_url = gui_get_resource_url,
};
struct gui_fetch_table *monkey_fetch_table = &fetch_table;
diff --git a/frontends/monkey/filetype.c b/frontends/monkey/filetype.c
index 20bd1edad..65c84f9bd 100644
--- a/frontends/monkey/filetype.c
+++ b/frontends/monkey/filetype.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
@@ -85,7 +86,8 @@ void monkey_fetch_filetype_init(const char *mimefile)
fh = fopen(mimefile, "r");
if (fh == NULL) {
- LOG("Unable to open a mime.types file, so using a minimal one for you.");
+ NSLOG(netsurf, INFO,
+ "Unable to open a mime.types file, so using a minimal one for you.");
return;
}
diff --git a/frontends/monkey/layout.c b/frontends/monkey/layout.c
index 4bcc51b68..0d6a3b4dc 100644
--- a/frontends/monkey/layout.c
+++ b/frontends/monkey/layout.c
@@ -30,11 +30,11 @@
#include "monkey/layout.h"
static nserror nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int *width)
+ const char *string, size_t length,
+ int *width)
{
- *width = (fstyle->size * utf8_bounded_length(string, length)) / FONT_SIZE_SCALE;
- return NSERROR_OK;
+ *width = (fstyle->size * utf8_bounded_length(string, length)) / PLOT_STYLE_SCALE;
+ return NSERROR_OK;
}
/**
@@ -50,14 +50,14 @@ static nserror nsfont_width(const plot_font_style_t *fstyle,
*/
static nserror nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
{
- *char_offset = x / (fstyle->size / FONT_SIZE_SCALE);
- if (*char_offset > length)
- *char_offset = length;
- *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE);
- return NSERROR_OK;
+ *char_offset = x / (fstyle->size / PLOT_STYLE_SCALE);
+ if (*char_offset > length)
+ *char_offset = length;
+ *actual_x = *char_offset * (fstyle->size / PLOT_STYLE_SCALE);
+ return NSERROR_OK;
}
@@ -85,27 +85,27 @@ static nserror nsfont_position_in_string(const plot_font_style_t *fstyle,
*/
static nserror nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
{
- int c_off = *char_offset = x / (fstyle->size / FONT_SIZE_SCALE);
- if (*char_offset > length) {
- *char_offset = length;
- } else {
- while (*char_offset > 0) {
- if (string[*char_offset] == ' ')
- break;
- (*char_offset)--;
- }
- if (*char_offset == 0) {
- *char_offset = c_off;
- while (*char_offset < length && string[*char_offset] != ' ') {
- (*char_offset)++;
- }
- }
- }
- *actual_x = *char_offset * (fstyle->size / FONT_SIZE_SCALE);
- return NSERROR_OK;
+ int c_off = *char_offset = x / (fstyle->size / PLOT_STYLE_SCALE);
+ if (*char_offset > length) {
+ *char_offset = length;
+ } else {
+ while (*char_offset > 0) {
+ if (string[*char_offset] == ' ')
+ break;
+ (*char_offset)--;
+ }
+ if (*char_offset == 0) {
+ *char_offset = c_off;
+ while (*char_offset < length && string[*char_offset] != ' ') {
+ (*char_offset)++;
+ }
+ }
+ }
+ *actual_x = *char_offset * (fstyle->size / PLOT_STYLE_SCALE);
+ return NSERROR_OK;
}
static struct gui_layout_table layout_table = {
diff --git a/frontends/monkey/main.c b/frontends/monkey/main.c
index 0059ff047..53cde5a72 100644
--- a/frontends/monkey/main.c
+++ b/frontends/monkey/main.c
@@ -66,8 +66,8 @@ static bool monkey_done = false;
*/
static void die(const char * const error)
{
- fprintf(stderr, "DIE %s\n", error);
- exit(EXIT_FAILURE);
+ fprintf(stderr, "DIE %s\n", error);
+ exit(EXIT_FAILURE);
}
/** obtain language from environment
@@ -78,29 +78,29 @@ static void die(const char * const error)
*/
static const char *get_language(void)
{
- const char *lang;
+ const char *lang;
- lang = getenv("LANGUAGE");
- if ((lang != NULL) && (lang[0] != '\0')) {
- return lang;
- }
+ lang = getenv("LANGUAGE");
+ if ((lang != NULL) && (lang[0] != '\0')) {
+ return lang;
+ }
- lang = getenv("LC_ALL");
- if ((lang != NULL) && (lang[0] != '\0')) {
- return lang;
- }
+ lang = getenv("LC_ALL");
+ if ((lang != NULL) && (lang[0] != '\0')) {
+ return lang;
+ }
- lang = getenv("LC_MESSAGES");
- if ((lang != NULL) && (lang[0] != '\0')) {
- return lang;
- }
+ lang = getenv("LC_MESSAGES");
+ if ((lang != NULL) && (lang[0] != '\0')) {
+ return lang;
+ }
- lang = getenv("LANG");
- if ((lang != NULL) && (lang[0] != '\0')) {
- return lang;
- }
+ lang = getenv("LANG");
+ if ((lang != NULL) && (lang[0] != '\0')) {
+ return lang;
+ }
- return NULL;
+ return NULL;
}
@@ -120,92 +120,97 @@ static const char *get_language(void)
*/
static const char * const *get_languagev(void)
{
- static const char *langv[LANGV_SIZE];
- int langidx = 0; /* index of next entry in vector */
- static char langs[LANGS_SIZE];
- char *curp; /* next language parameter in langs string */
- const char *lange; /* language from environment variable */
- int lang_len;
- char *cln; /* colon in lange */
-
- /* return cached vector */
- if (langv[0] != NULL) {
- return &langv[0];
- }
-
- curp = &langs[0];
-
- lange = get_language();
-
- if (lange != NULL) {
- lang_len = strlen(lange) + 1;
- if (lang_len < (LANGS_SIZE - 2)) {
- memcpy(curp, lange, lang_len);
- while ((curp[0] != 0) &&
- (langidx < (LANGV_SIZE - 2))) {
- /* avoid using strchrnul as it is not portable */
- cln = strchr(curp, ':');
- if (cln == NULL) {
- langv[langidx++] = curp;
- curp += lang_len;
- break;
- } else {
- if ((cln - curp) > 1) {
- /* only place non empty entries in vector */
- langv[langidx++] = curp;
- }
- *cln++ = 0; /* null terminate */
- lang_len -= (cln - curp);
- curp = cln;
+ static const char *langv[LANGV_SIZE];
+ int langidx = 0; /* index of next entry in vector */
+ static char langs[LANGS_SIZE];
+ char *curp; /* next language parameter in langs string */
+ const char *lange; /* language from environment variable */
+ int lang_len;
+ char *cln; /* colon in lange */
+
+ /* return cached vector */
+ if (langv[0] != NULL) {
+ return &langv[0];
}
- }
- }
- }
- /* ensure C language is present */
- langv[langidx++] = curp;
- *curp++ = 'C';
- *curp++ = 0;
- langv[langidx] = NULL;
+ curp = &langs[0];
+
+ lange = get_language();
+
+ if (lange != NULL) {
+ lang_len = strlen(lange) + 1;
+ if (lang_len < (LANGS_SIZE - 2)) {
+ memcpy(curp, lange, lang_len);
+ while ((curp[0] != 0) &&
+ (langidx < (LANGV_SIZE - 2))) {
+ /* avoid using strchrnul as it is not portable */
+ cln = strchr(curp, ':');
+ if (cln == NULL) {
+ langv[langidx++] = curp;
+ curp += lang_len;
+ break;
+ } else {
+ if ((cln - curp) > 1) {
+ /* only place non empty entries in vector */
+ langv[langidx++] = curp;
+ }
+ *cln++ = 0; /* null terminate */
+ lang_len -= (cln - curp);
+ curp = cln;
+ }
+ }
+ }
+ }
- return &langv[0];
+ /* ensure C language is present */
+ langv[langidx++] = curp;
+ *curp++ = 'C';
+ *curp++ = 0;
+ langv[langidx] = NULL;
+
+ return &langv[0];
}
/* Stolen from gtk/gui.c */
static char **
nsmonkey_init_resource(const char *resource_path)
{
- const char * const *langv;
- char **pathv; /* resource path string vector */
- char **respath; /* resource paths vector */
+ const char * const *langv;
+ char **pathv; /* resource path string vector */
+ char **respath; /* resource paths vector */
- pathv = filepath_path_to_strvec(resource_path);
+ pathv = filepath_path_to_strvec(resource_path);
- langv = get_languagev();
+ langv = get_languagev();
- respath = filepath_generate(pathv, langv);
+ respath = filepath_generate(pathv, langv);
- filepath_free_strvec(pathv);
+ filepath_free_strvec(pathv);
- return respath;
+ return respath;
}
static void monkey_quit(void)
{
- urldb_save_cookies(nsoption_charp(cookie_jar));
- urldb_save(nsoption_charp(url_file));
- monkey_fetch_filetype_fin();
+ urldb_save_cookies(nsoption_charp(cookie_jar));
+ urldb_save(nsoption_charp(url_file));
+ monkey_fetch_filetype_fin();
}
static nserror gui_launch_url(struct nsurl *url)
{
- fprintf(stdout, "GENERIC LAUNCH URL %s\n", nsurl_access(url));
- return NSERROR_OK;
+ fprintf(stdout, "GENERIC LAUNCH URL %s\n", nsurl_access(url));
+ return NSERROR_OK;
}
static void quit_handler(int argc, char **argv)
{
- monkey_done = true;
+ monkey_done = true;
+}
+
+static void monkey_options_handle_command(int argc, char **argv)
+{
+ nsoption_commandline(&argc, argv, nsoptions);
}
/**
@@ -216,12 +221,12 @@ static void quit_handler(int argc, char **argv)
*/
static nserror set_defaults(struct nsoption_s *defaults)
{
- /* Set defaults for absent option strings */
- nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
- nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
- nsoption_setnull_charp(url_file, strdup("~/.netsurf/URLs"));
+ /* Set defaults for absent option strings */
+ nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
+ nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
+ nsoption_setnull_charp(url_file, strdup("~/.netsurf/URLs"));
- return NSERROR_OK;
+ return NSERROR_OK;
}
@@ -230,170 +235,177 @@ static nserror set_defaults(struct nsoption_s *defaults)
*/
static bool nslog_stream_configure(FILE *fptr)
{
- /* set log stream to be non-buffering */
- setbuf(fptr, NULL);
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
- return true;
+ return true;
}
static struct gui_misc_table monkey_misc_table = {
- .schedule = monkey_schedule,
- .warning = monkey_warn_user,
+ .schedule = monkey_schedule,
+ .warning = monkey_warn_user,
- .quit = monkey_quit,
- .launch_url = gui_launch_url,
- .cert_verify = gui_cert_verify,
- .login = gui_401login_open,
+ .quit = monkey_quit,
+ .launch_url = gui_launch_url,
+ .cert_verify = gui_cert_verify,
+ .login = gui_401login_open,
};
static void monkey_run(void)
{
- fd_set read_fd_set, write_fd_set, exc_fd_set;
- int max_fd;
- int rdy_fd;
- int schedtm;
- struct timeval tv;
- struct timeval* timeout;
-
- while (!monkey_done) {
-
- /* clears fdset */
- fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
-
- /* add stdin to the set */
- if (max_fd < 0) {
- max_fd = 0;
- }
- FD_SET(0, &read_fd_set);
- FD_SET(0, &exc_fd_set);
-
- /* discover the next scheduled event time */
- schedtm = monkey_schedule_run();
-
- /* setup timeout */
- switch (schedtm) {
- case -1:
- LOG("Iterate blocking");
- fprintf(stdout, "GENERIC POLL BLOCKING\n");
- timeout = NULL;
- break;
-
- case 0:
- LOG("Iterate immediate");
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- timeout = &tv;
- break;
-
- default:
- LOG("Iterate non-blocking");
- fprintf(stdout, "GENERIC POLL TIMED\n");
- tv.tv_sec = schedtm / 1000; /* miliseconds to seconds */
- tv.tv_usec = (schedtm % 1000) * 1000; /* remainder to microseconds */
- timeout = &tv;
- break;
- }
-
- rdy_fd = select(max_fd + 1,
- &read_fd_set,
- &write_fd_set,
- &exc_fd_set,
- timeout);
- if (rdy_fd < 0) {
- monkey_done = true;
- } else if (rdy_fd > 0) {
- if (FD_ISSET(0, &read_fd_set)) {
- monkey_process_command();
- }
- }
- }
-
+ fd_set read_fd_set, write_fd_set, exc_fd_set;
+ int max_fd;
+ int rdy_fd;
+ int schedtm;
+ struct timeval tv;
+ struct timeval* timeout;
+
+ while (!monkey_done) {
+
+ /* clears fdset */
+ fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
+
+ /* add stdin to the set */
+ if (max_fd < 0) {
+ max_fd = 0;
+ }
+ FD_SET(0, &read_fd_set);
+ FD_SET(0, &exc_fd_set);
+
+ /* discover the next scheduled event time */
+ schedtm = monkey_schedule_run();
+
+ /* setup timeout */
+ switch (schedtm) {
+ case -1:
+ NSLOG(netsurf, INFO, "Iterate blocking");
+ fprintf(stdout, "GENERIC POLL BLOCKING\n");
+ timeout = NULL;
+ break;
+
+ case 0:
+ NSLOG(netsurf, INFO, "Iterate immediate");
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ timeout = &tv;
+ break;
+
+ default:
+ NSLOG(netsurf, INFO, "Iterate non-blocking");
+ fprintf(stdout, "GENERIC POLL TIMED %d\n", schedtm);
+ tv.tv_sec = schedtm / 1000; /* miliseconds to seconds */
+ tv.tv_usec = (schedtm % 1000) * 1000; /* remainder to microseconds */
+ timeout = &tv;
+ break;
+ }
+
+ rdy_fd = select(max_fd + 1,
+ &read_fd_set,
+ &write_fd_set,
+ &exc_fd_set,
+ timeout);
+ if (rdy_fd < 0) {
+ monkey_done = true;
+ } else if (rdy_fd > 0) {
+ if (FD_ISSET(0, &read_fd_set)) {
+ monkey_process_command();
+ }
+ }
+ }
}
int
main(int argc, char **argv)
{
- char *messages;
- char *options;
- char buf[PATH_MAX];
- nserror ret;
- struct netsurf_table monkey_table = {
- .misc = &monkey_misc_table,
- .window = monkey_window_table,
- .download = monkey_download_table,
- .fetch = monkey_fetch_table,
- .bitmap = monkey_bitmap_table,
- .layout = monkey_layout_table,
- };
-
- ret = netsurf_register(&monkey_table);
- if (ret != NSERROR_OK) {
- die("NetSurf operation table failed registration");
- }
-
- /* Unbuffer stdin/out/err */
- setbuf(stdin, NULL);
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
-
- /* Prep the search paths */
- respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./monkey/res");
-
- /* initialise logging. Not fatal if it fails but not much we can do
- * about it either.
- */
- nslog_init(nslog_stream_configure, &argc, argv);
-
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
- if (ret != NSERROR_OK) {
- die("Options failed to initialise");
- }
- options = filepath_find(respaths, "Choices");
- nsoption_read(options, nsoptions);
- free(options);
- nsoption_commandline(&argc, argv, nsoptions);
-
- messages = filepath_find(respaths, "Messages");
- ret = messages_add_from_file(messages);
- if (ret != NSERROR_OK) {
- LOG("Messages failed to load");
- }
-
- /* common initialisation */
- ret = netsurf_init(NULL);
- free(messages);
- if (ret != NSERROR_OK) {
- die("NetSurf failed to initialise");
- }
-
- filepath_sfinddef(respaths, buf, "mime.types", "/etc/");
- monkey_fetch_filetype_init(buf);
-
- urldb_load(nsoption_charp(url_file));
- urldb_load_cookies(nsoption_charp(cookie_file));
-
- ret = monkey_register_handler("QUIT", quit_handler);
- if (ret != NSERROR_OK) {
- die("quit handler failed to register");
- }
-
- ret = monkey_register_handler("WINDOW", monkey_window_handle_command);
- if (ret != NSERROR_OK) {
- die("window handler fialed to register");
- }
-
- fprintf(stdout, "GENERIC STARTED\n");
- monkey_run();
-
- fprintf(stdout, "GENERIC CLOSING_DOWN\n");
- monkey_kill_browser_windows();
-
- netsurf_exit();
- fprintf(stdout, "GENERIC FINISHED\n");
-
- /* finalise options */
- nsoption_finalise(nsoptions, nsoptions_default);
-
- return 0;
+ char *messages;
+ char *options;
+ char buf[PATH_MAX];
+ nserror ret;
+ struct netsurf_table monkey_table = {
+ .misc = &monkey_misc_table,
+ .window = monkey_window_table,
+ .download = monkey_download_table,
+ .fetch = monkey_fetch_table,
+ .bitmap = monkey_bitmap_table,
+ .layout = monkey_layout_table,
+ };
+
+ ret = netsurf_register(&monkey_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table failed registration");
+ }
+
+ /* Unbuffer stdin/out/err */
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ /* Prep the search paths */
+ respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./frontends/monkey/res");
+
+ /* initialise logging. Not fatal if it fails but not much we can do
+ * about it either.
+ */
+ nslog_init(nslog_stream_configure, &argc, argv);
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ die("Options failed to initialise");
+ }
+ options = filepath_find(respaths, "Choices");
+ nsoption_read(options, nsoptions);
+ free(options);
+ nsoption_commandline(&argc, argv, nsoptions);
+
+ messages = filepath_find(respaths, "Messages");
+ ret = messages_add_from_file(messages);
+ if (ret != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Messages failed to load");
+ }
+
+ /* common initialisation */
+ ret = netsurf_init(NULL);
+ free(messages);
+ if (ret != NSERROR_OK) {
+ die("NetSurf failed to initialise");
+ }
+
+ filepath_sfinddef(respaths, buf, "mime.types", "/etc/");
+ monkey_fetch_filetype_init(buf);
+
+ urldb_load(nsoption_charp(url_file));
+ urldb_load_cookies(nsoption_charp(cookie_file));
+
+ ret = monkey_register_handler("QUIT", quit_handler);
+ if (ret != NSERROR_OK) {
+ die("quit handler failed to register");
+ }
+
+ ret = monkey_register_handler("WINDOW", monkey_window_handle_command);
+ if (ret != NSERROR_OK) {
+ die("window handler failed to register");
+ }
+
+ ret = monkey_register_handler("OPTIONS", monkey_options_handle_command);
+ if (ret != NSERROR_OK) {
+ die("options handler failed to register");
+ }
+
+ fprintf(stdout, "GENERIC STARTED\n");
+ monkey_run();
+
+ fprintf(stdout, "GENERIC CLOSING_DOWN\n");
+ monkey_kill_browser_windows();
+
+ netsurf_exit();
+ fprintf(stdout, "GENERIC FINISHED\n");
+
+ /* finalise options */
+ nsoption_finalise(nsoptions, nsoptions_default);
+
+ /* finalise logging */
+ nslog_finalise();
+
+ return 0;
}
diff --git a/frontends/monkey/plot.c b/frontends/monkey/plot.c
index bd94e7551..2fc9a3cb6 100644
--- a/frontends/monkey/plot.c
+++ b/frontends/monkey/plot.c
@@ -19,82 +19,248 @@
#include <stdio.h>
#include "utils/utils.h"
+#include "utils/errors.h"
#include "netsurf/plotters.h"
-static bool
-monkey_plot_disc(int x, int y, int radius, const plot_style_t *style)
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
{
- return true;
+ fprintf(stdout,
+ "PLOT CLIP X0 %d Y0 %d X1 %d Y1 %d\n",
+ clip->x0, clip->y0, clip->x1, clip->y1);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
- return true;
+ fprintf(stdout,
+ "PLOT ARC X %d Y %d RADIUS %d ANGLE1 %d ANGLE2 %d\n",
+ x, y, radius, angle1, angle2);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
{
- return true;
+ fprintf(stdout,
+ "PLOT DISC X %d Y %d RADIUS %d\n",
+ x, y, radius);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
- fprintf(stdout, "PLOT TEXT X %d Y %d STR %*s\n", x, y, (int)length, text);
- return true;
+ fprintf(stdout,
+ "PLOT LINE X0 %d Y0 %d X1 %d Y1 %d\n",
+ line->x0, line->y0, line->x1, line->y1);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_bitmap(int x, int y,
- int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
{
- fprintf(stdout, "PLOT BITMAP X %d Y %d WIDTH %d HEIGHT %d\n",
- x, y, width, height);
- return true;
+ fprintf(stdout,
+ "PLOT RECT X0 %d Y0 %d X1 %d Y1 %d\n",
+ rect->x0, rect->y0, rect->x1, rect->y1);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
- fprintf(stdout, "PLOT RECT X0 %d Y0 %d X1 %d Y1 %d\n",
- x0, y0, x1, y1);
- return true;
+ fprintf(stdout,
+ "PLOT POLYGON VERTICIES %d\n",
+ n);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
- fprintf(stdout, "PLOT LINE X0 %d Y0 %d X1 %d Y1 %d\n",
- x0, y0, x1, y1);
- return true;
+ fprintf(stdout,
+ "PLOT PATH VERTICIES %d WIDTH %f\n",
+ n, plot_style_fixed_to_float(pstyle->stroke_width));
+ return NSERROR_OK;
}
-static bool
-monkey_plot_path(const float *p,
- unsigned int n,
- colour fill,
- float width,
- colour c,
- const float transform[6])
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
- return true;
+ fprintf(stdout,
+ "PLOT BITMAP X %d Y %d WIDTH %d HEIGHT %d\n",
+ x, y, width, height);
+ return NSERROR_OK;
}
-static bool
-monkey_plot_clip(const struct rect *clip)
+
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+monkey_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- fprintf(stdout, "PLOT CLIP X0 %d Y0 %d X1 %d Y1 %d\n",
- clip->x0, clip->y0, clip->x1, clip->y1);
- return true;
+ fprintf(stdout,
+ "PLOT TEXT X %d Y %d STR %*s\n",
+ x, y, (int)length, text);
+ return NSERROR_OK;
}
+
+/** monkey plotter operations table */
static const struct plotter_table plotters = {
.clip = monkey_plot_clip,
.arc = monkey_plot_arc,
@@ -105,7 +271,7 @@ static const struct plotter_table plotters = {
.path = monkey_plot_path,
.bitmap = monkey_plot_bitmap,
.text = monkey_plot_text,
- .option_knockout = true,
+ .option_knockout = true,
};
const struct plotter_table* monkey_plotters = &plotters;
diff --git a/frontends/monkey/schedule.c b/frontends/monkey/schedule.c
index 8c638c0b9..3d76997f4 100644
--- a/frontends/monkey/schedule.c
+++ b/frontends/monkey/schedule.c
@@ -24,12 +24,6 @@
#include "monkey/schedule.h"
-#ifdef DEBUG_SCHEDULER
-#define SRLOG(x...) LOG(x)
-#else
-#define SRLOG(x...) ((void) 0)
-#endif
-
/* linked list of scheduled callbacks */
static struct nscallback *schedule_list = NULL;
@@ -38,10 +32,10 @@ static struct nscallback *schedule_list = NULL;
*/
struct nscallback
{
- struct nscallback *next;
- struct timeval tv;
- void (*callback)(void *p);
- void *p;
+ struct nscallback *next;
+ struct timeval tv;
+ void (*callback)(void *p);
+ void *p;
};
/**
@@ -54,170 +48,164 @@ struct nscallback
*/
static nserror schedule_remove(void (*callback)(void *p), void *p)
{
- struct nscallback *cur_nscb;
- struct nscallback *prev_nscb;
- struct nscallback *unlnk_nscb;
-
- /* check there is something on the list to remove */
- if (schedule_list == NULL) {
- return NSERROR_OK;
- }
-
- SRLOG("removing %p, %p", callback, p);
-
- cur_nscb = schedule_list;
- prev_nscb = NULL;
-
- while (cur_nscb != NULL) {
- if ((cur_nscb->callback == callback) &&
- (cur_nscb->p == p)) {
- /* item to remove */
-
- SRLOG("callback entry %p removing %p(%p)",
- cur_nscb, cur_nscb->callback, cur_nscb->p);
-
- /* remove callback */
- unlnk_nscb = cur_nscb;
- cur_nscb = unlnk_nscb->next;
-
- if (prev_nscb == NULL) {
- schedule_list = cur_nscb;
- } else {
- prev_nscb->next = cur_nscb;
- }
- free (unlnk_nscb);
- } else {
- /* move to next element */
- prev_nscb = cur_nscb;
- cur_nscb = prev_nscb->next;
- }
- }
-
- return NSERROR_OK;
+ struct nscallback *cur_nscb;
+ struct nscallback *prev_nscb;
+ struct nscallback *unlnk_nscb;
+
+ /* check there is something on the list to remove */
+ if (schedule_list == NULL) {
+ return NSERROR_OK;
+ }
+
+ NSLOG(schedule, DEBUG, "removing %p, %p", callback, p);
+
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
+
+ while (cur_nscb != NULL) {
+ if ((cur_nscb->callback == callback) &&
+ (cur_nscb->p == p)) {
+ /* item to remove */
+
+ NSLOG(schedule, DEBUG, "callback entry %p removing %p(%p)",
+ cur_nscb, cur_nscb->callback, cur_nscb->p);
+
+ /* remove callback */
+ unlnk_nscb = cur_nscb;
+ cur_nscb = unlnk_nscb->next;
+
+ if (prev_nscb == NULL) {
+ schedule_list = cur_nscb;
+ } else {
+ prev_nscb->next = cur_nscb;
+ }
+ free (unlnk_nscb);
+ } else {
+ /* move to next element */
+ prev_nscb = cur_nscb;
+ cur_nscb = prev_nscb->next;
+ }
+ }
+
+ return NSERROR_OK;
}
-/* exported function documented in framebuffer/schedule.h */
+/* exported function documented in monkey/schedule.h */
nserror monkey_schedule(int tival, void (*callback)(void *p), void *p)
{
- struct nscallback *nscb;
- struct timeval tv;
- nserror ret;
+ struct nscallback *nscb;
+ struct timeval tv;
+ nserror ret;
- /* ensure uniqueness of the callback and context */
- ret = schedule_remove(callback, p);
- if ((tival < 0) || (ret != NSERROR_OK)) {
- return ret;
- }
+ /* ensure uniqueness of the callback and context */
+ ret = schedule_remove(callback, p);
+ if ((tival < 0) || (ret != NSERROR_OK)) {
+ return ret;
+ }
- SRLOG("Adding %p(%p) in %d", callback, p, tival);
+ NSLOG(schedule, DEBUG, "Adding %p(%p) in %d", callback, p, tival);
- tv.tv_sec = tival / 1000; /* miliseconds to seconds */
- tv.tv_usec = (tival % 1000) * 1000; /* remainder to microseconds */
+ tv.tv_sec = tival / 1000; /* miliseconds to seconds */
+ tv.tv_usec = (tival % 1000) * 1000; /* remainder to microseconds */
- nscb = calloc(1, sizeof(struct nscallback));
+ nscb = calloc(1, sizeof(struct nscallback));
- gettimeofday(&nscb->tv, NULL);
- timeradd(&nscb->tv, &tv, &nscb->tv);
+ gettimeofday(&nscb->tv, NULL);
+ timeradd(&nscb->tv, &tv, &nscb->tv);
- nscb->callback = callback;
- nscb->p = p;
+ nscb->callback = callback;
+ nscb->p = p;
- /* add to list front */
- nscb->next = schedule_list;
- schedule_list = nscb;
+ /* add to list front */
+ nscb->next = schedule_list;
+ schedule_list = nscb;
- return NSERROR_OK;
+ return NSERROR_OK;
}
-/* exported function documented in framebuffer/schedule.h */
+/* exported function documented in monkey/schedule.h */
int monkey_schedule_run(void)
{
- struct timeval tv;
- struct timeval nexttime;
- struct timeval rettime;
- struct nscallback *cur_nscb;
- struct nscallback *prev_nscb;
- struct nscallback *unlnk_nscb;
-
- if (schedule_list == NULL)
- return -1;
-
- /* reset enumeration to the start of the list */
- cur_nscb = schedule_list;
- prev_nscb = NULL;
- nexttime = cur_nscb->tv;
-
- gettimeofday(&tv, NULL);
-
- while (cur_nscb != NULL) {
- if (timercmp(&tv, &cur_nscb->tv, >)) {
- /* scheduled time */
-
- /* remove callback */
- unlnk_nscb = cur_nscb;
-
- if (prev_nscb == NULL) {
- schedule_list = unlnk_nscb->next;
- } else {
- prev_nscb->next = unlnk_nscb->next;
- }
-
- unlnk_nscb->callback(unlnk_nscb->p);
-
- free(unlnk_nscb);
-
- /* need to deal with callback modifying the list. */
- if (schedule_list == NULL)
- return -1; /* no more callbacks scheduled */
-
- /* reset enumeration to the start of the list */
- cur_nscb = schedule_list;
- prev_nscb = NULL;
- nexttime = cur_nscb->tv;
- } else {
- /* if the time to the event is sooner than the
- * currently recorded soonest event record it
- */
- if (timercmp(&nexttime, &cur_nscb->tv, >)) {
+ struct timeval tv;
+ struct timeval nexttime;
+ struct timeval rettime;
+ struct nscallback *cur_nscb;
+ struct nscallback *prev_nscb;
+ struct nscallback *unlnk_nscb;
+
+ if (schedule_list == NULL)
+ return -1;
+
+ /* reset enumeration to the start of the list */
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
nexttime = cur_nscb->tv;
- }
- /* move to next element */
- prev_nscb = cur_nscb;
- cur_nscb = prev_nscb->next;
- }
- }
-
- /* make rettime relative to now */
- timersub(&nexttime, &tv, &rettime);
- SRLOG("returning time to next event as %ldms",
- (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
-
- /* return next event time in milliseconds (24days max wait) */
- return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
+ gettimeofday(&tv, NULL);
+
+ while (cur_nscb != NULL) {
+ if (timercmp(&tv, &cur_nscb->tv, >)) {
+ /* scheduled time */
+
+ /* remove callback */
+ unlnk_nscb = cur_nscb;
+
+ if (prev_nscb == NULL) {
+ schedule_list = unlnk_nscb->next;
+ } else {
+ prev_nscb->next = unlnk_nscb->next;
+ }
+
+ unlnk_nscb->callback(unlnk_nscb->p);
+
+ free(unlnk_nscb);
+
+ /* need to deal with callback modifying the list. */
+ if (schedule_list == NULL)
+ return -1; /* no more callbacks scheduled */
+
+ /* reset enumeration to the start of the list */
+ cur_nscb = schedule_list;
+ prev_nscb = NULL;
+ nexttime = cur_nscb->tv;
+ } else {
+ /* if the time to the event is sooner than the
+ * currently recorded soonest event record it
+ */
+ if (timercmp(&nexttime, &cur_nscb->tv, >)) {
+ nexttime = cur_nscb->tv;
+ }
+ /* move to next element */
+ prev_nscb = cur_nscb;
+ cur_nscb = prev_nscb->next;
+ }
+ }
+
+ /* make rettime relative to now */
+ timersub(&nexttime, &tv, &rettime);
+
+ NSLOG(schedule, DEBUG, "returning time to next event as %ldms",
+ (long)((rettime.tv_sec * 1000) + (rettime.tv_usec / 1000)));
+
+ /* return next event time in milliseconds (24days max wait) */
+ return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
}
void monkey_schedule_list(void)
{
- struct timeval tv;
- struct nscallback *cur_nscb;
+ struct timeval tv;
+ struct nscallback *cur_nscb;
- gettimeofday(&tv, NULL);
+ gettimeofday(&tv, NULL);
- LOG("schedule list at %lld:%ld", (long long)tv.tv_sec, tv.tv_usec);
+ NSLOG(netsurf, INFO, "schedule list at %lld:%ld",
+ (long long)tv.tv_sec, tv.tv_usec);
- cur_nscb = schedule_list;
+ cur_nscb = schedule_list;
- while (cur_nscb != NULL) {
- LOG("Schedule %p at %lld:%ld",
- cur_nscb, (long long)cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
- cur_nscb = cur_nscb->next;
- }
+ while (cur_nscb != NULL) {
+ NSLOG(netsurf, INFO, "Schedule %p at %lld:%ld", cur_nscb,
+ (long long)cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
+ cur_nscb = cur_nscb->next;
+ }
}
-
-
-/*
- * Local Variables:
- * c-basic-offset:2
- * End:
- */
diff --git a/frontends/riscos/401login.c b/frontends/riscos/401login.c
index a23c01c90..4b2deb16b 100644
--- a/frontends/riscos/401login.c
+++ b/frontends/riscos/401login.c
@@ -191,7 +191,8 @@ void ro_gui_401login_close(wimp_w w)
error = xwimp_delete_window(w);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
ro_gui_wimp_event_finalise(w);
@@ -212,7 +213,7 @@ bool ro_gui_401login_apply(wimp_w w)
auth = malloc(strlen(session->uname) + strlen(session->pwd) + 2);
if (!auth) {
- LOG("calloc failed");
+ NSLOG(netsurf, INFO, "calloc failed");
ro_warn_user("NoMemory", 0);
return false;
}
diff --git a/frontends/riscos/Makefile b/frontends/riscos/Makefile
index 87790acc0..f531b6b5b 100644
--- a/frontends/riscos/Makefile
+++ b/frontends/riscos/Makefile
@@ -16,7 +16,7 @@ $(eval $(call feature_enabled,DRAW_EXPORT,-DWITH_DRAW_EXPORT,-lpencil,Drawfile e
TPD_RISCOS = $(foreach TPL,$(notdir $(TPL_RISCOS)), \
- !NetSurf/Resources/$(TPL)/Templates$(TPLEXT))
+ $(FRONTEND_SOURCE_DIR)/appdir/Resources/$(TPL)/Templates$(TPLEXT))
RESOURCES = $(TPD_RISCOS)
@@ -47,13 +47,14 @@ endif
# S_RISCOS are sources purely for the RISC OS build
S_FRONTEND := 401login.c assert.c bitmap.c buffer.c configure.c gui.c \
- dialog.c download.c filetype.c font.c help.c history.c image.c \
+ dialog.c download.c filetype.c font.c help.c image.c \
iconbar.c menus.c message.c mouse.c palettes.c plotters.c \
print.c query.c save.c save_draw.c save_pdf.c schedule.c \
search.c searchweb.c textarea.c textselection.c theme.c \
theme_install.c toolbar.c url_suggest.c wimp.c wimp_event.c \
ucstables.c uri.c url_complete.c url_protocol.c window.c \
- corewindow.c cookies.c sslcert.c global_history.c hotlist.c \
+ corewindow.c cookies.c sslcert.c hotlist.c \
+ local_history.c global_history.c \
$(addprefix content-handlers/,artworks.c awrender.s draw.c \
sprite.c) \
$(addprefix gui/,button_bar.c progress_bar.c status_bar.c \
@@ -67,16 +68,16 @@ S_FRONTEND := 401login.c assert.c bitmap.c buffer.c configure.c gui.c \
# are not yet available
SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRONTEND)
-EXETARGET := !NetSurf/!RunImage$(EXEEXT)
+EXETARGET := $(FRONTEND_SOURCE_DIR)/appdir/!RunImage$(EXEEXT)
# The filter and target for split messages
MESSAGES_FILTER=ro
-!NetSurf/!Run$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Run $(EXETARGET)
+$(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Run $(EXETARGET)
$(VQ)echo " MAKERUN: $@"
$(Q)$(MAKERUN) $(EXETARGET) $< $@
-!NetSurf/!Help$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Help
+$(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT): $(FRONTEND_SOURCE_DIR)/scripts/Help
$(VQ)echo " CP: $@"
$(Q)cp $< $@
@@ -85,16 +86,16 @@ $(DEPROOT)/squeeze.d: $(EXETARGET)
$(Q)$(SQUEEZE) -f -v $(EXETARGET)
$(Q)$(TOUCH) $@
-POSTEXES += !NetSurf/!Run$(RUNEXT) !NetSurf/!Help$(RUNEXT) $(DEPROOT)/squeeze.d
+POSTEXES += $(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT) $(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT) $(DEPROOT)/squeeze.d
clean-run:
- $(VQ)echo " CLEAN: !NetSurf/!Run$(RUNEXT)"
- $(Q) $(RM) !NetSurf/!Run$(RUNEXT)
+ $(VQ)echo " CLEAN: !Run$(RUNEXT)"
+ $(Q) $(RM) $(FRONTEND_SOURCE_DIR)/appdir/!Run$(RUNEXT)
clean-help:
- $(VQ)echo " CLEAN: !NetSurf/!Help$(RUNEXT)"
- $(Q) $(RM) !NetSurf/!Help$(RUNEXT)
+ $(VQ)echo " CLEAN: !Help$(RUNEXT)"
+ $(Q) $(RM) $(FRONTEND_SOURCE_DIR)/appdir/!Help$(RUNEXT)
CLEANS += clean-run clean-help
@@ -108,12 +109,12 @@ TPL_RISCOS := $(addprefix $(FRONTEND_SOURCE_DIR)/templates/,$(TPL_RISCOS))
# Template target creation macro
define compile_template
-!NetSurf/Resources/$(1)/Templates$$(TPLEXT): $(2)
+$(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)/Templates$$(TPLEXT): $(2)
$$(VQ)echo "TEMPLATE: $(2)"
- $$(Q)$$(MKDIR) -p !NetSurf/Resources/$(1)
+ $$(Q)$$(MKDIR) -p $(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)
$$(Q)$$(CC) -x c -E -P $$(CFLAGS) $(2) | $$(CCRES) - $$@
-CLEAN_TEMPLATES += !NetSurf/Resources/$(1)/Templates$$(TPLEXT)
+CLEAN_TEMPLATES += $(FRONTEND_SOURCE_DIR)/appdir/Resources/$(1)/Templates$$(TPLEXT)
endef
@@ -141,7 +142,7 @@ package-riscos: netsurf.zip
netsurf.zip: $(EXETARGET)
$(eval $@_TMPDIR := $(shell mktemp -d))
$(Q) $(RM) $@
- $(Q) rsync --archive --verbose $(CURDIR)/!NetSurf $($@_TMPDIR)
+ $(Q) cp -rLvp $(FRONTEND_SOURCE_DIR)/appdir $($@_TMPDIR)/!NetSurf
$(Q) $(CURDIR)/utils/git-date.sh $(FRONTEND_SOURCE_DIR)/distribution
$(Q) rsync --archive --verbose $(FRONTEND_SOURCE_DIR)/distribution/!Boot $($@_TMPDIR)
$(Q) rsync --archive --verbose $(FRONTEND_SOURCE_DIR)/distribution/!System $($@_TMPDIR)
diff --git a/!NetSurf/!Boot,feb b/frontends/riscos/appdir/!Boot,feb
index ca7a3feec..ca7a3feec 100644
--- a/!NetSurf/!Boot,feb
+++ b/frontends/riscos/appdir/!Boot,feb
diff --git a/!NetSurf/!Sprites,ff9 b/frontends/riscos/appdir/!Sprites,ff9
index 2c7d6f648..2c7d6f648 100644
--- a/!NetSurf/!Sprites,ff9
+++ b/frontends/riscos/appdir/!Sprites,ff9
Binary files differ
diff --git a/!NetSurf/!Sprites22,ff9 b/frontends/riscos/appdir/!Sprites22,ff9
index 8bc3aa616..8bc3aa616 100644
--- a/!NetSurf/!Sprites22,ff9
+++ b/frontends/riscos/appdir/!Sprites22,ff9
Binary files differ
diff --git a/!NetSurf/5Sprites,ff9 b/frontends/riscos/appdir/5Sprites,ff9
index b0cf1c95f..b0cf1c95f 100755
--- a/!NetSurf/5Sprites,ff9
+++ b/frontends/riscos/appdir/5Sprites,ff9
Binary files differ
diff --git a/!NetSurf/5Sprites11,ff9 b/frontends/riscos/appdir/5Sprites11,ff9
index c039ea180..c039ea180 100755
--- a/!NetSurf/5Sprites11,ff9
+++ b/frontends/riscos/appdir/5Sprites11,ff9
Binary files differ
diff --git a/!NetSurf/5Sprites22,ff9 b/frontends/riscos/appdir/5Sprites22,ff9
index 766471428..766471428 100755
--- a/!NetSurf/5Sprites22,ff9
+++ b/frontends/riscos/appdir/5Sprites22,ff9
Binary files differ
diff --git a/!NetSurf/ASprites,ff9 b/frontends/riscos/appdir/ASprites,ff9
index 5cab2a16b..5cab2a16b 100755
--- a/!NetSurf/ASprites,ff9
+++ b/frontends/riscos/appdir/ASprites,ff9
Binary files differ
diff --git a/!NetSurf/ASprites11,ff9 b/frontends/riscos/appdir/ASprites11,ff9
index 5f94dfbd9..5f94dfbd9 100755
--- a/!NetSurf/ASprites11,ff9
+++ b/frontends/riscos/appdir/ASprites11,ff9
Binary files differ
diff --git a/!NetSurf/ASprites22,ff9 b/frontends/riscos/appdir/ASprites22,ff9
index cc932844e..cc932844e 100755
--- a/!NetSurf/ASprites22,ff9
+++ b/frontends/riscos/appdir/ASprites22,ff9
Binary files differ
diff --git a/frontends/riscos/appdir/ChkSprites,ffb b/frontends/riscos/appdir/ChkSprites,ffb
new file mode 100644
index 000000000..4e38dfba5
--- /dev/null
+++ b/frontends/riscos/appdir/ChkSprites,ffb
Binary files differ
diff --git a/!NetSurf/Docs/online,b60 b/frontends/riscos/appdir/Docs/online,b60
index 1ef39f0c9..1ef39f0c9 100755
--- a/!NetSurf/Docs/online,b60
+++ b/frontends/riscos/appdir/Docs/online,b60
Binary files differ
diff --git a/!NetSurf/FixFonts,ffb b/frontends/riscos/appdir/FixFonts,ffb
index c6b73d0b0..c6b73d0b0 100644
--- a/!NetSurf/FixFonts,ffb
+++ b/frontends/riscos/appdir/FixFonts,ffb
diff --git a/!NetSurf/KickNS,ffb b/frontends/riscos/appdir/KickNS,ffb
index bc209ad02..bc209ad02 100644
--- a/!NetSurf/KickNS,ffb
+++ b/frontends/riscos/appdir/KickNS,ffb
Binary files differ
diff --git a/!NetSurf/OpenChoices,feb b/frontends/riscos/appdir/OpenChoices,feb
index 06ed7be01..06ed7be01 100755
--- a/!NetSurf/OpenChoices,feb
+++ b/frontends/riscos/appdir/OpenChoices,feb
diff --git a/!NetSurf/OpenHelp,ffb b/frontends/riscos/appdir/OpenHelp,ffb
index 8928652da..8928652da 100644
--- a/!NetSurf/OpenHelp,ffb
+++ b/frontends/riscos/appdir/OpenHelp,ffb
Binary files differ
diff --git a/!NetSurf/OpenScrap,feb b/frontends/riscos/appdir/OpenScrap,feb
index e45854bcd..e45854bcd 100755
--- a/!NetSurf/OpenScrap,feb
+++ b/frontends/riscos/appdir/OpenScrap,feb
diff --git a/frontends/riscos/appdir/Resources/AdBlock,f79 b/frontends/riscos/appdir/Resources/AdBlock,f79
new file mode 120000
index 000000000..8f57c43fd
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/AdBlock,f79
@@ -0,0 +1 @@
+../../../../resources/adblock.css \ No newline at end of file
diff --git a/!NetSurf/Resources/Aletheia,ffd b/frontends/riscos/appdir/Resources/Aletheia,ffd
index 9af7ea129..9af7ea129 100644
--- a/!NetSurf/Resources/Aletheia,ffd
+++ b/frontends/riscos/appdir/Resources/Aletheia,ffd
Binary files differ
diff --git a/frontends/riscos/appdir/Resources/CSS,f79 b/frontends/riscos/appdir/Resources/CSS,f79
new file mode 120000
index 000000000..3238d9188
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/CSS,f79
@@ -0,0 +1 @@
+../../../../resources/default.css \ No newline at end of file
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/Encoding b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Encoding
index c92dad17a..c92dad17a 100644
--- a/!NetSurf/Resources/Fonts/NSSymbol/Encoding
+++ b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Encoding
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/IntMetrics,ff6 b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/IntMetrics,ff6
index 4dcbc625d..4dcbc625d 100644
--- a/!NetSurf/Resources/Fonts/NSSymbol/IntMetrics,ff6
+++ b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/IntMetrics,ff6
Binary files differ
diff --git a/!NetSurf/Resources/Fonts/NSSymbol/Outlines,ff6 b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Outlines,ff6
index d2e624132..d2e624132 100644
--- a/!NetSurf/Resources/Fonts/NSSymbol/Outlines,ff6
+++ b/frontends/riscos/appdir/Resources/Fonts/NSSymbol/Outlines,ff6
Binary files differ
diff --git a/frontends/riscos/appdir/Resources/Icons b/frontends/riscos/appdir/Resources/Icons
new file mode 120000
index 000000000..6820377bb
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/Icons
@@ -0,0 +1 @@
+../../../../resources/icons \ No newline at end of file
diff --git a/!NetSurf/Resources/Image,ff9 b/frontends/riscos/appdir/Resources/Image,ff9
index a61ddefd2..a61ddefd2 100755
--- a/!NetSurf/Resources/Image,ff9
+++ b/frontends/riscos/appdir/Resources/Image,ff9
Binary files differ
diff --git a/!NetSurf/Resources/LangNames b/frontends/riscos/appdir/Resources/LangNames
index de7c76c65..de7c76c65 100644
--- a/!NetSurf/Resources/LangNames
+++ b/frontends/riscos/appdir/Resources/LangNames
diff --git a/frontends/riscos/appdir/Resources/Quirks,f79 b/frontends/riscos/appdir/Resources/Quirks,f79
new file mode 120000
index 000000000..995fafc61
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/Quirks,f79
@@ -0,0 +1 @@
+../../../../resources/quirks.css \ No newline at end of file
diff --git a/!NetSurf/Resources/SearchEngines b/frontends/riscos/appdir/Resources/SearchEngines
index e7fd7cb65..e7fd7cb65 100644
--- a/!NetSurf/Resources/SearchEngines
+++ b/frontends/riscos/appdir/Resources/SearchEngines
diff --git a/!NetSurf/Resources/Sprites,ff9 b/frontends/riscos/appdir/Resources/Sprites,ff9
index bdbd6e877..bdbd6e877 100755
--- a/!NetSurf/Resources/Sprites,ff9
+++ b/frontends/riscos/appdir/Resources/Sprites,ff9
Binary files differ
diff --git a/frontends/riscos/appdir/Resources/ca-bundle b/frontends/riscos/appdir/Resources/ca-bundle
new file mode 120000
index 000000000..2d99c7508
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/ca-bundle
@@ -0,0 +1 @@
+../../../../resources/ca-bundle \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/de/Messages b/frontends/riscos/appdir/Resources/de/Messages
new file mode 120000
index 000000000..aa4060685
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/de/Messages
@@ -0,0 +1 @@
+../../../../../resources/de/Messages \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/de/welcome.html,faf b/frontends/riscos/appdir/Resources/de/welcome.html,faf
new file mode 120000
index 000000000..d3cfb115d
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/de/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/de/welcome.html \ No newline at end of file
diff --git a/!NetSurf/Resources/en/!Help b/frontends/riscos/appdir/Resources/en/!Help
index 977f069d8..977f069d8 100644
--- a/!NetSurf/Resources/en/!Help
+++ b/frontends/riscos/appdir/Resources/en/!Help
diff --git a/frontends/riscos/appdir/Resources/en/Messages b/frontends/riscos/appdir/Resources/en/Messages
new file mode 120000
index 000000000..56c2ae237
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/Messages
@@ -0,0 +1 @@
+../../../../../resources/en/Messages \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/credits.html,faf b/frontends/riscos/appdir/Resources/en/credits.html,faf
new file mode 120000
index 000000000..7999c6c56
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/credits.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/licence.html,faf b/frontends/riscos/appdir/Resources/en/licence.html,faf
new file mode 120000
index 000000000..70371ada8
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/licence.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/maps.html,faf b/frontends/riscos/appdir/Resources/en/maps.html,faf
new file mode 120000
index 000000000..4ae4f6c42
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/maps.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/maps.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/en/welcome.html,faf b/frontends/riscos/appdir/Resources/en/welcome.html,faf
new file mode 120000
index 000000000..71020bfe8
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/en/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/en/welcome.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/fr/Messages b/frontends/riscos/appdir/Resources/fr/Messages
new file mode 120000
index 000000000..4c321aefd
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/fr/Messages
@@ -0,0 +1 @@
+../../../../../resources/fr/Messages \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/internal.css,f79 b/frontends/riscos/appdir/Resources/internal.css,f79
new file mode 120000
index 000000000..c807a4d3d
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/internal.css,f79
@@ -0,0 +1 @@
+../../../../resources/internal.css \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/Messages b/frontends/riscos/appdir/Resources/it/Messages
new file mode 120000
index 000000000..7dc2ae2b1
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/Messages
@@ -0,0 +1 @@
+../../../../../resources/it/Messages \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/credits.html,faf b/frontends/riscos/appdir/Resources/it/credits.html,faf
new file mode 120000
index 000000000..e0bd9a23f
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/credits.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/licence.html,faf b/frontends/riscos/appdir/Resources/it/licence.html,faf
new file mode 120000
index 000000000..7e8c83571
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/licence.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/it/welcome.html,faf b/frontends/riscos/appdir/Resources/it/welcome.html,faf
new file mode 120000
index 000000000..6e24135ff
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/it/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/it/welcome.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/ja/welcome.html,faf b/frontends/riscos/appdir/Resources/ja/welcome.html,faf
new file mode 120000
index 000000000..1dfdbd7ea
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/ja/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/ja/welcome.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/netsurf.png,b60 b/frontends/riscos/appdir/Resources/netsurf.png,b60
new file mode 120000
index 000000000..e7fa4cb87
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/netsurf.png,b60
@@ -0,0 +1 @@
+../../../../resources/netsurf.png \ No newline at end of file
diff --git a/!NetSurf/Resources/nl/!Help b/frontends/riscos/appdir/Resources/nl/!Help
index 4eca563bc..4eca563bc 100644
--- a/!NetSurf/Resources/nl/!Help
+++ b/frontends/riscos/appdir/Resources/nl/!Help
diff --git a/frontends/riscos/appdir/Resources/nl/Messages b/frontends/riscos/appdir/Resources/nl/Messages
new file mode 120000
index 000000000..20acc40f2
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/Messages
@@ -0,0 +1 @@
+../../../../../resources/nl/Messages \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/credits.html,faf b/frontends/riscos/appdir/Resources/nl/credits.html,faf
new file mode 120000
index 000000000..2380aa33c
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/credits.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/credits.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/licence.html,faf b/frontends/riscos/appdir/Resources/nl/licence.html,faf
new file mode 120000
index 000000000..46804ce86
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/licence.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/licence.html \ No newline at end of file
diff --git a/frontends/riscos/appdir/Resources/nl/welcome.html,faf b/frontends/riscos/appdir/Resources/nl/welcome.html,faf
new file mode 120000
index 000000000..6de5c4a73
--- /dev/null
+++ b/frontends/riscos/appdir/Resources/nl/welcome.html,faf
@@ -0,0 +1 @@
+../../../../../resources/nl/welcome.html \ No newline at end of file
diff --git a/frontends/riscos/bitmap.c b/frontends/riscos/bitmap.c
index 1a3524633..d554d54b4 100644
--- a/frontends/riscos/bitmap.c
+++ b/frontends/riscos/bitmap.c
@@ -287,7 +287,10 @@ bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
(bitmap->sprite_area), path);
if (error) {
- LOG("xosspriteop_save_sprite_file: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_save_sprite_file: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -347,7 +350,8 @@ bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
error = xosfind_openoutw(0, path, NULL, &fw);
if (error) {
- LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openoutw: 0x%x: %s",
+ error->errnum, error->errmess);
free(chunk_buf);
ro_warn_user("SaveError", error->errmess);
return false;
@@ -361,7 +365,8 @@ bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
if (!error)
error = xosgbpb_writew(fw, (byte*)p, image_size, NULL);
if (error) {
- LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosgbpb_writew: 0x%x: %s",
+ error->errnum, error->errmess);
free(chunk_buf);
xosfind_closew(fw);
ro_warn_user("SaveError", error->errmess);
@@ -406,7 +411,10 @@ bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
}
error = xosgbpb_writew(fw, (byte*)chunk_buf, dp-chunk_buf, NULL);
if (error) {
- LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosgbpb_writew: 0x%x: %s",
+ error->errnum,
+ error->errmess);
free(chunk_buf);
xosfind_closew(fw);
ro_warn_user("SaveError", error->errmess);
@@ -416,13 +424,15 @@ bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
error = xosfind_closew(fw);
if (error) {
- LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
error = xosfile_set_type(path, osfile_TYPE_SPRITE);
if (error) {
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
@@ -509,7 +519,8 @@ void riscos_bitmap_overlay_sprite(struct bitmap *bitmap,
(osspriteop_id)s,
&w, &h, NULL, NULL);
if (error) {
- LOG("xosspriteop_read_sprite_info: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosspriteop_read_sprite_info: 0x%x:%s",
+ error->errnum, error->errmess);
return;
}
sp_offset = ((s->width + 1) * 4) - w;
@@ -591,7 +602,7 @@ static osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap)
sprite_area = (osspriteop_area *)malloc(area_size);
if (!sprite_area) {
- LOG("no memory for malloc()");
+ NSLOG(netsurf, INFO, "no memory for malloc()");
return NULL;
}
sprite_area->size = area_size;
@@ -759,7 +770,8 @@ static void thumbnail_test(void)
area_size = sizeof(osspriteop_area) +
sizeof(osspriteop_header) + sizeof(int);
if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
- LOG("Insufficient memory to perform sprite test.");
+ NSLOG(netsurf, INFO,
+ "Insufficient memory to perform sprite test.");
return;
}
sprite_area->size = area_size + 1;
@@ -791,7 +803,7 @@ nserror riscos_bitmap_render(struct bitmap *bitmap,
assert(content);
assert(bitmap);
- LOG("content %p in bitmap %p", content, bitmap);
+ NSLOG(netsurf, INFO, "content %p in bitmap %p", content, bitmap);
/* check if we have access to 32bpp sprites natively */
if (thumbnail_32bpp_available == -1) {
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c
index 7176c1c1c..c63a270db 100644
--- a/frontends/riscos/buffer.c
+++ b/frontends/riscos/buffer.c
@@ -107,7 +107,12 @@ void ro_gui_buffer_open(wimp_draw *redraw)
*/
if ((clipping.x1 < clipping.x0) ||
(clipping.y1 < clipping.y0)) {
- LOG("Invalid clipping rectangle (%i, %i) to (%i,%i)", clipping.x0, clipping.y0, clipping.x1, clipping.y1);
+ NSLOG(netsurf, INFO,
+ "Invalid clipping rectangle (%i, %i) to (%i,%i)",
+ clipping.x0,
+ clipping.y0,
+ clipping.x1,
+ clipping.y1);
return;
}
@@ -138,7 +143,7 @@ void ro_gui_buffer_open(wimp_draw *redraw)
(word_width * sprite_size.y * 4) + palette_size;
buffer = (osspriteop_area *)malloc(total_size);
if (!buffer) {
- LOG("Failed to allocate memory");
+ NSLOG(netsurf, INFO, "Failed to allocate memory");
ro_gui_buffer_free();
return;
}
@@ -149,7 +154,8 @@ void ro_gui_buffer_open(wimp_draw *redraw)
mode = tinct_SPRITE_MODE;
#else
if ((error = xwimpreadsysinfo_wimp_mode(&mode)) != NULL) {
- LOG("Error reading mode '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Error reading mode '%s'",
+ error->errmess);
ro_gui_buffer_free();
return;
}
@@ -177,7 +183,9 @@ void ro_gui_buffer_open(wimp_draw *redraw)
error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), (int *)&vals);
if (error) {
- LOG("Error reading mode properties '%s'", error->errmess);
+ NSLOG(netsurf, INFO,
+ "Error reading mode properties '%s'",
+ error->errmess);
ro_gui_buffer_free();
return;
}
@@ -233,7 +241,9 @@ void ro_gui_buffer_open(wimp_draw *redraw)
}
break;
default:
- LOG("Unhandled 16bpp format from flags %d", vals.flags);
+ NSLOG(netsurf, INFO,
+ "Unhandled 16bpp format from flags %d",
+ vals.flags);
ro_gui_buffer_free();
return;
}
@@ -261,13 +271,16 @@ void ro_gui_buffer_open(wimp_draw *redraw)
}
break;
default:
- LOG("Unhandled 32bpp data format from flags %d", vals.flags);
+ NSLOG(netsurf, INFO,
+ "Unhandled 32bpp data format from flags %d",
+ vals.flags);
ro_gui_buffer_free();
return;
}
break;
default:
- LOG("Unhandled NCOLOUR value %d", vals.ncolour);
+ NSLOG(netsurf, INFO, "Unhandled NCOLOUR value %d",
+ vals.ncolour);
ro_gui_buffer_free();
return;
}
@@ -305,7 +318,7 @@ void ro_gui_buffer_open(wimp_draw *redraw)
buffer, buffer_name, palette,
clipping.x0, clipping.y0,
clipping.x1, clipping.y1)) != NULL) {
- LOG("Grab error '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Grab error '%s'", error->errmess);
ro_gui_buffer_free();
return;
}
@@ -314,7 +327,7 @@ void ro_gui_buffer_open(wimp_draw *redraw)
*/
if ((error = xosspriteop_read_save_area_size(osspriteop_PTR,
buffer, (osspriteop_id)(buffer + 1), &size)) != NULL) {
- LOG("Save area error '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Save area error '%s'", error->errmess);
ro_gui_buffer_free();
return;
}
@@ -329,7 +342,7 @@ void ro_gui_buffer_open(wimp_draw *redraw)
if ((error = xosspriteop_switch_output_to_sprite(osspriteop_PTR,
buffer, (osspriteop_id)(buffer + 1), save_area,
&context0, &context1, &context2, &context3)) != NULL) {
- LOG("Switching error '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Switching error '%s'", error->errmess);
free(save_area);
ro_gui_buffer_free();
return;
@@ -345,7 +358,8 @@ void ro_gui_buffer_open(wimp_draw *redraw)
*/
if ((error = xos_set_ecf_origin(-ro_plot_origin_x,
-ro_plot_origin_y)) != NULL) {
- LOG("Invalid ECF origin: '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Invalid ECF origin: '%s'",
+ error->errmess);
}
}
diff --git a/frontends/riscos/configure.c b/frontends/riscos/configure.c
index 9d28616ec..f4dced55b 100644
--- a/frontends/riscos/configure.c
+++ b/frontends/riscos/configure.c
@@ -212,7 +212,10 @@ void ro_gui_configure_open_window(wimp_open *open)
y + configure_icon_height -
CONFIGURE_ICON_PADDING_V);
if (error) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_resize_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
}
x += configure_icon_width;
l++;
@@ -225,7 +228,8 @@ void ro_gui_configure_open_window(wimp_open *open)
error = xwimp_force_redraw(configure_window,
0, -16384, 16384, 0);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -248,7 +252,8 @@ void ro_gui_configure_open_window(wimp_open *open)
extent.y0 = -max_height;
error = xwimp_set_extent(open->w, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -259,7 +264,8 @@ void ro_gui_configure_open_window(wimp_open *open)
/* open the window */
error = xwimp_open_window(open);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -276,7 +282,7 @@ void ro_gui_configure_register(const char *window,
/* create our tool */
tool = calloc(sizeof(struct configure_tool), 1);
if (!tool) {
- LOG("Insufficient memory for calloc()");
+ NSLOG(netsurf, INFO, "Insufficient memory for calloc()");
die("Insufficient memory");
return; /* For the benefit of scan-build */
}
@@ -284,7 +290,7 @@ void ro_gui_configure_register(const char *window,
tool->translated[0] = '\0';
tool->validation = malloc(strlen(window) + 2);
if (!tool->validation) {
- LOG("Insufficient memory for malloc()");
+ NSLOG(netsurf, INFO, "Insufficient memory for malloc()");
die("Insufficient memory");
}
sprintf(tool->validation, "S%s", window);
@@ -311,7 +317,8 @@ void ro_gui_configure_register(const char *window,
CONFIGURE_TOOL_TRANSLATED_SIZE;
error = xwimp_create_icon(&new_icon, &tool->i);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
die(error->errmess);
}
@@ -360,7 +367,8 @@ bool ro_gui_configure_translate(void)
error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0,
&alphabet);
if (error) {
- LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
+ error->errnum, error->errmess);
/* assume Latin1 */
alphabet = territory_ALPHABET_LATIN1;
}
@@ -381,7 +389,10 @@ bool ro_gui_configure_translate(void)
error = xwimptextop_string_width(tool->translated,
strlen(tool->translated), &icon_width);
if (error) {
- LOG("xwimptextop_string_width: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimptextop_string_width: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return false;
}
icon_width += CONFIGURE_ICON_PADDING_H;
@@ -395,7 +406,8 @@ bool ro_gui_configure_translate(void)
configure_icon_width,
0);
if (error) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
diff --git a/frontends/riscos/configure/con_image.c b/frontends/riscos/configure/con_image.c
index 49dd4f76d..c7fc7f314 100644
--- a/frontends/riscos/configure/con_image.c
+++ b/frontends/riscos/configure/con_image.c
@@ -150,8 +150,9 @@ void ro_gui_options_image_redraw(wimp_draw *redraw)
icon_state.i = IMAGE_CURRENT_DISPLAY;
error = xwimp_get_icon_state(&icon_state);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
return;
}
diff --git a/frontends/riscos/configure/con_language.c b/frontends/riscos/configure/con_language.c
index 2030c65c0..77e4f6cb4 100644
--- a/frontends/riscos/configure/con_language.c
+++ b/frontends/riscos/configure/con_language.c
@@ -98,7 +98,8 @@ bool ro_gui_options_language_ok(wimp_w w)
if (temp) {
nsoption_set_charp(language, temp);
} else {
- LOG("No memory to duplicate language code");
+ NSLOG(netsurf, INFO,
+ "No memory to duplicate language code");
ro_warn_user("NoMemory", 0);
}
}
@@ -113,7 +114,8 @@ bool ro_gui_options_language_ok(wimp_w w)
if (temp) {
nsoption_set_charp(accept_language,temp);
} else {
- LOG("No memory to duplicate language code");
+ NSLOG(netsurf, INFO,
+ "No memory to duplicate language code");
ro_warn_user("NoMemory", 0);
}
}
diff --git a/frontends/riscos/configure/con_theme.c b/frontends/riscos/configure/con_theme.c
index fb0d3dfb0..28195dea9 100644
--- a/frontends/riscos/configure/con_theme.c
+++ b/frontends/riscos/configure/con_theme.c
@@ -104,20 +104,23 @@ bool ro_gui_options_theme_initialise(wimp_w w)
return false;
error = xwimp_create_window(&theme_pane_definition, &theme_pane);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
state.w = w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
icon_state.w = w;
icon_state.i = THEME_PANE_AREA;
error = xwimp_get_icon_state(&icon_state);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
state.w = theme_pane;
@@ -126,7 +129,8 @@ bool ro_gui_options_theme_initialise(wimp_w w)
state.visible.x0 += icon_state.icon.extent.x0 + 16;
state.visible.y0 = state.visible.y1 + icon_state.icon.extent.y0 + 16;
state.visible.y1 += icon_state.icon.extent.y1 - 28;
- LOG("Y0 = %i, y1 = %i", icon_state.icon.extent.y0, icon_state.icon.extent.y1);
+ NSLOG(netsurf, INFO, "Y0 = %i, y1 = %i", icon_state.icon.extent.y0,
+ icon_state.icon.extent.y1);
error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), w,
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_XORIGIN_SHIFT |
@@ -141,7 +145,8 @@ bool ro_gui_options_theme_initialise(wimp_w w)
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
<< wimp_CHILD_TS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -176,7 +181,8 @@ void ro_gui_options_theme_finalise(wimp_w w)
ro_gui_wimp_event_finalise(theme_pane);
error = xwimp_delete_window(theme_pane);
if (error) {
- LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
theme_pane = 0;
@@ -269,7 +275,7 @@ void ro_gui_options_theme_load(void)
ro_toolbar_rebuild(toolbar);
toolbar_display = calloc(sizeof(struct toolbar_display), 1);
if (!toolbar_display) {
- LOG("No memory for calloc()");
+ NSLOG(netsurf, INFO, "No memory for calloc()");
ro_warn_user("NoMemory", 0);
return;
}
@@ -291,7 +297,8 @@ void ro_gui_options_theme_load(void)
state.w = theme_pane;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
diff --git a/frontends/riscos/content-handlers/artworks.c b/frontends/riscos/content-handlers/artworks.c
index f70b10ac7..8ec4edcae 100644
--- a/frontends/riscos/content-handlers/artworks.c
+++ b/frontends/riscos/content-handlers/artworks.c
@@ -183,18 +183,19 @@ bool artworks_convert(struct content *c)
xos_read_var_val_size("Alias$LoadArtWorksModules", 0, os_VARTYPE_STRING,
&used, NULL, NULL);
if (used >= 0) {
- LOG("Alias$LoadArtWorksModules not defined");
+ NSLOG(netsurf, INFO, "Alias$LoadArtWorksModules not defined");
msg_data.error = messages_get("AWNotSeen");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
/* load the modules, or do nothing if they're already loaded */
error = xos_cli("LoadArtWorksModules");
if (error) {
- LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_cli: 0x%x: %s", error->errnum,
+ error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -202,9 +203,10 @@ bool artworks_convert(struct content *c)
error = (os_error*)_swix(AWRender_FileInitAddress, _OUT(0) | _OUT(1),
&init_routine, &init_workspace);
if (error) {
- LOG("AWRender_FileInitAddress: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "AWRender_FileInitAddress: 0x%x: %s",
+ error->errnum, error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -212,9 +214,10 @@ bool artworks_convert(struct content *c)
&aw->render_routine,
&aw->render_workspace);
if (error) {
- LOG("AWRender_RenderAddress: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "AWRender_RenderAddress: 0x%x: %s",
+ error->errnum, error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -224,9 +227,10 @@ bool artworks_convert(struct content *c)
error = awrender_init(&source_data, &source_size,
init_routine, init_workspace);
if (error) {
- LOG("awrender_init: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "awrender_init: 0x%x : %s",
+ error->errnum, error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -239,13 +243,15 @@ bool artworks_convert(struct content *c)
&aw->y1);
if (error) {
- LOG("AWRender_DocBounds: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "AWRender_DocBounds: 0x%x: %s",
+ error->errnum, error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
- LOG("bounding box: %d,%d,%d,%d", aw->x0, aw->y0, aw->x1, aw->y1);
+ NSLOG(netsurf, INFO, "bounding box: %d,%d,%d,%d", aw->x0, aw->y0,
+ aw->x1, aw->y1);
/* create the resizable workspace required by the
ArtWorksRenderer rendering routine */
@@ -253,9 +259,10 @@ bool artworks_convert(struct content *c)
aw->size = INITIAL_BLOCK_SIZE;
aw->block = malloc(INITIAL_BLOCK_SIZE);
if (!aw->block) {
- LOG("failed to create block for ArtworksRenderer");
+ NSLOG(netsurf, INFO,
+ "failed to create block for ArtworksRenderer");
msg_data.error = messages_get("NoMemory");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -317,7 +324,7 @@ bool artworks_redraw(struct content *c, struct content_redraw_data *data,
int clip_x1 = clip->x1;
int clip_y1 = clip->y1;
- if (ctx->plot->flush && !ctx->plot->flush())
+ if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK))
return false;
/* pick up render addresses again in case they've changed
@@ -368,13 +375,15 @@ bool artworks_redraw(struct content *c, struct content_redraw_data *data,
error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), vals);
if (error) {
- LOG("xos_read_vdu_variables: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_read_vdu_variables: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
error = xwimp_read_palette((os_palette*)&vals[3]);
if (error) {
- LOG("xwimp_read_palette: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_read_palette: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -393,7 +402,8 @@ bool artworks_redraw(struct content *c, struct content_redraw_data *data,
aw->render_workspace);
if (error) {
- LOG("awrender_render: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "awrender_render: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
diff --git a/frontends/riscos/content-handlers/draw.c b/frontends/riscos/content-handlers/draw.c
index 9dff75736..bb66f9dbb 100644
--- a/frontends/riscos/content-handlers/draw.c
+++ b/frontends/riscos/content-handlers/draw.c
@@ -126,9 +126,10 @@ bool draw_convert(struct content *c)
error = xdrawfile_bbox(0, (drawfile_diagram *) data,
(int) source_size, 0, &bbox);
if (error) {
- LOG("xdrawfile_bbox: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xdrawfile_bbox: 0x%x: %s",
+ error->errnum, error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -184,7 +185,7 @@ bool draw_redraw(struct content *c, struct content_redraw_data *data,
const void *src_data;
os_error *error;
- if (ctx->plot->flush && !ctx->plot->flush())
+ if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK))
return false;
if (!c->width || !c->height)
@@ -208,7 +209,8 @@ bool draw_redraw(struct content *c, struct content_redraw_data *data,
error = xdrawfile_render(0, (drawfile_diagram *) src_data,
(int) source_size, &matrix, 0, 0);
if (error) {
- LOG("xdrawfile_render: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xdrawfile_render: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
diff --git a/frontends/riscos/content-handlers/sprite.c b/frontends/riscos/content-handlers/sprite.c
index ed06110ec..3556aa555 100644
--- a/frontends/riscos/content-handlers/sprite.c
+++ b/frontends/riscos/content-handlers/sprite.c
@@ -126,7 +126,7 @@ bool sprite_convert(struct content *c)
/* check for bad data */
if ((int)source_size + 4 != area->used) {
msg_data.error = messages_get("BadSprite");
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -135,9 +135,12 @@ bool sprite_convert(struct content *c)
(osspriteop_id) ((char *) area + area->first),
&w, &h, NULL, NULL);
if (error) {
- LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_read_sprite_info: 0x%x: %s",
+ error->errnum,
+ error->errmess);
msg_data.error = error->errmess;
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
@@ -180,7 +183,7 @@ bool sprite_redraw(struct content *c, struct content_redraw_data *data,
{
sprite_content *sprite = (sprite_content *) c;
- if (ctx->plot->flush && !ctx->plot->flush())
+ if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK))
return false;
return image_redraw(sprite->data,
diff --git a/frontends/riscos/cookies.c b/frontends/riscos/cookies.c
index 38963ab3a..125d04356 100644
--- a/frontends/riscos/cookies.c
+++ b/frontends/riscos/cookies.c
@@ -377,7 +377,7 @@ static nserror ro_cookie_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct ro_cookie_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
@@ -445,12 +445,12 @@ nserror ro_gui_cookies_present(void)
res = ro_cookie_init();
if (res == NSERROR_OK) {
- LOG("Presenting");
+ NSLOG(netsurf, INFO, "Presenting");
ro_gui_dialog_open_top(cookie_window->core.wh,
cookie_window->core.toolbar,
600, 800);
} else {
- LOG("Failed presenting code %d", res);
+ NSLOG(netsurf, INFO, "Failed presenting code %d", res);
}
return res;
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 3219be985..84177aa90 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -42,6 +42,7 @@
#include "riscos/wimp_event.h"
#include "riscos/dialog.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/toolbar.h"
#include "riscos/mouse.h"
#include "riscos/corewindow.h"
@@ -62,22 +63,22 @@ static void update_scrollbars(struct ro_corewindow *ro_cw, wimp_open *open)
int extent_height;
os_box extent;
- LOG("RO corewindow context %p", ro_cw);
+ NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
/* extent of content in not smaller than window so start there */
extent_width = open->visible.x1 - open->visible.x0;
extent_height = open->visible.y0 - open->visible.y1;
- LOG("extent w:%d h:%d content w:%d h:%d origin h:%d",
- extent_width, extent_height,
- ro_cw->content_width, ro_cw->content_height, ro_cw->origin_y);
+ NSLOG(netsurf, INFO,
+ "extent w:%d h:%d content w:%d h:%d origin h:%d", extent_width,
+ extent_height, ro_cw->content_width, ro_cw->content_height,
+ ro_cw->origin_y);
if (ro_cw->content_width > extent_width) {
extent_width = ro_cw->content_width;
}
if (extent_height > (ro_cw->origin_y + ro_cw->content_height)) {
extent_height = ro_cw->origin_y + ro_cw->content_height;
}
- LOG("extent w:%d h:%d",
- extent_width, extent_height);
+ NSLOG(netsurf, INFO, "extent w:%d h:%d", extent_width, extent_height);
extent.x0 = 0;
extent.y0 = extent_height;
extent.x1 = extent_width;
@@ -85,15 +86,15 @@ static void update_scrollbars(struct ro_corewindow *ro_cw, wimp_open *open)
error = xwimp_set_extent(ro_cw->wh, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
error = xwimp_open_window(open);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
@@ -129,8 +130,8 @@ static void ro_cw_redraw(wimp_draw *redraw)
error = xwimp_get_rectangle(redraw, &more);
}
if (error != NULL) {
- LOG("xwimp_redraw_window: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
@@ -144,7 +145,7 @@ static void ro_cw_scroll(wimp_scroll *scroll)
wimp_open open;
ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(scroll->w);
- LOG("RO corewindow context %p", ro_cw);
+ NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
page_x = scroll->visible.x1 - scroll->visible.x0 - 32;
page_y = scroll->visible.y1 - scroll->visible.y0 - 32;
@@ -201,8 +202,8 @@ static void ro_cw_scroll(wimp_scroll *scroll)
error = xwimp_open_window(&open);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
@@ -230,38 +231,38 @@ static void ro_cw_mouse_at(wimp_pointer *pointer, void *data)
ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(pointer->w);
if (ro_cw == NULL) {
- LOG("no corewindow conext for window: 0x%x",
- (unsigned int)pointer->w);
+ NSLOG(netsurf, INFO, "no corewindow conext for window: 0x%x",
+ (unsigned int)pointer->w);
return;
}
- LOG("RO corewindow context %p", ro_cw);
+ NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
- /* no futher processing required if no drag in progress */
- if (ro_cw->drag_status == CORE_WINDOW_DRAG_NONE) {
- return;
- }
-
- /* Not a Menu click and a drag is in progress. */
+ /* Not a Menu click. */
state.w = pointer->w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
- /* Convert the returned mouse coordinates into NetSurf's internal
- * units.
+ /* Convert the returned mouse coordinates into
+ * NetSurf's internal units.
*/
xpos = ((pointer->pos.x - state.visible.x0) + state.xscroll) / 2;
ypos = ((state.visible.y1 - pointer->pos.y) -
state.yscroll + ro_cw->origin_y) / 2;
- /* Start to process the mouse click. */
- mouse = ro_gui_mouse_drag_state(pointer->buttons,
- wimp_BUTTON_DOUBLE_CLICK_DRAG);
+ /* if no drag in progress report hover */
+ if (ro_cw->drag_status == CORE_WINDOW_DRAG_NONE) {
+ mouse = BROWSER_MOUSE_HOVER;
+ } else {
+ /* Start to process the mouse click. */
+ mouse = ro_gui_mouse_drag_state(pointer->buttons,
+ wimp_BUTTON_DOUBLE_CLICK_DRAG);
- ro_cw->mouse(ro_cw, mouse, xpos, ypos);
+ ro_cw->mouse(ro_cw, mouse, xpos, ypos);
+ }
if (!(mouse & BROWSER_MOUSE_DRAG_ON)) {
ro_cw->mouse(ro_cw, BROWSER_MOUSE_HOVER, xpos, ypos);
@@ -284,14 +285,15 @@ static void ro_cw_drag_end(wimp_dragged *drag, void *data)
error = xwimp_drag_box((wimp_drag *) -1);
if (error) {
- LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_auto_scroll(0, NULL, NULL);
if (error) {
- LOG("xwimp_auto_scroll: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -344,12 +346,13 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
break;
}
- LOG("Drag start...");
+ NSLOG(netsurf, INFO, "Drag start...");
error = xwimp_drag_box_with_flags(&drag,
wimp_DRAG_BOX_KEEP_IN_LINE | wimp_DRAG_BOX_CLIP);
if (error) {
- LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
} else {
auto_scroll.w = ro_cw->wh;
@@ -363,7 +366,8 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
error = xwimp_auto_scroll(wimp_AUTO_SCROLL_ENABLE_VERTICAL,
&auto_scroll, NULL);
if (error) {
- LOG("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -373,16 +377,40 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
/**
+ * Handle Pointer Leaving Window events.
+ *
+ * These events are delivered as the termination callback handler from
+ * ro_mouse's mouse tracking.
+ *
+ * \param leaving The Wimp_PointerLeavingWindow block.
+ * \param data NULL data pointer.
+ */
+static void ro_cw_pointer_leaving(wimp_leaving *leaving, void *data)
+{
+ struct ro_corewindow *ro_cw;
+
+ ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(leaving->w);
+ if (ro_cw == NULL) {
+ NSLOG(netsurf, INFO, "no corewindow conext for window: 0x%x",
+ (unsigned int)leaving->w);
+ return;
+ }
+
+ ro_cw->mouse(ro_cw, BROWSER_MOUSE_LEAVE, 0, 0);
+}
+
+
+/**
* Wimp callback on pointer entering window.
*
* The wimp has issued an event to the window because the pointer has
* entered it.
*
- * \param open The open event to be processed
+ * \param entering The entering event to be processed
*/
static void ro_cw_pointer_entering(wimp_entering *entering)
{
- ro_mouse_track_start(NULL, ro_cw_mouse_at, NULL);
+ ro_mouse_track_start(ro_cw_pointer_leaving, ro_cw_mouse_at, NULL);
}
@@ -414,14 +442,14 @@ static bool ro_cw_mouse_click(wimp_pointer *pointer)
struct ro_corewindow *ro_cw;
ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(pointer->w);
- LOG("RO corewindow context %p", ro_cw);
+ NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
state.w = ro_cw->wh;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -492,7 +520,7 @@ static bool ro_cw_keypress(wimp_key *key)
nserror res;
ro_cw = (struct ro_corewindow *)ro_gui_wimp_event_get_user_data(key->w);
- LOG("RO corewindow context %p", ro_cw);
+ NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
c = (uint32_t) key->c;
@@ -615,8 +643,8 @@ static void cw_tb_size(void *ctx)
state.w = ro_cw->wh;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -624,8 +652,8 @@ static void cw_tb_size(void *ctx)
0, state.visible.y0 - state.visible.y1,
state.visible.x1 - state.visible.x0, 0);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
@@ -664,6 +692,8 @@ static void cw_tb_update(void *ctx)
* Respond to user actions (click) in a corewindow.
*
* \param ctx Context as passed to toolbar creation.
+ * \param action_type type of action on toolbar
+ * \param action data for action.
*/
static void
cw_tb_click(void *ctx,
@@ -698,7 +728,9 @@ static void cw_tb_save(void *ctx, char *config)
-/** core window toolbar callbacks */
+/**
+ * riscos core window toolbar callbacks
+ */
static const struct toolbar_callbacks corewindow_toolbar_callbacks = {
.theme_update = cw_tb_theme,
.change_size = cw_tb_size,
@@ -707,24 +739,52 @@ static const struct toolbar_callbacks corewindow_toolbar_callbacks = {
.save_buttons = cw_tb_save,
};
+
/**
- * callback from core to request a redraw.
+ * callback from core to request an invalidation of a window area.
+ *
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] r area to redraw or NULL for the entire window area.
+ * \return NSERROR_OK on success or appropriate error code.
*/
-static void
-ro_cw_redraw_request(struct core_window *cw, const struct rect *r)
+static nserror
+ro_cw_invalidate(struct core_window *cw, const struct rect *r)
{
struct ro_corewindow *ro_cw = (struct ro_corewindow *)cw;
os_error *error;
+ wimp_window_info info;
+
+ if (r == NULL) {
+ info.w = ro_cw->wh;
+ error = xwimp_get_window_info_header_only(&info);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_info_header_only: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+ } else {
+ /* convert the passed rectangle into RO window dimensions */
+ info.extent.x0 = 2 * r->x0;
+ info.extent.y0 = (-2 * (r->y0 + (r->y1 - r->y0))) + ro_cw->origin_y;
+ info.extent.x1 = 2 * (r->x0 + (r->x1 - r->x0));
+ info.extent.y1 = (-2 * r->y0) + ro_cw->origin_y;
+ }
error = xwimp_force_redraw(ro_cw->wh,
- (2 * r->x0),
- (-2 * (r->y0 + (r->y1 - r->y0))) + ro_cw->origin_y,
- (2 * (r->x0 + (r->x1 - r->x0))),
- (-2 * r->y0) + ro_cw->origin_y);
+ info.extent.x0, info.extent.y0,
+ info.extent.x1, info.extent.y1);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
}
+ return NSERROR_OK;
}
@@ -739,8 +799,8 @@ ro_cw_update_size(struct core_window *cw, int width, int height)
wimp_window_state state;
os_error *error;
- LOG("content resize from w:%d h:%d to w:%d h:%d",
- ro_cw->content_width, ro_cw->content_height, width, height);
+ NSLOG(netsurf, INFO, "content resize from w:%d h:%d to w:%d h:%d",
+ ro_cw->content_width, ro_cw->content_height, width, height);
ro_cw->content_width = width * 2;
ro_cw->content_height = -(2 * height);
@@ -748,8 +808,8 @@ ro_cw_update_size(struct core_window *cw, int width, int height)
state.w = ro_cw->wh;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -793,8 +853,8 @@ ro_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
state.w = ro_cw->wh;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -815,7 +875,7 @@ ro_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
struct core_window_callback_table ro_cw_cb_table = {
- .redraw_request = ro_cw_redraw_request,
+ .invalidate = ro_cw_invalidate,
.update_size = ro_cw_update_size,
.scroll_visible = ro_cw_scroll_visible,
.get_window_dimensions = ro_cw_get_window_dimensions,
diff --git a/frontends/riscos/corewindow.h b/frontends/riscos/corewindow.h
index b340bde35..7d808c298 100644
--- a/frontends/riscos/corewindow.h
+++ b/frontends/riscos/corewindow.h
@@ -123,6 +123,10 @@ struct ro_corewindow {
* As a pre-requisite the draw, key and mouse callbacks must be defined
*
* \param ro_cw A riscos core window structure to initialise
+ * \param tb_buttons toolbar button bar context
+ * \param tb_order The order of toolbar buttons
+ * \param tb_style The style of toolbar buttons
+ * \param tb_help Thh toolbar help text
* \return NSERROR_OK on successful initialisation otherwise error code.
*/
nserror ro_corewindow_init(struct ro_corewindow *ro_cw, const struct button_bar_buttons *tb_buttons, char *tb_order, theme_style tb_style, const char *tb_help);
diff --git a/frontends/riscos/dialog.c b/frontends/riscos/dialog.c
index 18df1bfe4..a50d1289b 100644
--- a/frontends/riscos/dialog.c
+++ b/frontends/riscos/dialog.c
@@ -44,8 +44,10 @@
#include "riscos/configure.h"
#include "riscos/cookies.h"
#include "riscos/dialog.h"
+#include "riscos/local_history.h"
#include "riscos/global_history.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/hotlist.h"
#include "riscos/menus.h"
#include "riscos/save.h"
@@ -176,7 +178,7 @@ void ro_gui_dialog_init(void)
ro_gui_dialog_zoom_apply);
ro_gui_wimp_event_set_help_prefix(dialog_zoom, "HelpScaleView");
- /* Treeview initialisation has moved to the end, to allow any
+ /* core window based initialisation done last to allow any
* associated dialogues to be set up first.
*/
@@ -186,6 +188,9 @@ void ro_gui_dialog_init(void)
/* hotlist window */
ro_gui_hotlist_initialise();
+ /* local history window */
+ ro_gui_local_history_initialise();
+
/* global history window */
ro_gui_global_history_initialise();
@@ -215,7 +220,8 @@ wimp_w ro_gui_dialog_create(const char *template_name)
window->sprite_area = gui_sprites;
error = xwimp_create_window(window, &w);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
}
@@ -254,12 +260,13 @@ wimp_window * ro_gui_dialog_load_template(const char *template_name)
error = xwimp_load_template(wimp_GET_SIZE, 0, 0, wimp_NO_FONTS,
name, 0, &window_size, &data_size, &context);
if (error) {
- LOG("xwimp_load_template: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_load_template: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
}
if (!context) {
- LOG("template '%s' missing", template_name);
+ NSLOG(netsurf, INFO, "template '%s' missing", template_name);
xwimp_close_template();
die("Template");
}
@@ -276,7 +283,8 @@ wimp_window * ro_gui_dialog_load_template(const char *template_name)
error = xwimp_load_template(window, data, data + data_size,
wimp_NO_FONTS, name, 0, 0, 0, 0);
if (error) {
- LOG("xwimp_load_template: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_load_template: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
}
@@ -304,7 +312,8 @@ void ro_gui_dialog_open(wimp_w w)
state.w = w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -351,7 +360,8 @@ void ro_gui_dialog_close(wimp_w close)
*/
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
} else if (caret.w == close) {
/* Check if we are a persistent window */
@@ -362,7 +372,10 @@ void ro_gui_dialog_close(wimp_w close)
32, -1);
/* parent may have been closed first */
if ((error) && (error->errnum != 0x287)) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -370,7 +383,8 @@ void ro_gui_dialog_close(wimp_w close)
error = xwimp_close_window(close);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -455,7 +469,8 @@ void ro_gui_dialog_open_at_pointer(wimp_w w)
/* get the pointer position */
error = xwimp_get_pointer_info(&ptr);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -478,7 +493,8 @@ void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
state.w = w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -493,7 +509,8 @@ void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
* on screen */
error = xwimp_close_window(w);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -510,7 +527,8 @@ void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
* /param parent the parent window (NULL for centre of screen)
* /param child the child window
*/
-void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
+static void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child)
+{
os_error *error;
wimp_window_state state;
int mid_x, mid_y;
@@ -521,7 +539,10 @@ void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
state.w = parent;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -538,14 +559,15 @@ void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
state.w = child;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
/* move to the centre of the parent at the top of the stack */
dimension = state.visible.x1 - state.visible.x0;
- scroll_width = ro_get_vscroll_width(history_window);
+ scroll_width = ro_get_vscroll_width(parent);
state.visible.x0 = mid_x - (dimension + scroll_width) / 2;
state.visible.x1 = state.visible.x0 + dimension;
dimension = state.visible.y1 - state.visible.y0;
@@ -567,10 +589,11 @@ void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w child) {
void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer) {
- if (pointer)
+ if (pointer) {
ro_gui_dialog_open_at_pointer(w);
- else
+ } else {
ro_gui_dialog_open_centre_parent(parent, w);
+ }
/* todo: use wimp_event definitions rather than special cases */
if ((w == dialog_pageinfo) || (w == dialog_objinfo))
@@ -600,7 +623,7 @@ void ro_gui_dialog_add_persistent(wimp_w parent, wimp_w w) {
return;
}
}
- LOG("Unable to map persistent dialog to parent.");
+ NSLOG(netsurf, INFO, "Unable to map persistent dialog to parent.");
return;
}
@@ -629,7 +652,9 @@ void ro_gui_dialog_close_persistent(wimp_w parent) {
w = persistent_dialog[i].dialog;
ro_gui_dialog_close(w);
if (ro_gui_wimp_event_close_window(w))
- LOG("Persistent dialog close event: 0x%x", (unsigned)w);
+ NSLOG(netsurf, INFO,
+ "Persistent dialog close event: 0x%x",
+ (unsigned)w);
persistent_dialog[i].parent = NULL;
persistent_dialog[i].dialog = NULL;
}
@@ -706,7 +731,7 @@ static bool ro_gui_dialog_open_url_init(void)
if ((definition->icons[ICON_OPENURL_URL].flags & wimp_ICON_INDIRECTED)
== 0) {
- LOG("open_url URL icon not indirected");
+ NSLOG(netsurf, INFO, "open_url URL icon not indirected");
xwimp_close_template();
die("Template");
}
@@ -724,7 +749,8 @@ static bool ro_gui_dialog_open_url_init(void)
error = xwimp_create_window(definition, &dialog_openurl);
if (error != NULL) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
}
diff --git a/frontends/riscos/dialog.h b/frontends/riscos/dialog.h
index 463048436..2ec86c339 100644
--- a/frontends/riscos/dialog.h
+++ b/frontends/riscos/dialog.h
@@ -33,7 +33,6 @@ bool ro_gui_dialog_open_top(wimp_w w, struct toolbar *toolbar,
int width, int height);
void ro_gui_dialog_open_at_pointer(wimp_w w);
void ro_gui_dialog_open_xy(wimp_w, int x, int y);
-void ro_gui_dialog_open_centre_parent(wimp_w parent, wimp_w w);
void ro_gui_dialog_open_persistent(wimp_w parent, wimp_w w, bool pointer);
void ro_gui_dialog_add_persistent(wimp_w parent, wimp_w w);
diff --git a/frontends/riscos/download.c b/frontends/riscos/download.c
index 561409ed1..bdc705426 100644
--- a/frontends/riscos/download.c
+++ b/frontends/riscos/download.c
@@ -261,7 +261,10 @@ static nserror download_ro_filetype(download_context *ctx, bits *ftype_out)
mime_type = download_context_get_mime_type(ctx);
error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype);
if (error) {
- LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xmimemaptranslate_mime_type_to_filetype: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
ftype = 0xffd;
}
@@ -339,7 +342,8 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui)
error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
temp_name, 0, &dw->file);
if (error) {
- LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openoutw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
free(dw);
return 0;
@@ -372,7 +376,7 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui)
filename = strdup(temp_name);
if (filename == NULL) {
- LOG("Failed to establish download filename.");
+ NSLOG(netsurf, INFO, "Failed to establish download filename.");
ro_warn_user("SaveError", error->errmess);
free(dw);
return 0;
@@ -404,7 +408,7 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui)
if (err != NSERROR_OK) {
/* badenc should never happen */
assert(err !=NSERROR_BAD_ENCODING);
- LOG("utf8_to_local_encoding failed");
+ NSLOG(netsurf, INFO, "utf8_to_local_encoding failed");
ro_warn_user("NoMemory", 0);
free(dw);
return 0;
@@ -430,7 +434,8 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui)
/* create and open the download window */
error = xwimp_create_window(download_template, &dw->window);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
free(dw);
return 0;
@@ -485,7 +490,8 @@ static void gui_download_window_error(struct gui_download_window *dw,
wimp_COLOUR_RED << wimp_ICON_FG_COLOUR_SHIFT,
wimp_ICON_FG_COLOUR);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -493,7 +499,8 @@ static void gui_download_window_error(struct gui_download_window *dw,
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
wimp_ICON_SHADED, 0);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -501,7 +508,8 @@ static void gui_download_window_error(struct gui_download_window *dw,
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
wimp_ICON_SHADED, wimp_ICON_SHADED);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -528,11 +536,13 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
error = xosgbpb_writew(dw->file, (const byte *) data, size,
&unwritten);
if (error) {
- LOG("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosgbpb_writew: 0x%x: %s",
+ error->errnum, error->errmess);
msg = error->errmess;
} else if (unwritten) {
- LOG("xosgbpb_writew: unwritten %i", unwritten);
+ NSLOG(netsurf, INFO, "xosgbpb_writew: unwritten %i",
+ unwritten);
msg = messages_get("Unwritten");
}
else {
@@ -555,20 +565,29 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
wimp_ICON_SHADED, 0);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_DESTINATION,
wimp_ICON_DELETED, wimp_ICON_DELETED);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_set_icon_state(dw->window,
ICON_DOWNLOAD_PATH, wimp_ICON_DELETED, 0);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -717,13 +736,15 @@ void ro_gui_download_update_status(struct gui_download_window *dw)
download_progress_x0 + width,
download_progress_y1);
if (error) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_STATUS, 0, 0);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -759,13 +780,17 @@ void ro_gui_download_window_hide_caret(struct gui_download_window *dw)
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
else if (caret.w == dw->window) {
error = xwimp_set_caret_position(dw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_caret_position: 0x%x : %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -791,7 +816,8 @@ static void gui_download_window_done(struct gui_download_window *dw)
error = xosfind_closew(dw->file);
if (error) {
- LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
dw->file = 0;
@@ -800,7 +826,8 @@ static void gui_download_window_done(struct gui_download_window *dw)
error = xosfile_set_type(dw->path,
dw->file_type);
if (error) {
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
@@ -856,7 +883,8 @@ bool ro_gui_download_click(wimp_pointer *pointer)
*dot = 0;
error = xos_cli(command);
if (error) {
- LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_cli: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
}
}
@@ -929,7 +957,8 @@ static void ro_gui_download_drag_end(wimp_dragged *drag, void *data)
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -959,7 +988,10 @@ static void ro_gui_download_drag_end(wimp_dragged *drag, void *data)
error = xwimp_send_message_to_window(wimp_USER_MESSAGE, &message,
pointer.w, pointer.i, 0);
if (error) {
- LOG("xwimp_send_message_to_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_send_message_to_window: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -1011,7 +1043,10 @@ char *ro_gui_download_canonicalise(const char *path)
error = xosfscontrol_canonicalise_path(path, NULL, NULL, NULL, 0, &spare);
if (error) {
- LOG("xosfscontrol_canonicalise_path: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfscontrol_canonicalise_path: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return NULL;
}
@@ -1020,7 +1055,10 @@ char *ro_gui_download_canonicalise(const char *path)
error = xosfscontrol_canonicalise_path(path, buf, NULL, NULL,
1 - spare, NULL);
if (error) {
- LOG("xosfscontrol_canonicalise_path: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfscontrol_canonicalise_path: 0x%x: %s",
+ error->errnum,
+ error->errmess);
free(buf);
return NULL;
@@ -1065,13 +1103,17 @@ bool ro_gui_download_check_space(struct gui_download_window *dw,
error = xosfscontrol_free_space64(dir, &free_lo, &free_hi,
&max_file, NULL, NULL);
if (error) {
- LOG("xosfscontrol_free_space64: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfscontrol_free_space64: 0x%x: %s",
+ error->errnum, error->errmess);
free_hi = 0;
error = xosfscontrol_free_space(dir, (int*)&free_lo,
&max_file, NULL);
if (error) {
- LOG("xosfscontrol_free_space: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfscontrol_free_space: 0x%x: %s",
+ error->errnum,
+ error->errmess);
/* close our eyes and hope */
free(dir);
return true;
@@ -1108,7 +1150,10 @@ bool ro_gui_download_check_space(struct gui_download_window *dw,
error = xosargs_read_allocation(dw->file,
&allocation);
if (error) {
- LOG("xosargs_read_allocation: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosargs_read_allocation: 0x%x : %s",
+ error->errnum,
+ error->errmess);
}
else {
space += allocation;
@@ -1147,7 +1192,8 @@ os_error *ro_gui_download_move(struct gui_download_window *dw,
error = xosfind_closew(dw->file);
dw->file = 0;
if (error) {
- LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess);
return error;
}
}
@@ -1165,11 +1211,13 @@ os_error *ro_gui_download_move(struct gui_download_window *dw,
osfscontrol_COPY_LOOK,
0, 0, 0, 0, 0);
if (error) {
- LOG("xosfscontrol_copy: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfscontrol_copy: 0x%x: %s",
+ error->errnum, error->errmess);
return error;
}
} else if (error) {
- LOG("xosfscontrol_rename: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfscontrol_rename: 0x%x: %s",
+ error->errnum, error->errmess);
return error;
}
@@ -1179,20 +1227,23 @@ os_error *ro_gui_download_move(struct gui_download_window *dw,
fileswitch_ATTR_OWNER_READ |
fileswitch_ATTR_OWNER_WRITE);
if (error) {
- LOG("xosfile_write: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_write: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
dest_file, 0, &dw->file);
if (error) {
- LOG("xosfind_openupw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openupw: 0x%x: %s",
+ error->errnum, error->errmess);
return error;
}
error = xosargs_set_ptrw(dw->file, dw->received);
if (error) {
- LOG("xosargs_set_ptrw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosargs_set_ptrw: 0x%x: %s",
+ error->errnum, error->errmess);
return error;
}
@@ -1201,7 +1252,8 @@ os_error *ro_gui_download_move(struct gui_download_window *dw,
error = xosfile_set_type(dest_file,
dw->file_type);
if (error) {
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
}
@@ -1273,7 +1325,8 @@ bool ro_gui_download_save(struct gui_download_window *dw,
error = xosfile_read_stamped(file_name, &obj_type,
NULL, NULL, NULL, NULL, NULL);
if (error) {
- LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_read_stamped: 0x%x:%s",
+ error->errnum, error->errmess);
return false;
}
@@ -1309,12 +1362,16 @@ bool ro_gui_download_save(struct gui_download_window *dw,
error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
temp_name, 0, &dw->file);
if (error) {
- LOG("xosfind_openupw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openupw: 0x%x: %s",
+ error->errnum, error->errmess);
} else {
error = xosargs_set_ptrw(dw->file, dw->received);
if (error) {
- LOG("xosargs_set_ptrw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosargs_set_ptrw: 0x%x: %s",
+ error->errnum,
+ error->errmess);
}
}
@@ -1336,7 +1393,8 @@ bool ro_gui_download_save(struct gui_download_window *dw,
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON,
wimp_ICON_SHADED, wimp_ICON_SHADED);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -1349,13 +1407,15 @@ bool ro_gui_download_save(struct gui_download_window *dw,
error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
wimp_ICON_DELETED, wimp_ICON_DELETED);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_set_icon_state(dw->window,
ICON_DOWNLOAD_DESTINATION, wimp_ICON_DELETED, 0);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -1401,7 +1461,8 @@ void ro_gui_download_send_dataload(struct gui_download_window *dw)
* for the rather depressing details.
*/
if (error && error->errnum != error_WIMP_BAD_HANDLE) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -1482,7 +1543,8 @@ bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit)
/* delete window */
error = xwimp_delete_window(dw->window);
if (error) {
- LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
ro_gui_wimp_event_finalise(dw->window);
@@ -1491,7 +1553,8 @@ bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit)
if (dw->file) {
error = xosfind_closew(dw->file);
if (error) {
- LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
}
@@ -1502,7 +1565,8 @@ bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit)
error = xosfile_delete(temp_name, 0, 0, 0, 0, 0);
if (error) {
- LOG("xosfile_delete: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_delete: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
}
diff --git a/frontends/riscos/filetype.c b/frontends/riscos/filetype.c
index 75ff41414..73651cd63 100644
--- a/frontends/riscos/filetype.c
+++ b/frontends/riscos/filetype.c
@@ -72,7 +72,7 @@ const char *fetch_filetype(const char *unix_path)
int objtype;
if (!path) {
- LOG("Insufficient memory for calloc");
+ NSLOG(netsurf, INFO, "Insufficient memory for calloc");
ro_warn_user("NoMemory", 0);
return "application/riscos";
}
@@ -80,7 +80,7 @@ const char *fetch_filetype(const char *unix_path)
/* convert path to RISC OS format and read file type */
r = __riscosify(unix_path, 0, __RISCOSIFY_NO_SUFFIX, path, len, 0);
if (r == 0) {
- LOG("__riscosify failed");
+ NSLOG(netsurf, INFO, "__riscosify failed");
free(path);
return "application/riscos";
}
@@ -88,7 +88,9 @@ const char *fetch_filetype(const char *unix_path)
error = xosfile_read_stamped_no_path(path, &objtype, 0, 0, 0, 0,
&file_type);
if (error) {
- LOG("xosfile_read_stamped_no_path failed: %s", error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_read_stamped_no_path failed: %s",
+ error->errmess);
free(path);
return "application/riscos";
}
@@ -108,7 +110,10 @@ const char *fetch_filetype(const char *unix_path)
slash+1, &temp);
if (error)
/* ignore error and leave file_type alone */
- LOG("xmimemaptranslate_extension_to_filetype: ""0x%x %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xmimemaptranslate_extension_to_filetype: ""0x%x %s",
+ error->errnum,
+ error->errmess);
else
file_type = temp;
}
@@ -126,7 +131,7 @@ const char *fetch_filetype(const char *unix_path)
/* not in internal table, so ask MimeMap */
error = xmimemaptranslate_filetype_to_mime_type(file_type, type_buf);
if (error) {
- LOG("0x%x %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "0x%x %s", error->errnum, error->errmess);
free(path);
return "application/riscos";
}
@@ -139,7 +144,7 @@ const char *fetch_filetype(const char *unix_path)
free(path);
- LOG("mime type '%s'", type_buf);
+ NSLOG(netsurf, INFO, "mime type '%s'", type_buf);
return (const char *)type_buf;
}
@@ -155,14 +160,15 @@ char *fetch_mimetype(const char *ro_path)
struct type_entry *t;
if (!mime) {
- LOG("Insufficient memory for calloc");
+ NSLOG(netsurf, INFO, "Insufficient memory for calloc");
ro_warn_user("NoMemory", 0);
return 0;
}
e = xosfile_read_no_path(ro_path, &objtype, &load, 0, 0, 0);
if (e) {
- LOG("xosfile_read_no_path: 0x%x: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "xosfile_read_no_path: 0x%x: %s",
+ e->errnum, e->errmess);
free(mime);
return 0;
}
@@ -188,7 +194,7 @@ char *fetch_mimetype(const char *ro_path)
if (e)
/* if we get an error here, simply ignore it and
* leave filetype unchanged */
- LOG("0x%x %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "0x%x %s", e->errnum, e->errmess);
else
filetype = load;
}
@@ -205,7 +211,10 @@ char *fetch_mimetype(const char *ro_path)
/* not in internal table, so ask MimeMap */
e = xmimemaptranslate_filetype_to_mime_type(filetype, mime);
if (e) {
- LOG("xmimemaptranslate_filetype_to_mime_type: 0x%x: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO,
+ "xmimemaptranslate_filetype_to_mime_type: 0x%x: %s",
+ e->errnum,
+ e->errmess);
free(mime);
return 0;
}
@@ -322,7 +331,7 @@ bits ro_filetype_from_unix_path(const char *unix_path)
bits file_type;
if (!path) {
- LOG("Insufficient memory for calloc");
+ NSLOG(netsurf, INFO, "Insufficient memory for calloc");
ro_warn_user("NoMemory", 0);
return osfile_TYPE_DATA;
}
@@ -330,7 +339,7 @@ bits ro_filetype_from_unix_path(const char *unix_path)
/* convert path to RISC OS format and read file type */
r = __riscosify(unix_path, 0, __RISCOSIFY_NO_SUFFIX, path, len, 0);
if (r == 0) {
- LOG("__riscosify failed");
+ NSLOG(netsurf, INFO, "__riscosify failed");
free(path);
return osfile_TYPE_DATA;
}
@@ -338,7 +347,9 @@ bits ro_filetype_from_unix_path(const char *unix_path)
error = xosfile_read_stamped_no_path(path, 0, 0, 0, 0, 0,
&file_type);
if (error) {
- LOG("xosfile_read_stamped_no_path failed: %s", error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_read_stamped_no_path failed: %s",
+ error->errmess);
free(path);
return osfile_TYPE_DATA;
}
diff --git a/frontends/riscos/font.c b/frontends/riscos/font.c
index 560afc785..2ff309043 100644
--- a/frontends/riscos/font.c
+++ b/frontends/riscos/font.c
@@ -65,7 +65,8 @@ static void nsfont_check_fonts(void)
"<NetSurf$Dir>.FixFonts", 0);
die("FontBadInst");
} else {
- LOG("xfont_find_font: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xfont_find_font: 0x%x: %s",
+ error->errnum, error->errmess);
snprintf(s, sizeof s, messages_get("FontError"),
error->errmess);
die(s);
@@ -74,7 +75,8 @@ static void nsfont_check_fonts(void)
error = xfont_lose_font(font);
if (error) {
- LOG("xfont_lose_font: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xfont_lose_font: 0x%x: %s",
+ error->errnum, error->errmess);
snprintf(s, sizeof s, messages_get("FontError"),
error->errmess);
die(s);
@@ -118,17 +120,20 @@ void nsfont_init(void)
nsfont_check_fonts();
- LOG("Initialise RUfl");
+ NSLOG(netsurf, INFO, "Initialise RUfl");
code = rufl_init();
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_init: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_init: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_init: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_init: 0x%x", code);
die("The Unicode font library could not be initialized. "
"Please report this to the developers.");
}
- LOG("RUfl initialised");
+ NSLOG(netsurf, INFO, "RUfl initialised");
if (rufl_family_list_entries == 0)
die("No fonts could be found. At least one font must be "
@@ -162,9 +167,10 @@ const char *nsfont_fallback_font(void)
const char *fallback = "Homerton";
if (!nsfont_exists(fallback)) {
- LOG("Homerton not found, dumping RUfl family list");
+ NSLOG(netsurf, INFO,
+ "Homerton not found, dumping RUfl family list");
for (unsigned int i = 0; i < rufl_family_list_entries; i++) {
- LOG("'%s'", rufl_family_list[i]);
+ NSLOG(netsurf, INFO, "'%s'", rufl_family_list[i]);
}
fallback = rufl_family_list[0];
}
@@ -230,9 +236,12 @@ ro_font_width(const plot_font_style_t *fstyle,
width);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_width: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_width: 0x%x", code);
/* ro_warn_user("MiscError", "font error"); */
*width = 0;
return NSERROR_INVALID;
@@ -276,9 +285,12 @@ ro_font_position(const plot_font_style_t *fstyle,
x * 2, char_offset, actual_x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_x_to_offset: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_x_to_offset: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_x_to_offset: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_x_to_offset: 0x%x", code);
/* ro_warn_user("MiscError", "font error"); */
*char_offset = 0;
*actual_x = 0;
@@ -335,10 +347,12 @@ ro_font_split(const plot_font_style_t *fstyle,
x * 2, char_offset, actual_x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR) {
- LOG("rufl_split: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
- rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_split: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
} else {
- LOG("rufl_split: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_split: 0x%x", code);
}
/* ro_warn_user("MiscError", "font error"); */
*char_offset = 0;
@@ -370,10 +384,12 @@ ro_font_split(const plot_font_style_t *fstyle,
actual_x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR) {
- LOG("rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
- rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_width: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
} else {
- LOG("rufl_width: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_width: 0x%x", code);
}
/* ro_warn_user("MiscError", "font error"); */
*char_offset = 0;
@@ -416,9 +432,12 @@ bool nsfont_paint(const plot_font_style_t *fstyle, const char *string,
string, length, x, y, flags);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR) {
- LOG("rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
} else {
- LOG("rufl_paint: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_paint: 0x%x", code);
}
}
@@ -450,7 +469,7 @@ void nsfont_read_style(const plot_font_style_t *fstyle,
rufl_WEIGHT_900
};
- *font_size = (fstyle->size * 16) / FONT_SIZE_SCALE;
+ *font_size = (fstyle->size * 16) / PLOT_STYLE_SCALE;
if (1600 < *font_size)
*font_size = 1600;
@@ -513,7 +532,8 @@ ro_gui_wimp_desktop_font(char *family,
error = xwimpreadsysinfo_font(&font_handle, NULL);
if (error) {
- LOG("xwimpreadsysinfo_font: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimpreadsysinfo_font: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
goto failsafe;
}
@@ -525,20 +545,22 @@ ro_gui_wimp_desktop_font(char *family,
error = xfont_read_identifier(font_handle, NULL, &used);
if (error) {
- LOG("xfont_read_identifier: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xfont_read_identifier: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
goto failsafe;
}
if (family_size < (size_t) used + 1) {
- LOG("desktop font name too long");
+ NSLOG(netsurf, INFO, "desktop font name too long");
goto failsafe;
}
error = xfont_read_defn(font_handle, (byte *) family,
&ptx, &pty, NULL, NULL, NULL, NULL);
if (error) {
- LOG("xfont_read_defn: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xfont_read_defn: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
goto failsafe;
}
@@ -550,7 +572,7 @@ ro_gui_wimp_desktop_font(char *family,
}
}
- LOG("desktop font \"%s\"", family);
+ NSLOG(netsurf, INFO, "desktop font \"%s\"", family);
if (strcasestr(family, ".Medium"))
style = rufl_WEIGHT_500;
@@ -566,7 +588,8 @@ ro_gui_wimp_desktop_font(char *family,
*psize = max(ptx, pty);
*pstyle = style;
- LOG("family \"%s\", size %i, style %i", family, *psize, style);
+ NSLOG(netsurf, INFO, "family \"%s\", size %i, style %i", family,
+ *psize, style);
return;
diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c
index 94e1d4a03..7dfc58317 100644
--- a/frontends/riscos/global_history.c
+++ b/frontends/riscos/global_history.c
@@ -405,7 +405,7 @@ static nserror ro_global_history_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct ro_global_history_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
@@ -474,12 +474,12 @@ nserror ro_gui_global_history_present(void)
res = ro_global_history_init();
if (res == NSERROR_OK) {
- LOG("Presenting");
+ NSLOG(netsurf, INFO, "Presenting");
ro_gui_dialog_open_top(global_history_window->core.wh,
global_history_window->core.toolbar,
600, 800);
} else {
- LOG("Failed presenting code %d", res);
+ NSLOG(netsurf, INFO, "Failed presenting code %d", res);
}
return res;
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index 27b81d92e..be1bc8d9a 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -74,6 +74,7 @@
#include "riscos/window.h"
#include "riscos/iconbar.h"
#include "riscos/sslcert.h"
+#include "riscos/local_history.h"
#include "riscos/global_history.h"
#include "riscos/cookies.h"
#include "riscos/wimp_event.h"
@@ -194,6 +195,7 @@ static struct
static nsurl *gui_get_resource_url(const char *path)
{
static const char base_url[] = "file:///NetSurf:/Resources/";
+ const char *lang;
size_t path_len, length;
char *raw;
nsurl *url = NULL;
@@ -219,8 +221,12 @@ static nsurl *gui_get_resource_url(const char *path)
path_len = strlen(path);
+ lang = ro_gui_default_language();
+
/* Find max URL length */
- length = SLEN(base_url) + SLEN("xx/") + path_len + 1;
+ length = SLEN(base_url) +
+ strlen(lang) + 1 + /* <lang> + / */
+ path_len + 1; /* + NUL */
raw = malloc(length);
if (raw != NULL) {
@@ -229,13 +235,11 @@ static nsurl *gui_get_resource_url(const char *path)
ptr += SLEN(base_url);
/* Add language directory to URL, for translated files */
- /* TODO: handle non-en langauages
- * handle non-html translated files */
+ /* TODO: handle non-html translated files */
if (path_len > SLEN(".html") &&
strncmp(path + path_len - SLEN(".html"),
".html", SLEN(".html")) == 0) {
- memcpy(ptr, "en/", SLEN("en/"));
- ptr += SLEN("en/");
+ ptr += sprintf(ptr, "%s/", lang);
}
/* Add filename to URL */
@@ -273,8 +277,10 @@ set_colour_from_wimp(struct nsoption_s *opts,
error = xwimp_read_true_palette((os_palette *) &palette);
if (error != NULL) {
- LOG("xwimp_read_palette: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_read_palette: 0x%x: %s",
+ error->errnum,
+ error->errmess);
} else {
/* entries are in B0G0R0LL */
def_colour = palette.entries[wimp] >> 8;
@@ -306,7 +312,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
if (nsoption_charp(ca_bundle) == NULL ||
nsoption_charp(cookie_file) == NULL ||
nsoption_charp(cookie_jar) == NULL) {
- LOG("Failed initialising default options");
+ NSLOG(netsurf, INFO, "Failed initialising default options");
return NSERROR_BAD_PARAMETER;
}
@@ -429,7 +435,7 @@ static void ro_gui_signal(int sig)
if (used) {
int curr_slot;
xwimp_slot_size(-1, -1, &curr_slot, 0, 0);
- LOG("saving WimpSlot, size 0x%x", curr_slot);
+ NSLOG(netsurf, INFO, "saving WimpSlot, size 0x%x", curr_slot);
xosfile_save("$.NetSurf_Slot", 0x8000, 0,
(byte *) 0x8000,
(byte *) 0x8000 + curr_slot);
@@ -439,7 +445,11 @@ static void ro_gui_signal(int sig)
byte *base_address;
xosdynamicarea_read(__dynamic_num, &size,
&base_address, 0, 0, 0, 0, 0);
- LOG("saving DA %i, base %p, size 0x%x", __dynamic_num, base_address, size);
+ NSLOG(netsurf, INFO,
+ "saving DA %i, base %p, size 0x%x",
+ __dynamic_num,
+ base_address,
+ size);
xosfile_save("$.NetSurf_DA",
(bits) base_address, 0,
base_address,
@@ -451,7 +461,7 @@ static void ro_gui_signal(int sig)
* defines a coredump directory. */
const _kernel_oserror *err = __unixlib_write_coredump (NULL);
if (err != NULL)
- LOG("Coredump failed: %s", err->errmess);
+ NSLOG(netsurf, INFO, "Coredump failed: %s", err->errmess);
#endif
xhourglass_colours(old_sand, old_glass, 0, 0);
@@ -535,7 +545,8 @@ static char *ro_gui_uri_file_parse(const char *file_name, char **uri_title)
*uri_title = NULL;
fp = fopen(file_name, "rb");
if (!fp) {
- LOG("fopen(\"%s\", \"rb\"): %i: %s", file_name, errno, strerror(errno));
+ NSLOG(netsurf, INFO, "fopen(\"%s\", \"rb\"): %i: %s",
+ file_name, errno, strerror(errno));
ro_warn_user("LoadError", strerror(errno));
return 0;
}
@@ -596,14 +607,16 @@ static char *ro_gui_url_file_parse(const char *file_name)
fp = fopen(file_name, "r");
if (!fp) {
- LOG("fopen(\"%s\", \"r\"): %i: %s", file_name, errno, strerror(errno));
+ NSLOG(netsurf, INFO, "fopen(\"%s\", \"r\"): %i: %s",
+ file_name, errno, strerror(errno));
ro_warn_user("LoadError", strerror(errno));
return 0;
}
if (!fgets(line, sizeof line, fp)) {
if (ferror(fp)) {
- LOG("fgets: %i: %s", errno, strerror(errno));
+ NSLOG(netsurf, INFO, "fgets: %i: %s", errno,
+ strerror(errno));
ro_warn_user("LoadError", strerror(errno));
} else
ro_warn_user("LoadError", messages_get("EmptyError"));
@@ -640,7 +653,8 @@ static char *ro_gui_ieurl_file_parse(const char *file_name)
fp = fopen(file_name, "r");
if (!fp) {
- LOG("fopen(\"%s\", \"r\"): %i: %s", file_name, errno, strerror(errno));
+ NSLOG(netsurf, INFO, "fopen(\"%s\", \"r\"): %i: %s",
+ file_name, errno, strerror(errno));
ro_warn_user("LoadError", strerror(errno));
return 0;
}
@@ -659,7 +673,7 @@ static char *ro_gui_ieurl_file_parse(const char *file_name)
}
}
if (ferror(fp)) {
- LOG("fgets: %i: %s", errno, strerror(errno));
+ NSLOG(netsurf, INFO, "fgets: %i: %s", errno, strerror(errno));
ro_warn_user("LoadError", strerror(errno));
fclose(fp);
return 0;
@@ -731,7 +745,8 @@ static void ro_msg_dataopen(wimp_message *message)
message->your_ref = message->my_ref;
oserror = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender);
if (oserror) {
- LOG("xwimp_send_message: 0x%x: %s", oserror->errnum, oserror->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ oserror->errnum, oserror->errmess);
ro_warn_user("WimpError", oserror->errmess);
return;
}
@@ -854,7 +869,8 @@ static void ro_msg_dataload(wimp_message *message)
oserror = xwimp_send_message(wimp_USER_MESSAGE, message,
message->sender);
if (oserror) {
- LOG("xwimp_send_message: 0x%x: %s", oserror->errnum, oserror->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ oserror->errnum, oserror->errmess);
ro_warn_user("WimpError", oserror->errmess);
return;
}
@@ -924,7 +940,10 @@ static void ro_msg_datasave(wimp_message *message)
error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)dataxfer, message->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_send_message: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -976,7 +995,8 @@ static void ro_msg_prequit(wimp_message *message)
error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE,
message, message->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1002,7 +1022,8 @@ static void ro_msg_save_desktop(wimp_message *message)
}
if (error) {
- LOG("xosgbpb_writew/xos_bputw: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosgbpb_writew/xos_bputw: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
/* we must cancel the save by acknowledging the message */
@@ -1010,7 +1031,8 @@ static void ro_msg_save_desktop(wimp_message *message)
error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE,
message, message->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1061,7 +1083,8 @@ static void ro_gui_get_screen_properties(void)
error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), vals);
if (error) {
- LOG("xos_read_vdu_variables: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_read_vdu_variables: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
return;
}
@@ -1078,9 +1101,9 @@ static void ro_gui_check_resolvers(void)
char *resolvers;
resolvers = getenv("Inet$Resolvers");
if (resolvers && resolvers[0]) {
- LOG("Inet$Resolvers '%s'", resolvers);
+ NSLOG(netsurf, INFO, "Inet$Resolvers '%s'", resolvers);
} else {
- LOG("Inet$Resolvers not set or empty");
+ NSLOG(netsurf, INFO, "Inet$Resolvers not set or empty");
ro_warn_user("Resolvers", 0);
}
}
@@ -1179,17 +1202,24 @@ static nserror gui_init(int argc, char** argv)
/* Initialise save complete functionality */
save_complete_init();
+ /* Initialise the font subsystem */
+ nsfont_init();
+
/* Load in visited URLs, Cookies, and hostlist */
urldb_load(nsoption_charp(url_path));
urldb_load_cookies(nsoption_charp(cookie_file));
- hotlist_init(nsoption_charp(hotlist_path));
+ hotlist_init(nsoption_charp(hotlist_path),
+ nsoption_bool(external_hotlists) ?
+ NULL :
+ nsoption_charp(hotlist_save));
/* Initialise with the wimp */
error = xwimp_initialise(wimp_VERSION_RO38, task_name,
PTR_WIMP_MESSAGE_LIST(&task_messages), 0,
&task_handle);
if (error) {
- LOG("xwimp_initialise: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_initialise: 0x%x: %s",
+ error->errnum, error->errmess);
die(error->errmess);
}
/* Register message handlers */
@@ -1212,9 +1242,6 @@ static nserror gui_init(int argc, char** argv)
ro_message_register_route(message_WINDOW_INFO,
ro_msg_window_info);
- /* Initialise the font subsystem */
- nsfont_init();
-
/* Initialise global information */
ro_gui_get_screen_properties();
ro_gui_wimp_get_desktop_font();
@@ -1230,7 +1257,8 @@ static nserror gui_init(int argc, char** argv)
die("Failed to locate Templates resource.");
error = xwimp_open_template(path);
if (error) {
- LOG("xwimp_open_template failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_template failed: 0x%x: %s",
+ error->errnum, error->errmess);
die(error->errmess);
}
@@ -1249,9 +1277,6 @@ static nserror gui_init(int argc, char** argv)
/* Initialise query windows */
ro_gui_query_init();
- /* Initialise the history subsystem */
- ro_gui_history_init();
-
/* Initialise toolbars */
ro_toolbar_init();
@@ -1274,7 +1299,7 @@ static nserror gui_init(int argc, char** argv)
/* parse command-line arguments */
if (argc == 2) {
- LOG("parameters: '%s'", argv[1]);
+ NSLOG(netsurf, INFO, "parameters: '%s'", argv[1]);
/* this is needed for launching URI files */
if (strcasecmp(argv[1], "-nowin") == 0) {
return NSERROR_OK;
@@ -1282,7 +1307,8 @@ static nserror gui_init(int argc, char** argv)
ret = nsurl_create(NETSURF_HOMEPAGE, &url);
}
else if (argc == 3) {
- LOG("parameters: '%s' '%s'", argv[1], argv[2]);
+ NSLOG(netsurf, INFO, "parameters: '%s' '%s'", argv[1],
+ argv[2]);
open_window = true;
/* HTML files */
@@ -1293,7 +1319,7 @@ static nserror gui_init(int argc, char** argv)
else if (strcasecmp(argv[1], "-urlf") == 0) {
char *urlf = ro_gui_url_file_parse(argv[2]);
if (!urlf) {
- LOG("allocation failed");
+ NSLOG(netsurf, INFO, "allocation failed");
die("Insufficient memory for URL");
}
ret = nsurl_create(urlf, &url);
@@ -1305,7 +1331,8 @@ static nserror gui_init(int argc, char** argv)
}
/* Unknown => exit here. */
else {
- LOG("Unknown parameters: '%s' '%s'", argv[1], argv[2]);
+ NSLOG(netsurf, INFO, "Unknown parameters: '%s' '%s'",
+ argv[1], argv[2]);
return NSERROR_BAD_PARAMETER;
}
}
@@ -1353,7 +1380,8 @@ const char *ro_gui_default_language(void)
/* choose a language from the configured country number */
error = xosbyte_read(osbyte_VAR_COUNTRY_NUMBER, &country);
if (error) {
- LOG("xosbyte_read failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosbyte_read failed: 0x%x: %s",
+ error->errnum, error->errmess);
country = 1;
}
switch (country) {
@@ -1404,7 +1432,10 @@ static nserror ro_path_to_nsurl(const char *path, struct nsurl **url_out)
/* calculate the canonical risc os path */
error = xosfscontrol_canonicalise_path(path, 0, 0, 0, 0, &spare);
if (error) {
- LOG("xosfscontrol_canonicalise_path failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfscontrol_canonicalise_path failed: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("PathToURL", error->errmess);
return NSERROR_NOT_FOUND;
}
@@ -1417,7 +1448,10 @@ static nserror ro_path_to_nsurl(const char *path, struct nsurl **url_out)
error = xosfscontrol_canonicalise_path(path, canonical_path, 0, 0, 1 - spare, 0);
if (error) {
- LOG("xosfscontrol_canonicalise_path failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfscontrol_canonicalise_path failed: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("PathToURL", error->errmess);
free(canonical_path);
return NSERROR_NOT_FOUND;
@@ -1427,7 +1461,7 @@ static nserror ro_path_to_nsurl(const char *path, struct nsurl **url_out)
unix_path = __unixify(canonical_path, __RISCOSIFY_NO_REVERSE_SUFFIX, NULL, 0, 0);
if (unix_path == NULL) {
- LOG("__unixify failed: %s", canonical_path);
+ NSLOG(netsurf, INFO, "__unixify failed: %s", canonical_path);
free(canonical_path);
return NSERROR_BAD_PARAMETER;
}
@@ -1445,7 +1479,7 @@ static nserror ro_path_to_nsurl(const char *path, struct nsurl **url_out)
urllen = strlen(escaped_path) + FILE_SCHEME_PREFIX_LEN + 1;
url = malloc(urllen);
if (url == NULL) {
- LOG("Unable to allocate url");
+ NSLOG(netsurf, INFO, "Unable to allocate url");
free(escaped_path);
return NSERROR_NOMEM;
}
@@ -1557,6 +1591,7 @@ static void gui_quit(void)
urldb_save_cookies(nsoption_charp(cookie_jar));
urldb_save(nsoption_charp(url_save));
ro_gui_window_quit();
+ ro_gui_local_history_finalise();
ro_gui_global_history_finalise();
ro_gui_hotlist_finalise();
ro_gui_cookies_finalise();
@@ -1594,7 +1629,8 @@ static void ro_gui_keypress_cb(void *pw)
if (ro_gui_wimp_event_keypress(key) == false) {
os_error *error = xwimp_process_key(key->c);
if (error) {
- LOG("xwimp_process_key: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_process_key: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1631,7 +1667,8 @@ static void ro_gui_keypress(wimp_key *key)
} else if (ro_gui_wimp_event_keypress(key) == false) {
os_error *error = xwimp_process_key(key->c);
if (error) {
- LOG("xwimp_process_key: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_process_key: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1903,7 +1940,8 @@ void ro_gui_open_window_request(wimp_open *open)
error = xwimp_open_window(open);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1924,7 +1962,8 @@ static void ro_gui_view_source_bounce(wimp_message *message)
sprintf(command, "@RunType_FFF %s", filename);
error = xwimp_start_task(command, 0);
if (error) {
- LOG("xwimp_start_task failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_start_task failed: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1987,7 +2026,7 @@ void ro_gui_view_source(struct hlcache_handle *c)
r = __riscosify(full_name, 0, __RISCOSIFY_NO_SUFFIX,
message.file_name, 212, 0);
if (r == 0) {
- LOG("__riscosify failed");
+ NSLOG(netsurf, INFO, "__riscosify failed");
return;
}
message.file_name[211] = '\0';
@@ -1997,7 +2036,10 @@ void ro_gui_view_source(struct hlcache_handle *c)
(byte *) source_data,
(byte *) source_data + source_size);
if (error) {
- LOG("xosfile_save_stamped failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_save_stamped failed: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
return;
}
@@ -2067,7 +2109,7 @@ static void ro_gui_choose_language(void)
*/
nserror ro_warn_user(const char *warning, const char *detail)
{
- LOG("%s %s", warning, detail);
+ NSLOG(netsurf, INFO, "%s %s", warning, detail);
if (dialog_warning) {
char warn_buffer[300];
@@ -2111,7 +2153,7 @@ void die(const char * const error)
{
os_error warn_error;
- LOG("%s", error);
+ NSLOG(netsurf, INFO, "%s", error);
warn_error.errnum = 1; /* \todo: reasonable ? */
strncpy(warn_error.errmess, messages_get(error),
@@ -2348,7 +2390,7 @@ void ro_gui_dump_browser_window(struct browser_window *bw)
/* open file for dump */
FILE *stream = fopen("<Wimp$ScrapDir>.WWW.NetSurf.dump", "w");
if (!stream) {
- LOG("fopen: errno %i", errno);
+ NSLOG(netsurf, INFO, "fopen: errno %i", errno);
ro_warn_user("SaveError", strerror(errno));
return;
}
@@ -2361,7 +2403,8 @@ void ro_gui_dump_browser_window(struct browser_window *bw)
error = xwimp_start_task("Filer_Run <Wimp$ScrapDir>.WWW.NetSurf.dump",
0);
if (error) {
- LOG("xwimp_start_task failed: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_start_task failed: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -2401,7 +2444,7 @@ static char *get_cachepath(void)
cachedir = getenv("Cache$Dir");
if ((cachedir == NULL) || (cachedir[0] == 0)) {
- LOG("cachedir was null");
+ NSLOG(netsurf, INFO, "cachedir was null");
return NULL;
}
ret = netsurf_mkpath(&cachepath, NULL, 2, cachedir, "NetSurf");
@@ -2517,5 +2560,8 @@ int main(int argc, char** argv)
netsurf_exit();
nsoption_finalise(nsoptions, nsoptions_default);
+ /* finalise logging */
+ nslog_finalise();
+
return 0;
}
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 1f5070012..49a8ba417 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -59,7 +59,6 @@ extern wimp_w dialog_info, dialog_saveas, dialog_zoom, dialog_pageinfo,
extern wimp_w current_menu_window;
extern bool current_menu_open;
extern wimp_menu *recent_search_menu; /* search.c */
-extern wimp_w history_window;
extern bool gui_redraw_debug;
extern osspriteop_area *gui_sprites;
extern bool dialog_folder_add, dialog_entry_add, hotlist_insert;
@@ -140,39 +139,6 @@ void ro_gui_401login_init(void);
void gui_401login_open(struct nsurl *url, const char *realm,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
-/* in window.c */
-void ro_gui_window_set_scale(struct gui_window *g, float scale);
-bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message);
-void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data);
-void ro_gui_window_iconise(struct gui_window *g,
- wimp_full_message_window_info *wi);
-bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message);
-void ro_gui_window_redraw_all(void);
-void ro_gui_window_update_boxes(void);
-void ro_gui_window_quit(void);
-/* void ro_gui_window_close_all(void); */
-#define ro_gui_window_close_all ro_gui_window_quit /* no need for a separate fn */
-void ro_gui_throb(void);
-void ro_gui_window_default_options(struct gui_window *gui);
-struct gui_window *ro_gui_window_lookup(wimp_w window);
-struct gui_window *ro_gui_toolbar_lookup(wimp_w window);
-bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y,
- os_coord *pos);
-bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y,
- os_coord *pos);
-enum browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
- wimp_icon_flags type);
-enum browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
- wimp_icon_flags type);
-bool ro_gui_shift_pressed(void);
-bool ro_gui_ctrl_pressed(void);
-bool ro_gui_alt_pressed(void);
-void gui_window_set_pointer(struct gui_window *g, enum gui_pointer_shape shape);
-
-/* in history.c */
-void ro_gui_history_init(void);
-void ro_gui_history_open(struct gui_window *g, bool pointer);
-
/* in schedule.c */
extern bool sched_active;
extern os_t sched_time;
diff --git a/frontends/riscos/gui/button_bar.c b/frontends/riscos/gui/button_bar.c
index 6ecd7cffa..34ae39ae5 100644
--- a/frontends/riscos/gui/button_bar.c
+++ b/frontends/riscos/gui/button_bar.c
@@ -138,7 +138,7 @@ struct button_bar *ro_gui_button_bar_create(struct theme_descriptor *theme,
button_bar = malloc(sizeof(struct button_bar));
if (button_bar == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
return NULL;
}
@@ -538,7 +538,10 @@ bool ro_gui_button_bar_icon_update(struct button_bar *button_bar)
error = xwimp_create_icon(&icon, &button->icon);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_create_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
button->icon = -1;
return false;
@@ -548,7 +551,10 @@ bool ro_gui_button_bar_icon_update(struct button_bar *button_bar)
error = xwimp_delete_icon(button_bar->window,
button->icon);
if (error != NULL) {
- LOG("xwimp_delete_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_delete_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -598,7 +604,10 @@ bool ro_gui_button_bar_icon_resize(struct button_bar *button_bar)
button->y_pos +
button->y_size);
if (error != NULL) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_resize_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
button->icon = -1;
return false;
@@ -769,7 +778,10 @@ bool ro_gui_button_bar_click(struct button_bar *button_bar,
button_bar->sprites,
sprite, &box, NULL);
if (error)
- LOG("xdragasprite_start: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xdragasprite_start: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_mouse_drag_start(ro_gui_button_bar_drag_end,
NULL, NULL, NULL);
@@ -870,7 +882,8 @@ void ro_gui_button_bar_drag_end(wimp_dragged *drag, void *data)
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -880,7 +893,8 @@ void ro_gui_button_bar_drag_end(wimp_dragged *drag, void *data)
state.w = drag_start->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1068,7 +1082,7 @@ char *ro_gui_button_bar_get_config(struct button_bar *button_bar)
config = malloc(size);
if (config == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
ro_warn_user("NoMemory", 0);
return NULL;
}
diff --git a/frontends/riscos/gui/progress_bar.c b/frontends/riscos/gui/progress_bar.c
index c26b46c84..06d89dbf4 100644
--- a/frontends/riscos/gui/progress_bar.c
+++ b/frontends/riscos/gui/progress_bar.c
@@ -30,9 +30,9 @@
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
-#include "netsurf/plotters.h"
#include "utils/log.h"
#include "utils/utils.h"
+#include "netsurf/plotters.h"
#include "riscos/gui.h"
#include "riscos/tinct.h"
@@ -137,7 +137,8 @@ struct progress_bar *ro_gui_progress_bar_create(void)
error = xwimp_create_window((wimp_window *)&progress_bar_definition,
&pb->w);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
free(pb);
return NULL;
}
@@ -165,7 +166,8 @@ void ro_gui_progress_bar_destroy(struct progress_bar *pb)
ro_gui_wimp_event_finalise(pb->w);
error = xwimp_delete_window(pb->w);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
free(pb);
@@ -327,7 +329,8 @@ void ro_gui_progress_bar_update(struct progress_bar *pb, int width, int height)
redraw.box.x0 = cur.x1;
error = xwimp_update_window(&redraw, &more);
if (error) {
- LOG("Error getting update window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "Error getting update window: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
if (more)
@@ -351,7 +354,8 @@ void ro_gui_progress_bar_redraw(wimp_draw *redraw)
error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
if (more)
@@ -385,7 +389,8 @@ void ro_gui_progress_bar_animate(void *p)
redraw.box = pb->visible;
error = xwimp_update_window(&redraw, &more);
if (error != NULL) {
- LOG("Error getting update window: '%s'", error->errmess);
+ NSLOG(netsurf, INFO, "Error getting update window: '%s'",
+ error->errmess);
return;
}
if (more)
@@ -482,6 +487,11 @@ void ro_gui_progress_bar_redraw_window(wimp_draw *redraw,
osbool more = true;
struct rect clip;
int progress_ymid;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
/* initialise the plotters */
ro_plot_origin_x = 0;
@@ -513,22 +523,23 @@ void ro_gui_progress_bar_redraw_window(wimp_draw *redraw,
redraw->box.y0 + pb->visible.y0) >> 1;
if ((clip.x0 < clip.x1) && (clip.y0 < clip.y1)) {
if (progress_icon) {
- ro_plotters.clip(&clip);
+ ctx.plot->clip(&ctx, &clip);
_swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
progress_icon,
redraw->box.x0 - pb->offset,
progress_ymid - progress_height,
tinct_FILL_HORIZONTALLY);
} else {
- ro_plotters.rectangle(clip.x0, clip.y0,
- clip.x1, clip.y1,
- plot_style_fill_red);
+ ctx.plot->rectangle(&ctx,
+ plot_style_fill_red,
+ &clip);
}
}
}
error = xwimp_get_rectangle(redraw, &more);
if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
diff --git a/frontends/riscos/gui/status_bar.c b/frontends/riscos/gui/status_bar.c
index 9d1bada91..dd1aab639 100644
--- a/frontends/riscos/gui/status_bar.c
+++ b/frontends/riscos/gui/status_bar.c
@@ -28,9 +28,10 @@
#include "oslib/os.h"
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
-#include "netsurf/plotters.h"
+
#include "utils/log.h"
#include "utils/utils.h"
+#include "netsurf/plotters.h"
#include "riscos/gui.h"
#include "riscos/wimp.h"
@@ -130,7 +131,8 @@ struct status_bar *ro_gui_status_bar_create(wimp_w parent, unsigned int width)
error = xwimp_create_window((wimp_window *)&status_bar_definition,
&sb->w);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
free(sb);
return NULL;
}
@@ -164,7 +166,8 @@ void ro_gui_status_bar_destroy(struct status_bar *sb)
ro_gui_wimp_event_finalise(sb->w);
error = xwimp_delete_window(sb->w);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
ro_gui_progress_bar_destroy(sb->pb);
@@ -221,7 +224,8 @@ void ro_gui_status_bar_set_visible(struct status_bar *sb, bool visible)
} else {
os_error *error = xwimp_close_window(sb->w);
if (error) {
- LOG("xwimp_close_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
}
}
@@ -274,14 +278,15 @@ void ro_gui_status_bar_set_progress_range(struct status_bar *sb,
old_range = ro_gui_progress_bar_get_range(sb->pb);
ro_gui_progress_bar_set_range(sb->pb, range);
- LOG("Ranges are %i vs %i", old_range, range);
+ NSLOG(netsurf, INFO, "Ranges are %i vs %i", old_range, range);
if ((old_range == 0) && (range != 0)) {
ro_gui_status_position_progress_bar(sb);
} else if ((old_range != 0) && (range == 0)) {
os_error *error = xwimp_close_window(
ro_gui_progress_bar_get_window(sb->pb));
if (error) {
- LOG("xwimp_close_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
}
}
@@ -353,7 +358,8 @@ void ro_gui_status_bar_resize(struct status_bar *sb)
state.w = sb->parent;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
window_width = state.visible.x1 - state.visible.x0;
@@ -376,7 +382,8 @@ void ro_gui_status_bar_resize(struct status_bar *sb)
extent.y1 = status_height - 4;
error = xwimp_set_extent(sb->w, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -404,7 +411,10 @@ void ro_gui_status_bar_resize(struct status_bar *sb)
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_TS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
ro_gui_status_position_progress_bar(sb);
@@ -412,7 +422,8 @@ void ro_gui_status_bar_resize(struct status_bar *sb)
status_width - WIDGET_WIDTH, 0,
status_width, status_height - 4);
if (error) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -436,6 +447,12 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw)
os_error *error;
osbool more;
rufl_code code;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+ struct rect rect;
sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(redraw->w);
assert(sb);
@@ -447,7 +464,8 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw)
/* redraw the window */
error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
while (more) {
@@ -456,7 +474,10 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw)
error = xcolourtrans_set_font_colours(font_CURRENT,
0xeeeeee00, 0x00000000, 14, 0, 0, 0);
if (error) {
- LOG("xcolourtrans_set_font_colours: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_font_colours: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
code = rufl_paint(ro_gui_desktop_font_family,
@@ -467,22 +488,30 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw)
rufl_BLEND_FONT);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_paint: 0x%x", code);
+ NSLOG(netsurf, INFO,
+ "rufl_paint: 0x%x", code);
}
}
+ rect.x0 = (redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1;
+ rect.y0 = -redraw->box.y0 >> 1;
+ rect.x1 = (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1;
+ rect.y1 = -redraw->box.y1 >> 1;
+
/* separate the widget from the text with a line */
- ro_plotters.rectangle((redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1,
- -redraw->box.y0 >> 1,
- (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1,
- -redraw->box.y1 >> 1,
- plot_style_fill_black);
+ ctx.plot->rectangle(&ctx,
+ plot_style_fill_black,
+ &rect);
error = xwimp_get_rectangle(redraw, &more);
if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
@@ -521,7 +550,10 @@ bool ro_gui_status_bar_click(wimp_pointer *pointer)
drag.initial.y1 = pointer->pos.y;
error = xwimp_drag_box(&drag);
if (error) {
- LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_drag_box: 0x%x: %s",
+ error->errnum,
+ error->errmess);
}
break;
}
@@ -546,7 +578,8 @@ void ro_gui_status_bar_open(wimp_open *open)
state.w = sb->parent;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
window_width = state.visible.x1 - state.visible.x0;
@@ -585,7 +618,8 @@ void ro_gui_status_position_progress_bar(struct status_bar *sb)
state.w = sb->w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -615,7 +649,8 @@ void ro_gui_status_position_progress_bar(struct status_bar *sb)
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_TS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
/* update the progress bar display on non-standard width */
diff --git a/frontends/riscos/gui/throbber.c b/frontends/riscos/gui/throbber.c
index a326f806c..f3b79a68e 100644
--- a/frontends/riscos/gui/throbber.c
+++ b/frontends/riscos/gui/throbber.c
@@ -81,7 +81,7 @@ struct throbber *ro_gui_throbber_create(struct theme_descriptor *theme)
throbber = malloc(sizeof(struct throbber));
if (throbber == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
return NULL;
}
@@ -248,7 +248,8 @@ bool ro_gui_throbber_icon_update(struct throbber *throbber)
error = xwimp_create_icon(&icon, &throbber->icon);
if (error != NULL) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
throbber->icon = -1;
return false;
@@ -259,7 +260,8 @@ bool ro_gui_throbber_icon_update(struct throbber *throbber)
} else if (throbber->hidden && throbber->icon != -1) {
error = xwimp_delete_icon(throbber->window, throbber->icon);
if (error != NULL) {
- LOG("xwimp_delete_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -295,7 +297,8 @@ bool ro_gui_throbber_icon_resize(struct throbber *throbber)
throbber->extent.x0, throbber->extent.y0,
throbber->extent.x1, throbber->extent.y1);
if (error != NULL) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
throbber->icon = -1;
return false;
diff --git a/frontends/riscos/gui/url_bar.c b/frontends/riscos/gui/url_bar.c
index a5ec3f8c6..ee5c689df 100644
--- a/frontends/riscos/gui/url_bar.c
+++ b/frontends/riscos/gui/url_bar.c
@@ -140,7 +140,7 @@ struct url_bar *ro_gui_url_bar_create(struct theme_descriptor *theme)
url_bar = malloc(sizeof(struct url_bar));
if (url_bar == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
return NULL;
}
@@ -240,7 +240,8 @@ static bool ro_gui_url_bar_icon_resize(struct url_bar *url_bar, bool full)
url_bar->container_icon,
x0, y0, x1, y1);
if (error != NULL) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
url_bar->container_icon = -1;
return false;
@@ -260,7 +261,8 @@ static bool ro_gui_url_bar_icon_resize(struct url_bar *url_bar, bool full)
url_bar->suggest_icon,
x0, y0, x1, y1);
if (error != NULL) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
url_bar->suggest_icon = -1;
return false;
@@ -281,7 +283,8 @@ static bool ro_gui_url_bar_icon_resize(struct url_bar *url_bar, bool full)
url_bar->text_icon,
x0, y0, x1, y1);
if (error != NULL) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
url_bar->text_icon = -1;
return false;
@@ -362,7 +365,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
wimp_ICON_BUTTON_TYPE_SHIFT);
error = xwimp_create_icon(&icon, &url_bar->container_icon);
if (error != NULL) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
url_bar->container_icon = -1;
return false;
@@ -373,7 +377,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
error = xwimp_delete_icon(url_bar->window,
url_bar->container_icon);
if (error != NULL) {
- LOG("xwimp_delete_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -399,7 +404,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
wimp_ICON_BUTTON_TYPE_SHIFT);
error = xwimp_create_icon(&icon, &url_bar->text_icon);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
url_bar->text_icon = -1;
return false;
@@ -410,7 +416,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
error = xwimp_delete_icon(url_bar->window,
url_bar->text_icon);
if (error != NULL) {
- LOG("xwimp_delete_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -430,7 +437,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
wimp_ICON_BUTTON_TYPE_SHIFT);
error = xwimp_create_icon(&icon, &url_bar->suggest_icon);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -450,7 +458,8 @@ static bool ro_gui_url_bar_icon_update(struct url_bar *url_bar)
error = xwimp_delete_icon(url_bar->window,
url_bar->suggest_icon);
if (error != NULL) {
- LOG("xwimp_delete_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -940,7 +949,8 @@ bool ro_gui_url_bar_take_caret(struct url_bar *url_bar)
error = xwimp_set_caret_position(url_bar->window, url_bar->text_icon,
-1, -1, -1, 0);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
@@ -977,7 +987,7 @@ void ro_gui_url_bar_set_url(struct url_bar *url_bar, const char *url,
if (err != NSERROR_OK) {
/* A bad encoding should never happen, so assert this */
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
/* Paranoia */
local_text = NULL;
}
@@ -993,7 +1003,8 @@ void ro_gui_url_bar_set_url(struct url_bar *url_bar, const char *url,
if (strlen(local_url) >= url_bar->text_size) {
url_bar->text_buffer[0] = '\0';
ro_warn_user("LongURL", NULL);
- LOG("Long URL (%zu chars): %s", strlen(url), url);
+ NSLOG(netsurf, INFO, "Long URL (%zu chars): %s", strlen(url),
+ url);
} else {
strncpy(url_bar->text_buffer, local_url,
url_bar->text_size - 1);
@@ -1021,7 +1032,8 @@ void ro_gui_url_bar_set_url(struct url_bar *url_bar, const char *url,
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1034,7 +1046,10 @@ void ro_gui_url_bar_set_url(struct url_bar *url_bar, const char *url,
error = xwimp_set_caret_position(url_bar->window,
url_bar->text_icon, 0, 0, -1, strlen(set_url));
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1123,7 +1138,8 @@ bool ro_gui_url_bar_get_url_extent(struct url_bar *url_bar, os_box *extent)
state.i = url_bar->container_icon;
error = xwimp_get_icon_state(&state);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
diff --git a/frontends/riscos/help.c b/frontends/riscos/help.c
index b6871c5eb..952b3f2d1 100644
--- a/frontends/riscos/help.c
+++ b/frontends/riscos/help.c
@@ -166,7 +166,8 @@ void ro_gui_interactive_help_request(wimp_message *message)
error = xwimp_get_menu_state(wimp_GIVEN_WINDOW_AND_ICON,
&menu_tree, window, icon);
if (error) {
- LOG("xwimp_get_menu_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_menu_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -269,7 +270,8 @@ static void ro_gui_interactive_help_broadcast(wimp_message *message,
error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message *)reply,
reply->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -297,7 +299,10 @@ bool ro_gui_interactive_help_available(void)
error = xtaskmanager_enumerate_tasks(context, &task,
sizeof(taskmanager_task), &context, 0);
if (error) {
- LOG("xtaskmanager_enumerate_tasks: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xtaskmanager_enumerate_tasks: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
}
@@ -334,7 +339,8 @@ void ro_gui_interactive_help_start(void)
if ((help_start) && (help_start[0])) {
error = xwimp_start_task("<Help$Start>", &task);
if (error) {
- LOG("xwimp_start_tast: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_start_tast: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -344,7 +350,8 @@ void ro_gui_interactive_help_start(void)
if (!task) {
error = xwimp_start_task("Resources:$.Apps.!Help", &task);
if (error) {
- LOG("xwimp_start_tast: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_start_tast: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -354,7 +361,10 @@ void ro_gui_interactive_help_start(void)
if (task) {
error = xos_read_monotonic_time(&help_time);
if (error) {
- LOG("xwimp_read_monotonic_time: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_read_monotonic_time: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
diff --git a/frontends/riscos/history.c b/frontends/riscos/history.c
deleted file mode 100644
index de3af085d..000000000
--- a/frontends/riscos/history.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2005 Richard Wilson <info@tinct.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Browser history window (RISC OS implementation).
- *
- * There is only one history window, not one per browser window.
- */
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include "oslib/wimp.h"
-
-#include "utils/nsoption.h"
-#include "utils/log.h"
-#include "desktop/browser_history.h"
-#include "netsurf/plotters.h"
-
-#include "riscos/dialog.h"
-#include "riscos/gui.h"
-#include "riscos/mouse.h"
-#include "riscos/wimp.h"
-#include "riscos/wimp_event.h"
-#include "riscos/wimputils.h"
-
-static struct browser_window *history_bw;
-/* Last position of mouse in window. */
-static int mouse_x = 0;
-/* Last position of mouse in window. */
-static int mouse_y = 0;
-wimp_w history_window;
-
-static void ro_gui_history_redraw(wimp_draw *redraw);
-static bool ro_gui_history_click(wimp_pointer *pointer);
-static void ro_gui_history_pointer_entering(wimp_entering *entering);
-static void ro_gui_history_track_end(wimp_leaving *leaving, void *data);
-static void ro_gui_history_mouse_at(wimp_pointer *pointer, void *data);
-
-
-/**
- * Create history window.
- */
-
-void ro_gui_history_init(void)
-{
- history_window = ro_gui_dialog_create("history");
- ro_gui_wimp_event_register_redraw_window(history_window,
- ro_gui_history_redraw);
- ro_gui_wimp_event_register_mouse_click(history_window,
- ro_gui_history_click);
- ro_gui_wimp_event_register_pointer_entering_window(history_window,
- ro_gui_history_pointer_entering);
- ro_gui_wimp_event_set_help_prefix(history_window, "HelpHistory");
-}
-
-
-/**
- * Open history window.
- *
- * \param g The riscos window to open history for.
- * \param at_pointer open the window at the pointer.
- */
-
-void ro_gui_history_open(struct gui_window *g, bool at_pointer)
-{
- struct browser_window *bw;
- int width, height;
- os_box box = {0, 0, 0, 0};
- wimp_window_state state;
- os_error *error;
-
- assert(g != NULL);
- assert(g->bw != NULL);
- bw = g->bw;
- history_bw = bw;
-
- browser_window_history_size(bw, &width, &height);
- width *= 2;
- height *= 2;
-
- /* set extent */
- box.x1 = width;
- box.y0 = -height;
- error = xwimp_set_extent(history_window, &box);
- if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- /* open full size */
- state.w = history_window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- state.visible.x0 = 0;
- state.visible.y0 = 0;
- state.visible.x1 = width;
- state.visible.y1 = height;
- state.next = wimp_HIDDEN;
- error = xwimp_open_window(PTR_WIMP_OPEN(&state));
- if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- ro_gui_dialog_open_persistent(g->window, history_window, at_pointer);
-}
-
-
-/**
- * Redraw history window.
- */
-
-void ro_gui_history_redraw(wimp_draw *redraw)
-{
- osbool more;
- os_error *error;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
-
- error = xwimp_redraw_window(redraw, &more);
- if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- while (more) {
- ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
- browser_window_history_redraw(history_bw, &ctx);
- error = xwimp_get_rectangle(redraw, &more);
- if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- }
-}
-
-
-/**
- * Handle Pointer Entering Window events the history window.
- *
- * \param *entering The Wimp_PointerEnteringWindow block.
- */
-
-void ro_gui_history_pointer_entering(wimp_entering *entering)
-{
- ro_mouse_track_start(ro_gui_history_track_end,
- ro_gui_history_mouse_at, NULL);
-}
-
-
-/**
- * Handle Pointer Leaving Window events the history window. These arrive as the
- * termination callback handler from ro_mouse's mouse tracking.
- *
- * \param *leaving The Wimp_PointerLeavingWindow block.
- * \param *data NULL data pointer.
- */
-
-void ro_gui_history_track_end(wimp_leaving *leaving, void *data)
-{
- ro_gui_dialog_close(dialog_tooltip);
-}
-
-
-/**
- * Handle mouse movements over the history window.
- */
-
-void ro_gui_history_mouse_at(wimp_pointer *pointer, void *data)
-{
- int x, y;
- int width;
- const char *url;
- wimp_window_state state;
- wimp_icon_state ic;
- os_box box = {0, 0, 0, 0};
- os_error *error;
-
- LOG("Mouse at...");
-
- /* If the mouse hasn't moved, or if we don't want tooltips, exit */
- if ((mouse_x == pointer->pos.x && mouse_y == pointer->pos.y) ||
- !nsoption_bool(history_tooltip))
- return;
-
- /* Update mouse position */
- mouse_x = pointer->pos.x;
- mouse_y = pointer->pos.y;
-
- /* Find history tree entry under mouse */
- state.w = history_window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- x = (pointer->pos.x - (state.visible.x0 - state.xscroll)) / 2;
- y = -(pointer->pos.y - (state.visible.y1 - state.yscroll)) / 2;
- url = browser_window_history_position_url(history_bw, x, y);
- if (!url) {
- /* not over a tree entry => close tooltip window. */
- error = xwimp_close_window(dialog_tooltip);
- if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- return;
- }
-
- /* get width of string */
- error = xwimptextop_string_width(url,
- strlen(url) > 256 ? 256 : strlen(url),
- &width);
- if (error) {
- LOG("xwimptextop_string_width: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- ro_gui_set_icon_string(dialog_tooltip, 0, url, true);
-
- /* resize icon appropriately */
- ic.w = dialog_tooltip;
- ic.i = 0;
- error = xwimp_get_icon_state(&ic);
- if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- error = xwimp_resize_icon(dialog_tooltip, 0,
- ic.icon.extent.x0, ic.icon.extent.y0,
- width + 16, ic.icon.extent.y1);
- if (error) {
- LOG("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- state.w = dialog_tooltip;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- /* update window extent */
- box.x1 = width + 16;
- box.y0 = -36;
- error = xwimp_set_extent(dialog_tooltip, &box);
- if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-
- /* set visible area */
- state.visible.x0 = pointer->pos.x + 24;
- state.visible.y0 = pointer->pos.y - 22 - 36;
- state.visible.x1 = pointer->pos.x + 24 + width + 16;
- state.visible.y1 = pointer->pos.y - 22;
- state.next = wimp_TOP;
- /* open window */
- error = xwimp_open_window(PTR_WIMP_OPEN(&state));
- if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
-}
-
-
-/**
- * Handle mouse clicks in the history window.
- *
- * \return true if the event was handled, false to pass it on
- */
-
-bool ro_gui_history_click(wimp_pointer *pointer)
-{
- int x, y;
- wimp_window_state state;
- os_error *error;
-
- if (pointer->buttons != wimp_CLICK_SELECT &&
- pointer->buttons != wimp_CLICK_ADJUST)
- /* return if not select or adjust click */
- return true;
-
- state.w = history_window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return true;
- }
-
- x = (pointer->pos.x - (state.visible.x0 - state.xscroll)) / 2;
- y = -(pointer->pos.y - (state.visible.y1 - state.yscroll)) / 2;
- browser_window_history_click(history_bw, x, y,
- pointer->buttons == wimp_CLICK_ADJUST);
-
- return true;
-}
diff --git a/frontends/riscos/hotlist.c b/frontends/riscos/hotlist.c
index ea85bc3b5..b0ed1e2f4 100644
--- a/frontends/riscos/hotlist.c
+++ b/frontends/riscos/hotlist.c
@@ -466,7 +466,7 @@ static nserror ro_hotlist_init(void)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct ro_hotlist_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
@@ -548,19 +548,20 @@ nserror ro_gui_hotlist_present(void)
return NSERROR_OK;
}
- LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_cli: 0x%x: %s", error->errnum,
+ error->errmess);
ro_warn_user("Failed to launch external hotlist: %s",
error->errmess);
}
res = ro_hotlist_init();
if (res == NSERROR_OK) {
- LOG("Presenting");
+ NSLOG(netsurf, INFO, "Presenting");
ro_gui_dialog_open_top(hotlist_window->core.wh,
hotlist_window->core.toolbar,
600, 800);
} else {
- LOG("Failed presenting code %d", res);
+ NSLOG(netsurf, INFO, "Failed presenting code %d", res);
}
return res;
@@ -583,7 +584,7 @@ nserror ro_gui_hotlist_finalise(void)
return NSERROR_OK;
}
- res = hotlist_fini(nsoption_charp(hotlist_save));
+ res = hotlist_fini();
if (res == NSERROR_OK) {
res = ro_corewindow_fini(&hotlist_window->core);
diff --git a/frontends/riscos/iconbar.c b/frontends/riscos/iconbar.c
index 3430ed2f0..23f97258b 100644
--- a/frontends/riscos/iconbar.c
+++ b/frontends/riscos/iconbar.c
@@ -95,7 +95,8 @@ void ro_gui_iconbar_initialise(void)
{ "!netsurf" } } };
error = xwimp_create_icon(&icon, 0);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
die(error->errmess);
}
@@ -238,7 +239,8 @@ bool ro_gui_iconbar_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
return true;
case APPLICATION_QUIT:
if (ro_gui_prequit()) {
- LOG("QUIT in response to user request");
+ NSLOG(netsurf, INFO,
+ "QUIT in response to user request");
riscos_done = true;
}
return true;
diff --git a/frontends/riscos/image.c b/frontends/riscos/image.c
index acbe62d98..30cb30096 100644
--- a/frontends/riscos/image.c
+++ b/frontends/riscos/image.c
@@ -142,7 +142,8 @@ bool image_redraw_tinct(osspriteop_id header, int x, int y,
}
if (error) {
- LOG("xtinct_plotscaled%s: 0x%x: %s", (alpha ? "alpha" : ""), error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xtinct_plotscaled%s: 0x%x: %s",
+ (alpha ? "alpha" : ""), error->errnum, error->errmess);
return false;
}
@@ -176,13 +177,16 @@ bool image_redraw_os(osspriteop_id header, int x, int y, int req_width,
colourtrans_CURRENT_PALETTE,
0, colourtrans_GIVEN_SPRITE, 0, 0, &size);
if (error) {
- LOG("xcolourtrans_generate_table_for_sprite: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_generate_table_for_sprite: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return false;
}
table = calloc(size, sizeof(char));
if (!table) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
ro_warn_user("NoMemory", 0);
return false;
}
@@ -193,7 +197,10 @@ bool image_redraw_os(osspriteop_id header, int x, int y, int req_width,
colourtrans_CURRENT_PALETTE,
table, colourtrans_GIVEN_SPRITE, 0, 0, 0);
if (error) {
- LOG("xcolourtrans_generate_table_for_sprite: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_generate_table_for_sprite: 0x%x: %s",
+ error->errnum,
+ error->errmess);
free(table);
return false;
}
@@ -208,7 +215,10 @@ bool image_redraw_os(osspriteop_id header, int x, int y, int req_width,
x, (int)(y - req_height),
8, &f, table);
if (error) {
- LOG("xosspriteop_put_sprite_scaled: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_put_sprite_scaled: 0x%x: %s",
+ error->errnum,
+ error->errmess);
free(table);
return false;
}
diff --git a/frontends/riscos/local_history.c b/frontends/riscos/local_history.c
new file mode 100644
index 000000000..bbe6a1d12
--- /dev/null
+++ b/frontends/riscos/local_history.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of RISC OS local history.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <oslib/wimp.h>
+
+#include "utils/nsoption.h"
+#include "utils/messages.h"
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "netsurf/window.h"
+#include "netsurf/plotters.h"
+#include "netsurf/keypress.h"
+#include "desktop/local_history.h"
+
+#include "riscos/dialog.h"
+#include "riscos/gui.h"
+#include "riscos/menus.h"
+#include "riscos/save.h"
+#include "riscos/toolbar.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/wimputils.h"
+#include "riscos/corewindow.h"
+#include "riscos/local_history.h"
+
+struct ro_local_history_window {
+ struct ro_corewindow core;
+
+ /** local history window context */
+ struct local_history_session *session;
+
+ /** tooltip previous x */
+ int x;
+ /** tooltip previous y */
+ int y;
+};
+
+/** local_history window is a singleton */
+static struct ro_local_history_window *local_history_window = NULL;
+
+/** riscos template for local_history window */
+static wimp_window *dialog_local_history_template;
+
+
+/**
+ * callback to draw on drawable area of ro local history window
+ *
+ * \param ro_cw The riscos core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \param originx The risc os plotter x origin.
+ * \param originy The risc os plotter y origin.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+ro_local_history_draw(struct ro_corewindow *ro_cw,
+ int originx,
+ int originy,
+ struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+ struct ro_local_history_window *lhw;
+
+ lhw = (struct ro_local_history_window *)ro_cw;
+
+ ro_plot_origin_x = originx;
+ ro_plot_origin_y = originy;
+ no_font_blending = true;
+ local_history_redraw(lhw->session, 0, 0, r, &ctx);
+ no_font_blending = false;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * callback for keypress on ro coookie window
+ *
+ * \param ro_cw The ro core window structure.
+ * \param nskey The netsurf key code.
+ * \return NSERROR_OK if key processed,
+ * NSERROR_NOT_IMPLEMENTED if key not processed
+ * otherwise apropriate error code
+ */
+static nserror
+ro_local_history_key(struct ro_corewindow *ro_cw, uint32_t nskey)
+{
+ struct ro_local_history_window *lhw;
+
+ lhw = (struct ro_local_history_window *)ro_cw;
+
+ if (local_history_keypress(lhw->session, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * handle hover mouse movement for tooltips
+ */
+static nserror
+ro_local_history_tooltip(struct ro_local_history_window *lhw, int x, int y)
+{
+ int width;
+ nsurl *url;
+ wimp_window_state state;
+ wimp_icon_state ic;
+ os_box box = {0, 0, 0, 0};
+ os_error *error;
+ wimp_pointer pointer;
+ nserror res;
+
+ /* check if tooltip are required */
+ if (!nsoption_bool(history_tooltip)) {
+ return NSERROR_OK;
+ }
+
+ /* ensure pointer has moved */
+ if ((lhw->x == x) && (lhw->y == y)) {
+ return NSERROR_OK;
+ }
+
+ lhw->x = x;
+ lhw->y = y;
+
+ res = local_history_get_url(lhw->session, x, y, &url);
+ if (res != NSERROR_OK) {
+ /* not over a tree entry => close tooltip window. */
+ error = xwimp_close_window(dialog_tooltip);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+ return NSERROR_OK;
+ }
+
+ /* get width of string */
+ error = xwimptextop_string_width(nsurl_access(url),
+ nsurl_length(url) > 256 ? 256 : nsurl_length(url),
+ &width);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimptextop_string_width: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ nsurl_unref(url);
+ return NSERROR_NOMEM;
+ }
+
+ ro_gui_set_icon_string(dialog_tooltip, 0, nsurl_access(url), true);
+ nsurl_unref(url);
+
+ /* resize icon appropriately */
+ ic.w = dialog_tooltip;
+ ic.i = 0;
+ error = xwimp_get_icon_state(&ic);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+ error = xwimp_resize_icon(dialog_tooltip, 0,
+ ic.icon.extent.x0, ic.icon.extent.y0,
+ width + 16, ic.icon.extent.y1);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ state.w = dialog_tooltip;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ /* update window extent */
+ box.x1 = width + 16;
+ box.y0 = -36;
+ error = xwimp_set_extent(dialog_tooltip, &box);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ /* set visible area */
+ state.visible.x0 = pointer.pos.x + 24;
+ state.visible.y0 = pointer.pos.y - 22 - 36;
+ state.visible.x1 = pointer.pos.x + 24 + width + 16;
+ state.visible.y1 = pointer.pos.y - 22;
+ state.next = wimp_TOP;
+ /* open window */
+ error = xwimp_open_window(PTR_WIMP_OPEN(&state));
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * callback for mouse event on ro local_history window
+ *
+ * \param ro_cw The ro core window structure.
+ * \param mouse_state mouse state
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on sucess otherwise apropriate error code.
+ */
+static nserror
+ro_local_history_mouse(struct ro_corewindow *ro_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct ro_local_history_window *lhw;
+
+ lhw = (struct ro_local_history_window *)ro_cw;
+
+ switch (mouse_state) {
+
+ case BROWSER_MOUSE_HOVER:
+ ro_local_history_tooltip(lhw, x, y);
+ break;
+
+ case BROWSER_MOUSE_LEAVE:
+ ro_gui_dialog_close(dialog_tooltip);
+ break;
+
+ default:
+ local_history_mouse_action(lhw->session, mouse_state, x, y);
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Creates the window for the local_history tree.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror
+ro_local_history_init(struct browser_window *bw,
+ struct ro_local_history_window **win_out)
+{
+ struct ro_local_history_window *ncwin;
+ nserror res;
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ if ((*win_out) != NULL) {
+ res = local_history_set((*win_out)->session, bw);
+ return res;
+ }
+
+ ncwin = calloc(1, sizeof(*ncwin));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* create window from template */
+ ncwin->core.wh = wimp_create_window(dialog_local_history_template);
+
+ /* initialise callbacks */
+ ncwin->core.draw = ro_local_history_draw;
+ ncwin->core.key = ro_local_history_key;
+ ncwin->core.mouse = ro_local_history_mouse;
+
+ /* initialise core window */
+ res = ro_corewindow_init(&ncwin->core,
+ NULL,
+ NULL,
+ 0,
+ NULL);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ bw,
+ &ncwin->session);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ *win_out = ncwin;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * open RISC OS local history window at the correct size
+ */
+static nserror
+ro_local_history_open(struct ro_local_history_window *lhw, wimp_w parent)
+{
+ nserror res;
+ int width, height;
+ os_box box = {0, 0, 0, 0};
+ wimp_window_state state;
+ os_error *error;
+
+ res = local_history_get_size(lhw->session, &width, &height);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ width *= 2;
+ height *= 2;
+
+ /* set extent */
+ box.x1 = width;
+ box.y0 = -height;
+ error = xwimp_set_extent(lhw->core.wh, &box);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ /* open full size */
+ state.w = lhw->core.wh;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+ state.visible.x0 = 0;
+ state.visible.y0 = 0;
+ state.visible.x1 = width;
+ state.visible.y1 = height;
+ state.next = wimp_HIDDEN;
+ error = xwimp_open_window(PTR_WIMP_OPEN(&state));
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_NOMEM;
+ }
+
+ ro_gui_dialog_open_persistent(parent, lhw->core.wh, true);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in riscos/local_history.h */
+nserror ro_gui_local_history_present(wimp_w parent, struct browser_window *bw)
+{
+ nserror res;
+
+ res = ro_local_history_init(bw, &local_history_window);
+ if (res == NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Presenting");
+ res = ro_local_history_open(local_history_window, parent);
+ } else {
+ NSLOG(netsurf, INFO, "Failed presenting error code %d", res);
+ }
+
+ return res;
+}
+
+
+/* exported interface documented in riscos/local_history.h */
+void ro_gui_local_history_initialise(void)
+{
+ dialog_local_history_template = ro_gui_dialog_load_template("history");
+}
+
+
+/* exported interface documented in riscos/local_history.h */
+nserror ro_gui_local_history_finalise(void)
+{
+ nserror res;
+
+ if (local_history_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = local_history_fini(local_history_window->session);
+ if (res == NSERROR_OK) {
+ res = ro_corewindow_fini(&local_history_window->core);
+
+ free(local_history_window);
+ local_history_window = NULL;
+ }
+
+ return res;
+}
diff --git a/frontends/riscos/local_history.h b/frontends/riscos/local_history.h
new file mode 100644
index 000000000..d5b22b404
--- /dev/null
+++ b/frontends/riscos/local_history.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * RISC OS local history interface.
+ */
+
+#ifndef RISCOS_LOCALHISTORY_H
+#define RISCOS_LOCALHISTORY_H
+
+/**
+ * initialise the local history window template ready for subsequent use.
+ */
+void ro_gui_local_history_initialise(void);
+
+/**
+ * make the local history window visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror ro_gui_local_history_present(wimp_w parent, struct browser_window *bw);
+
+/**
+ * Free any resources allocated for the local history window.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror ro_gui_local_history_finalise(void);
+
+#endif
diff --git a/frontends/riscos/menus.c b/frontends/riscos/menus.c
index d46afa28e..a6e978a6c 100644
--- a/frontends/riscos/menus.c
+++ b/frontends/riscos/menus.c
@@ -232,7 +232,8 @@ void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w)
current_menu_open = true;
error = xwimp_create_menu(menu, x - 64, y);
if (error) {
- LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
ro_gui_menu_closed();
}
@@ -258,14 +259,16 @@ void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i)
icon_state.i = i;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
return;
}
error = xwimp_get_icon_state(&icon_state);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
return;
}
@@ -291,7 +294,8 @@ void ro_gui_menu_destroy(void)
error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
if (error) {
- LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
}
@@ -354,7 +358,8 @@ void ro_gui_menu_selection(wimp_selection *selection)
/* re-open the menu for Adjust clicks */
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
ro_gui_menu_closed();
return;
@@ -420,7 +425,8 @@ void ro_gui_menu_warning(wimp_message_menu_warning *warning)
error = xwimp_create_sub_menu(menu_entry->sub_menu,
warning->pos.x, warning->pos.y);
if (error) {
- LOG("xwimp_create_sub_menu: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_sub_menu: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
}
}
@@ -485,7 +491,8 @@ void ro_gui_menu_refresh(wimp_menu *menu)
os_error *error;
error = xwimp_create_menu(current_menu, 0, 0);
if (error) {
- LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_menu: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
}
}
@@ -851,7 +858,8 @@ int ro_gui_menu_get_checksum(void)
error = xwimp_get_menu_state((wimp_menu_state_flags)0,
&menu_tree, 0, 0);
if (error) {
- LOG("xwimp_get_menu_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_menu_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MenuError", error->errmess);
return 0;
}
@@ -894,7 +902,8 @@ bool ro_gui_menu_translate(struct menu_definition *menu)
/* read current alphabet */
error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet);
if (error) {
- LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
+ error->errnum, error->errmess);
/* assume Latin1 */
alphabet = territory_ALPHABET_LATIN1;
}
@@ -909,7 +918,7 @@ bool ro_gui_menu_translate(struct menu_definition *menu)
0, &translated);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
return false;
}
@@ -926,7 +935,7 @@ bool ro_gui_menu_translate(struct menu_definition *menu)
0, &translated);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
return false;
}
diff --git a/frontends/riscos/message.c b/frontends/riscos/message.c
index 1c54ea0b7..7a0216185 100644
--- a/frontends/riscos/message.c
+++ b/frontends/riscos/message.c
@@ -64,7 +64,8 @@ bool ro_message_send_message(wimp_event_no event, wimp_message *message,
/* send a message */
error = xwimp_send_message(event, message, task);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -101,7 +102,10 @@ bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *messag
/* send a message */
error = xwimp_send_message_to_window(event, message, to_w, to_i, to_t);
if (error) {
- LOG("xwimp_send_message_to_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_send_message_to_window: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
diff --git a/frontends/riscos/mouse.c b/frontends/riscos/mouse.c
index a0cc0e7ce..89184cff3 100644
--- a/frontends/riscos/mouse.c
+++ b/frontends/riscos/mouse.c
@@ -81,7 +81,8 @@ void ro_mouse_poll(void)
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -194,7 +195,7 @@ void ro_mouse_track_start(void (*poll_end)(wimp_leaving *leaving, void *data),
ro_mouse_ignore_leaving_event == false)
ro_mouse_poll_end_callback(NULL, ro_mouse_poll_data);
- LOG("Unexpected mouse track termination.");
+ NSLOG(netsurf, INFO, "Unexpected mouse track termination.");
ro_mouse_ignore_leaving_event = false;
ro_mouse_poll_end_callback = NULL;
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 06e732d99..2b306827d 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Target independent plotting (RISC OS screen implementation).
+/**
+ * \file
+ * RISC OS screen plotter implementation.
*/
#include <stdbool.h>
@@ -35,38 +36,6 @@
#include "riscos/font.h"
#include "riscos/oslib_pre7.h"
-static bool ro_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool ro_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool ro_plot_draw_path(const draw_path * const path, int width,
- colour c, bool dotted, bool dashed);
-static bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
-static bool ro_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6]);
-static bool ro_plot_clip(const struct rect *clip);
-static bool ro_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
-static bool ro_plot_disc(int x, int y, int radius, const plot_style_t *style);
-static bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style);
-static bool ro_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags);
-
-
-struct plotter_table plot;
-
-const struct plotter_table ro_plotters = {
- .rectangle = ro_plot_rectangle,
- .line = ro_plot_line,
- .polygon = ro_plot_polygon,
- .clip = ro_plot_clip,
- .text = ro_plot_text,
- .disc = ro_plot_disc,
- .arc = ro_plot_arc,
- .bitmap = ro_plot_bitmap,
- .path = ro_plot_path,
- .option_knockout = true,
-};
int ro_plot_origin_x = 0;
int ro_plot_origin_y = 0;
@@ -74,143 +43,404 @@ int ro_plot_origin_y = 0;
/** One version of the A9home OS is incapable of drawing patterned lines */
bool ro_plot_patterned_lines = true;
+/**
+ * plot a path on RISC OS
+ */
+static nserror
+ro_plot_draw_path(const draw_path * const path,
+ int width,
+ colour c,
+ bool dotted,
+ bool dashed)
+{
+ static const draw_line_style line_style = {
+ draw_JOIN_MITRED,
+ draw_CAP_BUTT,
+ draw_CAP_BUTT,
+ 0, 0x7fffffff,
+ 0, 0, 0, 0
+ };
+ draw_dash_pattern dash = { 0, 1, { 512 } };
+ const draw_dash_pattern *dash_pattern = 0;
+ os_error *error;
+
+ if (width < 1)
+ width = 1;
+
+ if (ro_plot_patterned_lines) {
+ if (dotted) {
+ dash.elements[0] = 512 * width;
+ dash_pattern = &dash;
+ } else if (dashed) {
+ dash.elements[0] = 1536 * width;
+ dash_pattern = &dash;
+ }
+ }
+
+ error = xcolourtrans_set_gcol(c << 8, 0, os_ACTION_OVERWRITE, 0, 0);
+ if (error) {
+ NSLOG(netsurf, INFO, "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ error = xdraw_stroke(path, 0, 0, 0, width * 2 * 256,
+ &line_style, dash_pattern);
+ if (error) {
+ NSLOG(netsurf, INFO, "xdraw_stroke: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ os_error *error;
+ char buf[12];
+
+ int clip_x0 = ro_plot_origin_x + clip->x0 * 2;
+ int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1;
+ int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1;
+ int clip_y1 = ro_plot_origin_y - clip->y1 * 2;
+
+ if (clip_x1 < clip_x0 || clip_y0 < clip_y1) {
+ NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
+ clip_x0, clip_y0, clip_x1, clip_y1);
+ return NSERROR_BAD_SIZE;
+ }
+
+ buf[0] = os_VDU_SET_GRAPHICS_WINDOW;
+ buf[1] = clip_x0;
+ buf[2] = clip_x0 >> 8;
+ buf[3] = clip_y1;
+ buf[4] = clip_y1 >> 8;
+ buf[5] = clip_x1;
+ buf[6] = clip_x1 >> 8;
+ buf[7] = clip_y0;
+ buf[8] = clip_y0 >> 8;
+
+ error = xos_writen(buf, 9);
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_writen: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
+}
-bool ro_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
{
+ os_error *error;
+ int sx, sy, ex, ey;
+ double t;
+
+ x = ro_plot_origin_x + x * 2;
+ y = ro_plot_origin_y - y * 2;
+ radius <<= 1;
+
+ error = xcolourtrans_set_gcol(style->fill_colour << 8, 0,
+ os_ACTION_OVERWRITE, 0, 0);
+
+ if (error) {
+ NSLOG(netsurf, INFO, "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ t = ((double)angle1 * M_PI) / 180.0;
+ sx = (x + (int)(radius * cos(t)));
+ sy = (y + (int)(radius * sin(t)));
+
+ t = ((double)angle2 * M_PI) / 180.0;
+ ex = (x + (int)(radius * cos(t)));
+ ey = (y + (int)(radius * sin(t)));
+
+ error = xos_plot(os_MOVE_TO, x, y); /* move to centre */
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ error = xos_plot(os_MOVE_TO, sx, sy); /* move to start */
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ error = xos_plot(os_PLOT_ARC | os_PLOT_TO, ex, ey); /* arc to end */
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x The x coordinate of the circle.
+ * \param y The y coordinate of the circle.
+ * \param radius The radius of the circle.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ os_error *error;
if (style->fill_type != PLOT_OP_TYPE_NONE) {
- os_error *error;
- error = xcolourtrans_set_gcol(style->fill_colour << 8,
- colourtrans_USE_ECFS_GCOL,
- os_ACTION_OVERWRITE, 0, 0);
+ error = xcolourtrans_set_gcol(style->fill_colour << 8, 0,
+ os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
}
-
error = xos_plot(os_MOVE_TO,
- ro_plot_origin_x + x0 * 2,
- ro_plot_origin_y - y0 * 2 - 1);
+ ro_plot_origin_x + x * 2,
+ ro_plot_origin_y - y * 2);
if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
}
-
- error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO,
- ro_plot_origin_x + x1 * 2 - 1,
- ro_plot_origin_y - y1 * 2);
+ error = xos_plot(os_PLOT_CIRCLE | os_PLOT_BY, radius * 2, 0);
if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
}
}
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- bool dotted = false;
- bool dashed = false;
-
- const int path[] = { draw_MOVE_TO,
- (ro_plot_origin_x + x0 * 2) * 256,
- (ro_plot_origin_y - y0 * 2 - 1) * 256,
- draw_LINE_TO,
- (ro_plot_origin_x + (x1) * 2) * 256,
- (ro_plot_origin_y - y0 * 2 - 1) * 256,
- draw_LINE_TO,
- (ro_plot_origin_x + (x1) * 2) * 256,
- (ro_plot_origin_y - (y1) * 2 - 1) * 256,
- draw_LINE_TO,
- (ro_plot_origin_x + x0 * 2) * 256,
- (ro_plot_origin_y - (y1) * 2 - 1) * 256,
- draw_CLOSE_LINE,
- (ro_plot_origin_x + x0 * 2) * 256,
- (ro_plot_origin_y - y0 * 2 - 1) * 256,
- draw_END_PATH };
-
- if (style->stroke_type == PLOT_OP_TYPE_DOT)
- dotted = true;
- if (style->stroke_type == PLOT_OP_TYPE_DASH)
- dashed = true;
+ error = xcolourtrans_set_gcol(style->stroke_colour << 8, 0,
+ os_ACTION_OVERWRITE, 0, 0);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
+ error = xos_plot(os_MOVE_TO,
+ ro_plot_origin_x + x * 2,
+ ro_plot_origin_y - y * 2);
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
+ }
+ error = xos_plot(os_PLOT_CIRCLE_OUTLINE | os_PLOT_BY,
+ radius * 2, 0);
- ro_plot_draw_path((const draw_path *)path,
- style->stroke_width,
- style->stroke_colour,
- dotted, dashed);
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
+ }
}
-
- return true;
+ return NSERROR_OK;
}
-bool ro_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
{
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- const int path[] = { draw_MOVE_TO,
- (ro_plot_origin_x + x0 * 2) * 256,
- (ro_plot_origin_y - y0 * 2 - 1) * 256,
- draw_LINE_TO,
- (ro_plot_origin_x + x1 * 2) * 256,
- (ro_plot_origin_y - y1 * 2 - 1) * 256,
- draw_END_PATH };
- bool dotted = false;
+ const int path[] = {
+ draw_MOVE_TO,
+ (ro_plot_origin_x + line->x0 * 2) * 256,
+ (ro_plot_origin_y - line->y0 * 2 - 1) * 256,
+ draw_LINE_TO,
+ (ro_plot_origin_x + line->x1 * 2) * 256,
+ (ro_plot_origin_y - line->y1 * 2 - 1) * 256,
+ draw_END_PATH };
+ bool dotted = false;
bool dashed = false;
- if (style->stroke_type == PLOT_OP_TYPE_DOT)
+ if (style->stroke_type == PLOT_OP_TYPE_DOT)
dotted = true;
- if (style->stroke_type == PLOT_OP_TYPE_DASH)
+ if (style->stroke_type == PLOT_OP_TYPE_DASH)
dashed = true;
- return ro_plot_draw_path((const draw_path *)path,
- style->stroke_width,
- style->stroke_colour,
- dotted, dashed);
+ return ro_plot_draw_path((const draw_path *)path,
+ plot_style_fixed_to_int(style->stroke_width),
+ style->stroke_colour,
+ dotted, dashed);
}
- return true;
+ return NSERROR_OK;
}
-bool ro_plot_draw_path(const draw_path * const path, int width,
- colour c, bool dotted, bool dashed)
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
{
- static const draw_line_style line_style = { draw_JOIN_MITRED,
- draw_CAP_BUTT, draw_CAP_BUTT, 0, 0x7fffffff,
- 0, 0, 0, 0 };
- draw_dash_pattern dash = { 0, 1, { 512 } };
- const draw_dash_pattern *dash_pattern = 0;
- os_error *error;
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ os_error *error;
+ error = xcolourtrans_set_gcol(style->fill_colour << 8,
+ colourtrans_USE_ECFS_GCOL,
+ os_ACTION_OVERWRITE, 0, 0);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
+ }
- if (width < 1)
- width = 1;
+ error = xos_plot(os_MOVE_TO,
+ ro_plot_origin_x + rect->x0 * 2,
+ ro_plot_origin_y - rect->y0 * 2 - 1);
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
+ }
- if (ro_plot_patterned_lines) {
- if (dotted) {
- dash.elements[0] = 512 * width;
- dash_pattern = &dash;
- } else if (dashed) {
- dash.elements[0] = 1536 * width;
- dash_pattern = &dash;
+ error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO,
+ ro_plot_origin_x + rect->x1 * 2 - 1,
+ ro_plot_origin_y - rect->y1 * 2);
+ if (error) {
+ NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
}
}
- error = xcolourtrans_set_gcol(c << 8, 0, os_ACTION_OVERWRITE, 0, 0);
- if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ bool dotted = false;
+ bool dashed = false;
- error = xdraw_stroke(path, 0, 0, 0, width * 2 * 256,
- &line_style, dash_pattern);
- if (error) {
- LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ const int path[] = {
+ draw_MOVE_TO,
+ (ro_plot_origin_x + rect->x0 * 2) * 256,
+ (ro_plot_origin_y - rect->y0 * 2 - 1) * 256,
+ draw_LINE_TO,
+ (ro_plot_origin_x + (rect->x1) * 2) * 256,
+ (ro_plot_origin_y - rect->y0 * 2 - 1) * 256,
+ draw_LINE_TO,
+ (ro_plot_origin_x + (rect->x1) * 2) * 256,
+ (ro_plot_origin_y - (rect->y1) * 2 - 1) * 256,
+ draw_LINE_TO,
+ (ro_plot_origin_x + rect->x0 * 2) * 256,
+ (ro_plot_origin_y - (rect->y1) * 2 - 1) * 256,
+ draw_CLOSE_LINE,
+ (ro_plot_origin_x + rect->x0 * 2) * 256,
+ (ro_plot_origin_y - rect->y0 * 2 - 1) * 256,
+ draw_END_PATH
+ };
+
+ if (style->stroke_type == PLOT_OP_TYPE_DOT)
+ dotted = true;
+
+ if (style->stroke_type == PLOT_OP_TYPE_DASH)
+ dashed = true;
+
+ ro_plot_draw_path((const draw_path *)path,
+ plot_style_fixed_to_int(style->stroke_width),
+ style->stroke_colour,
+ dotted,
+ dashed);
}
- return true;
+ return NSERROR_OK;
}
-bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
int path[n * 3 + 2];
unsigned int i;
@@ -225,43 +455,68 @@ bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
path[n * 3] = draw_END_PATH;
path[n * 3 + 1] = 0;
- error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, os_ACTION_OVERWRITE, 0, 0);
+ error = xcolourtrans_set_gcol(style->fill_colour << 8,
+ 0, os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO, "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum, error->errmess);
+ return NSERROR_INVALID;
}
error = xdraw_fill((draw_path *) path, 0, 0, 0);
if (error) {
- LOG("xdraw_fill: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO, "xdraw_fill: 0x%x: %s", error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
}
- return true;
+ return NSERROR_OK;
}
-bool ro_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
- static const draw_line_style line_style = { draw_JOIN_MITRED,
- draw_CAP_BUTT, draw_CAP_BUTT, 0, 0x7fffffff,
- 0, 0, 0, 0 };
+ static const draw_line_style line_style = {
+ draw_JOIN_MITRED,
+ draw_CAP_BUTT,
+ draw_CAP_BUTT,
+ 0, 0x7fffffff,
+ 0, 0, 0, 0
+ };
int *path = 0;
unsigned int i;
os_trfm trfm;
os_error *error;
- if (n == 0)
- return true;
+ if (n == 0) {
+ return NSERROR_OK;
+ }
if (p[0] != PLOTTER_PATH_MOVE) {
- LOG("path doesn't start with a move");
+ NSLOG(netsurf, INFO, "path doesn't start with a move");
goto error;
}
path = malloc(sizeof *path * (n + 10));
if (!path) {
- LOG("out of memory");
+ NSLOG(netsurf, INFO, "out of memory");
goto error;
}
@@ -289,7 +544,7 @@ bool ro_plot_path(const float *p, unsigned int n, colour fill, float width,
path[i + 6] = -p[i + 6] * 2 * 256;
i += 7;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
goto error;
}
}
@@ -303,222 +558,167 @@ bool ro_plot_path(const float *p, unsigned int n, colour fill, float width,
trfm.entries[2][0] = (ro_plot_origin_x + transform[4] * 2) * 256;
trfm.entries[2][1] = (ro_plot_origin_y - transform[5] * 2) * 256;
- if (fill != NS_TRANSPARENT) {
- error = xcolourtrans_set_gcol(fill << 8, 0,
+ if (pstyle->fill_colour != NS_TRANSPARENT) {
+ error = xcolourtrans_set_gcol(pstyle->fill_colour << 8, 0,
os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
goto error;
}
error = xdraw_fill((draw_path *) path, 0, &trfm, 0);
if (error) {
- LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xdraw_stroke: 0x%x: %s",
+ error->errnum, error->errmess);
goto error;
}
}
- if (c != NS_TRANSPARENT) {
- error = xcolourtrans_set_gcol(c << 8, 0,
+ if (pstyle->stroke_colour != NS_TRANSPARENT) {
+ error = xcolourtrans_set_gcol(pstyle->stroke_colour << 8, 0,
os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
goto error;
}
error = xdraw_stroke((draw_path *) path, 0, &trfm, 0,
- width * 2 * 256, &line_style, 0);
+ plot_style_fixed_to_int(
+ pstyle->stroke_width) * 2 * 256,
+ &line_style, 0);
if (error) {
- LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xdraw_stroke: 0x%x: %s",
+ error->errnum, error->errmess);
goto error;
}
}
free(path);
- return true;
+ return NSERROR_OK;
error:
free(path);
- return false;
+ return NSERROR_INVALID;
}
-
-
-bool ro_plot_clip(const struct rect *clip)
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
- os_error *error;
- char buf[12];
-
- int clip_x0 = ro_plot_origin_x + clip->x0 * 2;
- int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1;
- int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1;
- int clip_y1 = ro_plot_origin_y - clip->y1 * 2;
+ const uint8_t *buffer;
- if (clip_x1 < clip_x0 || clip_y0 < clip_y1) {
- LOG("bad clip rectangle %i %i %i %i", clip_x0, clip_y0, clip_x1, clip_y1);
- return false;
+ buffer = riscos_bitmap_get_buffer(bitmap);
+ if (!buffer) {
+ NSLOG(netsurf, INFO, "bitmap_get_buffer failed");
+ return NSERROR_INVALID;
}
- buf[0] = os_VDU_SET_GRAPHICS_WINDOW;
- buf[1] = clip_x0;
- buf[2] = clip_x0 >> 8;
- buf[3] = clip_y1;
- buf[4] = clip_y1 >> 8;
- buf[5] = clip_x1;
- buf[6] = clip_x1 >> 8;
- buf[7] = clip_y0;
- buf[8] = clip_y0 >> 8;
-
- error = xos_writen(buf, 9);
- if (error) {
- LOG("xos_writen: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ if (!image_redraw(bitmap->sprite_area,
+ ro_plot_origin_x + x * 2,
+ ro_plot_origin_y - y * 2,
+ width, height,
+ bitmap->width,
+ bitmap->height,
+ bg,
+ flags & BITMAPF_REPEAT_X, flags & BITMAPF_REPEAT_Y,
+ flags & BITMAPF_REPEAT_X || flags & BITMAPF_REPEAT_Y,
+ riscos_bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE :
+ IMAGE_PLOT_TINCT_ALPHA)) {
+ return NSERROR_INVALID;
}
-
- return true;
+ return NSERROR_OK;
}
-bool ro_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
os_error *error;
error = xcolourtrans_set_font_colours(font_CURRENT,
- fstyle->background << 8, fstyle->foreground << 8,
+ fstyle->background << 8, fstyle->foreground << 8,
14, 0, 0, 0);
if (error) {
- LOG("xcolourtrans_set_font_colours: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_font_colours: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ return NSERROR_INVALID;
}
- return nsfont_paint(fstyle, text, length,
+ if (!nsfont_paint(fstyle, text, length,
ro_plot_origin_x + x * 2,
- ro_plot_origin_y - y * 2);
-}
-
-
-bool ro_plot_disc(int x, int y, int radius, const plot_style_t *style)
-{
- os_error *error;
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
- error = xcolourtrans_set_gcol(style->fill_colour << 8, 0,
- os_ACTION_OVERWRITE, 0, 0);
- if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- error = xos_plot(os_MOVE_TO,
- ro_plot_origin_x + x * 2,
- ro_plot_origin_y - y * 2);
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- error = xos_plot(os_PLOT_CIRCLE | os_PLOT_BY, radius * 2, 0);
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- }
-
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
-
- error = xcolourtrans_set_gcol(style->stroke_colour << 8, 0,
- os_ACTION_OVERWRITE, 0, 0);
- if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- error = xos_plot(os_MOVE_TO,
- ro_plot_origin_x + x * 2,
- ro_plot_origin_y - y * 2);
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- error = xos_plot(os_PLOT_CIRCLE_OUTLINE | os_PLOT_BY,
- radius * 2, 0);
-
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
- }
- return true;
-}
-
-bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
-{
- os_error *error;
- int sx, sy, ex, ey;
- double t;
-
- x = ro_plot_origin_x + x * 2;
- y = ro_plot_origin_y - y * 2;
- radius <<= 1;
-
- error = xcolourtrans_set_gcol(style->fill_colour << 8, 0,
- os_ACTION_OVERWRITE, 0, 0);
-
- if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
- return false;
+ ro_plot_origin_y - y * 2)) {
+ return NSERROR_INVALID;
}
-
- t = ((double)angle1 * M_PI) / 180.0;
- sx = (x + (int)(radius * cos(t)));
- sy = (y + (int)(radius * sin(t)));
-
- t = ((double)angle2 * M_PI) / 180.0;
- ex = (x + (int)(radius * cos(t)));
- ey = (y + (int)(radius * sin(t)));
-
- error = xos_plot(os_MOVE_TO, x, y); /* move to centre */
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
-
- error = xos_plot(os_MOVE_TO, sx, sy); /* move to start */
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
-
- error = xos_plot(os_PLOT_ARC | os_PLOT_TO, ex, ey); /* arc to end */
- if (error) {
- LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess);
- return false;
- }
-
- return true;
+ return NSERROR_OK;
}
-
-bool ro_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
-{
- const uint8_t *buffer;
-
- buffer = riscos_bitmap_get_buffer(bitmap);
- if (!buffer) {
- LOG("bitmap_get_buffer failed");
- return false;
- }
-
- return image_redraw(bitmap->sprite_area,
- ro_plot_origin_x + x * 2,
- ro_plot_origin_y - y * 2,
- width, height,
- bitmap->width,
- bitmap->height,
- bg,
- flags & BITMAPF_REPEAT_X, flags & BITMAPF_REPEAT_Y,
- flags & BITMAPF_REPEAT_X || flags & BITMAPF_REPEAT_Y,
- riscos_bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE :
- IMAGE_PLOT_TINCT_ALPHA);
-}
+/**
+ * RISC OS plotter operation table
+ */
+const struct plotter_table ro_plotters = {
+ .rectangle = ro_plot_rectangle,
+ .line = ro_plot_line,
+ .polygon = ro_plot_polygon,
+ .clip = ro_plot_clip,
+ .text = ro_plot_text,
+ .disc = ro_plot_disc,
+ .arc = ro_plot_arc,
+ .bitmap = ro_plot_bitmap,
+ .path = ro_plot_path,
+ .option_knockout = true,
+};
diff --git a/frontends/riscos/print.c b/frontends/riscos/print.c
index 465627eea..b390c693d 100644
--- a/frontends/riscos/print.c
+++ b/frontends/riscos/print.c
@@ -41,6 +41,7 @@
#include "content/content.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/dialog.h"
#include "riscos/menus.h"
#include "riscos/print.h"
@@ -95,7 +96,6 @@ static unsigned int print_fonts_count;
/** Error in print_fonts_plot_text() or print_fonts_callback(). */
static const char *print_fonts_error;
-void gui_window_redraw_window(struct gui_window *g);
static bool ro_gui_print_click(wimp_pointer *pointer);
static bool ro_gui_print_apply(wimp_w w);
@@ -104,39 +104,12 @@ static void print_send_printsave(struct hlcache_handle *h);
static bool print_send_printtypeknown(wimp_message *m);
static bool print_document(struct gui_window *g, const char *filename);
static const char *print_declare_fonts(struct hlcache_handle *h);
-static bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
-static bool print_fonts_plot_clip(const struct rect *clip);
-static bool print_fonts_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
-static bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style);
-static bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style);
-static bool print_fonts_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags);
-static bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6]);
static void print_fonts_callback(void *context,
const char *font_name, unsigned int font_size,
const char *s8, unsigned short *s16, unsigned int n,
int x, int y);
-/** Plotter for print_declare_fonts(). All the functions do nothing except for
- * print_fonts_plot_text, which records the fonts used. */
-static const struct plotter_table print_fonts_plotters = {
- .rectangle = print_fonts_plot_rectangle,
- .line = print_fonts_plot_line,
- .polygon = print_fonts_plot_polygon,
- .clip = print_fonts_plot_clip,
- .text = print_fonts_plot_text,
- .disc = print_fonts_plot_disc,
- .arc = print_fonts_plot_arc,
- .bitmap = print_fonts_plot_bitmap,
- .path = print_fonts_plot_path,
- .option_knockout = false,
-};
/**
@@ -196,7 +169,8 @@ void ro_gui_print_prepare(struct gui_window *g)
/* Read Printer Driver name */
error = xpdriver_info(0, 0, 0, 0, &desc, 0, 0, 0);
if (error) {
- LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
+ error->errnum, error->errmess);
printers_exists = false;
}
@@ -333,7 +307,8 @@ void print_send_printsave(struct hlcache_handle *h)
e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED,
(wimp_message *)&m, 0);
if (e) {
- LOG("xwimp_send_message: 0x%x: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ e->errnum, e->errmess);
ro_warn_user("WimpError", e->errmess);
ro_print_cleanup();
}
@@ -357,7 +332,8 @@ bool print_send_printtypeknown(wimp_message *m)
m->action = message_PRINT_TYPE_KNOWN;
e = xwimp_send_message(wimp_USER_MESSAGE, m, m->sender);
if (e) {
- LOG("xwimp_send_message: 0x%x: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ e->errnum, e->errmess);
ro_warn_user("WimpError", e->errmess);
return false;
}
@@ -463,7 +439,8 @@ bool ro_print_ack(wimp_message *m)
/* read printer driver type */
error = xpdriver_info(&info_type, 0, 0, 0, 0, 0, 0, 0);
if (error) {
- LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
ro_print_cleanup();
return true;
@@ -488,7 +465,8 @@ bool ro_print_ack(wimp_message *m)
error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, m, m->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
/* and delete temporary file */
xosfile_delete(m->data.data_xfer.file_name,
@@ -560,7 +538,8 @@ bool print_document(struct gui_window *g, const char *filename)
/* read printer driver features */
error = xpdriver_info(0, 0, 0, &features, 0, 0, 0, 0);
if (error) {
- LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
return false;
}
@@ -568,7 +547,8 @@ bool print_document(struct gui_window *g, const char *filename)
/* read page size */
error = xpdriver_page_size(0, 0, &left, &bottom, &right, &top);
if (error) {
- LOG("xpdriver_page_size: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_page_size: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
return false;
}
@@ -591,7 +571,8 @@ bool print_document(struct gui_window *g, const char *filename)
error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR |
osfind_ERROR_IF_ABSENT, filename, 0, &fhandle);
if (error) {
- LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openoutw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
return false;
}
@@ -599,7 +580,8 @@ bool print_document(struct gui_window *g, const char *filename)
/* select print job */
error = xpdriver_select_jobw(fhandle, "NetSurf", &old_job);
if (error) {
- LOG("xpdriver_select_jobw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_select_jobw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
xosfind_closew(fhandle);
return false;
@@ -659,18 +641,23 @@ bool print_document(struct gui_window *g, const char *filename)
/* give page rectangle */
error = xpdriver_give_rectangle(0, &b, &t, &p, os_COLOUR_WHITE);
if (error) {
- LOG("xpdriver_give_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xpdriver_give_rectangle: 0x%x: %s",
+ error->errnum,
+ error->errmess);
error_message = error->errmess;
goto error;
}
- LOG("given rectangle: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1);
+ NSLOG(netsurf, INFO, "given rectangle: [(%d, %d), (%d, %d)]",
+ b.x0, b.y0, b.x1, b.y1);
/* and redraw the document */
error = xpdriver_draw_page(print_num_copies, &b, 0, 0,
&more, 0);
if (error) {
- LOG("xpdriver_draw_page: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_draw_page: 0x%x: %s",
+ error->errnum, error->errmess);
error_message = error->errmess;
goto error;
}
@@ -684,7 +671,9 @@ bool print_document(struct gui_window *g, const char *filename)
.plot = &ro_plotters
};
- LOG("redrawing area: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1);
+ NSLOG(netsurf, INFO,
+ "redrawing area: [(%d, %d), (%d, %d)]", b.x0,
+ b.y0, b.x1, b.y1);
clip.x0 = (b.x0 - ro_plot_origin_x) / 2;
clip.y0 = (ro_plot_origin_y - b.y1) / 2;
clip.x1 = (b.x1 - ro_plot_origin_x) / 2;
@@ -706,7 +695,10 @@ bool print_document(struct gui_window *g, const char *filename)
error = xpdriver_get_rectangle(&b, &more, 0);
if (error) {
- LOG("xpdriver_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xpdriver_get_rectangle: 0x%x: %s",
+ error->errnum,
+ error->errmess);
error_message = error->errmess;
goto error;
}
@@ -728,14 +720,16 @@ bool print_document(struct gui_window *g, const char *filename)
error = (os_error *) _swix(PDriver_EndJob, _IN(0), (int) fhandle);
if (error) {
- LOG("xpdriver_end_jobw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_end_jobw: 0x%x: %s",
+ error->errnum, error->errmess);
error_message = error->errmess;
goto error;
}
error = xosfind_closew(fhandle);
if (error) {
- LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("PrintError", error->errmess);
return false;
}
@@ -743,7 +737,10 @@ bool print_document(struct gui_window *g, const char *filename)
if (old_job) {
error = xpdriver_select_jobw(old_job, 0, 0);
if (error) {
- LOG("xpdriver_select_jobw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xpdriver_select_jobw: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("PrintError", error->errmess);
/* the printing succeeded anyway */
return true;
@@ -756,7 +753,7 @@ bool print_document(struct gui_window *g, const char *filename)
if (content_get_type(h) == CONTENT_HTML)
content_reformat(h, false, saved_width, saved_height);
- gui_window_redraw_window(g);
+ ro_gui_window_invalidate_area(g, NULL);
return true;
@@ -780,6 +777,145 @@ error:
}
+
+
+static nserror
+print_fonts_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
+{
+ return NSERROR_OK;
+}
+
+static nserror
+print_fonts_plot_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
+{
+ return NSERROR_OK;
+}
+
+/**
+ * text plotting during RO print font listing.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+print_fonts_plot_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
+{
+ const char *font_family;
+ unsigned int font_size;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+
+ code = rufl_paint_callback(font_family, font_style, font_size,
+ text, length, 0, 0, print_fonts_callback, 0);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR) {
+ NSLOG(netsurf, INFO,
+ "rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
+ print_fonts_error = rufl_fm_error->errmess;
+ } else {
+ NSLOG(netsurf, INFO, "rufl_paint_callback: 0x%x",
+ code);
+ }
+ return NSERROR_INVALID;
+ }
+ if (print_fonts_error)
+ return NSERROR_INVALID;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plotter table for print_declare_fonts().
+ *
+ * All the functions do nothing except for print_fonts_plot_text,
+ * which records the fonts used.
+*/
+static const struct plotter_table print_fonts_plotters = {
+ .rectangle = print_fonts_plot_rectangle,
+ .line = print_fonts_plot_line,
+ .polygon = print_fonts_plot_polygon,
+ .clip = print_fonts_plot_clip,
+ .text = print_fonts_plot_text,
+ .disc = print_fonts_plot_disc,
+ .arc = print_fonts_plot_arc,
+ .bitmap = print_fonts_plot_bitmap,
+ .path = print_fonts_plot_path,
+ .option_knockout = false,
+};
+
+
/**
* Declare fonts to the printer driver.
*
@@ -824,18 +960,22 @@ const char *print_declare_fonts(struct hlcache_handle *h)
}
for (i = 0; i != print_fonts_count; ++i) {
- LOG("%u %s", i, print_fonts_list[i]);
+ NSLOG(netsurf, INFO, "%u %s", i, print_fonts_list[i]);
error = xpdriver_declare_font(0, print_fonts_list[i],
pdriver_KERNED);
if (error) {
- LOG("xpdriver_declare_font: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xpdriver_declare_font: 0x%x: %s",
+ error->errnum,
+ error->errmess);
error_message = error->errmess;
goto end;
}
}
error = xpdriver_declare_font(0, 0, 0);
if (error) {
- LOG("xpdriver_declare_font: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xpdriver_declare_font: 0x%x: %s",
+ error->errnum, error->errmess);
error_message = error->errmess;
goto end;
}
@@ -850,84 +990,6 @@ end:
}
-bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- return true;
-}
-
-
-bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- return true;
-}
-
-bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
-{
- return true;
-}
-
-
-bool print_fonts_plot_clip(const struct rect *clip)
-{
- return true;
-}
-
-bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style)
-{
- return true;
-}
-
-bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style)
-{
- return true;
-}
-
-bool print_fonts_plot_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg, bitmap_flags_t flags)
-{
- return true;
-}
-
-bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- return true;
-}
-
-
-/**
- * Plotter for text plotting during font listing.
- */
-
-bool print_fonts_plot_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
-{
- const char *font_family;
- unsigned int font_size;
- rufl_style font_style;
- rufl_code code;
-
- nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
-
- code = rufl_paint_callback(font_family, font_style, font_size,
- text, length, 0, 0, print_fonts_callback, 0);
- if (code != rufl_OK) {
- if (code == rufl_FONT_MANAGER_ERROR) {
- LOG("rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
- print_fonts_error = rufl_fm_error->errmess;
- } else {
- LOG("rufl_paint_callback: 0x%x", code);
- }
- return false;
- }
- if (print_fonts_error)
- return false;
-
- return true;
-}
-
-
/**
* Callback for print_fonts_plot_text().
*
diff --git a/frontends/riscos/query.c b/frontends/riscos/query.c
index 1d7cf5120..49aea6321 100644
--- a/frontends/riscos/query.c
+++ b/frontends/riscos/query.c
@@ -175,7 +175,7 @@ query_id query_user_xy(const char *query, const char *detail,
err = utf8_to_local_encoding(yes, 0, &local_text);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_local_encoding_failed");
+ NSLOG(netsurf, INFO, "utf8_to_local_encoding_failed");
local_text = NULL;
}
@@ -191,7 +191,8 @@ query_id query_user_xy(const char *query, const char *detail,
error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
if (error) {
- LOG("xwimptextop_string_width: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimptextop_string_width: 0x%x:%s",
+ error->errnum, error->errmess);
width = len * 16;
}
if (!query_yes_width) query_yes_width = icn->extent.x1 - icn->extent.x0;
@@ -204,7 +205,7 @@ query_id query_user_xy(const char *query, const char *detail,
err = utf8_to_local_encoding(no, 0, &local_text);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_local_encoding_failed");
+ NSLOG(netsurf, INFO, "utf8_to_local_encoding_failed");
local_text = NULL;
}
@@ -222,7 +223,8 @@ query_id query_user_xy(const char *query, const char *detail,
icn->extent.x1 = tx - 16;
error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
if (error) {
- LOG("xwimptextop_string_width: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimptextop_string_width: 0x%x:%s",
+ error->errnum, error->errmess);
width = len * 16;
}
width += 28;
@@ -263,7 +265,8 @@ query_id query_user_xy(const char *query, const char *detail,
error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -307,7 +310,10 @@ void ro_gui_query_window_bring_to_front(query_id id)
error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_caret_position: 0x%x : %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -327,7 +333,8 @@ void ro_gui_query_close(wimp_w w)
ro_gui_dialog_close(w);
error = xwimp_delete_window(qw->window);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
ro_gui_wimp_event_finalise(w);
diff --git a/frontends/riscos/save.c b/frontends/riscos/save.c
index 37474b85c..76ce6d3e5 100644
--- a/frontends/riscos/save.c
+++ b/frontends/riscos/save.c
@@ -56,6 +56,7 @@
#include "riscos/bitmap.h"
#include "riscos/dialog.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/menus.h"
#include "riscos/message.h"
#include "riscos/mouse.h"
@@ -165,7 +166,8 @@ wimp_w ro_gui_saveas_create(const char *template_name)
error = xosmodule_alloc(area_size, (void **) &area);
if (error) {
- LOG("xosmodule_alloc: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosmodule_alloc: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
} else {
@@ -175,7 +177,10 @@ wimp_w ro_gui_saveas_create(const char *template_name)
error = xosspriteop_clear_sprites(osspriteop_USER_AREA, saveas_area);
if (error) {
- LOG("xosspriteop_clear_sprites: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_clear_sprites: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
xosmodule_free(saveas_area);
@@ -191,7 +196,8 @@ wimp_w ro_gui_saveas_create(const char *template_name)
/* create window */
error = xwimp_create_window(window, &w);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
xwimp_close_template();
die(error->errmess);
}
@@ -211,7 +217,8 @@ void ro_gui_saveas_quit(void)
if (saveas_area) {
os_error *error = xosmodule_free(saveas_area);
if (error) {
- LOG("xosmodule_free: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosmodule_free: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
}
saveas_area = NULL;
@@ -238,14 +245,14 @@ ro_gui_save_create_thumbnail(struct hlcache_handle *h, const char *name)
bitmap = riscos_bitmap_create(34, 34, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY);
if (!bitmap) {
- LOG("Thumbnail initialisation failed.");
+ NSLOG(netsurf, INFO, "Thumbnail initialisation failed.");
return false;
}
riscos_bitmap_render(bitmap, h);
area = riscos_bitmap_convert_8bpp(bitmap);
riscos_bitmap_destroy(bitmap);
if (!area) {
- LOG("Thumbnail conversion failed.");
+ NSLOG(netsurf, INFO, "Thumbnail conversion failed.");
return false;
}
@@ -390,7 +397,10 @@ ro_gui_save_set_state(struct hlcache_handle *h, gui_save_type save_type,
}
if (error) {
- LOG("ro_gui_wimp_get_sprite: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "ro_gui_wimp_get_sprite: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
} else {
/* the sprite area should always be large enough for
@@ -500,7 +510,8 @@ static void ro_gui_save_drag_end(wimp_dragged *drag, void *data)
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -626,7 +637,8 @@ static void ro_gui_save_done(void)
error = xwimp_send_message(wimp_USER_MESSAGE, message,
message->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
}
}
@@ -666,7 +678,10 @@ static void ro_gui_save_done(void)
ro_gui_dialog_close(dialog_saveas);
error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0);
if (error) {
- LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_create_menu: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MenuError", error->errmess);
}
}
@@ -769,8 +784,8 @@ static void ro_gui_save_set_file_type(const char *path, lwc_string *mime_type)
error = xosfile_set_type(path, rotype);
if (error != NULL) {
- LOG("xosfile_set_type: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
@@ -797,7 +812,8 @@ static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
/* Create dir */
error = xosfile_create_dir(path, 0);
if (error) {
- LOG("xosfile_create_dir: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_create_dir: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -806,7 +822,7 @@ static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
snprintf(buf, sizeof buf, "%s.!Run", path);
fp = fopen(buf, "w");
if (!fp) {
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
ro_warn_user("SaveError", strerror(errno));
return false;
}
@@ -815,7 +831,8 @@ static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
fclose(fp);
error = xosfile_set_type(buf, 0xfeb);
if (error) {
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -824,7 +841,8 @@ static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
snprintf(buf, sizeof buf, "%s.!RunImage", path);
fp = fopen(buf, "w");
if (!fp) {
- LOG("Creating !RunImage failed: errno = %i", errno);
+ NSLOG(netsurf, INFO, "Creating !RunImage failed: errno = %i",
+ errno);
} else {
fclose(fp);
}
@@ -850,7 +868,10 @@ static bool ro_gui_save_complete(struct hlcache_handle *h, char *path)
error = xosspriteop_save_sprite_file(osspriteop_NAME, saveas_area, buf);
if (error) {
- LOG("xosspriteop_save_sprite_file: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_save_sprite_file: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -896,7 +917,10 @@ static bool ro_gui_save_object_native(struct hlcache_handle *h, char *path)
(byte *) source_data,
(byte *) source_data + source_size);
if (error != NULL) {
- LOG("xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_save_stamped: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -946,7 +970,8 @@ ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
error = xosfile_read_stamped(path, &obj_type,
NULL, NULL, NULL, NULL, NULL);
if (error) {
- LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_read_stamped: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -1002,7 +1027,10 @@ ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
(byte *) source_data,
(byte *) source_data + source_size);
if (error) {
- LOG("xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_save_stamped: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -1028,14 +1056,20 @@ ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
return false;
error = xosfile_set_type(path, 0xfaf);
if (error)
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_set_type: 0x%x: %s",
+ error->errnum,
+ error->errmess);
break;
case GUI_SAVE_HISTORY_EXPORT_HTML:
if (global_history_export(path, NULL) != NSERROR_OK)
return false;
error = xosfile_set_type(path, 0xfaf);
if (error)
- LOG("xosfile_set_type: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_set_type: 0x%x: %s",
+ error->errnum,
+ error->errmess);
break;
case GUI_SAVE_TEXT_SELECTION:
@@ -1055,7 +1089,10 @@ ro_gui_save_content(struct hlcache_handle *h, char *path, bool force_overwrite)
return ro_gui_save_clipboard(path);
default:
- LOG("Unexpected content type: %d, path %s", gui_save_current_type, path);
+ NSLOG(netsurf, INFO,
+ "Unexpected content type: %d, path %s",
+ gui_save_current_type,
+ path);
return false;
}
return true;
@@ -1120,7 +1157,8 @@ void gui_drag_save_object(struct gui_window *g,
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1157,7 +1195,8 @@ void gui_drag_save_selection(struct gui_window *g, const char *selection)
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1209,8 +1248,8 @@ void ro_gui_drag_save_link(gui_save_type save_type, const nsurl *url,
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1251,7 +1290,10 @@ void ro_gui_drag_icon(int x, int y, const char *sprite)
saveas_area, (osspriteop_id)sprite, NULL);
if (error) {
if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) {
- LOG("xosspriteop_select_sprite: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_select_sprite: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
}
}
@@ -1271,7 +1313,8 @@ void ro_gui_drag_icon(int x, int y, const char *sprite)
return;
}
- LOG("xdragasprite_start: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xdragasprite_start: 0x%x: %s",
+ error->errnum, error->errmess);
}
drag.type = wimp_DRAG_USER_FIXED;
@@ -1284,7 +1327,8 @@ void ro_gui_drag_icon(int x, int y, const char *sprite)
error = xwimp_drag_box(&drag);
if (error) {
- LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("DragError", error->errmess);
} else {
dragbox_active = true;
@@ -1322,14 +1366,20 @@ void ro_gui_drag_box_cancel(void)
if (using_dragasprite) {
error = xdragasprite_stop();
if (error) {
- LOG("xdragasprite_stop: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xdragasprite_stop: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
else {
error = xwimp_drag_box(NULL);
if (error) {
- LOG("xwimp_drag_box: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_drag_box: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -1383,7 +1433,8 @@ void ro_gui_save_datasave_ack(wimp_message *message)
default:
if (!gui_save_content) {
- LOG("unexpected DataSaveAck: gui_save_content not set");
+ NSLOG(netsurf, INFO,
+ "unexpected DataSaveAck: gui_save_content not set");
return;
}
break;
diff --git a/frontends/riscos/save_draw.c b/frontends/riscos/save_draw.c
index 7e6c9462e..1e67d2d8d 100644
--- a/frontends/riscos/save_draw.c
+++ b/frontends/riscos/save_draw.c
@@ -18,7 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Export a content as a DrawFile (implementation).
*/
@@ -39,38 +40,6 @@
#include "riscos/save_draw.h"
#include "riscos/font.h"
-static bool ro_save_draw_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool ro_save_draw_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
-static bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *style);
-static bool ro_save_draw_path(const float *p, unsigned int n, colour fill,
- float width, colour c, const float transform[6]);
-static bool ro_save_draw_clip(const struct rect *clip);
-static bool ro_save_draw_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
-static bool ro_save_draw_disc(int x, int y, int radius, const plot_style_t *style);
-static bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style);
-static bool ro_save_draw_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg, bitmap_flags_t flags);
-static bool ro_save_draw_group_start(const char *name);
-static bool ro_save_draw_group_end(void);
-static bool ro_save_draw_error(pencil_code code);
-
-
-static const struct plotter_table ro_save_draw_plotters = {
- .rectangle = ro_save_draw_rectangle,
- .line = ro_save_draw_line,
- .polygon = ro_save_draw_polygon,
- .clip = ro_save_draw_clip,
- .text = ro_save_draw_text,
- .disc = ro_save_draw_disc,
- .arc = ro_save_draw_arc,
- .bitmap = ro_save_draw_bitmap,
- .group_start = ro_save_draw_group_start,
- .group_end = ro_save_draw_group_end,
- .path = ro_save_draw_path,
- .option_knockout = false,
-};
static struct pencil_diagram *ro_save_draw_diagram;
static int ro_save_draw_width;
@@ -78,157 +47,229 @@ static int ro_save_draw_height;
/**
- * Export a content as a DrawFile.
+ * Report an error from pencil.
*
- * \param h content to export
- * \param path path to save DrawFile as
- * \return true on success, false on error and error reported
+ * \param code error code
+ * \return false
*/
-
-bool save_as_draw(struct hlcache_handle *h, const char *path)
+static nserror ro_save_draw_error(pencil_code code)
{
- pencil_code code;
- char *drawfile_buffer;
- struct rect clip;
- struct content_redraw_data data;
- size_t drawfile_size;
- os_error *error;
- struct redraw_context ctx = {
- .interactive = false,
- .background_images = true,
- .plot = &ro_save_draw_plotters
- };
+ NSLOG(netsurf, INFO, "code %i", code);
- ro_save_draw_diagram = pencil_create();
- if (!ro_save_draw_diagram) {
+ switch (code) {
+ case pencil_OK:
+ assert(0);
+ break;
+
+ case pencil_OUT_OF_MEMORY:
ro_warn_user("NoMemory", 0);
- return false;
+ break;
+
+ case pencil_FONT_MANAGER_ERROR:
+ ro_warn_user("SaveError", rufl_fm_error->errmess);
+ break;
+
+ case pencil_FONT_NOT_FOUND:
+ case pencil_IO_ERROR:
+ case pencil_IO_EOF:
+ ro_warn_user("SaveError", "generating the DrawFile failed");
+ break;
}
- ro_save_draw_width = content_get_width(h);
- ro_save_draw_height = content_get_height(h);
+ return NSERROR_INVALID;
+}
- clip.x0 = clip.y0 = INT_MIN;
- clip.x1 = clip.y1 = INT_MAX;
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ return NSERROR_OK;
+}
- data.x = 0;
- data.y = -ro_save_draw_height;
- data.width = ro_save_draw_width;
- data.height = ro_save_draw_height;
- data.background_colour = 0xFFFFFF;
- data.scale = 1;
- data.repeat_x = false;
- data.repeat_y = false;
- if (!content_redraw(h, &data, &clip, &ctx)) {
- pencil_free(ro_save_draw_diagram);
- return false;
- }
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius, int angle1, int angle2)
+{
+ return NSERROR_OK;
+}
- /*pencil_dump(ro_save_draw_diagram);*/
- code = pencil_save_drawfile(ro_save_draw_diagram, "NetSurf",
- &drawfile_buffer, &drawfile_size);
- if (code != pencil_OK) {
- ro_warn_user("SaveError", 0);
- pencil_free(ro_save_draw_diagram);
- return false;
- }
- assert(drawfile_buffer);
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the circle plot.
+ * \param x The x coordinate of the circle.
+ * \param y The y coordinate of the circle.
+ * \param radius The radius of the circle.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ return NSERROR_OK;
+}
- error = xosfile_save_stamped(path, osfile_TYPE_DRAW,
- (byte *) drawfile_buffer,
- (byte *) drawfile_buffer + drawfile_size);
- if (error) {
- LOG("xosfile_save_stamped failed: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("SaveError", error->errmess);
- pencil_free(ro_save_draw_diagram);
- return false;
- }
- pencil_free(ro_save_draw_diagram);
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
+{
+ pencil_code code;
+ const int path[] = {
+ draw_MOVE_TO, line->x0 * 2, -line->y0 * 2 - 1,
+ draw_LINE_TO, line->x1 * 2, -line->y1 * 2 - 1,
+ draw_END_PATH
+ };
- return true;
+ code = pencil_path(ro_save_draw_diagram,
+ path,
+ sizeof path / sizeof path[0],
+ pencil_TRANSPARENT,
+ style->stroke_colour << 8,
+ plot_style_fixed_to_int(style->stroke_width),
+ pencil_JOIN_MITRED,
+ pencil_CAP_BUTT,
+ pencil_CAP_BUTT,
+ 0, 0, false,
+ pencil_SOLID);
+ if (code != pencil_OK)
+ return ro_save_draw_error(code);
+
+ return NSERROR_OK;
}
-bool ro_save_draw_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
{
pencil_code code;
- const int path[] = { draw_MOVE_TO, x0 * 2, -y0 * 2 - 1,
- draw_LINE_TO, x1 * 2, -y0 * 2 - 1,
- draw_LINE_TO, x1 * 2, -y1 * 2 - 1,
- draw_LINE_TO, x0 * 2, -y1 * 2 - 1,
- draw_CLOSE_LINE,
- draw_END_PATH };
+ const int path[] = {
+ draw_MOVE_TO, rect->x0 * 2, -rect->y0 * 2 - 1,
+ draw_LINE_TO, rect->x1 * 2, -rect->y0 * 2 - 1,
+ draw_LINE_TO, rect->x1 * 2, -rect->y1 * 2 - 1,
+ draw_LINE_TO, rect->x0 * 2, -rect->y1 * 2 - 1,
+ draw_CLOSE_LINE,
+ draw_END_PATH
+ };
- if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
- code = pencil_path(ro_save_draw_diagram,
+ code = pencil_path(ro_save_draw_diagram,
path,
sizeof path / sizeof path[0],
- style->fill_colour << 8,
- pencil_TRANSPARENT,
- 0,
+ style->fill_colour << 8,
+ pencil_TRANSPARENT,
+ 0,
pencil_JOIN_MITRED,
- pencil_CAP_BUTT,
- pencil_CAP_BUTT,
- 0,
- 0,
+ pencil_CAP_BUTT,
+ pencil_CAP_BUTT,
+ 0,
+ 0,
false,
pencil_SOLID);
if (code != pencil_OK)
return ro_save_draw_error(code);
}
- if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
- code = pencil_path(ro_save_draw_diagram,
+ code = pencil_path(ro_save_draw_diagram,
path,
sizeof path / sizeof path[0],
- pencil_TRANSPARENT,
- style->stroke_colour << 8,
- style->stroke_width,
+ pencil_TRANSPARENT,
+ style->stroke_colour << 8,
+ plot_style_fixed_to_int(style->stroke_width),
pencil_JOIN_MITRED,
- pencil_CAP_BUTT,
- pencil_CAP_BUTT,
- 0,
- 0,
+ pencil_CAP_BUTT,
+ pencil_CAP_BUTT,
+ 0,
+ 0,
false,
pencil_SOLID);
if (code != pencil_OK)
return ro_save_draw_error(code);
}
- return true;
-}
-
-
-bool ro_save_draw_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- pencil_code code;
- const int path[] = { draw_MOVE_TO, x0 * 2, -y0 * 2 - 1,
- draw_LINE_TO, x1 * 2, -y1 * 2 - 1,
- draw_END_PATH };
-
- code = pencil_path(ro_save_draw_diagram,
- path,
- sizeof path / sizeof path[0],
- pencil_TRANSPARENT,
- style->stroke_colour << 8,
- style->stroke_width,
- pencil_JOIN_MITRED,
- pencil_CAP_BUTT,
- pencil_CAP_BUTT,
- 0, 0, false,
- pencil_SOLID);
- if (code != pencil_OK)
- return ro_save_draw_error(code);
-
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *style)
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
{
pencil_code code;
int path[n * 3 + 1];
@@ -242,44 +283,64 @@ bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *styl
path[0] = draw_MOVE_TO;
path[n * 3] = draw_END_PATH;
- code = pencil_path(ro_save_draw_diagram,
+ code = pencil_path(ro_save_draw_diagram,
path, n * 3 + 1,
- style->fill_colour << 8,
- pencil_TRANSPARENT,
- 0,
+ style->fill_colour << 8,
+ pencil_TRANSPARENT,
+ 0,
pencil_JOIN_MITRED,
- pencil_CAP_BUTT,
- pencil_CAP_BUTT,
- 0,
- 0,
+ pencil_CAP_BUTT,
+ pencil_CAP_BUTT,
+ 0,
+ 0,
false,
pencil_SOLID);
if (code != pencil_OK)
return ro_save_draw_error(code);
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_path(const float *p, unsigned int n, colour fill,
- float width, colour c, const float transform[6])
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
{
+ pencil_code code;
+ int *path;
+ unsigned int i;
+ bool empty_path = true;
+
if (n == 0)
- return true;
+ return NSERROR_OK;
if (p[0] != PLOTTER_PATH_MOVE) {
- LOG("path doesn't start with a move");
- return false;
+ NSLOG(netsurf, INFO, "path doesn't start with a move");
+ return NSERROR_INVALID;
}
- int *path = malloc(sizeof *path * (n + 10));
+ path = malloc(sizeof *path * (n + 10));
if (!path) {
- LOG("out of memory");
- return false;
+ NSLOG(netsurf, INFO, "out of memory");
+ return NSERROR_INVALID;
}
- unsigned int i;
- bool empty_path = true;
for (i = 0; i < n; ) {
if (p[i] == PLOTTER_PATH_MOVE) {
path[i] = draw_MOVE_TO;
@@ -326,42 +387,114 @@ bool ro_save_draw_path(const float *p, unsigned int n, colour fill,
i += 7;
empty_path = false;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
free(path);
- return false;
+ return NSERROR_INVALID;
}
}
path[i] = draw_END_PATH;
if (empty_path) {
free(path);
- return true;
+ return NSERROR_OK;
}
- pencil_code code = pencil_path(ro_save_draw_diagram, path, i + 1,
- fill == NS_TRANSPARENT ? pencil_TRANSPARENT : fill << 8,
- c == NS_TRANSPARENT ? pencil_TRANSPARENT : c << 8,
- width, pencil_JOIN_MITRED,
- pencil_CAP_BUTT, pencil_CAP_BUTT, 0, 0, false,
- pencil_SOLID);
+ code = pencil_path(ro_save_draw_diagram,
+ path, i + 1,
+ pstyle->fill_colour == NS_TRANSPARENT ?
+ pencil_TRANSPARENT :
+ pstyle->fill_colour << 8,
+ pstyle->stroke_colour == NS_TRANSPARENT ?
+ pencil_TRANSPARENT :
+ pstyle->stroke_colour << 8,
+ plot_style_fixed_to_int(pstyle->stroke_width),
+ pencil_JOIN_MITRED,
+ pencil_CAP_BUTT,
+ pencil_CAP_BUTT,
+ 0,
+ 0,
+ false,
+ pencil_SOLID);
free(path);
if (code != pencil_OK)
return ro_save_draw_error(code);
- return true;
+ return NSERROR_OK;
}
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
+{
+ pencil_code code;
+ const uint8_t *buffer;
+
+ buffer = riscos_bitmap_get_buffer(bitmap);
+ if (!buffer) {
+ ro_warn_user("NoMemory", 0);
+ return NSERROR_INVALID;
+ }
+ code = pencil_sprite(ro_save_draw_diagram,
+ x * 2, (-y - height) * 2,
+ width * 2, height * 2,
+ ((char *) bitmap->sprite_area) +
+ bitmap->sprite_area->first);
+ if (code != pencil_OK)
+ return ro_save_draw_error(code);
-bool ro_save_draw_clip(const struct rect *clip)
-{
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
pencil_code code;
const char *font_family;
@@ -371,102 +504,135 @@ bool ro_save_draw_text(int x, int y, const char *text, size_t length,
nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
code = pencil_text(ro_save_draw_diagram, x * 2, -y * 2, font_family,
- font_style, font_size, text, length,
+ font_style, font_size, text, length,
fstyle->foreground << 8);
if (code != pencil_OK)
return ro_save_draw_error(code);
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_disc(int x, int y, int radius, const plot_style_t *style)
-{
- return true;
-}
-
-bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style)
-{
- return true;
-}
-
-bool ro_save_draw_bitmap(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg, bitmap_flags_t flags)
+/**
+ * Start of a group of objects.
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_group_start(const struct redraw_context *ctx, const char *name)
{
pencil_code code;
- const uint8_t *buffer;
- buffer = riscos_bitmap_get_buffer(bitmap);
- if (!buffer) {
- ro_warn_user("NoMemory", 0);
- return false;
- }
-
- code = pencil_sprite(ro_save_draw_diagram, x * 2, (-y - height) * 2,
- width * 2, height * 2,
- ((char *) bitmap->sprite_area) +
- bitmap->sprite_area->first);
+ code = pencil_group_start(ro_save_draw_diagram, name);
if (code != pencil_OK)
return ro_save_draw_error(code);
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_group_start(const char *name)
+/**
+ * End of the most recently started group.
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+ro_save_draw_group_end(const struct redraw_context *ctx)
{
pencil_code code;
- code = pencil_group_start(ro_save_draw_diagram, name);
+ code = pencil_group_end(ro_save_draw_diagram);
if (code != pencil_OK)
return ro_save_draw_error(code);
- return true;
+ return NSERROR_OK;
}
-bool ro_save_draw_group_end(void)
+static const struct plotter_table ro_save_draw_plotters = {
+ .rectangle = ro_save_draw_rectangle,
+ .line = ro_save_draw_line,
+ .polygon = ro_save_draw_polygon,
+ .clip = ro_save_draw_clip,
+ .text = ro_save_draw_text,
+ .disc = ro_save_draw_disc,
+ .arc = ro_save_draw_arc,
+ .bitmap = ro_save_draw_bitmap,
+ .group_start = ro_save_draw_group_start,
+ .group_end = ro_save_draw_group_end,
+ .path = ro_save_draw_path,
+ .option_knockout = false,
+};
+
+
+/* exported interface documented in save_draw.h */
+bool save_as_draw(struct hlcache_handle *h, const char *path)
{
pencil_code code;
+ char *drawfile_buffer;
+ struct rect clip;
+ struct content_redraw_data data;
+ size_t drawfile_size;
+ os_error *error;
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = true,
+ .plot = &ro_save_draw_plotters
+ };
- code = pencil_group_end(ro_save_draw_diagram);
- if (code != pencil_OK)
- return ro_save_draw_error(code);
+ ro_save_draw_diagram = pencil_create();
+ if (!ro_save_draw_diagram) {
+ ro_warn_user("NoMemory", 0);
+ return false;
+ }
- return true;
-}
+ ro_save_draw_width = content_get_width(h);
+ ro_save_draw_height = content_get_height(h);
+ clip.x0 = clip.y0 = INT_MIN;
+ clip.x1 = clip.y1 = INT_MAX;
-/**
- * Report an error from pencil.
- *
- * \param code error code
- * \return false
- */
+ data.x = 0;
+ data.y = -ro_save_draw_height;
+ data.width = ro_save_draw_width;
+ data.height = ro_save_draw_height;
+ data.background_colour = 0xFFFFFF;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
-bool ro_save_draw_error(pencil_code code)
-{
- LOG("code %i", code);
+ if (!content_redraw(h, &data, &clip, &ctx)) {
+ pencil_free(ro_save_draw_diagram);
+ return false;
+ }
- switch (code) {
- case pencil_OK:
- assert(0);
- break;
- case pencil_OUT_OF_MEMORY:
- ro_warn_user("NoMemory", 0);
- break;
- case pencil_FONT_MANAGER_ERROR:
- ro_warn_user("SaveError", rufl_fm_error->errmess);
- break;
- case pencil_FONT_NOT_FOUND:
- case pencil_IO_ERROR:
- case pencil_IO_EOF:
- ro_warn_user("SaveError", "generating the DrawFile failed");
- break;
+ /*pencil_dump(ro_save_draw_diagram);*/
+
+ code = pencil_save_drawfile(ro_save_draw_diagram, "NetSurf",
+ &drawfile_buffer, &drawfile_size);
+ if (code != pencil_OK) {
+ ro_warn_user("SaveError", 0);
+ pencil_free(ro_save_draw_diagram);
+ return false;
}
+ assert(drawfile_buffer);
- return false;
+ error = xosfile_save_stamped(path, osfile_TYPE_DRAW,
+ (byte *) drawfile_buffer,
+ (byte *) drawfile_buffer + drawfile_size);
+ if (error) {
+ NSLOG(netsurf, INFO, "xosfile_save_stamped failed: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("SaveError", error->errmess);
+ pencil_free(ro_save_draw_diagram);
+ return false;
+ }
+
+ pencil_free(ro_save_draw_diagram);
+
+ return true;
}
#endif
diff --git a/frontends/riscos/save_draw.h b/frontends/riscos/save_draw.h
index 7ae447790..99662e371 100644
--- a/frontends/riscos/save_draw.h
+++ b/frontends/riscos/save_draw.h
@@ -24,6 +24,13 @@
#include <stdbool.h>
struct hlcache_handle;
+/**
+ * Export a content as a DrawFile.
+ *
+ * \param h content to export
+ * \param path path to save DrawFile as
+ * \return true on success, false on error and error reported
+ */
bool save_as_draw(struct hlcache_handle *h, const char *path);
#endif
diff --git a/frontends/riscos/schedule.c b/frontends/riscos/schedule.c
index 54308b7a9..cb44d906d 100644
--- a/frontends/riscos/schedule.c
+++ b/frontends/riscos/schedule.c
@@ -108,7 +108,7 @@ nserror riscos_schedule(int t, void (*callback)(void *p), void *p)
entry = malloc(sizeof *entry);
if (!entry) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return NSERROR_NOMEM;
}
diff --git a/frontends/riscos/sslcert.c b/frontends/riscos/sslcert.c
index 85b84456e..4d81268f4 100644
--- a/frontends/riscos/sslcert.c
+++ b/frontends/riscos/sslcert.c
@@ -82,14 +82,14 @@ static void ro_gui_cert_release_window(struct ro_cert_window *certw)
error = xwimp_delete_window(certw->wh);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
error = xwimp_delete_window(certw->core.wh);
if (error) {
- LOG("xwimp_delete_window: 0x%x:%s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
+ error->errnum, error->errmess);
}
free(certw);
@@ -165,16 +165,16 @@ static nserror cert_attach_pane(wimp_w parent, wimp_w pane)
winfo.w = pane;
error = xwimp_get_window_info_header_only(&winfo);
if (error) {
- LOG("xwimp_get_window_info: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_info: 0x%x: %s",
+ error->errnum, error->errmess);
return NSERROR_INIT_FAILED;
}
wstate.w = parent;
error = xwimp_get_window_state(&wstate);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return NSERROR_INIT_FAILED;
}
@@ -182,8 +182,8 @@ static nserror cert_attach_pane(wimp_w parent, wimp_w pane)
istate.i = ICON_SSL_PANE;
error = xwimp_get_icon_state(&istate);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
return NSERROR_INIT_FAILED;
}
@@ -211,8 +211,8 @@ static nserror cert_attach_pane(wimp_w parent, wimp_w pane)
if (set_extent) {
error = xwimp_set_extent(pane, &(winfo.extent));
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
return NSERROR_INIT_FAILED;
}
}
@@ -225,8 +225,8 @@ static nserror cert_attach_pane(wimp_w parent, wimp_w pane)
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT << wimp_CHILD_LS_EDGE_SHIFT |
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT << wimp_CHILD_RS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum, error->errmess);
return NSERROR_INIT_FAILED;
}
@@ -336,8 +336,8 @@ gui_cert_verify(nsurl *url,
/* Create the SSL window */
error = xwimp_create_window(dialog_cert_template, &ncwin->wh);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
free(ncwin);
return NSERROR_INIT_FAILED;
}
@@ -345,8 +345,8 @@ gui_cert_verify(nsurl *url,
/* create ssl viewer pane window */
error = xwimp_create_window(cert_tree_template, &ncwin->core.wh);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
free(ncwin);
return NSERROR_INIT_FAILED;
}
diff --git a/frontends/riscos/textarea.c b/frontends/riscos/textarea.c
index d9872927c..6f41c640b 100644
--- a/frontends/riscos/textarea.c
+++ b/frontends/riscos/textarea.c
@@ -138,7 +138,7 @@ uintptr_t ro_textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
ret = malloc(sizeof(struct text_area));
if (!ret) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return 0;
}
@@ -148,7 +148,7 @@ uintptr_t ro_textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
ret->flags = flags;
ret->text = malloc(64);
if (!ret->text) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
free(ret);
return 0;
}
@@ -160,7 +160,7 @@ uintptr_t ro_textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
// ret->selection_end = (unsigned int)-1;
ret->font_family = strdup(font_family ? font_family : "Corpus");
if (!ret->font_family) {
- LOG("strdup failed");
+ NSLOG(netsurf, INFO, "strdup failed");
free(ret->text);
free(ret);
return 0;
@@ -181,7 +181,8 @@ uintptr_t ro_textarea_create(wimp_w parent, wimp_i icon, unsigned int flags,
text_area_definition.title_fg = wimp_COLOUR_BLACK;
error = xwimp_create_window(&text_area_definition, &ret->window);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
free(ret->font_family);
free(ret->text);
free(ret);
@@ -228,7 +229,8 @@ bool ro_textarea_update(uintptr_t self)
state.w = ta->parent;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -236,7 +238,8 @@ bool ro_textarea_update(uintptr_t self)
istate.i = ta->icon;
error = xwimp_get_icon_state(&istate);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -267,7 +270,8 @@ bool ro_textarea_update(uintptr_t self)
error = xwimp_set_extent(ta->window, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -282,7 +286,8 @@ bool ro_textarea_update(uintptr_t self)
wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
<< wimp_CHILD_RS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum, error->errmess);
return false;
}
@@ -307,7 +312,8 @@ void ro_textarea_destroy(uintptr_t self)
error = xwimp_delete_window(ta->window);
if (error) {
- LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
ro_gui_wimp_event_finalise(ta->window);
@@ -331,14 +337,14 @@ bool ro_textarea_set_text(uintptr_t self, const char *text)
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return true;
}
if (len >= ta->text_alloc) {
char *temp = realloc(ta->text, len + 64);
if (!temp) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
ta->text = temp;
@@ -368,7 +374,7 @@ int ro_textarea_get_text(uintptr_t self, char *buf, unsigned int len)
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return -1;
}
@@ -378,7 +384,7 @@ int ro_textarea_get_text(uintptr_t self, char *buf, unsigned int len)
}
if (len < ta->text_len) {
- LOG("buffer too small");
+ NSLOG(netsurf, INFO, "buffer too small");
return -1;
}
@@ -403,7 +409,7 @@ void ro_textarea_insert_text(uintptr_t self, unsigned int index,
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return;
}
@@ -420,7 +426,7 @@ void ro_textarea_insert_text(uintptr_t self, unsigned int index,
if (b_len + ta->text_len >= ta->text_alloc) {
char *temp = realloc(ta->text, b_len + ta->text_len + 64);
if (!temp) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return;
}
@@ -457,7 +463,7 @@ void ro_textarea_replace_text(uintptr_t self, unsigned int start,
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return;
}
@@ -491,7 +497,7 @@ void ro_textarea_replace_text(uintptr_t self, unsigned int start,
char *temp = realloc(ta->text,
b_len + ta->text_len - (b_end - b_start) + 64);
if (!temp) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return;
}
@@ -532,7 +538,7 @@ void ro_textarea_set_caret(uintptr_t self, unsigned int caret)
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return;
}
@@ -574,9 +580,10 @@ void ro_textarea_set_caret(uintptr_t self, unsigned int caret)
b_off - ta->lines[ta->caret_pos.line].b_start, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_width: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO, "rufl_width: 0x%x: %s",
+ rufl_fm_error->errnum, rufl_fm_error->errmess);
else
- LOG("rufl_width: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_width: 0x%x", code);
return;
}
@@ -585,7 +592,8 @@ void ro_textarea_set_caret(uintptr_t self, unsigned int caret)
ta->line_height / 4 + ta->line_spacing,
os_line_height.y, -1);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
@@ -609,7 +617,7 @@ void ro_textarea_set_caret_xy(uintptr_t self, int x, int y)
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return;
}
@@ -623,7 +631,8 @@ void ro_textarea_set_caret_xy(uintptr_t self, int x, int y)
state.w = ta->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -644,9 +653,10 @@ void ro_textarea_set_caret_xy(uintptr_t self, int x, int y)
x, &b_off, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_x_to_offset: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO, "rufl_x_to_offset: 0x%x: %s",
+ rufl_fm_error->errnum, rufl_fm_error->errmess);
else
- LOG("rufl_x_to_offset: 0x%x", code);
+ NSLOG(netsurf, INFO, "rufl_x_to_offset: 0x%x", code);
return;
}
@@ -670,7 +680,7 @@ unsigned int ro_textarea_get_caret(uintptr_t self)
ta = (struct text_area *)self;
if (!ta || ta->magic != MAGIC) {
- LOG("magic doesn't match");
+ NSLOG(netsurf, INFO, "magic doesn't match");
return -1;
}
@@ -711,7 +721,7 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
ta->lines =
malloc(LINE_CHUNK_SIZE * sizeof(struct line_info));
if (!ta->lines) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return;
}
}
@@ -734,9 +744,13 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
&b_off, &x);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_x_to_offset: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_x_to_offset: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_x_to_offset: 0x%x", code);
+ NSLOG(netsurf, INFO,
+ "rufl_x_to_offset: 0x%x", code);
return;
}
@@ -745,7 +759,7 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
(line_count + LINE_CHUNK_SIZE) *
sizeof(struct line_info));
if (!temp) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return;
}
@@ -809,7 +823,8 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
error = xwimp_set_extent(ta->window, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -826,7 +841,10 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
error = xwimp_get_window_state_and_nesting(&state,
&parent, &linkage);
if (error) {
- LOG("xwimp_get_window_state_and_nesting: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state_and_nesting: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
@@ -839,7 +857,10 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
state.w = ta->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
@@ -853,7 +874,10 @@ void ro_textarea_reflow(struct text_area *ta, unsigned int line)
error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
parent, linkage);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
@@ -1009,7 +1033,10 @@ bool ro_textarea_key_press(wimp_key *key)
(wimp_message*)&keypress, ta->parent,
ta->icon, 0);
if (error) {
- LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_send_message: 0x%x:%s",
+ error->errnum,
+ error->errmess);
}
break;
}
@@ -1060,7 +1087,8 @@ void ro_textarea_redraw_internal(wimp_draw *redraw, bool update)
else
error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -1076,13 +1104,17 @@ void ro_textarea_redraw_internal(wimp_draw *redraw, bool update)
colourtrans_SET_BG_GCOL | colourtrans_USE_ECFS_GCOL,
os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
error = xos_clg();
if (error) {
- LOG("xos_clg: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_clg: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
@@ -1113,7 +1145,10 @@ void ro_textarea_redraw_internal(wimp_draw *redraw, bool update)
0xD9D9D900 : 0xFFFFFF00,
0x00000000, 14, 0, 0, 0);
if (error) {
- LOG("xcolourtrans_set_font_colours: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_font_colours: 0x%x: %s",
+ error->errnum,
+ error->errmess);
return;
}
@@ -1128,15 +1163,20 @@ void ro_textarea_redraw_internal(wimp_draw *redraw, bool update)
rufl_BLEND_FONT);
if (code != rufl_OK) {
if (code == rufl_FONT_MANAGER_ERROR)
- LOG("rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ NSLOG(netsurf, INFO,
+ "rufl_paint: rufl_FONT_MANAGER_ERROR: 0x%x: %s",
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
else
- LOG("rufl_paint: 0x%x", code);
+ NSLOG(netsurf, INFO,
+ "rufl_paint: 0x%x", code);
}
}
error = xwimp_get_rectangle(redraw, &more);
if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
@@ -1153,7 +1193,8 @@ void ro_textarea_open(wimp_open *open)
error = xwimp_open_window(open);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
return;
}
}
diff --git a/frontends/riscos/textselection.c b/frontends/riscos/textselection.c
index bce35750f..e5be27791 100644
--- a/frontends/riscos/textselection.c
+++ b/frontends/riscos/textselection.c
@@ -36,6 +36,7 @@
#include "netsurf/browser_window.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/menus.h"
#include "riscos/message.h"
#include "riscos/mouse.h"
@@ -91,12 +92,13 @@ void gui_start_selection(struct gui_window *g)
wimp_drag drag;
os_error *error;
- LOG("starting text_selection drag");
+ NSLOG(netsurf, INFO, "starting text_selection drag");
state.w = g->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -110,7 +112,8 @@ void gui_start_selection(struct gui_window *g)
error = xwimp_send_message(wimp_USER_MESSAGE,
(wimp_message*)&msg, wimp_BROADCAST);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
owns_caret_and_selection = true;
@@ -126,7 +129,8 @@ void gui_start_selection(struct gui_window *g)
wimp_AUTO_SCROLL_ENABLE_HORIZONTAL,
&scroll, 0);
if (error)
- LOG("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess);
ro_mouse_drag_start(ro_gui_selection_drag_end, ro_gui_window_mouse_at,
NULL, g);
@@ -140,7 +144,8 @@ void gui_start_selection(struct gui_window *g)
error = xwimp_drag_box(&drag);
if (error) {
- LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
last_start_window = g;
@@ -165,17 +170,20 @@ static void ro_gui_selection_drag_end(wimp_dragged *drag, void *data)
scroll.w = g->window;
error = xwimp_auto_scroll(0, &scroll, 0);
if (error)
- LOG("xwimp_auto_scroll: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_auto_scroll: 0x%x: %s",
+ error->errnum, error->errmess);
error = xwimp_drag_box((wimp_drag*)-1);
if (error) {
- LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -216,7 +224,7 @@ static void gui_set_clipboard(const char *buffer, size_t length,
wimp_full_message_claim_entity msg;
os_error *error;
- LOG("claiming clipboard");
+ NSLOG(netsurf, INFO, "claiming clipboard");
msg.size = sizeof(msg);
msg.your_ref = 0;
@@ -226,13 +234,14 @@ static void gui_set_clipboard(const char *buffer, size_t length,
error = xwimp_send_message(wimp_USER_MESSAGE,
(wimp_message*)&msg, wimp_BROADCAST);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
owns_clipboard = true;
}
- LOG("clipboard now holds %zd bytes", clip_length);
+ NSLOG(netsurf, INFO, "clipboard now holds %zd bytes", clip_length);
}
@@ -440,7 +449,7 @@ void ro_gui_selection_claim_entity(wimp_full_message_claim_entity *claim)
/* ignore our own broadcasts! */
if (claim->sender != task_handle) {
- LOG("%x", claim->flags);
+ NSLOG(netsurf, INFO, "%x", claim->flags);
if (claim->flags & wimp_CLAIM_CARET_OR_SELECTION) {
owns_caret_and_selection = false;
@@ -473,7 +482,7 @@ void ro_gui_selection_data_request(wimp_full_message_data_request *req)
// bits ftype = req->file_types[i];
// if (ftype == ~0U) break; /* list terminator */
//
-// LOG("type %x", ftype);
+// NSLOG(netsurf, INFO, "type %x", ftype);
// i++;
// }
@@ -523,7 +532,8 @@ bool ro_gui_save_clipboard(const char *path)
free(local_cb);
if (error) {
- LOG("xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_save_stamped: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("SaveError", error->errmess);
return false;
}
@@ -605,7 +615,8 @@ void ro_gui_selection_send_dragging(wimp_pointer *pointer)
{
wimp_full_message_dragging dragmsg;
- LOG("sending DRAGGING to %p, %d", pointer->w, pointer->i);
+ NSLOG(netsurf, INFO, "sending DRAGGING to %p, %d", pointer->w,
+ pointer->i);
dragmsg.size = offsetof(wimp_full_message_dragging, file_types) + 8;
dragmsg.your_ref = 0;
diff --git a/frontends/riscos/theme.c b/frontends/riscos/theme.c
index b0b4ab879..341b7f7cd 100644
--- a/frontends/riscos/theme.c
+++ b/frontends/riscos/theme.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Window themes (implementation).
+/**
+ * \file
+ * Window themes implementation.
*/
#include <alloca.h>
@@ -180,8 +181,10 @@ static void ro_gui_theme_get_available_in_dir(const char *directory)
(osgbpb_info_list *) &info, 1, context,
sizeof(info), 0, &read_count, &context);
if (error) {
- LOG("xosgbpb_dir_entries_info: 0x%x: %s",
- error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosgbpb_dir_entries_info: 0x%x: %s",
+ error->errnum,
+ error->errmess);
if (error->errnum == 0xd6) /* no such dir */
return;
ro_warn_user("MiscError", error->errmess);
@@ -364,7 +367,7 @@ bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname)
/* create a full filename */
filename = malloc(strlen(folder) + strlen(leafname) + 2);
if (!filename) {
- LOG("No memory for malloc");
+ NSLOG(netsurf, INFO, "No memory for malloc");
ro_warn_user("NoMemory", 0);
return false;
}
@@ -374,7 +377,8 @@ bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname)
error = xosfind_openinw(osfind_NO_PATH, filename, 0,
&file_handle);
if (error) {
- LOG("xosfind_openinw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfind_openinw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("FileError", error->errmess);
free(filename);
return false;
@@ -389,7 +393,8 @@ bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname)
0, &output_left);
xosfind_closew(file_handle);
if (error) {
- LOG("xosbgpb_read_atw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosbgpb_read_atw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("FileError", error->errmess);
free(filename);
return false;
@@ -403,7 +408,7 @@ bool ro_gui_theme_add_descriptor(const char *folder, const char *leafname)
current = (struct theme_descriptor *)calloc(1,
sizeof(struct theme_descriptor));
if (!current) {
- LOG("calloc failed");
+ NSLOG(netsurf, INFO, "calloc failed");
ro_warn_user("NoMemory", 0);
free(filename);
return false;
@@ -521,7 +526,7 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
descriptor->theme = (struct theme *)calloc(1,
sizeof(struct theme));
if (!descriptor->theme) {
- LOG("calloc() failed");
+ NSLOG(netsurf, INFO, "calloc() failed");
ro_warn_user("NoMemory", 0);
continue;
}
@@ -531,7 +536,10 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
error = xosfile_read_stamped_no_path(descriptor->filename,
&obj_type, 0, 0, &file_size, 0, 0);
if (error) {
- LOG("xosfile_read_stamped_no_path: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_read_stamped_no_path: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("FileError", error->errmess);
continue;
}
@@ -539,7 +547,7 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
continue;
raw_data = malloc(file_size);
if (!raw_data) {
- LOG("malloc() failed");
+ NSLOG(netsurf, INFO, "malloc() failed");
ro_warn_user("NoMemory", 0);
continue;
}
@@ -547,7 +555,10 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
(byte *)raw_data, 0, 0, 0, 0, 0);
if (error) {
free(raw_data);
- LOG("xosfile_load_stamped_no_path: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_load_stamped_no_path: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("FileError", error->errmess);
continue;
}
@@ -556,7 +567,10 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
error = xsquash_decompress_return_sizes(-1, &workspace_size, 0);
if (error) {
free(raw_data);
- LOG("xsquash_decompress_return_sizes: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xsquash_decompress_return_sizes: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
continue;
}
@@ -566,7 +580,7 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
if ((!decompressed) || (!workspace)) {
free(decompressed);
free(raw_data);
- LOG("malloc() failed");
+ NSLOG(netsurf, INFO, "malloc() failed");
ro_warn_user("NoMemory", 0);
continue;
}
@@ -581,7 +595,8 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
free(raw_data);
if (error) {
free(decompressed);
- LOG("xsquash_decompress: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xsquash_decompress: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
continue;
}
@@ -599,7 +614,10 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
descriptor->theme->sprite_area,
sprite_name, 16, i, 0);
if (error) {
- LOG("xosspriteop_return_name: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_return_name: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
continue;
}
@@ -614,7 +632,10 @@ bool ro_gui_theme_open(struct theme_descriptor *descriptor, bool list)
&dimensions.x, &dimensions.y,
(osbool *) 0, &mode);
if (error) {
- LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_read_sprite_info: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
continue;
}
diff --git a/frontends/riscos/theme_install.c b/frontends/riscos/theme_install.c
index 43ecb4687..fbca9e4fa 100644
--- a/frontends/riscos/theme_install.c
+++ b/frontends/riscos/theme_install.c
@@ -182,7 +182,7 @@ bool ro_gui_theme_install_apply(wimp_w w)
/* convert spaces to hard spaces */
theme_file = strdup(theme_install_descriptor.name);
if (!theme_file) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
ro_warn_user("NoMemory", 0);
return false;
}
@@ -203,7 +203,8 @@ bool ro_gui_theme_install_apply(wimp_w w)
(byte *) source_data,
(byte *) source_data + source_size);
if (error) {
- LOG("xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xosfile_save_stamped: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("ThemeInstallErr", 0);
free(theme_file);
return false;
diff --git a/frontends/riscos/toolbar.c b/frontends/riscos/toolbar.c
index 2b5cb3415..758c90cc2 100644
--- a/frontends/riscos/toolbar.c
+++ b/frontends/riscos/toolbar.c
@@ -227,7 +227,7 @@ struct toolbar *ro_toolbar_create(struct theme_descriptor *descriptor,
toolbar = calloc(sizeof(struct toolbar), 1);
if (toolbar == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
ro_warn_user("NoMemory", 0);
return NULL;
}
@@ -366,7 +366,8 @@ bool ro_toolbar_rebuild(struct toolbar *toolbar)
old_window = toolbar->toolbar_handle;
error = xwimp_delete_window(toolbar->toolbar_handle);
if (error)
- LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess);
toolbar->toolbar_handle = NULL;
}
@@ -375,7 +376,8 @@ bool ro_toolbar_rebuild(struct toolbar *toolbar)
error = xwimp_create_window(&ro_toolbar_window,
&toolbar->toolbar_handle);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -493,7 +495,8 @@ bool ro_toolbar_rebuild(struct toolbar *toolbar)
icon.icon.data.indirected_text.size = 1;
error = xwimp_create_icon(&icon, &toolbar->editor_div1);
if (error) {
- LOG("xwimp_create_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
toolbar->editor_div1 = -1;
}
@@ -558,7 +561,10 @@ bool ro_toolbar_attach(struct toolbar *toolbar, wimp_w parent)
wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
<< wimp_CHILD_TS_EDGE_SHIFT);
if (error) {
- LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_open_window_nested: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -568,7 +574,8 @@ bool ro_toolbar_attach(struct toolbar *toolbar, wimp_w parent)
error = xwimp_close_window(toolbar->toolbar_handle);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -601,7 +608,10 @@ bool ro_toolbar_process(struct toolbar *toolbar, int width, bool reformat)
outline.w = toolbar->parent_handle;
error = xwimp_get_window_outline(&outline);
if (error) {
- LOG("xwimp_get_window_outline: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_outline: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -621,7 +631,10 @@ bool ro_toolbar_process(struct toolbar *toolbar, int width, bool reformat)
state.w = toolbar->parent_handle;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -647,7 +660,10 @@ bool ro_toolbar_process(struct toolbar *toolbar, int width, bool reformat)
error = xwimp_set_extent(toolbar->toolbar_handle,
&extent);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -935,7 +951,7 @@ void ro_toolbar_destroy(struct toolbar *toolbar)
if (toolbar == NULL)
return;
- LOG("Destroying toolbar 0x%x", (unsigned int)toolbar);
+ NSLOG(netsurf, INFO, "Destroying toolbar 0x%x", (unsigned int)toolbar);
/* Destroy the widgets. */
@@ -994,7 +1010,8 @@ void ro_toolbar_redraw(wimp_draw *redraw)
error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1013,7 +1030,8 @@ void ro_toolbar_redraw(wimp_draw *redraw)
error = xwimp_get_rectangle(redraw, &more);
if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1046,7 +1064,8 @@ bool ro_toolbar_click(wimp_pointer *pointer)
state.w = toolbar->toolbar_handle;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -1325,7 +1344,8 @@ const char *ro_toolbar_get_help_suffix(wimp_w w, wimp_i i, os_coord *pos,
state.w = toolbar->toolbar_handle;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return NULL;
}
diff --git a/frontends/riscos/ucstables.c b/frontends/riscos/ucstables.c
index 8e538ef95..3e31c992e 100644
--- a/frontends/riscos/ucstables.c
+++ b/frontends/riscos/ucstables.c
@@ -623,7 +623,8 @@ nserror utf8_from_local_encoding(const char *string, size_t len, char **result)
off - prev_off, &temp, NULL);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_from_enc failed");
+ NSLOG(netsurf, INFO,
+ "utf8_from_enc failed");
free(*result);
return NSERROR_NOMEM;
}
@@ -665,7 +666,7 @@ nserror utf8_from_local_encoding(const char *string, size_t len, char **result)
&temp, NULL);
if (err != NSERROR_OK) {
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_from_enc failed");
+ NSLOG(netsurf, INFO, "utf8_from_enc failed");
free(*result);
return NSERROR_NOMEM;
}
@@ -680,7 +681,7 @@ nserror utf8_from_local_encoding(const char *string, size_t len, char **result)
/* and copy into more reasonably-sized buffer */
temp = realloc((*result), cur_off + 1);
if (!temp) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
free(*result);
return NSERROR_NOMEM;
}
diff --git a/frontends/riscos/uri.c b/frontends/riscos/uri.c
index a2f126b31..d79cfe56d 100644
--- a/frontends/riscos/uri.c
+++ b/frontends/riscos/uri.c
@@ -120,7 +120,8 @@ void ro_uri_bounce(wimp_message *msg)
/* Get required buffer size */
e = xuri_request_uri(0, NULL, 0, message->handle, &size);
if (e) {
- LOG("xuri_request_uri: %d: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "xuri_request_uri: %d: %s", e->errnum,
+ e->errmess);
return;
}
@@ -131,7 +132,8 @@ void ro_uri_bounce(wimp_message *msg)
/* Get URI */
e = xuri_request_uri(0, uri_buf, size, message->handle, 0);
if (e) {
- LOG("xuri_request_uri: %d: %s", e->errnum, e->errmess);
+ NSLOG(netsurf, INFO, "xuri_request_uri: %d: %s", e->errnum,
+ e->errmess);
free(uri_buf);
return;
}
diff --git a/frontends/riscos/url_complete.c b/frontends/riscos/url_complete.c
index 3ca9be4c0..82c2d2c67 100644
--- a/frontends/riscos/url_complete.c
+++ b/frontends/riscos/url_complete.c
@@ -36,6 +36,7 @@
#include "riscos/global_history.h"
#include "riscos/gui.h"
+#include "riscos/window.h"
#include "riscos/mouse.h"
#include "riscos/toolbar.h"
#include "riscos/url_complete.h"
@@ -170,7 +171,8 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
-(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -209,7 +211,10 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
state.w = parent;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -227,7 +232,10 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
error = xwimp_force_redraw(dialog_url_complete,
0, -(i + 1) * 44, 65536, -i * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_force_redraw: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError",
error->errmess);
}
@@ -280,7 +288,8 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
0, -(old_selection + 1) * 44,
65536, -old_selection * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -288,7 +297,8 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
0, -(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -319,7 +329,8 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return true;
}
@@ -334,7 +345,8 @@ bool ro_gui_url_complete_keypress(struct toolbar *toolbar, uint32_t key)
error = xwimp_open_window(PTR_WIMP_OPEN(&state));
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return true;
}
@@ -410,7 +422,8 @@ void ro_gui_url_complete_resize(struct toolbar *toolbar, wimp_open *open)
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -422,13 +435,14 @@ void ro_gui_url_complete_resize(struct toolbar *toolbar, wimp_open *open)
toolbar_state.w = ro_toolbar_get_window(toolbar);
error = xwimp_get_window_state(&toolbar_state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
if (!ro_toolbar_get_url_field_extent(toolbar, &url_extent)) {
- LOG("Failed to read URL field extent.");
+ NSLOG(netsurf, INFO, "Failed to read URL field extent.");
return;
}
@@ -437,7 +451,8 @@ void ro_gui_url_complete_resize(struct toolbar *toolbar, wimp_open *open)
extent.x1 = 65536;
error = xwimp_set_extent(dialog_url_complete, &extent);
if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -459,14 +474,16 @@ void ro_gui_url_complete_resize(struct toolbar *toolbar, wimp_open *open)
if (state.visible.x1 - state.visible.x0 < 0) {
error = xwimp_close_window(dialog_url_complete);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
} else {
error = xwimp_open_window_nested_with_flags(&state,
(wimp_w)-1, 0);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -506,7 +523,8 @@ bool ro_gui_url_complete_close(void)
error = xwimp_close_window(dialog_url_complete);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -546,7 +564,7 @@ void ro_gui_url_complete_redraw(wimp_draw *redraw)
/* no matches? no redraw */
if (!url_complete_matches) {
- LOG("Attempt to redraw with no matches made");
+ NSLOG(netsurf, INFO, "Attempt to redraw with no matches made");
/* Fill is never used, so make it something obvious */
ro_gui_user_redraw(redraw, false, os_COLOUR_BLACK);
return;
@@ -581,7 +599,10 @@ void ro_gui_url_complete_redraw(wimp_draw *redraw)
error = xwimp_plot_icon(&url_complete_icon);
if (error) {
- LOG("xwimp_plot_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_plot_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -603,7 +624,10 @@ void ro_gui_url_complete_redraw(wimp_draw *redraw)
url_complete_sprite.extent.y0 = -(line + 1) * 44;
error = xwimp_plot_icon(&url_complete_sprite);
if (error) {
- LOG("xwimp_plot_icon: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_plot_icon: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -657,7 +681,8 @@ bool ro_gui_url_complete_click(wimp_pointer *pointer)
state.w = dialog_url_complete;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -684,14 +709,16 @@ bool ro_gui_url_complete_click(wimp_pointer *pointer)
0, -(old_selection + 1) * 44,
65536, -old_selection * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_force_redraw(dialog_url_complete,
0, -(url_complete_matches_selection + 1) * 44,
65536, -url_complete_matches_selection * 44);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
diff --git a/frontends/riscos/url_protocol.c b/frontends/riscos/url_protocol.c
index 9a7ae062c..184aaeab0 100644
--- a/frontends/riscos/url_protocol.c
+++ b/frontends/riscos/url_protocol.c
@@ -75,17 +75,19 @@ void ro_url_message_received(wimp_message *message)
} else {
if (!url_message->indirect.url.offset) {
- LOG("no URL in message");
+ NSLOG(netsurf, INFO, "no URL in message");
return;
}
if (28 < message->size &&
url_message->indirect.body_file.offset) {
- LOG("POST for URL message not implemented");
+ NSLOG(netsurf, INFO,
+ "POST for URL message not implemented");
return;
}
if (url_message->indirect.url.offset < 28 ||
236 <= url_message->indirect.url.offset) {
- LOG("external pointers in URL message unimplemented");
+ NSLOG(netsurf, INFO,
+ "external pointers in URL message unimplemented");
/* these messages have never been seen in the wild,
* and there is the problem of invalid addresses which
* would cause an abort */
@@ -122,7 +124,8 @@ void ro_url_message_received(wimp_message *message)
error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE, message,
message->sender);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -165,7 +168,8 @@ void ro_url_broadcast(const char *url)
error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED,
(wimp_message *) &message, 0);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -184,7 +188,7 @@ void ro_url_load(const char *url)
colon = strchr(url, ':');
if (!colon) {
- LOG("invalid url '%s'", url);
+ NSLOG(netsurf, INFO, "invalid url '%s'", url);
return;
}
@@ -204,7 +208,8 @@ void ro_url_load(const char *url)
error = xwimp_start_task(command, 0);
if (error) {
- LOG("xwimp_start_task: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_start_task: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
diff --git a/frontends/riscos/wimp.c b/frontends/riscos/wimp.c
index abf099a55..d851ab59e 100644
--- a/frontends/riscos/wimp.c
+++ b/frontends/riscos/wimp.c
@@ -103,7 +103,10 @@ void ro_gui_wimp_cache_furniture_sizes(wimp_w w)
furniture_sizes.border_widths.x1 = 40;
error = xwimpextend_get_furniture_sizes(&furniture_sizes);
if (error) {
- LOG("xwimpextend_get_furniture_sizes: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimpextend_get_furniture_sizes: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -123,13 +126,15 @@ bool ro_gui_wimp_read_eig_factors(os_mode mode, int *xeig, int *yeig)
error = xos_read_mode_variable(mode, os_MODEVAR_XEIG_FACTOR, xeig, 0);
if (error) {
- LOG("xos_read_mode_variable: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_read_mode_variable: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
return false;
}
error = xos_read_mode_variable(mode, os_MODEVAR_YEIG_FACTOR, yeig, 0);
if (error) {
- LOG("xos_read_mode_variable: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xos_read_mode_variable: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("MiscError", error->errmess);
return false;
}
@@ -196,14 +201,16 @@ void ro_gui_force_redraw_icon(wimp_w w, wimp_i i)
ic.i = i;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
error = xwimp_force_redraw(w, ic.icon.extent.x0, ic.icon.extent.y0,
ic.icon.extent.x1, ic.icon.extent.y1);
if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -235,7 +242,8 @@ const char *ro_gui_get_icon_string(wimp_w w, wimp_i i)
ic.i = i;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return NULL;
}
@@ -277,7 +285,7 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
if (err != NSERROR_OK) {
/* A bad encoding should never happen, so assert this */
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
/* Paranoia */
local_text = NULL;
}
@@ -292,7 +300,8 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
ic.i = i;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
goto exit;
}
@@ -325,7 +334,10 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
(button_type == wimp_BUTTON_WRITE_CLICK_DRAG)) {
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
goto exit;
}
@@ -336,7 +348,10 @@ void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
error = xwimp_set_caret_position(w, i, caret.pos.x,
caret.pos.y, -1, caret.index);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -433,7 +448,8 @@ void ro_gui_set_icon_selected_state(wimp_w w, wimp_i i, bool state)
error = xwimp_set_icon_state(w, i,
(state ? wimp_ICON_SELECTED : 0), wimp_ICON_SELECTED);
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -452,7 +468,8 @@ bool ro_gui_get_icon_selected_state(wimp_w w, wimp_i i)
ic.i = i;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -478,7 +495,8 @@ void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state)
error = xwimp_set_icon_state(w, i,
(state ? wimp_ICON_SHADED : 0), wimp_ICON_SHADED);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
if (!state)
@@ -487,7 +505,8 @@ void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state)
/* ensure the caret is not in a shaded icon */
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -499,7 +518,8 @@ void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state)
/* lose the caret */
error = xwimp_set_caret_position((wimp_w)-1, (wimp_i)-1, -1, -1, -1, -1);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -540,7 +560,8 @@ void ro_gui_set_icon_deleted_state(wimp_w w, wimp_i i, bool state)
error = xwimp_set_icon_state(w, i,
(state ? wimp_ICON_DELETED : 0), wimp_ICON_DELETED);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
if (!state)
@@ -549,7 +570,8 @@ void ro_gui_set_icon_deleted_state(wimp_w w, wimp_i i, bool state)
/* ensure the caret is not in a shaded icon */
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -561,7 +583,8 @@ void ro_gui_set_icon_deleted_state(wimp_w w, wimp_i i, bool state)
/* lose the caret */
error = xwimp_set_caret_position((wimp_w)-1, (wimp_i)-1, -1, -1, -1, -1);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -597,7 +620,8 @@ void ro_gui_set_icon_button_type(wimp_w w, wimp_i i, int type)
error = xwimp_set_icon_state(w, i, wimp_ICON_BUTTON_TYPE,
(type << wimp_ICON_BUTTON_TYPE_SHIFT));
if (error) {
- LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -622,7 +646,8 @@ void ro_gui_set_icon_sprite(wimp_w w, wimp_i i, osspriteop_area *area,
ic.i = i;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -659,7 +684,8 @@ void ro_gui_set_window_title(wimp_w w, const char *text)
window.w = w;
error = xwimp_get_window_info_header_only((wimp_window_info *)&window);
if (error) {
- LOG("xwimp_get_window_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -670,7 +696,7 @@ void ro_gui_set_window_title(wimp_w w, const char *text)
/* A bad encoding should never happen,
* so assert this */
assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
return;
}
@@ -686,7 +712,8 @@ void ro_gui_set_window_title(wimp_w w, const char *text)
*/
error = xwimp_force_redraw_title(w);
if (error) {
- LOG("xwimp_force_redraw_title: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_force_redraw_title: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -713,7 +740,8 @@ bool ro_gui_set_caret_first(wimp_w w)
win_state.w = w;
error = xwimp_get_window_state(&win_state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -724,7 +752,8 @@ bool ro_gui_set_caret_first(wimp_w w)
window.w = w;
error = xwimp_get_window_info_header_only((wimp_window_info *)&window);
if (error) {
- LOG("xwimp_get_window_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_info: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -735,7 +764,10 @@ bool ro_gui_set_caret_first(wimp_w w)
state.i = icon;
error = xwimp_get_icon_state(&state);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -752,7 +784,10 @@ bool ro_gui_set_caret_first(wimp_w w)
error = xwimp_set_caret_position(w, icon, 0, 0, -1,
strlen(state.icon.data.indirected_text.text));
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
return true;
@@ -778,7 +813,10 @@ osspriteop_area *ro_gui_load_sprite_file(const char *pathname)
error = xosfile_read_stamped_no_path(pathname,
&obj_type, 0, 0, &len, 0, 0);
if (error) {
- LOG("xosfile_read_stamped_no_path: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosfile_read_stamped_no_path: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
return 0;
}
@@ -801,7 +839,10 @@ osspriteop_area *ro_gui_load_sprite_file(const char *pathname)
error = xosspriteop_load_sprite_file(osspriteop_USER_AREA,
area, pathname);
if (error) {
- LOG("xosspriteop_load_sprite_file: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_load_sprite_file: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
free(area);
return 0;
@@ -831,7 +872,10 @@ bool ro_gui_wimp_sprite_exists(const char *sprite)
error = xwimpspriteop_select_sprite(sprite, 0);
if (error) {
if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) {
- LOG("xwimpspriteop_select_sprite: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimpspriteop_select_sprite: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
}
return false;
@@ -904,7 +948,10 @@ bool ro_gui_wimp_get_sprite_dimensions(osspriteop_area *area, char *sprite,
if (height != NULL)
*height = dimensions.y;
} else if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) {
- LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xosspriteop_read_sprite_info: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
return false;
}
@@ -929,7 +976,8 @@ void ro_gui_user_redraw(wimp_draw *redraw, bool user_fill,
error = xwimp_redraw_window(redraw, &more);
if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -939,14 +987,18 @@ void ro_gui_user_redraw(wimp_draw *redraw, bool user_fill,
colourtrans_SET_BG_GCOL,
os_ACTION_OVERWRITE, 0, 0);
if (error) {
- LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xcolourtrans_set_gcol: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("MiscError", error->errmess);
}
os_clg();
}
error = xwimp_get_rectangle(redraw, &more);
if (error) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -973,7 +1025,8 @@ void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask,
state.w = w;
error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -986,7 +1039,8 @@ void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask,
state.next = wimp_HIDDEN;
error = xwimp_open_window_nested_with_flags(&state, parent, linkage);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -994,7 +1048,8 @@ void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask,
if (!open) {
error = xwimp_close_window(w);
if (error) {
- LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -1016,7 +1071,8 @@ bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask)
state.w = w;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -1116,7 +1172,8 @@ void ro_gui_scroll(wimp_scroll *scroll)
error = xwimp_open_window((wimp_open *) scroll);
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
}
}
diff --git a/frontends/riscos/wimp_event.c b/frontends/riscos/wimp_event.c
index 015e87baf..cdca470da 100644
--- a/frontends/riscos/wimp_event.c
+++ b/frontends/riscos/wimp_event.c
@@ -156,7 +156,9 @@ bool ro_gui_wimp_event_memorise(wimp_w w)
ro_gui_get_icon_string(window->w, event->i));
if (!event->previous_value.textual) {
error = true;
- LOG("Unable to store state for icon %i", event->i);
+ NSLOG(netsurf, INFO,
+ "Unable to store state for icon %i",
+ event->i);
}
break;
case EVENT_CHECKBOX:
@@ -267,7 +269,10 @@ bool ro_gui_wimp_event_transfer(wimp_w from, wimp_w to)
struct event_window *window;
int h;
- LOG("Transferring all events from window 0x%x to window 0x%x", (unsigned int)from, (unsigned int)to);
+ NSLOG(netsurf, INFO,
+ "Transferring all events from window 0x%x to window 0x%x",
+ (unsigned int)from,
+ (unsigned int)to);
window = ro_gui_wimp_event_remove_window(from);
if (window == NULL || window->w != from)
@@ -293,7 +298,8 @@ void ro_gui_wimp_event_finalise(wimp_w w)
struct event_window *window;
struct icon_event *event;
- LOG("Removing all events for window 0x%x", (unsigned int)w);
+ NSLOG(netsurf, INFO, "Removing all events for window 0x%x",
+ (unsigned int)w);
window = ro_gui_wimp_event_remove_window(w);
if (!window)
return;
@@ -330,7 +336,8 @@ void ro_gui_wimp_event_deregister(wimp_w w, wimp_i i)
struct event_window *window;
struct icon_event *event, *parent, *child;
- LOG("Removing all events for window 0x%x, icon %d", (unsigned int)w, (int)i);
+ NSLOG(netsurf, INFO, "Removing all events for window 0x%x, icon %d",
+ (unsigned int)w, (int)i);
window = ro_gui_wimp_event_get_window(w);
if (!window)
return;
@@ -344,7 +351,8 @@ void ro_gui_wimp_event_deregister(wimp_w w, wimp_i i)
child = event->next;
if (event->i == i) {
- LOG("Removing event 0x%x", (unsigned int)event);
+ NSLOG(netsurf, INFO, "Removing event 0x%x",
+ (unsigned int)event);
if (parent == NULL)
window->first = child;
@@ -576,7 +584,8 @@ bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu,
ic.i = event->data.menu_gright.field;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -586,7 +595,8 @@ bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu,
return prepared;
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -594,7 +604,10 @@ bool ro_gui_wimp_event_menu_selection(wimp_w w, wimp_i i, wimp_menu *menu,
error = xwimp_set_caret_position(window->w, event->data.menu_gright.field,
-1, -1, -1, strlen(menu_entry->data.indirected_text.text));
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -666,7 +679,7 @@ bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer)
for (search = window->first; search; search = search->next)
if (search->i == event->data.linked_icon) break;
if (!search) {
- LOG("Incorrect reference.");
+ NSLOG(netsurf, INFO, "Incorrect reference.");
return false;
}
stepping = search->data.numeric_field.stepping;
@@ -703,13 +716,19 @@ bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer)
open.w = pointer->w;
error = xwimp_get_window_state(&open);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -718,7 +737,10 @@ bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer)
ro_gui_menu_destroy();
error = xwimp_open_window(PTR_WIMP_OPEN(&open));
if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_open_window: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -728,7 +750,10 @@ bool ro_gui_wimp_event_mouse_click(wimp_pointer *pointer)
caret.pos.x, caret.pos.y,
-1, caret.index);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
@@ -796,7 +821,8 @@ void ro_gui_wimp_event_prepare_gright_menu(wimp_w w, struct icon_event *event)
ic.i = event->data.menu_gright.field;
error = xwimp_get_icon_state(&ic);
if (error) {
- LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
@@ -903,7 +929,8 @@ bool ro_gui_wimp_event_keypress(wimp_key *key)
*/
error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &t_alphabet);
if (error) {
- LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
+ error->errnum, error->errmess);
/* prevent any corruption of ucstable */
t_alphabet = alphabet;
}
@@ -917,7 +944,10 @@ bool ro_gui_wimp_event_keypress(wimp_key *key)
error = xserviceinternational_get_ucs_conversion_table(
alphabet, &unclaimed, &ostable);
if (error != NULL) {
- LOG("failed reading UCS conversion table: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "failed reading UCS conversion table: 0x%x: %s",
+ error->errnum,
+ error->errmess);
/* Try using our own table instead */
ucstable = ucstable_from_alphabet(alphabet);
} else if (unclaimed) {
@@ -974,7 +1004,9 @@ bool ro_gui_wimp_event_keypress(wimp_key *key)
/* If this ever happens,
* RISC OS' UTF8 keyboard
* drivers are broken */
- LOG("unexpected UTF8 start"" byte %x (ignoring)", c);
+ NSLOG(netsurf, INFO,
+ "unexpected UTF8 start"" byte %x (ignoring)",
+ c);
return true;
}
/* Anything else is ASCII, so just
@@ -985,7 +1017,9 @@ bool ro_gui_wimp_event_keypress(wimp_key *key)
/* If this ever happens,
* RISC OS' UTF8 keyboard
* drivers are broken */
- LOG("unexpected keycode: ""%x (ignoring)", c);
+ NSLOG(netsurf, INFO,
+ "unexpected keycode: ""%x (ignoring)",
+ c);
return true;
}
@@ -1074,7 +1108,8 @@ bool ro_gui_wimp_event_close_window(wimp_w w)
{
struct event_window *window;
- LOG("Close event received for window 0x%x", (unsigned int)w);
+ NSLOG(netsurf, INFO, "Close event received for window 0x%x",
+ (unsigned int)w);
if (w == ro_gui_wimp_event_submenu)
ro_gui_wimp_event_submenu = 0;
window = ro_gui_wimp_event_find_window(w);
@@ -1615,7 +1650,8 @@ struct event_window *ro_gui_wimp_event_get_window(wimp_w w)
if (window)
return window;
- LOG("Creating structure for window 0x%x", (unsigned int)w);
+ NSLOG(netsurf, INFO, "Creating structure for window 0x%x",
+ (unsigned int)w);
window = calloc(1, sizeof(struct event_window));
if (!window)
return NULL;
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index b1ea58ae1..e41f6096f 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -35,6 +35,7 @@
#include <stdint.h>
#include <time.h>
#include <string.h>
+#include <limits.h>
#include <oslib/colourtrans.h>
#include <oslib/osbyte.h>
#include <oslib/osfile.h>
@@ -63,12 +64,12 @@
#include "netsurf/keypress.h"
#include "desktop/browser_history.h"
#include "desktop/cookie_manager.h"
-#include "desktop/scrollbar.h"
#include "riscos/bitmap.h"
#include "riscos/buffer.h"
#include "riscos/cookies.h"
#include "riscos/dialog.h"
+#include "riscos/local_history.h"
#include "riscos/global_history.h"
#include "riscos/gui.h"
#include "riscos/gui/status_bar.h"
@@ -90,72 +91,6 @@
#include "riscos/ucstables.h"
#include "riscos/filetype.h"
-void gui_window_redraw_window(struct gui_window *g);
-
-static void gui_window_set_extent(struct gui_window *g, int width, int height);
-
-static void ro_gui_window_redraw(wimp_draw *redraw);
-static void ro_gui_window_scroll(wimp_scroll *scroll);
-static void ro_gui_window_pointer_entering(wimp_entering *entering);
-static void ro_gui_window_track_end(wimp_leaving *leaving, void *data);
-static void ro_gui_window_open(wimp_open *open);
-static void ro_gui_window_close(wimp_w w);
-static bool ro_gui_window_click(wimp_pointer *mouse);
-static bool ro_gui_window_keypress(wimp_key *key);
-static bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key);
-static bool ro_gui_window_handle_local_keypress(struct gui_window *g,
- wimp_key *key, bool is_toolbar);
-static bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_pointer *pointer);
-static void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection, menu_action action);
-static bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection, menu_action action);
-static void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu);
-
-static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data);
-
-static void ro_gui_window_scroll_action(struct gui_window *g,
- int scroll_x, int scroll_y);
-
-static void ro_gui_window_toolbar_click(void *data,
- toolbar_action_type action_type, union toolbar_action action);
-
-static bool ro_gui_window_content_export_types(struct hlcache_handle *h,
- bool *export_draw, bool *export_sprite);
-static void ro_gui_window_prepare_pageinfo(struct gui_window *g);
-static void ro_gui_window_prepare_objectinfo(struct hlcache_handle *object,
- nsurl *target_url);
-
-static void ro_gui_window_launch_url(struct gui_window *g, const char *url);
-static void ro_gui_window_action_home(struct gui_window *g);
-static void ro_gui_window_action_new_window(struct gui_window *g);
-static void ro_gui_window_action_local_history(struct gui_window *g);
-static void ro_gui_window_action_save(struct gui_window *g,
- gui_save_type save_type);
-static void ro_gui_window_action_search(struct gui_window *g);
-static void ro_gui_window_action_zoom(struct gui_window *g);
-static void ro_gui_window_action_add_bookmark(struct gui_window *g);
-static void ro_gui_window_action_remove_bookmark(struct gui_window *g);
-static void ro_gui_window_action_print(struct gui_window *g);
-static void ro_gui_window_action_page_info(struct gui_window *g);
-
-static void ro_gui_window_remove_update_boxes(struct gui_window *g);
-static void ro_gui_window_update_toolbar_buttons(struct gui_window *g);
-static void ro_gui_window_update_toolbar(void *data);
-static void ro_gui_window_save_toolbar_buttons(void *data, char *config);
-static void ro_gui_window_update_theme(void *data, bool ok);
-
-static bool ro_gui_window_import_text(struct gui_window *g,
- const char *filename);
-static void ro_gui_window_clone_options(
- struct gui_window *new_gui,
- struct gui_window *old_gui);
-
-static bool ro_gui_window_prepare_form_select_menu(struct gui_window *bw,
- struct form_control *control);
-static void ro_gui_window_process_form_select_menu(struct gui_window *g,
- wimp_selection *selection);
#ifndef wimp_KEY_END
#define wimp_KEY_END wimp_KEY_COPY
@@ -168,6 +103,11 @@ static void ro_gui_window_process_form_select_menu(struct gui_window *g,
#define SCROLL_VISIBLE_PADDING 32
+#define SCROLL_TOP INT_MIN
+#define SCROLL_PAGE_UP (INT_MIN + 1)
+#define SCROLL_PAGE_DOWN (INT_MAX - 1)
+#define SCROLL_BOTTOM INT_MAX
+
/** Remembers which iconised sprite numbers are in use */
static bool iconise_used[64];
static int iconise_next = 0;
@@ -206,7 +146,8 @@ struct ro_gui_pointer_entry {
int yactive;
};
-/** Map from gui_pointer_shape to pointer sprite data. Must be ordered as
+/**
+ * Map from gui_pointer_shape to pointer sprite data. Must be ordered as
* enum gui_pointer_shape. */
struct ro_gui_pointer_entry ro_gui_pointer_table[] = {
{ true, "ptr_default", 0, 0 },
@@ -243,1609 +184,1046 @@ struct update_box {
struct update_box *pending_updates;
#define MARGIN 4
-static const struct toolbar_callbacks ro_gui_window_toolbar_callbacks = {
- ro_gui_window_update_theme,
- ro_gui_window_update_toolbar,
- (void (*)(void *)) ro_gui_window_update_toolbar_buttons,
- ro_gui_window_toolbar_click,
- ro_gui_window_toolbar_keypress,
- ro_gui_window_save_toolbar_buttons
-};
-
-
-/**
- * Initialise the browser window module and its menus.
- */
-
-void ro_gui_window_initialise(void)
-{
- /* Build the browser window menu. */
-
- static const struct ns_menu browser_definition = {
- "NetSurf", {
- { "Page", BROWSER_PAGE, 0 },
- { "Page.PageInfo",BROWSER_PAGE_INFO, &dialog_pageinfo },
- { "Page.Save", BROWSER_SAVE, &dialog_saveas },
- { "Page.SaveComp", BROWSER_SAVE_COMPLETE, &dialog_saveas },
- { "Page.Export", NO_ACTION, 0 },
-#ifdef WITH_DRAW_EXPORT
- { "Page.Export.Draw", BROWSER_EXPORT_DRAW, &dialog_saveas },
-#endif
-#ifdef WITH_PDF_EXPORT
- { "Page.Export.PDF", BROWSER_EXPORT_PDF, &dialog_saveas },
-#endif
- { "Page.Export.Text", BROWSER_EXPORT_TEXT, &dialog_saveas },
- { "Page.SaveURL", NO_ACTION, 0 },
- { "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, &dialog_saveas },
- { "Page.SaveURL.URL", BROWSER_SAVE_URL_URL, &dialog_saveas },
- { "Page.SaveURL.LinkText", BROWSER_SAVE_URL_TEXT, &dialog_saveas },
- { "_Page.Print", BROWSER_PRINT, &dialog_print },
- { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 },
- { "Page.FindText", BROWSER_FIND_TEXT, &dialog_search },
- { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 },
- { "Object", BROWSER_OBJECT, 0 },
- { "Object.Object", BROWSER_OBJECT_OBJECT, 0 },
- { "Object.Object.ObjInfo", BROWSER_OBJECT_INFO, &dialog_objinfo },
- { "Object.Object.ObjSave", BROWSER_OBJECT_SAVE, &dialog_saveas },
- { "Object.Object.Export", BROWSER_OBJECT_EXPORT, 0 },
- { "Object.Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, &dialog_saveas },
-#ifdef WITH_DRAW_EXPORT
- { "Object.Object.Export.ObjDraw", BROWSER_OBJECT_EXPORT_DRAW, &dialog_saveas },
-#endif
- { "Object.Object.SaveURL", NO_ACTION, 0 },
- { "Object.Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, &dialog_saveas },
- { "Object.Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, &dialog_saveas },
- { "Object.Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, &dialog_saveas },
- { "Object.Object.ObjPrint", BROWSER_OBJECT_PRINT, 0 },
- { "Object.Object.ObjReload", BROWSER_OBJECT_RELOAD, 0 },
- { "Object.Link", BROWSER_OBJECT_LINK, 0 },
- { "Object.Link.LinkSave", BROWSER_LINK_SAVE, 0 },
- { "Object.Link.LinkSave.URI", BROWSER_LINK_SAVE_URI, &dialog_saveas },
- { "Object.Link.LinkSave.URL", BROWSER_LINK_SAVE_URL, &dialog_saveas },
- { "Object.Link.LinkSave.LinkText", BROWSER_LINK_SAVE_TEXT, &dialog_saveas },
- { "_Object.Link.LinkDload", BROWSER_LINK_DOWNLOAD, 0 },
- { "Object.Link.LinkNew", BROWSER_LINK_NEW_WINDOW, 0 },
- { "Selection", BROWSER_SELECTION, 0 },
- { "_Selection.SelSave", BROWSER_SELECTION_SAVE, &dialog_saveas },
- { "Selection.Copy", BROWSER_SELECTION_COPY, 0 },
- { "Selection.Cut", BROWSER_SELECTION_CUT, 0 },
- { "_Selection.Paste", BROWSER_SELECTION_PASTE, 0 },
- { "Selection.Clear", BROWSER_SELECTION_CLEAR, 0 },
- { "Selection.SelectAll", BROWSER_SELECTION_ALL, 0 },
- { "Navigate", NO_ACTION, 0 },
- { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 },
- { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 },
- { "Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 },
- { "_Navigate.UpLevel", BROWSER_NAVIGATE_UP, 0 },
- { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 },
- { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 },
- { "View", NO_ACTION, 0 },
- { "View.ScaleView", BROWSER_SCALE_VIEW, &dialog_zoom },
- { "View.Images", NO_ACTION, 0 },
- { "View.Images.ForeImg", BROWSER_IMAGES_FOREGROUND, 0 },
- { "View.Images.BackImg", BROWSER_IMAGES_BACKGROUND, 0 },
- { "View.Toolbars", NO_ACTION, 0 },
- { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
- { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 },
- { "_View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 },
- { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 },
- { "_View.Render", NO_ACTION, 0 },
- { "View.Render.RenderAnims", BROWSER_BUFFER_ANIMS, 0 },
- { "View.Render.RenderAll", BROWSER_BUFFER_ALL, 0 },
- { "_View.OptDefault", BROWSER_SAVE_VIEW, 0 },
- { "View.Window", NO_ACTION, 0 },
- { "View.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 },
- { "View.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 },
- { "_View.Window.WindowSize", BROWSER_WINDOW_COPY, 0 },
- { "View.Window.WindowReset", BROWSER_WINDOW_RESET, 0 },
- { "Utilities", NO_ACTION, 0 },
- { "Utilities.Hotlist", HOTLIST_SHOW, 0 },
- { "Utilities.Hotlist.HotlistAdd", HOTLIST_ADD_URL, 0 },
- { "Utilities.Hotlist.HotlistShow", HOTLIST_SHOW, 0 },
- { "Utilities.History", HISTORY_SHOW_GLOBAL, 0 },
- { "Utilities.History.HistLocal", HISTORY_SHOW_LOCAL, 0 },
- { "Utilities.History.HistGlobal", HISTORY_SHOW_GLOBAL, 0 },
- { "Utilities.Cookies", COOKIES_SHOW, 0 },
- { "Utilities.Cookies.ShowCookies", COOKIES_SHOW, 0 },
- { "Utilities.Cookies.DeleteCookies", COOKIES_DELETE, 0 },
- { "Help", HELP_OPEN_CONTENTS, 0 },
- { "Help.HelpContent", HELP_OPEN_CONTENTS, 0 },
- { "Help.HelpGuide", HELP_OPEN_GUIDE, 0 },
- { "_Help.HelpInfo", HELP_OPEN_INFORMATION, 0 },
- { "Help.HelpCredits", HELP_OPEN_CREDITS, 0 },
- { "_Help.HelpLicence", HELP_OPEN_LICENCE, 0 },
- { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 },
- {NULL, 0, 0}
- }
- };
- ro_gui_browser_window_menu =
- ro_gui_menu_define_menu(&browser_definition);
-
-}
-
-
-/*
- * Interface With Core
- */
/**
* Place the caret in a browser window.
*
- * \param g window with caret
- * \param x coordinates of caret
- * \param y coordinates of caret
- * \param height height of caret
- * \param clip clip rectangle, or NULL if none
+ * \param g window with caret
+ * \param x coordinates of caret
+ * \param y coordinates of caret
+ * \param height height of caret
+ * \param clip clip rectangle, or NULL if none
*/
-
-static void gui_window_place_caret(struct gui_window *g, int x, int y, int height,
- const struct rect *clip)
+static void
+gui_window_place_caret(struct gui_window *g,
+ int x,
+ int y,
+ int height,
+ const struct rect *clip)
{
os_error *error;
error = xwimp_set_caret_position(g->window, -1,
x * 2, -(y + height) * 2, height * 2, -1);
if (error) {
- LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
}
+
/**
- * Create and open a new browser window.
+ * Updates a windows extent.
*
- * \param bw bw to create gui_window for
- * \param existing an existing gui_window, may be NULL
- * \param flags flags for gui window creation
- * \return gui window, or NULL on error
+ * \param g the gui_window to update
+ * \param width the minimum width, or -1 to use window width
+ * \param height the minimum height, or -1 to use window height
*/
-
-static struct gui_window *gui_window_create(struct browser_window *bw,
- struct gui_window *existing,
- gui_window_create_flags flags)
+static void gui_window_set_extent(struct gui_window *g, int width, int height)
{
- int screen_width, screen_height;
- static int window_count = 2;
- wimp_window window;
+ int screen_width;
+ int toolbar_height = 0;
wimp_window_state state;
os_error *error;
- bool open_centred = true;
- struct gui_window *g;
- g = malloc(sizeof *g);
- if (!g) {
- ro_warn_user("NoMemory", 0);
- return 0;
+ if (g->toolbar) {
+ toolbar_height = ro_toolbar_full_height(g->toolbar);
}
- g->bw = bw;
- g->toolbar = 0;
- g->status_bar = 0;
- g->old_width = 0;
- g->old_height = 0;
- g->update_extent = true;
- g->active = false;
- strcpy(g->title, "NetSurf");
- g->iconise_icon = -1;
- g->scale = browser_window_get_scale(bw);
- /* Set the window position */
- if (existing != NULL &&
- flags & GW_CREATE_CLONE &&
- nsoption_bool(window_size_clone)) {
- state.w = existing->window;
+ /* get the current state */
+ if ((height == -1) || (width == -1)) {
+ state.w = g->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
+ return;
}
- window.visible.x0 = state.visible.x0;
- window.visible.x1 = state.visible.x1;
- window.visible.y0 = state.visible.y0 - 48;
- window.visible.y1 = state.visible.y1 - 48;
- open_centred = false;
- } else {
- int win_width, win_height;
- ro_gui_screen_size(&screen_width, &screen_height);
-
- /* Check if we have a preferred position */
- if ((nsoption_int(window_screen_width) != 0) &&
- (nsoption_int(window_screen_height) != 0)) {
- win_width = (nsoption_int(window_width) *
- screen_width) /
- nsoption_int(window_screen_width);
- win_height = (nsoption_int(window_height) *
- screen_height) /
- nsoption_int(window_screen_height);
- window.visible.x0 = (nsoption_int(window_x) *
- screen_width) /
- nsoption_int(window_screen_width);
- window.visible.y0 = (nsoption_int(window_y) *
- screen_height) /
- nsoption_int(window_screen_height);
- if (nsoption_bool(window_stagger)) {
- window.visible.y0 += 96 -
- (48 * (window_count % 5));
- }
- open_centred = false;
- if (win_width < 100)
- win_width = 100;
- if (win_height < 100)
- win_height = 100;
- } else {
-
- /* Base how we define the window height/width
- on the compile time options set */
- win_width = screen_width * 3 / 4;
- if (1600 < win_width)
- win_width = 1600;
- win_height = win_width * 3 / 4;
-
- window.visible.x0 = (screen_width - win_width) / 2;
- window.visible.y0 = ((screen_height - win_height) / 2) +
- 96 - (48 * (window_count % 5));
+ if (width == -1)
+ width = state.visible.x1 - state.visible.x0;
+ if (height == -1) {
+ height = state.visible.y1 - state.visible.y0;
+ height -= toolbar_height;
}
- window.visible.x1 = window.visible.x0 + win_width;
- window.visible.y1 = window.visible.y0 + win_height;
}
- /* General flags for a non-movable, non-resizable, no-title bar window */
- window.xscroll = 0;
- window.yscroll = 0;
- window.next = wimp_TOP;
- window.flags = wimp_WINDOW_MOVEABLE |
- wimp_WINDOW_NEW_FORMAT |
- wimp_WINDOW_VSCROLL |
- wimp_WINDOW_HSCROLL |
- wimp_WINDOW_IGNORE_XEXTENT |
- wimp_WINDOW_IGNORE_YEXTENT |
- wimp_WINDOW_SCROLL_REPEAT;
- window.title_fg = wimp_COLOUR_BLACK;
- window.title_bg = wimp_COLOUR_LIGHT_GREY;
- window.work_fg = wimp_COLOUR_LIGHT_GREY;
- window.work_bg = wimp_COLOUR_TRANSPARENT;
- window.scroll_outer = wimp_COLOUR_DARK_GREY;
- window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY;
- window.highlight_bg = wimp_COLOUR_CREAM;
- window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST |
- wimp_WINDOW_GIVE_SHADED_ICON_INFO;
- window.extent.x0 = 0;
- window.extent.y0 = -(window.visible.y1 - window.visible.y0);
- window.extent.x1 = window.visible.x1 - window.visible.x0;
- window.extent.y1 = 0;
- window.title_flags = wimp_ICON_TEXT |
- wimp_ICON_INDIRECTED |
- wimp_ICON_HCENTRED;
- window.work_flags = wimp_BUTTON_DOUBLE_CLICK_DRAG <<
- wimp_ICON_BUTTON_TYPE_SHIFT;
- window.sprite_area = wimpspriteop_AREA;
- window.xmin = 1;
- window.ymin = 1;
- window.title_data.indirected_text.text = g->title;
- window.title_data.indirected_text.validation = (char *) -1;
- window.title_data.indirected_text.size = 255;
- window.icon_count = 0;
-
- /* Add in flags */
- window.flags |= wimp_WINDOW_SIZE_ICON |
- wimp_WINDOW_BACK_ICON |
- wimp_WINDOW_CLOSE_ICON |
- wimp_WINDOW_TITLE_ICON |
- wimp_WINDOW_TOGGLE_ICON;
-
- if (open_centred) {
- int scroll_width = ro_get_vscroll_width(NULL);
- window.visible.x0 -= scroll_width;
+ /* the top-level framed window is a total pain. to get it to maximise
+ * to the top of the screen we need to fake it having a suitably large
+ * extent */
+ if (browser_window_is_frameset(g->bw)) {
+ ro_gui_screen_size(&screen_width, &height);
+ if (g->toolbar)
+ height -= ro_toolbar_full_height(g->toolbar);
+ height -= ro_get_hscroll_height(g->window);
+ height -= ro_get_title_height(g->window);
}
-
- error = xwimp_create_window(&window, &g->window);
+ if (browser_window_has_content(g->bw)) {
+ int w, h;
+ browser_window_get_extents(g->bw, true, &w, &h);
+ width = max(width, w * 2);
+ height = max(height, h * 2);
+ }
+ os_box extent = { 0, -height, width, toolbar_height };
+ error = xwimp_set_extent(g->window, &extent);
if (error) {
- LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
- free(g);
- return 0;
+ return;
}
+}
- /* Link into window list */
- g->prev = 0;
- g->next = window_list;
- if (window_list)
- window_list->prev = g;
- window_list = g;
- window_count++;
- /* Add in a toolbar and status bar */
- g->status_bar = ro_gui_status_bar_create(g->window,
- nsoption_int(toolbar_status_size));
- g->toolbar = ro_toolbar_create(NULL, g->window,
- THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE,
- &ro_gui_window_toolbar_callbacks, g,
- "HelpToolbar");
- if (g->toolbar != NULL) {
- ro_toolbar_add_buttons(g->toolbar,
- brower_toolbar_buttons,
- nsoption_charp(toolbar_browser));
- ro_toolbar_add_url(g->toolbar);
- ro_toolbar_add_throbber(g->toolbar);
- ro_toolbar_rebuild(g->toolbar);
- }
+/**
+ * Open a window
+ *
+ * opens a window using the given wimp_open, handling toolbars and resizing.
+ *
+ * \param open the window open event information
+ */
+static void ro_gui_window_open(wimp_open *open)
+{
+ struct gui_window *g;
+ int width = open->visible.x1 - open->visible.x0;
+ int height = open->visible.y1 - open->visible.y0;
+ browser_scrolling h_scroll;
+ browser_scrolling v_scroll;
+ int toolbar_height = 0;
+ float new_scale = 0;
+ wimp_window_state state;
+ os_error *error;
+ wimp_w parent;
+ bits linkage;
+ bool have_content;
- /* Register event handlers. Do this quickly, as some of the things
- * that follow will indirectly look up our user data: this MUST
- * be set first!
- */
- ro_gui_wimp_event_set_user_data(g->window, g);
- ro_gui_wimp_event_register_open_window(g->window, ro_gui_window_open);
- ro_gui_wimp_event_register_close_window(g->window, ro_gui_window_close);
- ro_gui_wimp_event_register_redraw_window(g->window, ro_gui_window_redraw);
- ro_gui_wimp_event_register_scroll_window(g->window, ro_gui_window_scroll);
- ro_gui_wimp_event_register_pointer_entering_window(g->window, ro_gui_window_pointer_entering);
- ro_gui_wimp_event_register_keypress(g->window, ro_gui_window_keypress);
- ro_gui_wimp_event_register_mouse_click(g->window, ro_gui_window_click);
- ro_gui_wimp_event_register_menu(g->window, ro_gui_browser_window_menu,
- true, false);
- ro_gui_wimp_event_register_menu_prepare(g->window,
- ro_gui_window_menu_prepare);
- ro_gui_wimp_event_register_menu_selection(g->window,
- ro_gui_window_menu_select);
- ro_gui_wimp_event_register_menu_warning(g->window,
- ro_gui_window_menu_warning);
- ro_gui_wimp_event_register_menu_close(g->window,
- ro_gui_window_menu_close);
+ g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w);
- /* Set the window options */
- ro_gui_window_clone_options(g, existing);
- ro_gui_window_update_toolbar_buttons(g);
+ if (open->next == wimp_TOP && g->iconise_icon >= 0) {
+ /* window is no longer iconised, release its sprite number */
+ iconise_used[g->iconise_icon] = false;
+ g->iconise_icon = -1;
+ }
- /* Open the window at the top of the stack */
+ have_content = browser_window_has_content(g->bw);
+
+ /* get the current flags/nesting state */
state.w = g->window;
- error = xwimp_get_window_state(&state);
+ error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage);
if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
- return g;
+ return;
}
- state.next = wimp_TOP;
-
- ro_gui_window_open(PTR_WIMP_OPEN(&state));
+ /* account for toolbar height, if present */
+ if (g->toolbar)
+ toolbar_height = ro_toolbar_full_height(g->toolbar);
+ height -= toolbar_height;
- /* Claim the caret */
- if (ro_toolbar_take_caret(g->toolbar))
- ro_gui_url_complete_start(g->toolbar);
- else
- gui_window_place_caret(g, -100, -100, 0, NULL);
+ /* work with the state from now on so we can modify flags */
+ state.visible = open->visible;
+ state.xscroll = open->xscroll;
+ state.yscroll = open->yscroll;
+ state.next = open->next;
- return g;
-}
+ browser_window_get_scrollbar_type(g->bw, &h_scroll, &v_scroll);
+ /* handle 'auto' scroll bars' and non-fitting scrollbar removal */
+ if ((h_scroll != BW_SCROLLING_NO) && (v_scroll != BW_SCROLLING_NO)) {
+ int size;
-/**
- * Close a browser window and free any related resources.
- *
- * \param g gui_window to destroy
- */
+ /* windows lose scrollbars when containing a frameset */
+ bool no_hscroll = false;
+ bool no_vscroll = browser_window_is_frameset(g->bw);
-static void gui_window_destroy(struct gui_window *g)
-{
- os_error *error;
- wimp_w w;
+ /* hscroll */
+ size = ro_get_hscroll_height(NULL);
+ size -= 2; /* 1px border on both sides */
+ if (!no_hscroll) {
+ if (!(state.flags & wimp_WINDOW_HSCROLL)) {
+ height -= size;
+ state.visible.y0 += size;
+ if (have_content) {
+ browser_window_schedule_reformat(g->bw);
+ }
+ }
+ state.flags |= wimp_WINDOW_HSCROLL;
+ } else {
+ if (state.flags & wimp_WINDOW_HSCROLL) {
+ height += size;
+ state.visible.y0 -= size;
+ if (have_content) {
+ browser_window_schedule_reformat(g->bw);
+ }
+ }
+ state.flags &= ~wimp_WINDOW_HSCROLL;
+ }
- assert(g);
+ /* vscroll */
+ size = ro_get_vscroll_width(NULL);
+ size -= 2; /* 1px border on both sides */
+ if (!no_vscroll) {
+ if (!(state.flags & wimp_WINDOW_VSCROLL)) {
+ width -= size;
+ state.visible.x1 -= size;
+ if (have_content) {
+ browser_window_schedule_reformat(g->bw);
+ }
+ }
+ state.flags |= wimp_WINDOW_VSCROLL;
+ } else {
+ if (state.flags & wimp_WINDOW_VSCROLL) {
+ width += size;
+ state.visible.x1 += size;
+ if (have_content) {
+ browser_window_schedule_reformat(g->bw);
+ }
+ }
+ state.flags &= ~wimp_WINDOW_VSCROLL;
+ }
+ }
- /* stop any tracking */
- ro_mouse_kill(g);
+ /* reformat or change extent if necessary */
+ if (have_content &&
+ (g->old_width != width || g->old_height != height)) {
+ /* Ctrl-resize of a top-level window scales the content size */
+ if ((g->old_width > 0) && (g->old_width != width) &&
+ (ro_gui_ctrl_pressed()))
+ new_scale = (g->scale * width) / g->old_width;
+ browser_window_schedule_reformat(g->bw);
+ }
+ if (g->update_extent || g->old_width != width ||
+ g->old_height != height) {
+ g->old_width = width;
+ g->old_height = height;
+ g->update_extent = false;
+ gui_window_set_extent(g, width, height);
+ }
- /* remove from list */
- if (g->prev)
- g->prev->next = g->next;
- else
- window_list = g->next;
- if (g->next)
- g->next->prev = g->prev;
+ /* first resize stops any flickering by making the URL window on top */
+ ro_gui_url_complete_resize(g->toolbar, PTR_WIMP_OPEN(&state));
- /* destroy toolbar */
- if (g->toolbar)
- ro_toolbar_destroy(g->toolbar);
- if (g->status_bar)
- ro_gui_status_bar_destroy(g->status_bar);
+ /* Windows containing framesets can only be scrolled via the core, which
+ * is implementing frame scrollbars itself. The x and y offsets are
+ * therefore fixed.
+ */
- w = g->window;
- ro_gui_url_complete_close();
- ro_gui_dialog_close_persistent(w);
- if (current_menu_window == w)
- ro_gui_menu_destroy();
- ro_gui_window_remove_update_boxes(g);
+ if (browser_window_is_frameset(g->bw)) {
+ state.xscroll = 0;
+ state.yscroll = toolbar_height;
+ }
- /* delete window */
- error = xwimp_delete_window(w);
+ error = xwimp_open_window_nested_with_flags(&state, parent, linkage);
if (error) {
- LOG("xwimp_delete_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
+ return;
}
- ro_gui_wimp_event_finalise(w);
-
- free(g);
-}
-
-/**
- * Set the title of a browser window.
- *
- * \param g gui_window to update
- * \param title new window title, copied
- */
-
-static void gui_window_set_title(struct gui_window *g, const char *title)
-{
- assert(g);
- assert(title);
-
- if (g->scale != 1.0) {
- int scale_disp = g->scale * 100;
-
- if (ABS((float)scale_disp - g->scale * 100) >= 0.05)
- snprintf(g->title, sizeof g->title, "%s (%.1f%%)",
- title, g->scale * 100);
- else
- snprintf(g->title, sizeof g->title, "%s (%i%%)",
- title, scale_disp);
- } else {
- strncpy(g->title, title, sizeof g->title);
+ /* update the toolbar */
+ if (g->status_bar)
+ ro_gui_status_bar_resize(g->status_bar);
+ if (g->toolbar) {
+ ro_toolbar_process(g->toolbar, -1, false);
+ /* second resize updates to the new URL bar width */
+ ro_gui_url_complete_resize(g->toolbar, open);
}
- ro_gui_set_window_title(g->window, g->title);
+ /* set the new scale from a ctrl-resize. this must be done at the end as
+ * it may cause a frameset recalculation based on the new window size.
+ */
+ if (new_scale > 0) {
+ ro_gui_window_set_scale(g, new_scale);
+ }
}
/**
- * Force a redraw of the entire contents of a browser window.
+ * Update the extent of the inside of a browser window to that of the
+ * current content.
*
- * \param g gui_window to redraw
+ * \param g gui_window to update the extent of
*/
-void gui_window_redraw_window(struct gui_window *g)
+static void gui_window_update_extent(struct gui_window *g)
{
- wimp_window_info info;
os_error *error;
+ wimp_window_info info;
assert(g);
+
info.w = g->window;
error = xwimp_get_window_info_header_only(&info);
if (error) {
- LOG("xwimp_get_window_info_header_only: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_info_header_only: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
- error = xwimp_force_redraw(g->window, info.extent.x0, info.extent.y0,
- info.extent.x1, info.extent.y1);
- if (error) {
- LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+
+ /* scroll on toolbar height change */
+ if (g->toolbar) {
+ int scroll = ro_toolbar_height(g->toolbar) - info.extent.y1;
+ info.yscroll += scroll;
}
+
+ /* Handle change of extents */
+ g->update_extent = true;
+ ro_gui_window_open(PTR_WIMP_OPEN(&info));
}
/**
- * Redraw an area of a window.
+ * Update a window and its toolbar
*
- * \param g The window to update
- * \param rect The area of the window to update.
+ * makes a window and toolbar reflect a new theme: used as a callback
+ * by the toolbar module when a theme change affects a toolbar.
+ *
+ * \param data void pointer to the window's gui_window struct
+ * \param ok true if the bar still exists; else false.
*/
-
-static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
+static void ro_gui_window_update_theme(void *data, bool ok)
{
- bool use_buffer;
- int x0, y0, x1, y1;
- struct update_box *cur;
-
- x0 = floorf(rect->x0 * 2 * g->scale);
- y0 = -ceilf(rect->y1 * 2 * g->scale);
- x1 = ceilf(rect->x1 * 2 * g->scale) + 1;
- y1 = -floorf(rect->y0 * 2 * g->scale) + 1;
- use_buffer =
- (g->option.buffer_everything || g->option.buffer_animations);
-
- /* try to optimise buffered redraws */
- if (use_buffer) {
- for (cur = pending_updates; cur != NULL; cur = cur->next) {
- if ((cur->g != g) || (!cur->use_buffer))
- continue;
- if ((((cur->x0 - x1) < MARGIN) || ((cur->x1 - x0) < MARGIN)) &&
- (((cur->y0 - y1) < MARGIN) || ((cur->y1 - y0) < MARGIN))) {
- cur->x0 = min(cur->x0, x0);
- cur->y0 = min(cur->y0, y0);
- cur->x1 = max(cur->x1, x1);
- cur->y1 = max(cur->y1, y1);
- return;
- }
+ struct gui_window *g = (struct gui_window *) data;
+ if (g != NULL && g->toolbar != NULL) {
+ if (ok) {
+ gui_window_update_extent(g);
+ } else {
+ g->toolbar = NULL;
}
}
- cur = malloc(sizeof(struct update_box));
- if (!cur) {
- LOG("No memory for malloc.");
- ro_warn_user("NoMemory", 0);
- return;
- }
- cur->x0 = x0;
- cur->y0 = y0;
- cur->x1 = x1;
- cur->y1 = y1;
- cur->next = pending_updates;
- pending_updates = cur;
- cur->g = g;
- cur->use_buffer = use_buffer;
}
/**
- * Get the scroll position of a browser window.
+ * Update a window to reflect a change in toolbar size: used as a callback by
+ * the toolbar module when a toolbar height changes.
*
- * \param g gui_window
- * \param sx receives x ordinate of point at top-left of window
- * \param sy receives y ordinate of point at top-left of window
- * \return true iff successful
+ * \param data void pointer the window's gui_window struct
*/
-
-static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
+static void ro_gui_window_update_toolbar(void *data)
{
- wimp_window_state state;
- os_error *error;
- int toolbar_height = 0;
-
- assert(g);
+ struct gui_window *g = (struct gui_window *) data;
- state.w = g->window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
+ if (g != NULL) {
+ gui_window_update_extent(g);
}
-
- if (g->toolbar)
- toolbar_height = ro_toolbar_full_height(g->toolbar);
- *sx = state.xscroll / (2 * g->scale);
- *sy = -(state.yscroll - toolbar_height) / (2 * g->scale);
- return true;
}
/**
- * Set the scroll position of a browser window.
+ * Update the toolbar buttons for a given browser window to reflect the
+ * current state of its contents.
*
- * \param g gui_window to scroll
- * \param sx point to place at top-left of window
- * \param sy point to place at top-left of window
+ * Note that the parameters to this function are arranged so that it can be
+ * supplied to the toolbar module as an button state update callback.
+ *
+ * \param g The browser window to update.
*/
-
-static void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
+static void ro_gui_window_update_toolbar_buttons(struct gui_window *g)
{
- wimp_window_state state;
- os_error *error;
-
- assert(g);
+ struct browser_window *bw;
+ struct toolbar *toolbar;
- state.w = g->window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (g == NULL || g->toolbar == NULL)
return;
- }
- state.xscroll = sx * 2 * g->scale;
- state.yscroll = -sy * 2 * g->scale;
- if (g->toolbar)
- state.yscroll += ro_toolbar_full_height(g->toolbar);
- ro_gui_window_open(PTR_WIMP_OPEN(&state));
-}
+ bw = g->bw;
+ toolbar = g->toolbar;
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_RELOAD,
+ !browser_window_reload_available(bw));
-/**
- * Scrolls the specified area of a browser window into view.
- *
- * \param g gui_window to scroll
- * \param x0 left point to ensure visible
- * \param y0 bottom point to ensure visible
- * \param x1 right point to ensure visible
- * \param y1 top point to ensure visible
- */
-static void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, int x1, int y1)
-{
- wimp_window_state state;
- os_error *error;
- int cx0, cy0, width, height;
- int padding_available;
- int toolbar_height = 0;
- int correction;
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_STOP,
+ !browser_window_stop_available(bw));
- assert(g);
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_BACK,
+ !browser_window_back_available(bw));
- state.w = g->window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_FORWARD,
+ !browser_window_forward_available(bw));
- if (g->toolbar)
- toolbar_height = ro_toolbar_full_height(g->toolbar);
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_UP,
+ !browser_window_up_available(bw));
- x0 = x0 * 2 * g->scale;
- y0 = y0 * 2 * g->scale;
- x1 = x1 * 2 * g->scale;
- y1 = y1 * 2 * g->scale;
-
- cx0 = state.xscroll;
- cy0 = -state.yscroll + toolbar_height;
- width = state.visible.x1 - state.visible.x0;
- height = state.visible.y1 - state.visible.y0 - toolbar_height;
-
- /* make sure we're visible */
- correction = (x1 - cx0 - width);
- if (correction > 0)
- cx0 += correction;
- correction = (y1 - cy0 - height);
- if (correction > 0)
- cy0 += correction;
- if (x0 < cx0)
- cx0 = x0;
- if (y0 < cy0)
- cy0 = y0;
-
- /* try to give a SCROLL_VISIBLE_PADDING border of space around us */
- padding_available = (width - x1 + x0) / 2;
- if (padding_available > 0) {
- if (padding_available > SCROLL_VISIBLE_PADDING)
- padding_available = SCROLL_VISIBLE_PADDING;
- correction = (cx0 + width - x1);
- if (correction < padding_available)
- cx0 += padding_available;
- correction = (x0 - cx0);
- if (correction < padding_available)
- cx0 -= padding_available;
- }
- padding_available = (height - y1 + y0) / 2;
- if (padding_available > 0) {
- if (padding_available > SCROLL_VISIBLE_PADDING)
- padding_available = SCROLL_VISIBLE_PADDING;
- correction = (cy0 + height - y1);
- if (correction < padding_available)
- cy0 += padding_available;
- correction = (y0 - cy0);
- if (correction < padding_available)
- cy0 -= padding_available;
- }
-
- state.xscroll = cx0;
- state.yscroll = -cy0 + toolbar_height;
- ro_gui_window_open(PTR_WIMP_OPEN(&state));
-}
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SEARCH,
+ !browser_window_can_search(bw));
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SCALE,
+ !browser_window_has_content(bw));
-/**
- * Find the current dimensions of a browser window's content area.
- *
- * \param g gui_window to measure
- * \param width receives width of window
- * \param height receives height of window
- * \param scaled whether to return scaled values
- */
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_PRINT,
+ !browser_window_has_content(bw));
-static void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bool scaled)
-{
- /* use the cached window sizes */
- *width = g->old_width / 2;
- *height = g->old_height / 2;
- if (scaled) {
- *width /= g->scale;
- *height /= g->scale;
- }
+ ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SAVE_SOURCE,
+ !browser_window_has_content(bw));
+
+ ro_toolbar_update_urlsuggest(toolbar);
}
/**
- * Update the extent of the inside of a browser window to that of the
- * current content.
+ * Add a hotlist entry for a browser window.
*
- * \param g gui_window to update the extent of
+ * \param g The browser window to act on.
*/
-
-static void gui_window_update_extent(struct gui_window *g)
+static void ro_gui_window_action_add_bookmark(struct gui_window *g)
{
- os_error *error;
- wimp_window_info info;
-
- assert(g);
+ nsurl *url;
- info.w = g->window;
- error = xwimp_get_window_info_header_only(&info);
- if (error) {
- LOG("xwimp_get_window_info_header_only: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (g == NULL || g->bw == NULL || g->toolbar == NULL ||
+ browser_window_has_content(g->bw) == false)
return;
- }
- /* scroll on toolbar height change */
- if (g->toolbar) {
- int scroll = ro_toolbar_height(g->toolbar) - info.extent.y1;
- info.yscroll += scroll;
- }
+ url = browser_window_access_url(g->bw);
- /* Handle change of extents */
- g->update_extent = true;
- ro_gui_window_open(PTR_WIMP_OPEN(&info));
+ ro_gui_hotlist_add_page(url);
+ ro_toolbar_update_hotlist(g->toolbar);
}
/**
- * Set the status bar of a browser window.
+ * Remove a hotlist entry for a browser window.
*
- * \param g gui_window to update
- * \param text new status text
+ * \param g The browser window to act on.
*/
-
-static void riscos_window_set_status(struct gui_window *g, const char *text)
+static void ro_gui_window_action_remove_bookmark(struct gui_window *g)
{
- if (g->status_bar)
- ro_gui_status_bar_set_text(g->status_bar, text);
+ nsurl *url;
+
+ if (g == NULL || g->bw == NULL || g->toolbar == NULL ||
+ browser_window_has_content(g->bw) == false)
+ return;
+
+ url = browser_window_access_url(g->bw);
+
+ ro_gui_hotlist_remove_page(url);
}
/**
- * Change mouse pointer shape
+ * Open a local history pane for a browser window.
+ *
+ * \param gw The browser window to act on.
*/
-
-void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
+static void ro_gui_window_action_local_history(struct gui_window *gw)
{
- static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT;
- struct ro_gui_pointer_entry *entry;
- os_error *error;
+ nserror res;
- if (shape == curr_pointer)
+ if ((gw == NULL) || (gw->bw == NULL)) {
return;
+ }
- assert(shape < sizeof ro_gui_pointer_table /
- sizeof ro_gui_pointer_table[0]);
-
- entry = &ro_gui_pointer_table[shape];
+ res = ro_gui_local_history_present(gw->window, gw->bw);
- if (entry->wimp_area) {
- /* pointer in the Wimp's sprite area */
- error = xwimpspriteop_set_pointer_shape(entry->sprite_name,
- 1, entry->xactive, entry->yactive, 0, 0);
- if (error) {
- LOG("xwimpspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- }
- } else {
- /* pointer in our own sprite area */
- error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA,
- gui_sprites,
- (osspriteop_id) entry->sprite_name,
- 1, entry->xactive, entry->yactive, 0, 0);
- if (error) {
- LOG("xosspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- }
+ if (res != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(res), 0);
}
-
- curr_pointer = shape;
}
-/* exported function documented in riscos/window.h */
-nserror ro_gui_window_set_url(struct gui_window *g, nsurl *url)
+/**
+ * Perform a Navigate Home action on a browser window.
+ *
+ * \param g The browser window to act on.
+ */
+static void ro_gui_window_action_home(struct gui_window *g)
{
- size_t idn_url_l;
- char *idn_url_s = NULL;
-
- if (g->toolbar) {
- if (nsoption_bool(display_decoded_idn) == true) {
- if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK)
- idn_url_s = NULL;
- }
-
- ro_toolbar_set_url(g->toolbar, idn_url_s ? idn_url_s : nsurl_access(url), true, false);
+ static const char *addr = NETSURF_HOMEPAGE;
+ nsurl *url;
+ nserror error;
- if (idn_url_s)
- free(idn_url_s);
+ if (g == NULL || g->bw == NULL)
+ return;
- ro_gui_url_complete_start(g->toolbar);
+ if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
}
- return NSERROR_OK;
+ error = nsurl_create(addr, &url);
+ if (error == NSERROR_OK) {
+ error = browser_window_navigate(g->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ }
}
/**
- * Update the interface to reflect start of page loading.
+ * Open a text search dialogue for a browser window.
*
- * \param g window with start of load
+ * \param g The browser window to act on.
*/
-
-static void gui_window_start_throbber(struct gui_window *g)
+static void ro_gui_window_action_search(struct gui_window *g)
{
- ro_gui_window_update_toolbar_buttons(g);
- ro_gui_menu_refresh(ro_gui_browser_window_menu);
- if (g->toolbar != NULL)
- ro_toolbar_start_throbbing(g->toolbar);
- g->active = true;
-}
+ if (g == NULL || g->bw == NULL || !browser_window_can_search(g->bw))
+ return;
+ ro_gui_search_prepare(g->bw);
+ ro_gui_dialog_open_persistent(g->window, dialog_search, true);
+}
/**
- * Update the interface to reflect page loading stopped.
+ * Open a zoom dialogue for a browser window.
*
- * \param g window with start of load
+ * \param g The browser window to act on.
*/
-
-static void gui_window_stop_throbber(struct gui_window *g)
+static void ro_gui_window_action_zoom(struct gui_window *g)
{
- ro_gui_window_update_toolbar_buttons(g);
- ro_gui_menu_refresh(ro_gui_browser_window_menu);
- if (g->toolbar != NULL)
- ro_toolbar_stop_throbbing(g->toolbar);
- g->active = false;
-}
-
-/**
- * set favicon
- */
-
-static void gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon)
-{
- if (g == NULL || g->toolbar == NULL)
+ if (g == NULL)
return;
- ro_toolbar_set_site_favicon(g->toolbar, icon);
+ ro_gui_dialog_prepare_zoom(g);
+ ro_gui_dialog_open_persistent(g->window, dialog_zoom, true);
}
-
/**
- * Remove the caret, if present.
+ * Open a save dialogue for a browser window contents.
*
- * \param g window with caret
+ * \param g The browser window to act on.
+ * \param save_type The type of save to open.
*/
-
-static void gui_window_remove_caret(struct gui_window *g)
+static void
+ro_gui_window_action_save(struct gui_window *g, gui_save_type save_type)
{
- wimp_caret caret;
- os_error *error;
+ struct hlcache_handle *h;
- error = xwimp_get_caret_position(&caret);
- if (error) {
- LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (g == NULL || g->bw == NULL || !browser_window_has_content(g->bw))
return;
- }
- if (caret.w != g->window)
- /* we don't have the caret: do nothing */
+ h = browser_window_get_content(g->bw);
+ if (h == NULL)
return;
- /* hide caret, but keep input focus */
- gui_window_place_caret(g, -100, -100, 0, NULL);
+ ro_gui_save_prepare(save_type, h, NULL, NULL, NULL);
+ ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
}
/**
- * Called when the gui_window has new content.
+ * Open a print dialogue for a browser window.
*
- * \param g the gui_window that has new content
+ * \param g The browser window to act on.
*/
-
-static void gui_window_new_content(struct gui_window *g)
+static void ro_gui_window_action_print(struct gui_window *g)
{
- ro_gui_menu_refresh(ro_gui_browser_window_menu);
- ro_gui_window_update_toolbar_buttons(g);
- ro_gui_dialog_close_persistent(g->window);
- ro_toolbar_set_content_favicon(g->toolbar, g);
+ if (g != NULL) {
+ ro_gui_print_prepare(g);
+ ro_gui_dialog_open_persistent(g->window, dialog_print, true);
+ }
}
/**
- * Starts drag scrolling of a browser window
+ * Prepare the page info window for use.
*
- * \param g the window to scroll
+ * \param g The GUI window block to use.
*/
-
-static bool gui_window_scroll_start(struct gui_window *g)
+static void ro_gui_window_prepare_pageinfo(struct gui_window *g)
{
- wimp_window_info_base info;
- wimp_pointer pointer;
- os_error *error;
- wimp_drag drag;
- int height;
- int width;
-
- error = xwimp_get_pointer_info(&pointer);
- if (error) {
- LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
- }
+ struct hlcache_handle *h = browser_window_get_content(g->bw);
+ char icon_buf[20] = "file_xxx";
+ char enc_buf[40];
+ const char *icon = icon_buf;
+ const char *title, *url;
+ lwc_string *mime;
+ const char *enc = "-";
- info.w = g->window;
- error = xwimp_get_window_info_header_only((wimp_window_info*)&info);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x : %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
- }
+ assert(h);
- width = info.extent.x1 - info.extent.x0;
- height = info.extent.y1 - info.extent.y0;
+ title = content_get_title(h);
+ if (title == NULL)
+ title = "-";
+ url = nsurl_access(hlcache_handle_get_url(h));
+ if (url == NULL)
+ url = "-";
+ mime = content_get_mime_type(h);
- drag.type = wimp_DRAG_USER_POINT;
- drag.bbox.x1 = pointer.pos.x + info.xscroll;
- drag.bbox.y0 = pointer.pos.y + info.yscroll;
- drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0));
- drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0));
+ sprintf(icon_buf, "file_%x", ro_content_filetype(h));
+ if (!ro_gui_wimp_sprite_exists(icon_buf))
+ sprintf(icon_buf, "file_xxx");
- if (g->toolbar) {
- int tbar_height = ro_toolbar_full_height(g->toolbar);
- drag.bbox.y0 -= tbar_height;
- drag.bbox.y1 -= tbar_height;
+ if (content_get_type(h) == CONTENT_HTML) {
+ if (content_get_encoding(h, CONTENT_ENCODING_NORMAL)) {
+ snprintf(enc_buf, sizeof enc_buf, "%s (%s)",
+ content_get_encoding(h, CONTENT_ENCODING_NORMAL),
+ content_get_encoding(h, CONTENT_ENCODING_SOURCE));
+ enc = enc_buf;
+ } else {
+ enc = messages_get("EncodingUnk");
+ }
}
- error = xwimp_drag_box(&drag);
- if (error) {
- LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
- }
+ ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ICON,
+ icon, true);
+ ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TITLE,
+ title, true);
+ ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_URL,
+ url, true);
+ ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC,
+ enc, true);
+ ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE,
+ lwc_string_data(mime), true);
- ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at,
- NULL, g);
- return true;
+ lwc_string_unref(mime);
}
/**
- * Platform-dependent part of starting drag operation.
+ * Open a page info box for a browser window.
*
- * \param g gui window containing the drag
- * \param type type of drag the core is performing
- * \param rect rectangle to constrain pointer to (relative to drag start coord)
- * \return true iff succesful
+ * \param g The browser window to act on.
*/
-
-static bool gui_window_drag_start(struct gui_window *g, gui_drag_type type,
- const struct rect *rect)
+static void ro_gui_window_action_page_info(struct gui_window *g)
{
- wimp_pointer pointer;
- wimp_drag drag;
-
- if (rect != NULL) {
- /* We have a box to constrain the pointer to, for the drag
- * duration */
- os_error *error = xwimp_get_pointer_info(&pointer);
- if (error) {
- LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
- }
-
- drag.type = wimp_DRAG_USER_POINT;
- drag.bbox.x0 = pointer.pos.x +
- (int)(rect->x0 * 2 * g->scale);
- drag.bbox.y0 = pointer.pos.y +
- (int)(rect->y0 * 2 * g->scale);
- drag.bbox.x1 = pointer.pos.x +
- (int)(rect->x1 * 2 * g->scale);
- drag.bbox.y1 = pointer.pos.y +
- (int)(rect->y1 * 2 * g->scale);
-
- error = xwimp_drag_box(&drag);
- if (error) {
- LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return false;
- }
- }
-
- switch (type) {
- case GDRAGGING_SCROLLBAR:
- /* Dragging a core scrollbar */
- ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at,
- NULL, g);
- break;
-
- default:
- /* Not handled here yet */
- break;
- }
+ if (g == NULL || g->bw == NULL ||
+ browser_window_has_content(g->bw) == false)
+ return;
- return true;
+ ro_gui_window_prepare_pageinfo(g);
+ ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, false);
}
/**
- * Save the specified content as a link.
+ * Process Mouse_Click events in a toolbar's button bar.
*
- * \param g The window containing the content
- * \param url The url of the link
- * \param title The title of the link
- */
-static nserror
-gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
-{
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
- return NSERROR_OK;
-}
-
-
-/**
- * Updates a windows extent.
+ * This does not handle other clicks in a toolbar: these are handled
+ * by the toolbar module itself.
*
- * \param g the gui_window to update
- * \param width the minimum width, or -1 to use window width
- * \param height the minimum height, or -1 to use window height
+ * \param data The GUI window associated with the click.
+ * \param action_type The action type to be handled.
+ * \param action The action to process.
*/
-
-void gui_window_set_extent(struct gui_window *g, int width, int height)
+static void
+ro_gui_window_toolbar_click(void *data,
+ toolbar_action_type action_type,
+ union toolbar_action action)
{
- int screen_width;
- int toolbar_height = 0;
- wimp_window_state state;
- os_error *error;
-
- if (g->toolbar)
- toolbar_height = ro_toolbar_full_height(g->toolbar);
-
- /* get the current state */
- if ((height == -1) || (width == -1)) {
- state.w = g->window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
- if (width == -1)
- width = state.visible.x1 - state.visible.x0;
- if (height == -1) {
- height = state.visible.y1 - state.visible.y0;
- height -= toolbar_height;
- }
- }
+ struct gui_window *g = data;
+ nserror err;
- /* the top-level framed window is a total pain. to get it to maximise
- * to the top of the screen we need to fake it having a suitably large
- * extent */
- if (browser_window_is_frameset(g->bw)) {
- ro_gui_screen_size(&screen_width, &height);
- if (g->toolbar)
- height -= ro_toolbar_full_height(g->toolbar);
- height -= ro_get_hscroll_height(g->window);
- height -= ro_get_title_height(g->window);
- }
- if (browser_window_has_content(g->bw)) {
- int w, h;
- browser_window_get_extents(g->bw, true, &w, &h);
- width = max(width, w * 2);
- height = max(height, h * 2);
- }
- os_box extent = { 0, -height, width, toolbar_height };
- error = xwimp_set_extent(g->window, &extent);
- if (error) {
- LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (g == NULL)
return;
- }
-}
-/**
- * Display a menu of options for a form select control.
- *
- * \param g gui window containing form control
- * \param control form control of type GADGET_SELECT
- */
-
-static void gui_window_create_form_select_menu(struct gui_window *g,
- struct form_control *control)
-{
- os_error *error;
- wimp_pointer pointer;
-
- /* The first time the menu is opened, control bypasses the normal
- * Menu Prepare event and so we prepare here. On any re-opens,
- * ro_gui_window_prepare_form_select_menu() is called from the
- * normal wimp event.
- */
-
- if (!ro_gui_window_prepare_form_select_menu(g, control))
- return;
-
- error = xwimp_get_pointer_info(&pointer);
- if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- ro_gui_menu_destroy();
- return;
- }
+ if (action_type == TOOLBAR_ACTION_URL) {
+ switch (action.url) {
+ case TOOLBAR_URL_DRAG_URL:
+ {
+ gui_save_type save_type;
+ nserror err;
+ nsurl *url;
- gui_form_select_control = control;
- ro_gui_menu_create(gui_form_select_menu,
- pointer.pos.x, pointer.pos.y, g->window);
-}
+ if (!browser_window_has_content(g->bw))
+ break;
+ if (ro_gui_shift_pressed())
+ save_type = GUI_SAVE_LINK_URL;
+ else
+ save_type = GUI_SAVE_LINK_TEXT;
-/*
- * RISC OS Wimp Event Handlers
- */
+ err = browser_window_get_url(g->bw, true, &url);
+ if (err != NSERROR_OK) {
+ /* Fall back to access (won't get fragment). */
+ url = nsurl_ref(
+ browser_window_access_url(g->bw));
+ }
+ ro_gui_drag_save_link(save_type, url,
+ browser_window_get_title(g->bw), g);
-/**
- * Handle a Redraw_Window_Request for a browser window.
- */
+ nsurl_unref(url);
+ }
+ break;
-void ro_gui_window_redraw(wimp_draw *redraw)
-{
- osbool more;
- struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
- os_error *error;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
+ case TOOLBAR_URL_SELECT_HOTLIST:
+ ro_gui_window_action_add_bookmark(g);
+ break;
- /* We can't render locked contents. If the browser window is not
- * ready for redraw, do nothing. Else, in the case of buffered
- * rendering we'll show random data. */
- if (!browser_window_redraw_ready(g->bw))
- return;
+ case TOOLBAR_URL_ADJUST_HOTLIST:
+ ro_gui_window_action_remove_bookmark(g);
+ break;
- ro_gui_current_redraw_gui = g;
+ default:
+ break;
+ }
- error = xwimp_redraw_window(redraw, &more);
- if (error) {
- LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
return;
}
- while (more) {
- struct rect clip;
- /* OS's redraw request coordinates are in screen coordinates,
- * with an origin at the bottom left of the screen.
- * Find the coordinate of the top left of the document in terms
- * of OS screen coordinates.
- * NOTE: OS units are 2 per px. */
- ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
- /* Convert OS redraw rectangle request coordinates into NetSurf
- * coordinates. NetSurf coordinates have origin at top left of
- * document and units are in px. */
- clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
- clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
- clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
- clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
+ /* By now, the only valid action left is a button click. If it isn't
+ * one of those, give up.
+ */
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_open(redraw);
+ if (action_type != TOOLBAR_ACTION_BUTTON)
+ return;
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
+ switch (action.button) {
+ case TOOLBAR_BUTTON_BACK:
+ if (g->bw != NULL)
+ browser_window_history_back(g->bw, false);
+ break;
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_close();
+ case TOOLBAR_BUTTON_BACK_NEW:
+ if (g->bw != NULL)
+ browser_window_history_back(g->bw, true);
+ break;
- /* Check to see if there are more rectangles to draw and
- * get next one */
- error = xwimp_get_rectangle(redraw, &more);
- /* RISC OS 3.7 returns an error here if enough buffer was
- claimed to cause a new dynamic area to be created. It
- doesn't actually stop anything working, so we mask it out
- for now until a better fix is found. This appears to be a
- bug in RISC OS. */
- if (error && !(ro_gui_current_redraw_gui->
- option.buffer_everything &&
- error->errnum == error_WIMP_GET_RECT)) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- ro_gui_current_redraw_gui = NULL;
- return;
- }
- }
- ro_gui_current_redraw_gui = NULL;
-}
+ case TOOLBAR_BUTTON_FORWARD:
+ if (g->bw != NULL)
+ browser_window_history_forward(g->bw, false);
+ break;
+ case TOOLBAR_BUTTON_FORWARD_NEW:
+ if (g->bw != NULL)
+ browser_window_history_forward(g->bw, true);
+ break;
-/**
- * Set a gui_window's scale
- */
-void ro_gui_window_set_scale(struct gui_window *g, float scale)
-{
- g->scale = scale;
- browser_window_set_scale(g->bw, scale, true);
-}
+ case TOOLBAR_BUTTON_STOP:
+ if (g->bw != NULL)
+ browser_window_stop(g->bw);
+ break;
+ case TOOLBAR_BUTTON_RELOAD:
+ if (g->bw != NULL)
+ browser_window_reload(g->bw, false);
+ break;
-/**
- * Open a window using the given wimp_open, handling toolbars and resizing.
- */
+ case TOOLBAR_BUTTON_RELOAD_ALL:
+ if (g->bw != NULL)
+ browser_window_reload(g->bw, true);
+ break;
-void ro_gui_window_open(wimp_open *open)
-{
- struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(open->w);
- int width = open->visible.x1 - open->visible.x0;
- int height = open->visible.y1 - open->visible.y0;
- browser_scrolling h_scroll;
- browser_scrolling v_scroll;
- int toolbar_height = 0;
- float new_scale = 0;
- wimp_window_state state;
- os_error *error;
- wimp_w parent;
- bits linkage;
- bool have_content;
+ case TOOLBAR_BUTTON_HISTORY_LOCAL:
+ ro_gui_window_action_local_history(g);
+ break;
- if (open->next == wimp_TOP && g->iconise_icon >= 0) {
- /* window is no longer iconised, release its sprite number */
- iconise_used[g->iconise_icon] = false;
- g->iconise_icon = -1;
- }
+ case TOOLBAR_BUTTON_HISTORY_GLOBAL:
+ ro_gui_global_history_present();
+ break;
- have_content = browser_window_has_content(g->bw);
+ case TOOLBAR_BUTTON_HOME:
+ ro_gui_window_action_home(g);
+ break;
- /* get the current flags/nesting state */
- state.w = g->window;
- error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- return;
- }
+ case TOOLBAR_BUTTON_SEARCH:
+ ro_gui_window_action_search(g);
+ break;
- /* account for toolbar height, if present */
- if (g->toolbar)
- toolbar_height = ro_toolbar_full_height(g->toolbar);
- height -= toolbar_height;
+ case TOOLBAR_BUTTON_SCALE:
+ ro_gui_window_action_zoom(g);
+ break;
- /* work with the state from now on so we can modify flags */
- state.visible = open->visible;
- state.xscroll = open->xscroll;
- state.yscroll = open->yscroll;
- state.next = open->next;
+ case TOOLBAR_BUTTON_BOOKMARK_OPEN:
+ ro_gui_hotlist_present();
+ break;
- browser_window_get_scrollbar_type(g->bw, &h_scroll, &v_scroll);
+ case TOOLBAR_BUTTON_BOOKMARK_ADD:
+ ro_gui_window_action_add_bookmark(g);
+ break;
- /* handle 'auto' scroll bars' and non-fitting scrollbar removal */
- if ((h_scroll != BW_SCROLLING_NO) && (v_scroll != BW_SCROLLING_NO)) {
- int size;
+ case TOOLBAR_BUTTON_SAVE_SOURCE:
+ ro_gui_window_action_save(g, GUI_SAVE_SOURCE);
+ break;
- /* windows lose scrollbars when containing a frameset */
- bool no_hscroll = false;
- bool no_vscroll = browser_window_is_frameset(g->bw);
+ case TOOLBAR_BUTTON_SAVE_COMPLETE:
+ ro_gui_window_action_save(g, GUI_SAVE_COMPLETE);
+ break;
- /* hscroll */
- size = ro_get_hscroll_height(NULL);
- size -= 2; /* 1px border on both sides */
- if (!no_hscroll) {
- if (!(state.flags & wimp_WINDOW_HSCROLL)) {
- height -= size;
- state.visible.y0 += size;
- if (have_content) {
- browser_window_schedule_reformat(g->bw);
- }
- }
- state.flags |= wimp_WINDOW_HSCROLL;
- } else {
- if (state.flags & wimp_WINDOW_HSCROLL) {
- height += size;
- state.visible.y0 -= size;
- if (have_content) {
- browser_window_schedule_reformat(g->bw);
- }
- }
- state.flags &= ~wimp_WINDOW_HSCROLL;
+ case TOOLBAR_BUTTON_PRINT:
+ ro_gui_window_action_print(g);
+ break;
+
+ case TOOLBAR_BUTTON_UP:
+ err = browser_window_navigate_up(g->bw, false);
+ if (err != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(err), NULL);
}
+ break;
- /* vscroll */
- size = ro_get_vscroll_width(NULL);
- size -= 2; /* 1px border on both sides */
- if (!no_vscroll) {
- if (!(state.flags & wimp_WINDOW_VSCROLL)) {
- width -= size;
- state.visible.x1 -= size;
- if (have_content) {
- browser_window_schedule_reformat(g->bw);
- }
- }
- state.flags |= wimp_WINDOW_VSCROLL;
- } else {
- if (state.flags & wimp_WINDOW_VSCROLL) {
- width += size;
- state.visible.x1 += size;
- if (have_content) {
- browser_window_schedule_reformat(g->bw);
- }
- }
- state.flags &= ~wimp_WINDOW_VSCROLL;
+ case TOOLBAR_BUTTON_UP_NEW:
+ err = browser_window_navigate_up(g->bw, true);
+ if (err != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(err), NULL);
}
- }
+ break;
- /* reformat or change extent if necessary */
- if (have_content &&
- (g->old_width != width || g->old_height != height)) {
- /* Ctrl-resize of a top-level window scales the content size */
- if ((g->old_width > 0) && (g->old_width != width) &&
- (ro_gui_ctrl_pressed()))
- new_scale = (g->scale * width) / g->old_width;
- browser_window_schedule_reformat(g->bw);
- }
- if (g->update_extent || g->old_width != width ||
- g->old_height != height) {
- g->old_width = width;
- g->old_height = height;
- g->update_extent = false;
- gui_window_set_extent(g, width, height);
+ default:
+ break;
}
- /* first resize stops any flickering by making the URL window on top */
- ro_gui_url_complete_resize(g->toolbar, PTR_WIMP_OPEN(&state));
+ ro_gui_window_update_toolbar_buttons(g);
+}
- /* Windows containing framesets can only be scrolled via the core, which
- * is implementing frame scrollbars itself. The x and y offsets are
- * therefore fixed.
- */
- if (browser_window_is_frameset(g->bw)) {
- state.xscroll = 0;
- state.yscroll = toolbar_height;
- }
+/**
+ * Launch a new url in the given window.
+ *
+ * \param g gui_window to update
+ * \param url1 url to be launched
+ */
+static void ro_gui_window_launch_url(struct gui_window *g, const char *url1)
+{
+ nserror error;
+ nsurl *url;
- error = xwimp_open_window_nested_with_flags(&state, parent, linkage);
- if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (url1 == NULL)
return;
- }
- /* update the toolbar */
- if (g->status_bar)
- ro_gui_status_bar_resize(g->status_bar);
- if (g->toolbar) {
- ro_toolbar_process(g->toolbar, -1, false);
- /* second resize updates to the new URL bar width */
- ro_gui_url_complete_resize(g->toolbar, open);
- }
+ ro_gui_url_complete_close();
- /* set the new scale from a ctrl-resize. this must be done at the end as
- * it may cause a frameset recalculation based on the new window size.
- */
- if (new_scale > 0) {
- ro_gui_window_set_scale(g, new_scale);
+ error = nsurl_create(url1, &url);
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
+ } else {
+ ro_gui_window_set_url(g, url);
+
+ browser_window_navigate(g->bw, url,
+ NULL, BW_NAVIGATE_HISTORY,
+ NULL, NULL, NULL);
+ nsurl_unref(url);
}
}
/**
- * Handle wimp closing event
+ * Open a new browser window.
+ *
+ * \param g The browser window to act on.
*/
-
-void ro_gui_window_close(wimp_w w)
+static void ro_gui_window_action_new_window(struct gui_window *g)
{
- struct gui_window *g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w);
- wimp_pointer pointer;
- os_error *error;
- char *temp_name;
- char *filename = NULL;
- struct nsurl *url;
- bool destroy;
+ nserror error;
- error = xwimp_get_pointer_info(&pointer);
- if (error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
+ if (g == NULL || g->bw == NULL)
return;
- }
- if (pointer.buttons & wimp_CLICK_ADJUST) {
- destroy = !ro_gui_shift_pressed();
+ error = browser_window_create(BW_CREATE_CLONE,
+ browser_window_access_url(g->bw),
+ NULL, g->bw, NULL);
- url = browser_window_get_url(g->bw);
- if (url != NULL) {
- netsurf_nsurl_to_path(url, &filename);
- }
- if (filename != NULL) {
- temp_name = malloc(strlen(filename) + 32);
- if (temp_name) {
- char *r;
- sprintf(temp_name, "Filer_OpenDir %s",
- filename);
- r = temp_name + strlen(temp_name);
- while (r > temp_name) {
- if (*r == '.') {
- *r = '\0';
- break;
- }
- r--;
- }
- error = xos_cli(temp_name);
- if (error) {
- LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("MiscError", error->errmess);
- return;
- }
- free(temp_name);
- }
- free(filename);
- } else {
- /* this is pointless if we are about to close the
- * window */
- if (!destroy && url != NULL)
- browser_window_navigate_up(g->bw, false);
- }
+ if (error != NSERROR_OK) {
+ ro_warn_user(messages_get_errorcode(error), 0);
}
- else
- destroy = true;
-
- if (destroy)
- browser_window_destroy(g->bw);
}
/**
- * Handle Mouse_Click events in a browser window. This should never see
- * Menu clicks, as these will be routed to the menu handlers.
+ * Scroll a browser window.
+ *
+ * the scroll is either via the core or directly using the normal
+ * Wimp_OpenWindow interface.
+ *
+ * Scroll steps are supplied in terms of the (extended) Scroll Event direction
+ * values returned by Wimp_Poll. Special values of 0x7fffffff and 0x80000000
+ * are added to mean "Home" and "End".
*
- * \param *pointer details of mouse click
- * \return true if click handled, false otherwise
+ * \param g The GUI Window to be scrolled.
+ * \param scroll_x The X scroll step to be applied.
+ * \param scroll_y The Y scroll step to be applied.
*/
-
-bool ro_gui_window_click(wimp_pointer *pointer)
+static void
+ro_gui_window_scroll_action(struct gui_window *g,
+ wimp_scroll_direction scroll_x,
+ wimp_scroll_direction scroll_y)
{
- struct gui_window *g;
- os_coord pos;
+ int visible_x, visible_y;
+ int step_x = 0, step_y = 0;
+ int toolbar_y;
+ wimp_window_state state;
+ wimp_pointer pointer;
+ os_error *error;
+ os_coord pos;
+ bool handled = false;
+ struct toolbar *toolbar;
- /* We should never see Menu clicks. */
+ if (g == NULL)
+ return;
- if (pointer->buttons == wimp_CLICK_MENU)
- return false;
+ /* Get the current window, toolbar and pointer details. */
- g = (struct gui_window *) ro_gui_wimp_event_get_user_data(pointer->w);
+ state.w = g->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ return;
+ }
- /* try to close url-completion */
- ro_gui_url_complete_close();
+ toolbar = ro_toolbar_parent_window_lookup(g->window);
+ assert(g == NULL || g->toolbar == NULL || g->toolbar == toolbar);
- /* set input focus */
- if (pointer->buttons & (wimp_SINGLE_SELECT | wimp_SINGLE_ADJUST))
- gui_window_place_caret(g, -100, -100, 0, NULL);
+ toolbar_y = (toolbar == NULL) ? 0 : ro_toolbar_full_height(toolbar);
- if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos))
- browser_window_mouse_click(g->bw,
- ro_gui_mouse_click_state(pointer->buttons,
- wimp_BUTTON_DOUBLE_CLICK_DRAG),
- pos.x, pos.y);
+ visible_x = state.visible.x1 - state.visible.x0 - 32;
+ visible_y = state.visible.y1 - state.visible.y0 - 32 - toolbar_y;
- return true;
-}
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info 0x%x : %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ /* Turn the scroll requirement from Scroll Event codes into coordinates
+ * that the core can understand.
+ */
-/**
- * Process Key_Pressed events in a browser window.
- *
- * \param *key The wimp keypress block for the event.
- * \return true if the event was handled, else false.
- */
+ switch (scroll_x) {
+ case wimp_SCROLL_PAGE_LEFT:
+ step_x = SCROLL_PAGE_DOWN;
+ break;
+ case wimp_SCROLL_AUTO_LEFT:
+ case wimp_SCROLL_COLUMN_LEFT:
+ step_x = -16;
+ break;
+ case wimp_SCROLL_AUTO_RIGHT:
+ case wimp_SCROLL_COLUMN_RIGHT:
+ step_x = 16;
+ break;
+ case wimp_SCROLL_PAGE_RIGHT:
+ step_x = SCROLL_PAGE_UP;
+ break;
+ case 0x80000000:
+ step_x = SCROLL_BOTTOM;
+ break;
+ case 0x7fffffff:
+ step_x = SCROLL_TOP;
+ break;
+ default:
+ step_x = (visible_x * (scroll_x>>2)) >> 2;
+ break;
+ }
-bool ro_gui_window_keypress(wimp_key *key)
-{
- struct gui_window *g;
- uint32_t c = (uint32_t) key->c;
+ switch (scroll_y) {
+ case wimp_SCROLL_PAGE_UP:
+ step_y = SCROLL_PAGE_UP;
+ break;
+ case wimp_SCROLL_AUTO_UP:
+ case wimp_SCROLL_LINE_UP:
+ step_y = -16;
+ break;
+ case wimp_SCROLL_AUTO_DOWN:
+ case wimp_SCROLL_LINE_DOWN:
+ step_y = 16;
+ break;
+ case wimp_SCROLL_PAGE_DOWN:
+ step_y = SCROLL_PAGE_DOWN;
+ break;
+ case 0x80000000:
+ step_y = SCROLL_BOTTOM;
+ break;
+ case 0x7fffffff:
+ step_y = SCROLL_TOP;
+ break;
+ default:
+ step_y = -((visible_y * (scroll_y>>2)) >> 2);
+ break;
+ }
- g = (struct gui_window *) ro_gui_wimp_event_get_user_data(key->w);
- if (g == NULL)
- return false;
+ /* If no scrolling is required, there's no point trying to do any. */
- /* First send the key to the browser window, eg. form fields. */
+ if (step_x == 0 && step_y == 0)
+ return;
- if ((unsigned)c < 0x20 || (0x7f <= c && c <= 0x9f) ||
- (c & IS_WIMP_KEY)) {
- /* Munge control keys into unused control chars */
- /* We can't map onto 1->26 (reserved for ctrl+<qwerty>
- That leaves 27->31 and 128->159 */
- switch (c & ~IS_WIMP_KEY) {
- case wimp_KEY_TAB: c = 9; break;
- case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break;
+ /* If the pointer is over the window being scrolled, then try to get
+ * the core to do the scrolling on the object under the pointer.
+ */
- /* cursor movement keys */
- case wimp_KEY_HOME:
- case wimp_KEY_CONTROL | wimp_KEY_LEFT:
- c = NS_KEY_LINE_START;
+ if (pointer.w == g->window &&
+ ro_gui_window_to_window_pos(g,
+ pointer.pos.x, pointer.pos.y, &pos))
+ handled = browser_window_scroll_at_point(g->bw, pos.x, pos.y,
+ step_x, step_y);
+
+ /* If the core didn't do the scrolling, handle it via the Wimp.
+ * Windows which contain frames can only be scrolled by the core,
+ * because it implements frame scroll bars.
+ */
+
+ if (!handled && (browser_window_is_frameset(g->bw) == false)) {
+ switch (step_x) {
+ case SCROLL_TOP:
+ state.xscroll -= 0x10000000;
break;
- case wimp_KEY_END:
- if (os_version >= RISCOS5)
- c = NS_KEY_LINE_END;
- else
- c = NS_KEY_DELETE_RIGHT;
+ case SCROLL_BOTTOM:
+ state.xscroll += 0x10000000;
break;
- case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = NS_KEY_LINE_END; break;
- case wimp_KEY_CONTROL | wimp_KEY_UP: c = NS_KEY_TEXT_START; break;
- case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = NS_KEY_TEXT_END; break;
- case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = NS_KEY_WORD_LEFT ; break;
- case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = NS_KEY_WORD_RIGHT; break;
- case wimp_KEY_SHIFT | wimp_KEY_UP: c = NS_KEY_PAGE_UP; break;
- case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = NS_KEY_PAGE_DOWN; break;
- case wimp_KEY_LEFT: c = NS_KEY_LEFT; break;
- case wimp_KEY_RIGHT: c = NS_KEY_RIGHT; break;
- case wimp_KEY_UP: c = NS_KEY_UP; break;
- case wimp_KEY_DOWN: c = NS_KEY_DOWN; break;
-
- /* editing */
- case wimp_KEY_CONTROL | wimp_KEY_END:
- c = NS_KEY_DELETE_LINE_END;
+ case SCROLL_PAGE_UP:
+ state.xscroll += visible_x;
break;
- case wimp_KEY_DELETE:
- if (ro_gui_ctrl_pressed())
- c = NS_KEY_DELETE_LINE_START;
- else if (os_version < RISCOS5)
- c = NS_KEY_DELETE_LEFT;
+ case SCROLL_PAGE_DOWN:
+ state.xscroll -= visible_x;
break;
+ default:
+ state.xscroll += 2 * step_x;
+ break;
+ }
- case wimp_KEY_F8:
- c = NS_KEY_UNDO;
+ switch (step_y) {
+ case SCROLL_TOP:
+ state.yscroll += 0x10000000;
break;
- case wimp_KEY_F9:
- c = NS_KEY_REDO;
+ case SCROLL_BOTTOM:
+ state.yscroll -= 0x10000000;
+ break;
+ case SCROLL_PAGE_UP:
+ state.yscroll += visible_y;
+ break;
+ case SCROLL_PAGE_DOWN:
+ state.yscroll -= visible_y;
break;
-
default:
+ state.yscroll -= 2 * step_y;
break;
}
- }
- if (!(c & IS_WIMP_KEY)) {
- if (browser_window_key_press(g->bw, c))
- return true;
+ error = xwimp_open_window((wimp_open *) &state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
+ error->errnum, error->errmess);
+ }
}
-
- return ro_gui_window_handle_local_keypress(g, key, false);
}
/**
- * Callback handler for keypresses within browser window toolbars.
+ * Handle keypresses within the RISC OS GUI
*
- * \param *data Client data, pointing to the GUI Window.
- * \param *key The keypress data.
- * \return true if the keypress was handled; else false.
- */
-
-bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key)
-{
- struct gui_window *g = (struct gui_window *) data;
-
- if (g != NULL)
- return ro_gui_window_handle_local_keypress(g, key, true);
-
- return false;
-}
-
-
-/**
- * Handle keypresses within the RISC OS GUI: this is to be called after the
- * core has been given a chance to act, or on keypresses in the toolbar where
- * the core doesn't get involved.
+ * this is to be called after the core has been given a chance to act,
+ * or on keypresses in the toolbar where the core doesn't get
+ * involved.
*
- * \param *g The gui window to which the keypress applies.
- * \param *key The keypress data.
- * \param is_toolbar true if the keypress is from a toolbar;
- * else false.
- * \return true if the keypress was claimed; else false.
+ * \param *g The gui window to which the keypress applies.
+ * \param *key The keypress data.
+ * \param is_toolbar true if the keypress is from a toolbar else false.
+ * \return true if the keypress was claimed; else false.
*/
-
-bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key,
- bool is_toolbar)
+static bool
+ro_gui_window_handle_local_keypress(struct gui_window *g,
+ wimp_key *key,
+ bool is_toolbar)
{
struct browser_window_features cont;
os_error *ro_error;
@@ -1862,7 +1240,8 @@ bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key,
ro_error = xwimp_get_pointer_info(&pointer);
if (ro_error) {
- LOG("xwimp_get_pointer_info: 0x%x: %s\n", ro_error->errnum, ro_error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s\n",
+ ro_error->errnum, ro_error->errmess);
ro_warn_user("WimpError", ro_error->errmess);
return false;
}
@@ -1983,7 +1362,7 @@ bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key,
/* Toggle display of box outlines. */
browser_window_debug(g->bw, CONTENT_DEBUG_REDRAW);
- gui_window_redraw_window(g);
+ ro_gui_window_invalidate_area(g, NULL);
return true;
case wimp_KEY_RETURN:
@@ -2108,18 +1487,648 @@ bool ro_gui_window_handle_local_keypress(struct gui_window *g, wimp_key *key,
/**
- * Prepare the browser window menu for (re-)opening
+ * Callback handler for keypresses within browser window toolbars.
+ *
+ * \param data Client data, pointing to the GUI Window.
+ * \param key The keypress data.
+ * \return true if the keypress was handled; else false.
+ */
+static bool ro_gui_window_toolbar_keypress(void *data, wimp_key *key)
+{
+ struct gui_window *g = (struct gui_window *) data;
+
+ if (g != NULL) {
+ return ro_gui_window_handle_local_keypress(g, key, true);
+ }
+
+ return false;
+}
+
+
+/**
+ * Save a new toolbar button configuration
+ *
+ * used as a callback by the toolbar module when a buttonbar edit has
+ * finished.
+ *
+ * \param data void pointer to the window's gui_window struct
+ * \param config pointer to a malloc()'d button config string.
+ */
+static void ro_gui_window_save_toolbar_buttons(void *data, char *config)
+{
+ nsoption_set_charp(toolbar_browser, config);
+ ro_gui_save_options();
+}
+
+
+/**
+ * toolbar callbacks for a browser window.
+ */
+static const struct toolbar_callbacks ro_gui_window_toolbar_callbacks = {
+ ro_gui_window_update_theme,
+ ro_gui_window_update_toolbar,
+ (void (*)(void *)) ro_gui_window_update_toolbar_buttons,
+ ro_gui_window_toolbar_click,
+ ro_gui_window_toolbar_keypress,
+ ro_gui_window_save_toolbar_buttons
+};
+
+
+/**
+ * Handle wimp closing event
+ *
+ * \param w The window handle the event occoured on
+ */
+static void ro_gui_window_close(wimp_w w)
+{
+ struct gui_window *g;
+ wimp_pointer pointer;
+ os_error *error;
+ char *temp_name;
+ char *filename = NULL;
+ struct nsurl *url;
+ bool destroy;
+
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+
+ g = (struct gui_window *)ro_gui_wimp_event_get_user_data(w);
+
+ if (pointer.buttons & wimp_CLICK_ADJUST) {
+ destroy = !ro_gui_shift_pressed();
+
+ url = browser_window_access_url(g->bw);
+ if (url != NULL) {
+ netsurf_nsurl_to_path(url, &filename);
+ }
+ if (filename != NULL) {
+ temp_name = malloc(strlen(filename) + 32);
+ if (temp_name) {
+ char *r;
+ sprintf(temp_name, "Filer_OpenDir %s",
+ filename);
+ r = temp_name + strlen(temp_name);
+ while (r > temp_name) {
+ if (*r == '.') {
+ *r = '\0';
+ break;
+ }
+ r--;
+ }
+ error = xos_cli(temp_name);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xos_cli: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ return;
+ }
+ free(temp_name);
+ }
+ free(filename);
+ } else {
+ /* this is pointless if we are about to close the
+ * window */
+ if (!destroy && url != NULL)
+ browser_window_navigate_up(g->bw, false);
+ }
+ } else {
+ destroy = true;
+ }
+
+ if (destroy) {
+ browser_window_destroy(g->bw);
+ }
+}
+
+
+/**
+ * Handle a Redraw_Window_Request for a browser window.
+ *
+ * \param redraw The redraw event
+ */
+static void ro_gui_window_redraw(wimp_draw *redraw)
+{
+ osbool more;
+ struct gui_window *g;
+ os_error *error;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+
+ g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
+
+ /* We cannot render locked contents. If the browser window is not
+ * ready for redraw, do nothing. Else, in the case of buffered
+ * rendering we'll show random data. */
+ if (!browser_window_redraw_ready(g->bw)) {
+ return;
+ }
+
+ ro_gui_current_redraw_gui = g;
+
+ error = xwimp_redraw_window(redraw, &more);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return;
+ }
+ while (more) {
+ struct rect clip;
+
+ /* OS's redraw request coordinates are in screen coordinates,
+ * with an origin at the bottom left of the screen.
+ * Find the coordinate of the top left of the document in terms
+ * of OS screen coordinates.
+ * NOTE: OS units are 2 per px. */
+ ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
+ ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
+
+ /* Convert OS redraw rectangle request coordinates into NetSurf
+ * coordinates. NetSurf coordinates have origin at top left of
+ * document and units are in px. */
+ clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
+ clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
+ clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
+ clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
+
+ if (ro_gui_current_redraw_gui->option.buffer_everything)
+ ro_gui_buffer_open(redraw);
+
+ browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
+
+ if (ro_gui_current_redraw_gui->option.buffer_everything)
+ ro_gui_buffer_close();
+
+ /* Check to see if there are more rectangles to draw and
+ * get next one */
+ error = xwimp_get_rectangle(redraw, &more);
+ /* RISC OS 3.7 returns an error here if enough buffer was
+ claimed to cause a new dynamic area to be created. It
+ doesn't actually stop anything working, so we mask it out
+ for now until a better fix is found. This appears to be a
+ bug in RISC OS. */
+ if (error && !(ro_gui_current_redraw_gui->
+ option.buffer_everything &&
+ error->errnum == error_WIMP_GET_RECT)) {
+ NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ ro_gui_current_redraw_gui = NULL;
+ return;
+ }
+ }
+ ro_gui_current_redraw_gui = NULL;
+}
+
+
+/**
+ * Process Scroll_Request events in a browser window.
+ *
+ * \param scroll The wimp scroll event data block.
+ */
+static void ro_gui_window_scroll(wimp_scroll *scroll)
+{
+ struct gui_window *g = ro_gui_window_lookup(scroll->w);
+
+ if (g && browser_window_has_content(g->bw) && ro_gui_shift_pressed()) {
+ /* extended scroll request with shift held down; change zoom */
+ float scale, inc;
+
+ if (scroll->ymin & 3)
+ inc = 0.02; /* RO5 sends the msg 5 times;
+ * don't ask me why
+ *
+ * @todo this is liable to break if
+ * HID is configured optimally for
+ * frame scrolling. *5 appears to be
+ * an artifact of non-HID mode scrolling.
+ */
+ else
+ inc = (1 << (ABS(scroll->ymin)>>2)) / 20.0F;
+
+ if (scroll->ymin > 0) {
+ scale = g->scale + inc;
+ if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1])
+ scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1];
+ } else {
+ scale = g->scale - inc;
+ if (scale < scale_snap_to[0])
+ scale = scale_snap_to[0];
+ }
+ if (g->scale != scale)
+ ro_gui_window_set_scale(g, scale);
+ } else if (g != NULL) {
+ ro_gui_window_scroll_action(g, scroll->xmin, scroll->ymin);
+ }
+}
+
+
+/**
+ * Process Pointer Leaving Window events in a browser window.
+ *
+ * These arrive via the termination callback handler from ro_mouse's
+ * mouse tracking.
+ *
+ * \param leaving The wimp pointer leaving event data block.
+ * \param data The GUI window that the pointer is leaving.
+ */
+static void ro_gui_window_track_end(wimp_leaving *leaving, void *data)
+{
+ struct gui_window *g = (struct gui_window *)data;
+
+ if (g != NULL) {
+ gui_window_set_pointer(g, GUI_POINTER_DEFAULT);
+ }
+}
+
+
+/**
+ * Process Pointer Entering Window events in a browser window.
+ *
+ * \param entering The wimp pointer entering event data block.
+ */
+static void ro_gui_window_pointer_entering(wimp_entering *entering)
+{
+ struct gui_window *g = ro_gui_window_lookup(entering->w);
+
+ if (g != NULL) {
+ ro_mouse_track_start(ro_gui_window_track_end,
+ ro_gui_window_mouse_at,
+ g);
+ }
+}
+
+
+/**
+ * Process Key_Pressed events in a browser window.
+ *
+ * \param key The wimp keypress block for the event.
+ * \return true if the event was handled, else false.
+ */
+static bool ro_gui_window_keypress(wimp_key *key)
+{
+ struct gui_window *g;
+ uint32_t c = (uint32_t) key->c;
+
+ g = (struct gui_window *) ro_gui_wimp_event_get_user_data(key->w);
+ if (g == NULL) {
+ return false;
+ }
+
+ /* First send the key to the browser window, eg. form fields. */
+
+ if ((unsigned)c < 0x20 ||
+ (0x7f <= c && c <= 0x9f) ||
+ (c & IS_WIMP_KEY)) {
+ /* Munge control keys into unused control chars */
+ /* We can't map onto 1->26 (reserved for ctrl+<qwerty>
+ That leaves 27->31 and 128->159 */
+ switch (c & ~IS_WIMP_KEY) {
+ case wimp_KEY_TAB:
+ c = 9;
+ break;
+
+ case wimp_KEY_SHIFT | wimp_KEY_TAB:
+ c = 11;
+ break;
+
+ /* cursor movement keys */
+ case wimp_KEY_HOME:
+ case wimp_KEY_CONTROL | wimp_KEY_LEFT:
+ c = NS_KEY_LINE_START;
+ break;
+
+ case wimp_KEY_END:
+ if (os_version >= RISCOS5) {
+ c = NS_KEY_LINE_END;
+ } else {
+ c = NS_KEY_DELETE_RIGHT;
+ }
+ break;
+
+ case wimp_KEY_CONTROL | wimp_KEY_RIGHT:
+ c = NS_KEY_LINE_END;
+ break;
+
+ case wimp_KEY_CONTROL | wimp_KEY_UP:
+ c = NS_KEY_TEXT_START;
+ break;
+
+ case wimp_KEY_CONTROL | wimp_KEY_DOWN:
+ c = NS_KEY_TEXT_END;
+ break;
+
+ case wimp_KEY_SHIFT | wimp_KEY_LEFT:
+ c = NS_KEY_WORD_LEFT ;
+ break;
+
+ case wimp_KEY_SHIFT | wimp_KEY_RIGHT:
+ c = NS_KEY_WORD_RIGHT;
+ break;
+
+ case wimp_KEY_SHIFT | wimp_KEY_UP:
+ c = NS_KEY_PAGE_UP;
+ break;
+
+ case wimp_KEY_SHIFT | wimp_KEY_DOWN:
+ c = NS_KEY_PAGE_DOWN;
+ break;
+
+ case wimp_KEY_LEFT:
+ c = NS_KEY_LEFT;
+ break;
+
+ case wimp_KEY_RIGHT:
+ c = NS_KEY_RIGHT;
+ break;
+
+ case wimp_KEY_UP:
+ c = NS_KEY_UP;
+ break;
+
+ case wimp_KEY_DOWN:
+ c = NS_KEY_DOWN;
+ break;
+
+ /* editing */
+ case wimp_KEY_CONTROL | wimp_KEY_END:
+ c = NS_KEY_DELETE_LINE_END;
+ break;
+
+ case wimp_KEY_DELETE:
+ if (ro_gui_ctrl_pressed()) {
+ c = NS_KEY_DELETE_LINE_START;
+ } else if (os_version < RISCOS5) {
+ c = NS_KEY_DELETE_LEFT;
+ }
+ break;
+
+ case wimp_KEY_F8:
+ c = NS_KEY_UNDO;
+ break;
+
+ case wimp_KEY_F9:
+ c = NS_KEY_REDO;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!(c & IS_WIMP_KEY)) {
+ if (browser_window_key_press(g->bw, c)) {
+ return true;
+ }
+ }
+
+ return ro_gui_window_handle_local_keypress(g, key, false);
+}
+
+
+/**
+ * Handle Mouse_Click events in a browser window.
+ *
+ * This should never see Menu clicks, as these will be routed to the
+ * menu handlers.
+ *
+ * \param pointer details of mouse click
+ * \return true if click handled, false otherwise
+ */
+static bool ro_gui_window_click(wimp_pointer *pointer)
+{
+ struct gui_window *g;
+ os_coord pos;
+
+ /* We should never see Menu clicks. */
+
+ if (pointer->buttons == wimp_CLICK_MENU) {
+ return false;
+ }
+
+ g = (struct gui_window *) ro_gui_wimp_event_get_user_data(pointer->w);
+
+ /* try to close url-completion */
+ ro_gui_url_complete_close();
+
+ /* set input focus */
+ if (pointer->buttons & (wimp_SINGLE_SELECT | wimp_SINGLE_ADJUST))
+ gui_window_place_caret(g, -100, -100, 0, NULL);
+
+ if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos)) {
+ browser_window_mouse_click(g->bw,
+ ro_gui_mouse_click_state(pointer->buttons,
+ wimp_BUTTON_DOUBLE_CLICK_DRAG),
+ pos.x, pos.y);
+ }
+
+ return true;
+}
+
+
+/**
+ * Prepare or reprepare a form select menu
+ *
+ * setting up the menu handle globals in the process.
+ *
+ * \param g The RISC OS gui window the menu is in.
+ * \param control The form control needing a menu.
+ * \return true if the menu is OK to be opened; else false.
+ */
+static bool
+ro_gui_window_prepare_form_select_menu(struct gui_window *g,
+ struct form_control *control)
+{
+ unsigned int item, entries;
+ char *text_convert, *temp;
+ struct form_option *option;
+ bool reopen = true;
+ nserror err;
+
+ assert(control);
+
+ /* enumerate the entries */
+ entries = 0;
+ option = form_select_get_option(control, entries);
+ while (option != NULL) {
+ entries++;
+ option = form_select_get_option(control, entries);
+ }
+
+ if (entries == 0) {
+ /* no menu to display */
+ ro_gui_menu_destroy();
+ return false;
+ }
+
+ /* free riscos menu if there already is one */
+ if ((gui_form_select_menu) && (control != gui_form_select_control)) {
+ for (item = 0; ; item++) {
+ free(gui_form_select_menu->entries[item].data.
+ indirected_text.text);
+ if (gui_form_select_menu->entries[item].menu_flags &
+ wimp_MENU_LAST)
+ break;
+ }
+ free(gui_form_select_menu->title_data.indirected_text.text);
+ free(gui_form_select_menu);
+ gui_form_select_menu = 0;
+ }
+
+ /* allocate new riscos menu */
+ if (!gui_form_select_menu) {
+ reopen = false;
+ gui_form_select_menu = malloc(wimp_SIZEOF_MENU(entries));
+ if (!gui_form_select_menu) {
+ ro_warn_user("NoMemory", 0);
+ ro_gui_menu_destroy();
+ return false;
+ }
+ err = utf8_to_local_encoding(messages_get("SelectMenu"), 0,
+ &text_convert);
+ if (err != NSERROR_OK) {
+ /* badenc should never happen */
+ assert(err != NSERROR_BAD_ENCODING);
+ NSLOG(netsurf, INFO, "utf8_to_local_encoding failed");
+ ro_warn_user("NoMemory", 0);
+ ro_gui_menu_destroy();
+ return false;
+ }
+ gui_form_select_menu->title_data.indirected_text.text =
+ text_convert;
+ ro_gui_menu_init_structure(gui_form_select_menu, entries);
+ }
+
+ /* initialise menu entries from form control */
+ for (item = 0; item < entries; item++) {
+ option = form_select_get_option(control, item);
+ gui_form_select_menu->entries[item].menu_flags = 0;
+ if (option->selected)
+ gui_form_select_menu->entries[item].menu_flags =
+ wimp_MENU_TICKED;
+ if (!reopen) {
+
+ /* convert spaces to hard spaces to stop things
+ * like 'Go Home' being treated as if 'Home' is a
+ * keyboard shortcut and right aligned in the menu.
+ */
+
+ temp = cnv_space2nbsp(option->text);
+ if (!temp) {
+ NSLOG(netsurf, INFO, "cnv_space2nbsp failed");
+ ro_warn_user("NoMemory", 0);
+ ro_gui_menu_destroy();
+ return false;
+ }
+
+ err = utf8_to_local_encoding(temp,
+ 0, &text_convert);
+ if (err != NSERROR_OK) {
+ /* A bad encoding should never happen,
+ * so assert this */
+ assert(err != NSERROR_BAD_ENCODING);
+ NSLOG(netsurf, INFO, "utf8_to_enc failed");
+ ro_warn_user("NoMemory", 0);
+ ro_gui_menu_destroy();
+ return false;
+ }
+
+ free(temp);
+
+ gui_form_select_menu->entries[item].data.indirected_text.text =
+ text_convert;
+ gui_form_select_menu->entries[item].data.indirected_text.size =
+ strlen(gui_form_select_menu->entries[item].
+ data.indirected_text.text) + 1;
+ }
+ }
+
+ gui_form_select_menu->entries[0].menu_flags |=
+ wimp_MENU_TITLE_INDIRECTED;
+ gui_form_select_menu->entries[item - 1].menu_flags |= wimp_MENU_LAST;
+
+ return true;
+}
+
+
+/**
+ * Return boolean flags to show what RISC OS types we can sensibly convert
+ * the given object into.
+ *
+ * \todo This should probably be somewhere else but in window.c, and
+ * should probably even be done in content_().
*
- * \param w The window owning the menu.
- * \param i The icon owning the menu.
- * \param *menu The menu about to be opened.
- * \param *pointer Pointer to the relevant wimp event block, or
- * NULL for an Adjust click.
- * \return true if the event was handled; else false.
+ * \param h The object to test.
+ * \param export_draw true on exit if a drawfile would be possible.
+ * \param export_sprite true on exit if a sprite would be possible.
+ * \return true if valid data is returned; else false.
*/
+static bool
+ro_gui_window_content_export_types(struct hlcache_handle *h,
+ bool *export_draw,
+ bool *export_sprite)
+{
+ bool found_type = false;
-bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_pointer *pointer)
+ if (export_draw != NULL) {
+ *export_draw = false;
+ }
+ if (export_sprite != NULL) {
+ *export_sprite = false;
+ }
+
+ if (h != NULL && content_get_type(h) == CONTENT_IMAGE) {
+ switch (ro_content_native_type(h)) {
+ case osfile_TYPE_SPRITE:
+ /* bitmap types (Sprite export possible) */
+ found_type = true;
+ if (export_sprite != NULL) {
+ *export_sprite = true;
+ }
+ break;
+
+ case osfile_TYPE_DRAW:
+ /* vector types (Draw export possible) */
+ found_type = true;
+ if (export_draw != NULL) {
+ *export_draw = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return found_type;
+}
+
+
+/**
+ * Prepare the browser window menu for (re-)opening
+ *
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param menu The menu about to be opened.
+ * \param pointer Pointer to the relevant wimp event block, or
+ * NULL for an Adjust click.
+ * \return true if the event was handled; else false.
+ */
+static bool
+ro_gui_window_menu_prepare(wimp_w w,
+ wimp_i i,
+ wimp_menu *menu,
+ wimp_pointer *pointer)
{
struct gui_window *g;
struct browser_window *bw;
@@ -2144,13 +2153,13 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
gui_form_select_control);
}
- if (menu != ro_gui_browser_window_menu)
+ if (menu != ro_gui_browser_window_menu) {
return false;
+ }
/* If this is a new opening for the browser window menu (ie. not for a
* toolbar menu), get details of the object under the pointer.
*/
-
if (pointer != NULL && g->window == w) {
ro_gui_url_complete_close();
@@ -2261,13 +2270,14 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_SAVE_URL_TEXT,
current_menu_object == NULL);
- if (current_menu_object != NULL)
+ if (current_menu_object != NULL) {
ro_gui_window_content_export_types(current_menu_object,
&export_draw, &export_sprite);
- else
+ } else {
ro_gui_window_content_export_types(
browser_window_get_content(bw),
&export_draw, &export_sprite);
+ }
ro_gui_menu_set_entry_shaded(menu, BROWSER_OBJECT_EXPORT,
(!have_content && current_menu_object == NULL)
@@ -2325,14 +2335,15 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
/* View Submenu */
ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_FOREGROUND,
- g != NULL && nsoption_bool(foreground_images));
+ g != NULL && nsoption_bool(foreground_images));
ro_gui_menu_set_entry_ticked(menu, BROWSER_IMAGES_BACKGROUND,
- g != NULL && nsoption_bool(background_images));
+ g != NULL && nsoption_bool(background_images));
ro_gui_menu_set_entry_shaded(menu, BROWSER_BUFFER_ANIMS,
g == NULL || g->option.buffer_everything);
- ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ANIMS, g != NULL &&
+ ro_gui_menu_set_entry_ticked(menu, BROWSER_BUFFER_ANIMS,
+ g != NULL &&
(g->option.buffer_animations ||
g->option.buffer_everything));
@@ -2343,16 +2354,16 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
ro_gui_menu_set_entry_shaded(menu, BROWSER_SCALE_VIEW, !have_content);
ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_STAGGER,
- nsoption_int(window_screen_width) == 0);
+ nsoption_int(window_screen_width) == 0);
ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_STAGGER,
- ((nsoption_int(window_screen_width) == 0) ||
- nsoption_bool(window_stagger)));
+ ((nsoption_int(window_screen_width) == 0) ||
+ nsoption_bool(window_stagger)));
ro_gui_menu_set_entry_ticked(menu, BROWSER_WINDOW_COPY,
- nsoption_bool(window_size_clone));
+ nsoption_bool(window_size_clone));
ro_gui_menu_set_entry_shaded(menu, BROWSER_WINDOW_RESET,
- nsoption_int(window_screen_width) == 0);
+ nsoption_int(window_screen_width) == 0);
/* Utilities Submenu */
@@ -2376,199 +2387,72 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu,
/**
- * Handle submenu warnings for a browser window menu
+ * Process selections from a form select menu, passing them back to the core.
*
- * \param w The window owning the menu.
- * \param i The icon owning the menu.
- * \param *menu The menu to which the warning applies.
- * \param *selection The wimp menu selection data.
- * \param action The selected menu action.
+ * \param g The browser window affected by the menu.
+ * \param selection The menu selection.
*/
-
-void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection, menu_action action)
+static void
+ro_gui_window_process_form_select_menu(struct gui_window *g,
+ wimp_selection *selection)
{
- struct gui_window *g;
- struct hlcache_handle *h;
- bool export;
-
- if (menu != ro_gui_browser_window_menu)
- return;
-
- g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w);
- h = browser_window_get_content(g->bw);
-
- switch (action) {
- case BROWSER_PAGE_INFO:
- if (h != NULL)
- ro_gui_window_prepare_pageinfo(g);
- break;
-
- case BROWSER_FIND_TEXT:
- if (h != NULL && (content_get_type(h) == CONTENT_HTML ||
- content_get_type(h) == CONTENT_TEXTPLAIN))
- ro_gui_search_prepare(g->bw);
- break;
-
- case BROWSER_SCALE_VIEW:
- if (h != NULL)
- ro_gui_dialog_prepare_zoom(g);
- break;
-
- case BROWSER_PRINT:
- if (h != NULL)
- ro_gui_print_prepare(g);
- break;
-
- case BROWSER_OBJECT_INFO:
- if (current_menu_object != NULL)
- ro_gui_window_prepare_objectinfo(current_menu_object,
- current_menu_url);
- break;
-
- case BROWSER_OBJECT_SAVE:
- if (current_menu_object != NULL)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG,
- current_menu_object, NULL, NULL, NULL);
- break;
-
- case BROWSER_SELECTION_SAVE:
- if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY)
- ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL,
- browser_window_get_selection(g->bw),
- NULL, NULL);
- break;
-
- case BROWSER_SAVE_URL_URI:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
- hlcache_handle_get_url(h),
- content_get_title(h));
- break;
-
- case BROWSER_SAVE_URL_URL:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
- hlcache_handle_get_url(h),
- content_get_title(h));
- break;
-
- case BROWSER_SAVE_URL_TEXT:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
- hlcache_handle_get_url(h),
- content_get_title(h));
- break;
-
- case BROWSER_OBJECT_SAVE_URL_URI:
- if (current_menu_object != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
- hlcache_handle_get_url(
- current_menu_object),
- content_get_title(current_menu_object));
- break;
-
- case BROWSER_OBJECT_SAVE_URL_URL:
- if (current_menu_object != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
- hlcache_handle_get_url(
- current_menu_object),
- content_get_title(current_menu_object));
- break;
-
- case BROWSER_OBJECT_SAVE_URL_TEXT:
- if (current_menu_object != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
- hlcache_handle_get_url(
- current_menu_object),
- content_get_title(current_menu_object));
- break;
-
- case BROWSER_SAVE:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL);
- break;
-
- case BROWSER_SAVE_COMPLETE:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL);
- break;
-
- case BROWSER_EXPORT_DRAW:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL);
- break;
-
- case BROWSER_EXPORT_PDF:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL);
- break;
-
- case BROWSER_EXPORT_TEXT:
- if (h != NULL)
- ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL);
- break;
-
- case BROWSER_LINK_SAVE_URI:
- if (current_menu_url != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
- current_menu_url, NULL);
- break;
-
- case BROWSER_LINK_SAVE_URL:
- if (current_menu_url != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
- current_menu_url, NULL);
- break;
+ assert(g != NULL);
- case BROWSER_LINK_SAVE_TEXT:
- if (current_menu_url != NULL)
- ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
- current_menu_url, NULL);
- break;
+ if (selection->items[0] >= 0) {
+ form_select_process_selection(gui_form_select_control,
+ selection->items[0]);
+ }
+}
- case BROWSER_OBJECT_EXPORT_SPRITE:
- if (current_menu_object != NULL) {
- ro_gui_window_content_export_types(current_menu_object,
- NULL, &export);
- if (export)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- current_menu_object,
- NULL, NULL, NULL);
- } else if (h != NULL) {
- ro_gui_window_content_export_types(h, NULL, &export);
+/**
+ * Prepare the object info window for use
+ *
+ * \param object the object for which information is to be displayed
+ * \param target_url corresponding url, if any
+ */
+static void
+ro_gui_window_prepare_objectinfo(struct hlcache_handle *object,
+ nsurl *target_url)
+{
+ char icon_buf[20] = "file_xxx";
+ const char *url;
+ lwc_string *mime;
+ const char *target = "-";
- if (export)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- h, NULL, NULL, NULL);
- }
- break;
+ sprintf(icon_buf, "file_%.3x",ro_content_filetype(object));
+ if (!ro_gui_wimp_sprite_exists(icon_buf)) {
+ sprintf(icon_buf, "file_xxx");
+ }
- case BROWSER_OBJECT_EXPORT_DRAW:
- if (current_menu_object != NULL) {
- ro_gui_window_content_export_types(current_menu_object,
- &export, NULL);
+ url = nsurl_access(hlcache_handle_get_url(object));
+ if (url == NULL) {
+ url = "-";
+ }
+ mime = content_get_mime_type(object);
- if (export)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- current_menu_object,
- NULL, NULL, NULL);
- } else if (h != NULL) {
- ro_gui_window_content_export_types(h, &export, NULL);
+ if (target_url != NULL) {
+ target = nsurl_access(target_url);
+ }
- if (export)
- ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- h, NULL, NULL, NULL);
- }
- break;
+ ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_ICON,
+ icon_buf, true);
+ ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_URL,
+ url, true);
+ ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TARGET,
+ target, true);
+ ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TYPE,
+ lwc_string_data(mime), true);
- default:
- break;
- }
+ lwc_string_unref(mime);
}
+/**
+ * callback to handle window paste operation
+ *
+ * \param pw context containing browser window
+ */
static void ro_gui_window_paste_cb(void *pw)
{
struct browser_window *bw = pw;
@@ -2580,22 +2464,25 @@ static void ro_gui_window_paste_cb(void *pw)
/**
* Handle selections from a browser window menu
*
- * \param w The window owning the menu.
- * \param i The icon owning the menu.
- * \param *menu The menu from which the selection was made.
- * \param *selection The wimp menu selection data.
- * \param action The selected menu action.
- * \return true if action accepted; else false.
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param menu The menu from which the selection was made.
+ * \param selection The wimp menu selection data.
+ * \param action The selected menu action.
+ * \return true if action accepted; else false.
*/
-
-bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
- wimp_selection *selection, menu_action action)
+static bool
+ro_gui_window_menu_select(wimp_w w,
+ wimp_i i,
+ wimp_menu *menu,
+ wimp_selection *selection,
+ menu_action action)
{
- struct gui_window *g;
- struct browser_window *bw;
- struct hlcache_handle *h;
- struct toolbar *toolbar;
- wimp_window_state state;
+ struct gui_window *g;
+ struct browser_window *bw;
+ struct hlcache_handle *h;
+ struct toolbar *toolbar;
+ wimp_window_state state;
nsurl *url;
nserror error = NSERROR_OK;
@@ -2607,7 +2494,6 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
/* If this is a form menu from the core, handle it now and then exit.
* Otherwise, carry on to the main browser window menu.
*/
-
if (menu == gui_form_select_menu && w == g->window) {
ro_gui_window_process_form_select_menu(g, selection);
@@ -2625,10 +2511,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
error = nsurl_create("http://www.netsurf-browser.org/documentation/", &url);
if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
break;
@@ -2637,10 +2523,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
error = nsurl_create("http://www.netsurf-browser.org/documentation/guide", &url);
if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
break;
@@ -2649,10 +2535,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
error = nsurl_create("http://www.netsurf-browser.org/documentation/info", &url);
if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
break;
@@ -2661,10 +2547,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
error = nsurl_create("about:credits", &url);
if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
break;
@@ -2673,10 +2559,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
error = nsurl_create("about:licence", &url);
if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
+ url,
+ NULL,
+ NULL,
+ NULL);
nsurl_unref(url);
}
break;
@@ -2686,7 +2572,8 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
ro_gui_interactive_help_start();
nsoption_set_bool(interactive_help, true);
} else {
- nsoption_set_bool(interactive_help, !nsoption_bool(interactive_help));
+ nsoption_set_bool(interactive_help,
+ !nsoption_bool(interactive_help));
}
break;
@@ -2738,9 +2625,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
case BROWSER_OBJECT_INFO:
if (current_menu_object != NULL) {
ro_gui_window_prepare_objectinfo(current_menu_object,
- current_menu_url);
+ current_menu_url);
ro_gui_dialog_open_persistent(g->window,
- dialog_objinfo, false);
+ dialog_objinfo,
+ false);
}
break;
case BROWSER_OBJECT_RELOAD:
@@ -2753,50 +2641,62 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
/* link actions */
case BROWSER_LINK_SAVE_URI:
if (current_menu_url != NULL) {
- ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
- current_menu_url, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ ro_gui_save_prepare(GUI_SAVE_LINK_URI,
+ NULL,
+ NULL,
+ current_menu_url,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
case BROWSER_LINK_SAVE_URL:
if (current_menu_url != NULL) {
- ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
- current_menu_url, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL,
+ NULL,
+ NULL,
+ current_menu_url,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
case BROWSER_LINK_SAVE_TEXT:
if (current_menu_url != NULL) {
- ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
- current_menu_url, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ ro_gui_save_prepare(GUI_SAVE_LINK_TEXT,
+ NULL,
+ NULL,
+ current_menu_url,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
case BROWSER_LINK_DOWNLOAD:
if (current_menu_url != NULL) {
- error = browser_window_navigate(bw,
- current_menu_url,
- browser_window_get_url(bw),
- BW_NAVIGATE_DOWNLOAD,
- NULL,
- NULL,
- NULL);
+ error = browser_window_navigate(
+ bw,
+ current_menu_url,
+ browser_window_access_url(bw),
+ BW_NAVIGATE_DOWNLOAD,
+ NULL,
+ NULL,
+ NULL);
}
break;
case BROWSER_LINK_NEW_WINDOW:
if (current_menu_url != NULL) {
error = browser_window_create(
- BW_CREATE_HISTORY |
- BW_CREATE_CLONE,
- current_menu_url,
- browser_window_get_url(bw),
- bw,
- NULL);
+ BW_CREATE_HISTORY | BW_CREATE_CLONE,
+ current_menu_url,
+ browser_window_access_url(bw),
+ bw,
+ NULL);
}
break;
@@ -2805,24 +2705,36 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
case BROWSER_OBJECT_SAVE:
if (current_menu_object != NULL) {
ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG,
- current_menu_object, NULL, NULL, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ current_menu_object,
+ NULL,
+ NULL,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
case BROWSER_OBJECT_EXPORT_SPRITE:
if (current_menu_object != NULL) {
ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- current_menu_object, NULL, NULL, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ current_menu_object,
+ NULL,
+ NULL,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
case BROWSER_OBJECT_EXPORT_DRAW:
if (current_menu_object != NULL) {
ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
- current_menu_object, NULL, NULL, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ current_menu_object,
+ NULL,
+ NULL,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
@@ -2854,10 +2766,13 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
/* selection actions */
case BROWSER_SELECTION_SAVE:
if (h != NULL) {
- ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL,
+ ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION,
+ NULL,
browser_window_get_selection(bw),
- NULL, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas,
+ NULL,
+ NULL);
+ ro_gui_dialog_open_persistent(g->window,
+ dialog_saveas,
false);
}
break;
@@ -2944,7 +2859,10 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
state.w = w;
oserror = xwimp_get_window_state(&state);
if (oserror) {
- LOG("xwimp_get_window_state: 0x%x: %s", oserror->errnum, oserror->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ oserror->errnum,
+ oserror->errmess);
ro_warn_user("WimpError", oserror->errmess);
}
nsoption_set_int(window_x, state.visible.x0);
@@ -2976,19 +2894,19 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
case TOOLBAR_BUTTONS:
assert(toolbar);
ro_toolbar_set_display_buttons(toolbar,
- !ro_toolbar_get_display_buttons(toolbar));
+ !ro_toolbar_get_display_buttons(toolbar));
break;
case TOOLBAR_ADDRESS_BAR:
assert(toolbar);
ro_toolbar_set_display_url(toolbar,
- !ro_toolbar_get_display_url(toolbar));
+ !ro_toolbar_get_display_url(toolbar));
if (ro_toolbar_get_display_url(toolbar))
ro_toolbar_take_caret(toolbar);
break;
case TOOLBAR_THROBBER:
assert(toolbar);
ro_toolbar_set_display_throbber(toolbar,
- !ro_toolbar_get_display_throbber(toolbar));
+ !ro_toolbar_get_display_throbber(toolbar));
break;
case TOOLBAR_EDIT:
assert(toolbar);
@@ -3008,467 +2926,881 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu,
/**
- * Handle the closure of a browser window menu
+ * Handle submenu warnings for a browser window menu
*
- * \param w The window owning the menu.
- * \param i The icon owning the menu.
- * \param *menu The menu that is being closed.
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param menu The menu to which the warning applies.
+ * \param selection The wimp menu selection data.
+ * \param action The selected menu action.
*/
-
-void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu)
+static void
+ro_gui_window_menu_warning(wimp_w w,
+ wimp_i i,
+ wimp_menu *menu,
+ wimp_selection *selection,
+ menu_action action)
{
- if (menu == ro_gui_browser_window_menu) {
- current_menu_object = NULL;
- current_menu_url = NULL;
- } else if (menu == gui_form_select_menu) {
- gui_form_select_control = NULL;
+ struct gui_window *g;
+ struct hlcache_handle *h;
+ bool export;
+
+ if (menu != ro_gui_browser_window_menu) {
+ return;
}
-}
+ g = (struct gui_window *) ro_gui_wimp_event_get_user_data(w);
+ h = browser_window_get_content(g->bw);
-/**
- * Process Scroll_Request events in a browser window.
- *
- * \param *scroll The wimp scroll event data block.
- */
+ switch (action) {
+ case BROWSER_PAGE_INFO:
+ if (h != NULL) {
+ ro_gui_window_prepare_pageinfo(g);
+ }
+ break;
-void ro_gui_window_scroll(wimp_scroll *scroll)
-{
- struct gui_window *g = ro_gui_window_lookup(scroll->w);
+ case BROWSER_FIND_TEXT:
+ if (h != NULL &&
+ (content_get_type(h) == CONTENT_HTML ||
+ content_get_type(h) == CONTENT_TEXTPLAIN)) {
+ ro_gui_search_prepare(g->bw);
+ }
+ break;
- if (g && browser_window_has_content(g->bw) && ro_gui_shift_pressed()) {
- /* extended scroll request with shift held down; change zoom */
- float scale, inc;
+ case BROWSER_SCALE_VIEW:
+ if (h != NULL) {
+ ro_gui_dialog_prepare_zoom(g);
+ }
+ break;
- if (scroll->ymin & 3)
- inc = 0.02; /* RO5 sends the msg 5 times;
- * don't ask me why
- *
- * @todo this is liable to break if
- * HID is configured optimally for
- * frame scrolling. *5 appears to be
- * an artifact of non-HID mode scrolling.
- */
- else
- inc = (1 << (ABS(scroll->ymin)>>2)) / 20.0F;
+ case BROWSER_PRINT:
+ if (h != NULL) {
+ ro_gui_print_prepare(g);
+ }
+ break;
- if (scroll->ymin > 0) {
- scale = g->scale + inc;
- if (scale > scale_snap_to[SCALE_SNAP_TO_SIZE - 1])
- scale = scale_snap_to[SCALE_SNAP_TO_SIZE - 1];
- } else {
- scale = g->scale - inc;
- if (scale < scale_snap_to[0])
- scale = scale_snap_to[0];
+ case BROWSER_OBJECT_INFO:
+ if (current_menu_object != NULL) {
+ ro_gui_window_prepare_objectinfo(current_menu_object,
+ current_menu_url);
}
- if (g->scale != scale)
- ro_gui_window_set_scale(g, scale);
- } else if (g != NULL) {
- ro_gui_window_scroll_action(g, scroll->xmin, scroll->ymin);
+ break;
+
+ case BROWSER_OBJECT_SAVE:
+ if (current_menu_object != NULL) {
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_ORIG,
+ current_menu_object,
+ NULL,
+ NULL,
+ NULL);
+ }
+ break;
+
+ case BROWSER_SELECTION_SAVE:
+ if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY)
+ ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL,
+ browser_window_get_selection(g->bw),
+ NULL, NULL);
+ break;
+
+ case BROWSER_SAVE_URL_URI:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
+ hlcache_handle_get_url(h),
+ content_get_title(h));
+ break;
+
+ case BROWSER_SAVE_URL_URL:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
+ hlcache_handle_get_url(h),
+ content_get_title(h));
+ break;
+
+ case BROWSER_SAVE_URL_TEXT:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
+ hlcache_handle_get_url(h),
+ content_get_title(h));
+ break;
+
+ case BROWSER_OBJECT_SAVE_URL_URI:
+ if (current_menu_object != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
+ hlcache_handle_get_url(
+ current_menu_object),
+ content_get_title(current_menu_object));
+ break;
+
+ case BROWSER_OBJECT_SAVE_URL_URL:
+ if (current_menu_object != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
+ hlcache_handle_get_url(
+ current_menu_object),
+ content_get_title(current_menu_object));
+ break;
+
+ case BROWSER_OBJECT_SAVE_URL_TEXT:
+ if (current_menu_object != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
+ hlcache_handle_get_url(
+ current_menu_object),
+ content_get_title(current_menu_object));
+ break;
+
+ case BROWSER_SAVE:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_SOURCE, h, NULL, NULL, NULL);
+ break;
+
+ case BROWSER_SAVE_COMPLETE:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_COMPLETE, h, NULL, NULL, NULL);
+ break;
+
+ case BROWSER_EXPORT_DRAW:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_DRAW, h, NULL, NULL, NULL);
+ break;
+
+ case BROWSER_EXPORT_PDF:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_PDF, h, NULL, NULL, NULL);
+ break;
+
+ case BROWSER_EXPORT_TEXT:
+ if (h != NULL)
+ ro_gui_save_prepare(GUI_SAVE_TEXT, h, NULL, NULL, NULL);
+ break;
+
+ case BROWSER_LINK_SAVE_URI:
+ if (current_menu_url != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URI, NULL, NULL,
+ current_menu_url, NULL);
+ break;
+
+ case BROWSER_LINK_SAVE_URL:
+ if (current_menu_url != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL,
+ current_menu_url, NULL);
+ break;
+
+ case BROWSER_LINK_SAVE_TEXT:
+ if (current_menu_url != NULL)
+ ro_gui_save_prepare(GUI_SAVE_LINK_TEXT, NULL, NULL,
+ current_menu_url, NULL);
+ break;
+
+ case BROWSER_OBJECT_EXPORT_SPRITE:
+ if (current_menu_object != NULL) {
+ ro_gui_window_content_export_types(current_menu_object,
+ NULL, &export);
+
+ if (export)
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
+ current_menu_object,
+ NULL, NULL, NULL);
+ } else if (h != NULL) {
+ ro_gui_window_content_export_types(h, NULL, &export);
+
+ if (export)
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
+ h, NULL, NULL, NULL);
+ }
+ break;
+
+ case BROWSER_OBJECT_EXPORT_DRAW:
+ if (current_menu_object != NULL) {
+ ro_gui_window_content_export_types(current_menu_object,
+ &export, NULL);
+
+ if (export)
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
+ current_menu_object,
+ NULL, NULL, NULL);
+ } else if (h != NULL) {
+ ro_gui_window_content_export_types(h, &export, NULL);
+
+ if (export)
+ ro_gui_save_prepare(GUI_SAVE_OBJECT_NATIVE,
+ h, NULL, NULL, NULL);
+ }
+ break;
+
+ default:
+ break;
}
}
+
/**
- * Process Pointer Entering Window events in a browser window.
+ * Handle the closure of a browser window menu
*
- * \param *entering The wimp pointer entering event data block.
+ * \param w The window owning the menu.
+ * \param i The icon owning the menu.
+ * \param menu The menu that is being closed.
*/
-
-static void ro_gui_window_pointer_entering(wimp_entering *entering)
+static void ro_gui_window_menu_close(wimp_w w, wimp_i i, wimp_menu *menu)
{
- struct gui_window *g = ro_gui_window_lookup(entering->w);
-
- if (g != NULL)
- ro_mouse_track_start(ro_gui_window_track_end,
- ro_gui_window_mouse_at, g);
+ if (menu == ro_gui_browser_window_menu) {
+ current_menu_object = NULL;
+ current_menu_url = NULL;
+ } else if (menu == gui_form_select_menu) {
+ gui_form_select_control = NULL;
+ }
}
+
/**
- * Process Pointer Leaving Window events in a browser window. These arrive via
- * the termination callback handler from ro_mouse's mouse tracking.
+ * Clones a browser window's options.
*
- * \param *leaving The wimp pointer leaving event data block.
- * \param *data The GUI window that the pointer is leaving.
+ * \param new_gui the new gui window
+ * \param old_gui the gui window to clone from, or NULL for default
*/
-
-static void ro_gui_window_track_end(wimp_leaving *leaving, void *data)
+static void
+ro_gui_window_clone_options(struct gui_window *new_gui,
+ struct gui_window *old_gui)
{
- struct gui_window *g = (struct gui_window *) data;
+ assert(new_gui);
- if (g != NULL)
- gui_window_set_pointer(g, GUI_POINTER_DEFAULT);
+ /* Clone the basic options
+ */
+ if (!old_gui) {
+ new_gui->option.buffer_animations = nsoption_bool(buffer_animations);
+ new_gui->option.buffer_everything = nsoption_bool(buffer_everything);
+ } else {
+ new_gui->option = old_gui->option;
+ }
+
+ /* Set up the toolbar
+ */
+ if (new_gui->toolbar) {
+ ro_toolbar_set_display_buttons(new_gui->toolbar,
+ nsoption_bool(toolbar_show_buttons));
+ ro_toolbar_set_display_url(new_gui->toolbar,
+ nsoption_bool(toolbar_show_address));
+ ro_toolbar_set_display_throbber(new_gui->toolbar,
+ nsoption_bool(toolbar_show_throbber));
+ if ((old_gui) && (old_gui->toolbar)) {
+ ro_toolbar_set_display_buttons(new_gui->toolbar,
+ ro_toolbar_get_display_buttons(
+ old_gui->toolbar));
+ ro_toolbar_set_display_url(new_gui->toolbar,
+ ro_toolbar_get_display_url(
+ old_gui->toolbar));
+ ro_toolbar_set_display_throbber(new_gui->toolbar,
+ ro_toolbar_get_display_throbber(
+ old_gui->toolbar));
+ ro_toolbar_process(new_gui->toolbar, -1, true);
+ }
+ }
}
/**
- * Scroll a browser window, either via the core or directly using the
- * normal Wimp_OpenWindow interface.
- *
- * Scroll steps are supplied in terms of the (extended) Scroll Event direction
- * values returned by Wimp_Poll. Special values of 0x7fffffff and 0x80000000
- * are added to mean "Home" and "End".
+ * Create and open a new browser window.
*
- * \param *g The GUI Window to be scrolled.
- * \param scroll_x The X scroll step to be applied.
- * \param scroll_y The Y scroll step to be applied.
+ * \param bw bw to create gui_window for
+ * \param existing an existing gui_window, may be NULL
+ * \param flags flags for gui window creation
+ * \return gui window, or NULL on error
*/
-
-void ro_gui_window_scroll_action(struct gui_window *g,
- wimp_scroll_direction scroll_x, wimp_scroll_direction scroll_y)
+static struct gui_window *gui_window_create(struct browser_window *bw,
+ struct gui_window *existing,
+ gui_window_create_flags flags)
{
- int visible_x, visible_y;
- int step_x = 0, step_y = 0;
- int toolbar_y;
- wimp_window_state state;
- wimp_pointer pointer;
- os_error *error;
- os_coord pos;
- bool handled = false;
- struct toolbar *toolbar;
+ int screen_width, screen_height;
+ static int window_count = 2;
+ wimp_window window;
+ wimp_window_state state;
+ os_error *error;
+ bool open_centred = true;
+ struct gui_window *g;
- if (g == NULL)
- return;
+ g = malloc(sizeof *g);
+ if (!g) {
+ ro_warn_user("NoMemory", 0);
+ return 0;
+ }
+ g->bw = bw;
+ g->toolbar = 0;
+ g->status_bar = 0;
+ g->old_width = 0;
+ g->old_height = 0;
+ g->update_extent = true;
+ g->active = false;
+ strcpy(g->title, "NetSurf");
+ g->iconise_icon = -1;
+ g->scale = browser_window_get_scale(bw);
- /* Get the current window, toolbar and pointer details. */
+ /* Set the window position */
+ if (existing != NULL &&
+ flags & GW_CREATE_CLONE &&
+ nsoption_bool(window_size_clone)) {
+ state.w = existing->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_state: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ window.visible.x0 = state.visible.x0;
+ window.visible.x1 = state.visible.x1;
+ window.visible.y0 = state.visible.y0 - 48;
+ window.visible.y1 = state.visible.y1 - 48;
+ open_centred = false;
+ } else {
+ int win_width, win_height;
+ ro_gui_screen_size(&screen_width, &screen_height);
- state.w = g->window;
- error = xwimp_get_window_state(&state);
- if (error) {
- LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess);
- return;
+ /* Check if we have a preferred position */
+ if ((nsoption_int(window_screen_width) != 0) &&
+ (nsoption_int(window_screen_height) != 0)) {
+ win_width = (nsoption_int(window_width) *
+ screen_width) /
+ nsoption_int(window_screen_width);
+ win_height = (nsoption_int(window_height) *
+ screen_height) /
+ nsoption_int(window_screen_height);
+ window.visible.x0 = (nsoption_int(window_x) *
+ screen_width) /
+ nsoption_int(window_screen_width);
+ window.visible.y0 = (nsoption_int(window_y) *
+ screen_height) /
+ nsoption_int(window_screen_height);
+ if (nsoption_bool(window_stagger)) {
+ window.visible.y0 += 96 -
+ (48 * (window_count % 5));
+ }
+ open_centred = false;
+ if (win_width < 100)
+ win_width = 100;
+ if (win_height < 100)
+ win_height = 100;
+ } else {
+
+ /* Base how we define the window height/width
+ on the compile time options set */
+ win_width = screen_width * 3 / 4;
+ if (1600 < win_width)
+ win_width = 1600;
+ win_height = win_width * 3 / 4;
+
+ window.visible.x0 = (screen_width - win_width) / 2;
+ window.visible.y0 = ((screen_height - win_height) / 2) +
+ 96 - (48 * (window_count % 5));
+ }
+ window.visible.x1 = window.visible.x0 + win_width;
+ window.visible.y1 = window.visible.y0 + win_height;
}
- toolbar = ro_toolbar_parent_window_lookup(g->window);
- assert(g == NULL || g->toolbar == NULL || g->toolbar == toolbar);
+ /* General flags for a non-movable, non-resizable, no-title bar window */
+ window.xscroll = 0;
+ window.yscroll = 0;
+ window.next = wimp_TOP;
+ window.flags = wimp_WINDOW_MOVEABLE |
+ wimp_WINDOW_NEW_FORMAT |
+ wimp_WINDOW_VSCROLL |
+ wimp_WINDOW_HSCROLL |
+ wimp_WINDOW_IGNORE_XEXTENT |
+ wimp_WINDOW_IGNORE_YEXTENT |
+ wimp_WINDOW_SCROLL_REPEAT;
+ window.title_fg = wimp_COLOUR_BLACK;
+ window.title_bg = wimp_COLOUR_LIGHT_GREY;
+ window.work_fg = wimp_COLOUR_LIGHT_GREY;
+ window.work_bg = wimp_COLOUR_TRANSPARENT;
+ window.scroll_outer = wimp_COLOUR_DARK_GREY;
+ window.scroll_inner = wimp_COLOUR_MID_LIGHT_GREY;
+ window.highlight_bg = wimp_COLOUR_CREAM;
+ window.extra_flags = wimp_WINDOW_USE_EXTENDED_SCROLL_REQUEST |
+ wimp_WINDOW_GIVE_SHADED_ICON_INFO;
+ window.extent.x0 = 0;
+ window.extent.y0 = -(window.visible.y1 - window.visible.y0);
+ window.extent.x1 = window.visible.x1 - window.visible.x0;
+ window.extent.y1 = 0;
+ window.title_flags = wimp_ICON_TEXT |
+ wimp_ICON_INDIRECTED |
+ wimp_ICON_HCENTRED;
+ window.work_flags = wimp_BUTTON_DOUBLE_CLICK_DRAG <<
+ wimp_ICON_BUTTON_TYPE_SHIFT;
+ window.sprite_area = wimpspriteop_AREA;
+ window.xmin = 1;
+ window.ymin = 1;
+ window.title_data.indirected_text.text = g->title;
+ window.title_data.indirected_text.validation = (char *) -1;
+ window.title_data.indirected_text.size = 255;
+ window.icon_count = 0;
- toolbar_y = (toolbar == NULL) ? 0 : ro_toolbar_full_height(toolbar);
+ /* Add in flags */
+ window.flags |= wimp_WINDOW_SIZE_ICON |
+ wimp_WINDOW_BACK_ICON |
+ wimp_WINDOW_CLOSE_ICON |
+ wimp_WINDOW_TITLE_ICON |
+ wimp_WINDOW_TOGGLE_ICON;
- visible_x = state.visible.x1 - state.visible.x0 - 32;
- visible_y = state.visible.y1 - state.visible.y0 - 32 - toolbar_y;
+ if (open_centred) {
+ int scroll_width = ro_get_vscroll_width(NULL);
+ window.visible.x0 -= scroll_width;
+ }
- error = xwimp_get_pointer_info(&pointer);
+ error = xwimp_create_window(&window, &g->window);
if (error) {
- LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
- return;
+ free(g);
+ return 0;
}
- /* Turn the scroll requirement from Scroll Event codes into coordinates
- * that the core can understand.
- */
+ /* Link into window list */
+ g->prev = 0;
+ g->next = window_list;
+ if (window_list)
+ window_list->prev = g;
+ window_list = g;
+ window_count++;
- switch (scroll_x) {
- case wimp_SCROLL_PAGE_LEFT:
- step_x = SCROLL_PAGE_DOWN;
- break;
- case wimp_SCROLL_AUTO_LEFT:
- case wimp_SCROLL_COLUMN_LEFT:
- step_x = -16;
- break;
- case wimp_SCROLL_AUTO_RIGHT:
- case wimp_SCROLL_COLUMN_RIGHT:
- step_x = 16;
- break;
- case wimp_SCROLL_PAGE_RIGHT:
- step_x = SCROLL_PAGE_UP;
- break;
- case 0x80000000:
- step_x = SCROLL_BOTTOM;
- break;
- case 0x7fffffff:
- step_x = SCROLL_TOP;
- break;
- default:
- step_x = (visible_x * (scroll_x>>2)) >> 2;
- break;
+ /* Add in a toolbar and status bar */
+ g->status_bar = ro_gui_status_bar_create(g->window,
+ nsoption_int(toolbar_status_size));
+ g->toolbar = ro_toolbar_create(NULL, g->window,
+ THEME_STYLE_BROWSER_TOOLBAR, TOOLBAR_FLAGS_NONE,
+ &ro_gui_window_toolbar_callbacks, g,
+ "HelpToolbar");
+ if (g->toolbar != NULL) {
+ ro_toolbar_add_buttons(g->toolbar,
+ brower_toolbar_buttons,
+ nsoption_charp(toolbar_browser));
+ ro_toolbar_add_url(g->toolbar);
+ ro_toolbar_add_throbber(g->toolbar);
+ ro_toolbar_rebuild(g->toolbar);
}
- switch (scroll_y) {
- case wimp_SCROLL_PAGE_UP:
- step_y = SCROLL_PAGE_UP;
- break;
- case wimp_SCROLL_AUTO_UP:
- case wimp_SCROLL_LINE_UP:
- step_y = -16;
- break;
- case wimp_SCROLL_AUTO_DOWN:
- case wimp_SCROLL_LINE_DOWN:
- step_y = 16;
- break;
- case wimp_SCROLL_PAGE_DOWN:
- step_y = SCROLL_PAGE_DOWN;
- break;
- case 0x80000000:
- step_y = SCROLL_BOTTOM;
- break;
- case 0x7fffffff:
- step_y = SCROLL_TOP;
- break;
- default:
- step_y = -((visible_y * (scroll_y>>2)) >> 2);
- break;
- }
+ /* Register event handlers. Do this quickly, as some of the things
+ * that follow will indirectly look up our user data: this MUST
+ * be set first!
+ */
+ ro_gui_wimp_event_set_user_data(g->window, g);
+ ro_gui_wimp_event_register_open_window(g->window,
+ ro_gui_window_open);
+ ro_gui_wimp_event_register_close_window(g->window,
+ ro_gui_window_close);
+ ro_gui_wimp_event_register_redraw_window(g->window,
+ ro_gui_window_redraw);
+ ro_gui_wimp_event_register_scroll_window(g->window,
+ ro_gui_window_scroll);
+ ro_gui_wimp_event_register_pointer_entering_window(g->window,
+ ro_gui_window_pointer_entering);
+ ro_gui_wimp_event_register_keypress(g->window,
+ ro_gui_window_keypress);
+ ro_gui_wimp_event_register_mouse_click(g->window,
+ ro_gui_window_click);
+ ro_gui_wimp_event_register_menu(g->window,
+ ro_gui_browser_window_menu,
+ true, false);
+ ro_gui_wimp_event_register_menu_prepare(g->window,
+ ro_gui_window_menu_prepare);
+ ro_gui_wimp_event_register_menu_selection(g->window,
+ ro_gui_window_menu_select);
+ ro_gui_wimp_event_register_menu_warning(g->window,
+ ro_gui_window_menu_warning);
+ ro_gui_wimp_event_register_menu_close(g->window,
+ ro_gui_window_menu_close);
- /* If no scrolling is required, there's no point trying to do any. */
+ /* Set the window options */
+ ro_gui_window_clone_options(g, existing);
+ ro_gui_window_update_toolbar_buttons(g);
- if (step_x == 0 && step_y == 0)
- return;
+ /* Open the window at the top of the stack */
+ state.w = g->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return g;
+ }
- /* If the pointer is over the window being scrolled, then try to get
- * the core to do the scrolling on the object under the pointer.
- */
+ state.next = wimp_TOP;
- if (pointer.w == g->window &&
- ro_gui_window_to_window_pos(g,
- pointer.pos.x, pointer.pos.y, &pos))
- handled = browser_window_scroll_at_point(g->bw, pos.x, pos.y,
- step_x, step_y);
+ ro_gui_window_open(PTR_WIMP_OPEN(&state));
- /* If the core didn't do the scrolling, handle it via the Wimp.
- * Windows which contain frames can only be scrolled by the core,
- * because it implements frame scroll bars.
- */
+ /* Claim the caret */
+ if (ro_toolbar_take_caret(g->toolbar)) {
+ ro_gui_url_complete_start(g->toolbar);
+ } else {
+ gui_window_place_caret(g, -100, -100, 0, NULL);
+ }
- if (!handled && (browser_window_is_frameset(g->bw) == false)) {
- switch (step_x) {
- case SCROLL_TOP:
- state.xscroll -= 0x10000000;
- break;
- case SCROLL_BOTTOM:
- state.xscroll += 0x10000000;
- break;
- case SCROLL_PAGE_UP:
- state.xscroll += visible_x;
- break;
- case SCROLL_PAGE_DOWN:
- state.xscroll -= visible_x;
- break;
- default:
- state.xscroll += 2 * step_x;
- break;
- }
+ return g;
+}
- switch (step_y) {
- case SCROLL_TOP:
- state.yscroll += 0x10000000;
- break;
- case SCROLL_BOTTOM:
- state.yscroll -= 0x10000000;
- break;
- case SCROLL_PAGE_UP:
- state.yscroll += visible_y;
- break;
- case SCROLL_PAGE_DOWN:
- state.yscroll -= visible_y;
- break;
- default:
- state.yscroll -= 2 * step_y;
- break;
- }
- error = xwimp_open_window((wimp_open *) &state);
- if (error) {
- LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess);
+/**
+ * Remove all pending update boxes for a window
+ *
+ * \param g gui_window
+ */
+static void ro_gui_window_remove_update_boxes(struct gui_window *g)
+{
+ struct update_box *cur;
+
+ for (cur = pending_updates; cur != NULL; cur = cur->next) {
+ if (cur->g == g) {
+ cur->g = NULL;
}
}
}
/**
- * Handle Message_DataLoad (file dragged in) for a window.
- *
- * \param g window
- * \param message Message_DataLoad block
- * \return true if the load was processed
+ * Close a browser window and free any related resources.
*
- * If the file was dragged into a form file input, it is used as the value.
+ * \param g gui_window to destroy
*/
-
-bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
+static void gui_window_destroy(struct gui_window *g)
{
os_error *error;
- os_coord pos;
+ wimp_w w;
- /* Ignore directories etc. */
- if (0x1000 <= message->data.data_xfer.file_type)
- return false;
+ assert(g);
- if (!ro_gui_window_to_window_pos(g, message->data.data_xfer.pos.x,
- message->data.data_xfer.pos.y, &pos))
- return false;
+ /* stop any tracking */
+ ro_mouse_kill(g);
- if (browser_window_drop_file_at_point(g->bw, pos.x, pos.y,
- message->data.data_xfer.file_name) == false)
- return false;
+ /* remove from list */
+ if (g->prev)
+ g->prev->next = g->next;
+ else
+ window_list = g->next;
+ if (g->next)
+ g->next->prev = g->prev;
- /* send DataLoadAck */
- message->action = message_DATA_LOAD_ACK;
- message->your_ref = message->my_ref;
- error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender);
+ /* destroy toolbar */
+ if (g->toolbar)
+ ro_toolbar_destroy(g->toolbar);
+ if (g->status_bar)
+ ro_gui_status_bar_destroy(g->status_bar);
+
+ w = g->window;
+ ro_gui_url_complete_close();
+ ro_gui_dialog_close_persistent(w);
+ if (current_menu_window == w)
+ ro_gui_menu_destroy();
+ ro_gui_window_remove_update_boxes(g);
+
+ /* delete window */
+ error = xwimp_delete_window(w);
if (error) {
- LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
+ ro_gui_wimp_event_finalise(w);
- return true;
+ free(g);
}
/**
- * Handle pointer movements in a browser window.
+ * Set the title of a browser window.
*
- * \param *pointer new mouse position
- * \param *data browser window that the pointer is in
+ * \param g gui_window to update
+ * \param title new window title, copied
*/
-
-void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data)
+static void gui_window_set_title(struct gui_window *g, const char *title)
{
- os_coord pos;
- struct gui_window *g = (struct gui_window *) data;
+ assert(g);
+ assert(title);
- if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos))
- browser_window_mouse_track(g->bw,
- ro_gui_mouse_drag_state(pointer->buttons,
- wimp_BUTTON_DOUBLE_CLICK_DRAG),
- pos.x, pos.y);
+ if (g->scale != 1.0) {
+ int scale_disp = g->scale * 100;
+
+ if (ABS((float)scale_disp - g->scale * 100) >= 0.05)
+ snprintf(g->title, sizeof g->title, "%s (%.1f%%)",
+ title, g->scale * 100);
+ else
+ snprintf(g->title, sizeof g->title, "%s (%i%%)",
+ title, scale_disp);
+ } else {
+ strncpy(g->title, title, sizeof g->title);
+ }
+
+ ro_gui_set_window_title(g->window, g->title);
}
/**
- * Window is being iconised. Create a suitable thumbnail sprite
- * (which, sadly, must be in the Wimp sprite pool), and return
- * the sprite name and truncated title to the iconiser
+ * Get the scroll position of a browser window.
*
- * \param g the gui window being iconised
- * \param wi the WindowInfo message from the iconiser
+ * \param g gui_window
+ * \param sx receives x ordinate of point at top-left of window
+ * \param sy receives y ordinate of point at top-left of window
+ * \return true iff successful
*/
+static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
+{
+ wimp_window_state state;
+ os_error *error;
+ int toolbar_height = 0;
+
+ assert(g);
+
+ state.w = g->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
+
+ if (g->toolbar)
+ toolbar_height = ro_toolbar_full_height(g->toolbar);
+ *sx = state.xscroll / (2 * g->scale);
+ *sy = -(state.yscroll - toolbar_height) / (2 * g->scale);
+ return true;
+}
+
-void ro_gui_window_iconise(struct gui_window *g,
- wimp_full_message_window_info *wi)
+/**
+ * Set the scroll position of a riscos browser window.
+ *
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown.
+ *
+ * \param g gui window to scroll
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
+ */
+static nserror
+gui_window_set_scroll(struct gui_window *g, const struct rect *rect)
{
- /* sadly there is no 'legal' way to get the sprite into
- * the Wimp sprite pool other than via a filing system */
- const char *temp_fname = "Pipe:$._tmpfile";
- struct browser_window *bw = g->bw;
- osspriteop_header *overlay = NULL;
- osspriteop_header *sprite_header;
- struct bitmap *bitmap;
- osspriteop_area *area;
- int width = 34, height = 34;
- struct hlcache_handle *h;
+ wimp_window_state state;
os_error *error;
- int len, id;
+ int toolbar_height = 0;
- assert(bw);
+ assert(g);
- h = browser_window_get_content(bw);
- if (!h) return;
+ state.w = g->window;
+ error = xwimp_get_window_state(&state);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_BAD_PARAMETER;
+ }
- /* if an overlay sprite is defined, locate it and gets its dimensions
- * so that we can produce a thumbnail with the same dimensions */
- if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) {
- error = xosspriteop_read_sprite_info(osspriteop_PTR,
- (osspriteop_area *)0x100,
- (osspriteop_id)overlay, &width, &height, NULL,
- NULL);
- if (error) {
- LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess);
- ro_warn_user("MiscError", error->errmess);
- overlay = NULL;
+ if (g->toolbar) {
+ toolbar_height = ro_toolbar_full_height(g->toolbar);
+ }
+
+ if ((rect->x0 == rect->x1) && (rect->y0 == rect->y1)) {
+ /* scroll to top */
+ state.xscroll = rect->x0 * 2 * g->scale;
+ state.yscroll = (-rect->y0 * 2 * g->scale) + toolbar_height;
+ } else {
+ /* scroll area into view with padding */
+ int x0, y0, x1, y1;
+ int cx0, cy0, width, height;
+ int padding_available;
+ int correction;
+
+ x0 = rect->x0 * 2 * g->scale;
+ y0 = rect->y0 * 2 * g->scale;
+ x1 = rect->x1 * 2 * g->scale;
+ y1 = rect->y1 * 2 * g->scale;
+
+ cx0 = state.xscroll;
+ cy0 = -state.yscroll + toolbar_height;
+ width = state.visible.x1 - state.visible.x0;
+ height = state.visible.y1 - state.visible.y0 - toolbar_height;
+
+ /* make sure we're visible */
+ correction = (x1 - cx0 - width);
+ if (correction > 0) {
+ cx0 += correction;
}
- else if (sprite_bpp(overlay) != 8) {
- LOG("overlay sprite is not 8bpp");
- overlay = NULL;
+ correction = (y1 - cy0 - height);
+ if (correction > 0) {
+ cy0 += correction;
+ }
+ if (x0 < cx0) {
+ cx0 = x0;
+ }
+ if (y0 < cy0) {
+ cy0 = y0;
}
- }
- /* create the thumbnail sprite */
- bitmap = riscos_bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE |
- BITMAP_CLEAR_MEMORY);
- if (!bitmap) {
- LOG("Thumbnail initialisation failed.");
- return;
+ /* try to give a SCROLL_VISIBLE_PADDING border of space around us */
+ padding_available = (width - x1 + x0) / 2;
+ if (padding_available > 0) {
+ if (padding_available > SCROLL_VISIBLE_PADDING) {
+ padding_available = SCROLL_VISIBLE_PADDING;
+ }
+ correction = (cx0 + width - x1);
+ if (correction < padding_available) {
+ cx0 += padding_available;
+ }
+ correction = (x0 - cx0);
+ if (correction < padding_available) {
+ cx0 -= padding_available;
+ }
+ }
+ padding_available = (height - y1 + y0) / 2;
+ if (padding_available > 0) {
+ if (padding_available > SCROLL_VISIBLE_PADDING) {
+ padding_available = SCROLL_VISIBLE_PADDING;
+ }
+ correction = (cy0 + height - y1);
+ if (correction < padding_available) {
+ cy0 += padding_available;
+ }
+ correction = (y0 - cy0);
+ if (correction < padding_available) {
+ cy0 -= padding_available;
+ }
+ }
+
+ state.xscroll = cx0;
+ state.yscroll = -cy0 + toolbar_height;
}
- riscos_bitmap_render(bitmap, h);
- if (overlay) {
- riscos_bitmap_overlay_sprite(bitmap, overlay);
+ ro_gui_window_open(PTR_WIMP_OPEN(&state));
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find the current dimensions of a browser window's content area.
+ *
+ * \param gw gui window to measure
+ * \param width receives width of window
+ * \param height receives height of window
+ * \param scaled whether to return scaled values
+ */
+static nserror
+gui_window_get_dimensions(struct gui_window *gw,
+ int *width, int *height,
+ bool scaled)
+{
+ /* use the cached window sizes */
+ *width = gw->old_width / 2;
+ *height = gw->old_height / 2;
+
+ if (scaled) {
+ *width /= gw->scale;
+ *height /= gw->scale;
}
- area = riscos_bitmap_convert_8bpp(bitmap);
- riscos_bitmap_destroy(bitmap);
- if (!area) {
- LOG("Thumbnail conversion failed.");
- return;
+ return NSERROR_OK;
+}
+
+
+/**
+ * Set the status bar of a browser window.
+ *
+ * \param g gui_window to update
+ * \param text new status text
+ */
+static void riscos_window_set_status(struct gui_window *g, const char *text)
+{
+ if (g->status_bar) {
+ ro_gui_status_bar_set_text(g->status_bar, text);
}
+}
- /* choose a suitable sprite name */
- id = 0;
- while (iconise_used[id])
- if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) {
- id = iconise_next;
- if ((unsigned)++iconise_next >=
- NOF_ELEMENTS(iconise_used))
- iconise_next = 0;
- break;
- }
- sprite_header = (osspriteop_header *)(area + 1);
- len = sprintf(sprite_header->name, "ic_netsf%.2d", id);
+/**
+ * Update the interface to reflect start of page loading.
+ *
+ * \param g window with start of load
+ */
+static void gui_window_start_throbber(struct gui_window *g)
+{
+ ro_gui_window_update_toolbar_buttons(g);
+ ro_gui_menu_refresh(ro_gui_browser_window_menu);
+ if (g->toolbar != NULL)
+ ro_toolbar_start_throbbing(g->toolbar);
+ g->active = true;
+}
- error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
- area, temp_fname);
- if (error) {
- LOG("xosspriteop_save_sprite_file: 0x%x:%s", error->errnum, error->errmess);
- ro_warn_user("MiscError", error->errmess);
- free(area);
- return;
- }
- error = xwimpspriteop_merge_sprite_file(temp_fname);
- if (error) {
- LOG("xwimpspriteop_merge_sprite_file: 0x%x:%s", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- remove(temp_fname);
- free(area);
+
+/**
+ * Update the interface to reflect page loading stopped.
+ *
+ * \param g window with start of load
+ */
+static void gui_window_stop_throbber(struct gui_window *g)
+{
+ ro_gui_window_update_toolbar_buttons(g);
+ ro_gui_menu_refresh(ro_gui_browser_window_menu);
+ if (g->toolbar != NULL)
+ ro_toolbar_stop_throbbing(g->toolbar);
+ g->active = false;
+}
+
+/**
+ * set favicon
+ */
+static void
+gui_window_set_icon(struct gui_window *g, struct hlcache_handle *icon)
+{
+ if (g == NULL || g->toolbar == NULL)
return;
- }
- memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */
- strncpy(wi->title, g->title, sizeof(wi->title));
- wi->title[sizeof(wi->title) - 1] = '\0';
+ ro_toolbar_set_site_favicon(g->toolbar, icon);
+}
- if (wimptextop_string_width(wi->title, 0) > 182) {
- /* work around bug in Pinboard where it will fail to display
- * the icon if the text is very wide */
- if (strlen(wi->title) > 10)
- wi->title[10] = '\0'; /* pinboard does this anyway */
- while (wimptextop_string_width(wi->title, 0) > 182)
- wi->title[strlen(wi->title) - 1] = '\0';
- }
- wi->size = sizeof(wimp_full_message_window_info);
- wi->your_ref = wi->my_ref;
- error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi,
- wi->sender);
+
+/**
+ * Remove the caret, if present.
+ *
+ * \param g window with caret
+ */
+static void gui_window_remove_caret(struct gui_window *g)
+{
+ wimp_caret caret;
+ os_error *error;
+
+ error = xwimp_get_caret_position(&caret);
if (error) {
- LOG("xwimp_send_message: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
+ return;
}
- else {
- g->iconise_icon = id;
- iconise_used[id] = true;
+
+ if (caret.w == g->window) {
+ /* we have the caret: hide caret, but keep input focus */
+ gui_window_place_caret(g, -100, -100, 0, NULL);
}
+}
- free(area);
+
+/**
+ * Called when the gui_window has new content.
+ *
+ * \param g the gui_window that has new content
+ */
+static void gui_window_new_content(struct gui_window *g)
+{
+ ro_gui_menu_refresh(ro_gui_browser_window_menu);
+ ro_gui_window_update_toolbar_buttons(g);
+ ro_gui_dialog_close_persistent(g->window);
+ ro_toolbar_set_content_favicon(g->toolbar, g);
}
/**
* Completes scrolling of a browser window
*
- * \param *drag The DragEnd event data block.
- * \param *data gui window block pointer.
+ * \param drag The DragEnd event data block.
+ * \param data gui window block pointer.
*/
-
static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data)
{
wimp_pointer pointer;
@@ -3481,20 +3813,25 @@ static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data)
error = xwimp_drag_box((wimp_drag*)-1);
if (error) {
- LOG("xwimp_drag_box: 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
}
error = xwimp_get_pointer_info(&pointer);
if (error) {
- LOG("xwimp_get_pointer_info 0x%x : %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info 0x%x : %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return;
}
error = xwimpspriteop_set_pointer_shape("ptr_default", 0x31, 0, 0, 0, 0);
if (error) {
- LOG("xwimpspriteop_set_pointer_shape: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimpspriteop_set_pointer_shape: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
}
@@ -3504,630 +3841,736 @@ static void ro_gui_window_scroll_end(wimp_dragged *drag, void *data)
/**
- * Process Mouse_Click events in a toolbar's button bar. This does not handle
- * other clicks in a toolbar: these are handled by the toolbar module itself.
+ * Starts drag scrolling of a browser window
*
- * \param *data The GUI window associated with the click.
- * \param action_type The action type to be handled.
- * \param action The action to process.
+ * \param g the window to scroll
*/
-
-void ro_gui_window_toolbar_click(void *data,
- toolbar_action_type action_type, union toolbar_action action)
+static bool gui_window_scroll_start(struct gui_window *g)
{
- struct gui_window *g = data;
- nserror err;
-
- if (g == NULL)
- return;
-
-
- if (action_type == TOOLBAR_ACTION_URL) {
- switch (action.url) {
- case TOOLBAR_URL_DRAG_URL:
- {
- gui_save_type save_type;
-
- if (!browser_window_has_content(g->bw))
- break;
-
- if (ro_gui_shift_pressed())
- save_type = GUI_SAVE_LINK_URL;
- else
- save_type = GUI_SAVE_LINK_TEXT;
-
- ro_gui_drag_save_link(save_type,
- browser_window_get_url(g->bw),
- browser_window_get_title(g->bw), g);
- }
- break;
-
- case TOOLBAR_URL_SELECT_HOTLIST:
- ro_gui_window_action_add_bookmark(g);
- break;
-
- case TOOLBAR_URL_ADJUST_HOTLIST:
- ro_gui_window_action_remove_bookmark(g);
- break;
-
- default:
- break;
- }
+ wimp_window_info_base info;
+ wimp_pointer pointer;
+ os_error *error;
+ wimp_drag drag;
+ int height;
+ int width;
- return;
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info 0x%x : %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
}
+ info.w = g->window;
+ error = xwimp_get_window_info_header_only((wimp_window_info*)&info);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x : %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
- /* By now, the only valid action left is a button click. If it isn't
- * one of those, give up.
- */
-
- if (action_type != TOOLBAR_ACTION_BUTTON)
- return;
-
- switch (action.button) {
- case TOOLBAR_BUTTON_BACK:
- if (g->bw != NULL)
- browser_window_history_back(g->bw, false);
- break;
-
- case TOOLBAR_BUTTON_BACK_NEW:
- if (g->bw != NULL)
- browser_window_history_back(g->bw, true);
- break;
-
- case TOOLBAR_BUTTON_FORWARD:
- if (g->bw != NULL)
- browser_window_history_forward(g->bw, false);
- break;
-
- case TOOLBAR_BUTTON_FORWARD_NEW:
- if (g->bw != NULL)
- browser_window_history_forward(g->bw, true);
- break;
-
- case TOOLBAR_BUTTON_STOP:
- if (g->bw != NULL)
- browser_window_stop(g->bw);
- break;
-
- case TOOLBAR_BUTTON_RELOAD:
- if (g->bw != NULL)
- browser_window_reload(g->bw, false);
- break;
-
- case TOOLBAR_BUTTON_RELOAD_ALL:
- if (g->bw != NULL)
- browser_window_reload(g->bw, true);
- break;
-
- case TOOLBAR_BUTTON_HISTORY_LOCAL:
- ro_gui_window_action_local_history(g);
- break;
-
- case TOOLBAR_BUTTON_HISTORY_GLOBAL:
- ro_gui_global_history_present();
- break;
+ width = info.extent.x1 - info.extent.x0;
+ height = info.extent.y1 - info.extent.y0;
- case TOOLBAR_BUTTON_HOME:
- ro_gui_window_action_home(g);
- break;
+ drag.type = wimp_DRAG_USER_POINT;
+ drag.bbox.x1 = pointer.pos.x + info.xscroll;
+ drag.bbox.y0 = pointer.pos.y + info.yscroll;
+ drag.bbox.x0 = drag.bbox.x1 - (width - (info.visible.x1 - info.visible.x0));
+ drag.bbox.y1 = drag.bbox.y0 + (height - (info.visible.y1 - info.visible.y0));
- case TOOLBAR_BUTTON_SEARCH:
- ro_gui_window_action_search(g);
- break;
+ if (g->toolbar) {
+ int tbar_height = ro_toolbar_full_height(g->toolbar);
+ drag.bbox.y0 -= tbar_height;
+ drag.bbox.y1 -= tbar_height;
+ }
- case TOOLBAR_BUTTON_SCALE:
- ro_gui_window_action_zoom(g);
- break;
+ error = xwimp_drag_box(&drag);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x : %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
- case TOOLBAR_BUTTON_BOOKMARK_OPEN:
- ro_gui_hotlist_present();
- break;
+ ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at,
+ NULL, g);
+ return true;
+}
- case TOOLBAR_BUTTON_BOOKMARK_ADD:
- ro_gui_window_action_add_bookmark(g);
- break;
- case TOOLBAR_BUTTON_SAVE_SOURCE:
- ro_gui_window_action_save(g, GUI_SAVE_SOURCE);
- break;
+/**
+ * Platform-dependent part of starting drag operation.
+ *
+ * \param g gui window containing the drag
+ * \param type type of drag the core is performing
+ * \param rect rectangle to constrain pointer to (relative to drag start coord)
+ * \return true iff succesful
+ */
+static bool
+gui_window_drag_start(struct gui_window *g,
+ gui_drag_type type,
+ const struct rect *rect)
+{
+ wimp_pointer pointer;
+ wimp_drag drag;
- case TOOLBAR_BUTTON_SAVE_COMPLETE:
- ro_gui_window_action_save(g, GUI_SAVE_COMPLETE);
- break;
+ if (rect != NULL) {
+ /* We have a box to constrain the pointer to, for the drag
+ * duration */
+ os_error *error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimp_get_pointer_info 0x%x : %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
+ }
- case TOOLBAR_BUTTON_PRINT:
- ro_gui_window_action_print(g);
- break;
+ drag.type = wimp_DRAG_USER_POINT;
+ drag.bbox.x0 = pointer.pos.x +
+ (int)(rect->x0 * 2 * g->scale);
+ drag.bbox.y0 = pointer.pos.y +
+ (int)(rect->y0 * 2 * g->scale);
+ drag.bbox.x1 = pointer.pos.x +
+ (int)(rect->x1 * 2 * g->scale);
+ drag.bbox.y1 = pointer.pos.y +
+ (int)(rect->y1 * 2 * g->scale);
- case TOOLBAR_BUTTON_UP:
- err = browser_window_navigate_up(g->bw, false);
- if (err != NSERROR_OK) {
- ro_warn_user(messages_get_errorcode(err), NULL);
+ error = xwimp_drag_box(&drag);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_drag_box: 0x%x : %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return false;
}
- break;
+ }
- case TOOLBAR_BUTTON_UP_NEW:
- err = browser_window_navigate_up(g->bw, true);
- if (err != NSERROR_OK) {
- ro_warn_user(messages_get_errorcode(err), NULL);
- }
+ switch (type) {
+ case GDRAGGING_SCROLLBAR:
+ /* Dragging a core scrollbar */
+ ro_mouse_drag_start(ro_gui_window_scroll_end, ro_gui_window_mouse_at,
+ NULL, g);
break;
default:
+ /* Not handled here yet */
break;
}
- ro_gui_window_update_toolbar_buttons(g);
+ return true;
}
/**
- * Handle Message_DataLoad (file dragged in) for a toolbar
- *
- * @todo This belongs in the toolbar module, and should be moved there
- * once the module is able to usefully handle its own events.
+ * Save the specified content as a link.
*
- * \param g window
- * \param message Message_DataLoad block
- * \return true if the load was processed
+ * \param g The window containing the content
+ * \param url The url of the link
+ * \param title The title of the link
*/
-
-bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message)
+static nserror
+gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
{
- if (message->data.data_xfer.file_type == osfile_TYPE_TEXT &&
- ro_gui_window_import_text(g,
- message->data.data_xfer.file_name)) {
- os_error *error;
-
- /* send DataLoadAck */
- message->action = message_DATA_LOAD_ACK;
- message->your_ref = message->my_ref;
- error = xwimp_send_message(wimp_USER_MESSAGE, message,
- message->sender);
- if (error) {
- LOG("xwimp_send_message: 0x%x: %s\n", error->errnum, error->errmess);
- ro_warn_user("WimpError", error->errmess);
- }
- return true;
- }
- return false;
+ ro_gui_save_prepare(GUI_SAVE_LINK_URL, NULL, NULL, url, title);
+ ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
+ return NSERROR_OK;
}
-/*
- * Helper code for the Wimp Event Handlers.
- */
-
/**
- * Check if a particular menu handle is a browser window menu
+ * Display a menu of options for a form select control.
*
- * \param *menu The menu in question.
- * \return true if this menu is a browser window menu
+ * \param g gui window containing form control
+ * \param control form control of type GADGET_SELECT
*/
-
-bool ro_gui_window_check_menu(wimp_menu *menu)
+static void
+gui_window_create_form_select_menu(struct gui_window *g,
+ struct form_control *control)
{
- return (ro_gui_browser_window_menu == menu) ? true : false;
-}
-
-
-/**
- * Return boolean flags to show what RISC OS types we can sensibly convert
- * the given object into.
- *
- * \todo This should probably be somewhere else but in window.c, and
- * should probably even be done in content_().
- *
- * \param h The object to test.
- * \param export_draw true on exit if a drawfile would be possible.
- * \param export_sprite true on exit if a sprite would be possible.
- * \return true if valid data is returned; else false.
- */
+ os_error *error;
+ wimp_pointer pointer;
-bool ro_gui_window_content_export_types(struct hlcache_handle *h,
- bool *export_draw, bool *export_sprite)
-{
- bool found_type = false;
+ /* The first time the menu is opened, control bypasses the normal
+ * Menu Prepare event and so we prepare here. On any re-opens,
+ * ro_gui_window_prepare_form_select_menu() is called from the
+ * normal wimp event.
+ */
- if (export_draw != NULL)
- *export_draw = false;
- if (export_sprite != NULL)
- *export_sprite = false;
+ if (!ro_gui_window_prepare_form_select_menu(g, control))
+ return;
- if (h != NULL && content_get_type(h) == CONTENT_IMAGE) {
- switch (ro_content_native_type(h)) {
- case osfile_TYPE_SPRITE:
- /* bitmap types (Sprite export possible) */
- found_type = true;
- if (export_sprite != NULL)
- *export_sprite = true;
- break;
- case osfile_TYPE_DRAW:
- /* vector types (Draw export possible) */
- found_type = true;
- if (export_draw != NULL)
- *export_draw = true;
- break;
- default:
- break;
- }
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ ro_gui_menu_destroy();
+ return;
}
- return found_type;
+ gui_form_select_control = control;
+ ro_gui_menu_create(gui_form_select_menu,
+ pointer.pos.x, pointer.pos.y, g->window);
}
/**
- * Prepare the page info window for use.
+ * Import text file into window
*
- * \param *g The GUI window block to use.
+ * \param g gui window containing textarea
+ * \param filename pathname of file to be imported
+ * \return true iff successful
*/
-
-void ro_gui_window_prepare_pageinfo(struct gui_window *g)
+static bool
+ro_gui_window_import_text(struct gui_window *g, const char *filename)
{
- struct hlcache_handle *h = browser_window_get_content(g->bw);
- char icon_buf[20] = "file_xxx";
- char enc_buf[40];
- const char *icon = icon_buf;
- const char *title, *url;
- lwc_string *mime;
- const char *enc = "-";
-
- assert(h);
-
- title = content_get_title(h);
- if (title == NULL)
- title = "-";
- url = nsurl_access(hlcache_handle_get_url(h));
- if (url == NULL)
- url = "-";
- mime = content_get_mime_type(h);
-
- sprintf(icon_buf, "file_%x", ro_content_filetype(h));
- if (!ro_gui_wimp_sprite_exists(icon_buf))
- sprintf(icon_buf, "file_xxx");
+ fileswitch_object_type obj_type;
+ os_error *error;
+ char *buf, *utf8_buf, *sp;
+ int size;
+ nserror ret;
+ const char *ep;
+ char *p;
- if (content_get_type(h) == CONTENT_HTML) {
- if (content_get_encoding(h, CONTENT_ENCODING_NORMAL)) {
- snprintf(enc_buf, sizeof enc_buf, "%s (%s)",
- content_get_encoding(h, CONTENT_ENCODING_NORMAL),
- content_get_encoding(h, CONTENT_ENCODING_SOURCE));
- enc = enc_buf;
- } else {
- enc = messages_get("EncodingUnk");
- }
+ error = xosfile_read_stamped(filename, &obj_type, NULL, NULL,
+ &size, NULL, NULL);
+ if (error) {
+ NSLOG(netsurf, INFO, "xosfile_read_stamped: 0x%x:%s",
+ error->errnum, error->errmess);
+ ro_warn_user("FileError", error->errmess);
+ return true; /* was for us, but it didn't work! */
}
- ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ICON,
- icon, true);
- ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TITLE,
- title, true);
- ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_URL,
- url, true);
- ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC,
- enc, true);
- ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE,
- lwc_string_data(mime), true);
-
- lwc_string_unref(mime);
-}
-
+ /* Allocate one byte more than needed to ensure that the buffer is
+ * always terminated, regardless of file contents.
+ */
-/**
- * Prepare the object info window for use
- *
- * \param *object the object for which information is to be displayed
- * \param *target_url corresponding url, if any
- */
+ buf = calloc(size + 1, sizeof(char));
+ if (!buf) {
+ ro_warn_user("NoMemory", NULL);
+ return true;
+ }
-void ro_gui_window_prepare_objectinfo(struct hlcache_handle *object, nsurl *target_url)
-{
- char icon_buf[20] = "file_xxx";
- const char *url;
- lwc_string *mime;
- const char *target = "-";
+ error = xosfile_load_stamped(filename, (byte*)buf,
+ NULL, NULL, NULL, NULL, NULL);
- sprintf(icon_buf, "file_%.3x",ro_content_filetype(object));
- if (!ro_gui_wimp_sprite_exists(icon_buf)) {
- sprintf(icon_buf, "file_xxx");
+ if (error) {
+ NSLOG(netsurf, INFO, "xosfile_load_stamped: 0x%x:%s",
+ error->errnum, error->errmess);
+ ro_warn_user("LoadError", error->errmess);
+ free(buf);
+ return true;
}
- url = nsurl_access(hlcache_handle_get_url(object));
- if (url == NULL) {
- url = "-";
+ ret = utf8_from_local_encoding(buf, size, &utf8_buf);
+ if (ret != NSERROR_OK) {
+ /* bad encoding shouldn't happen */
+ assert(ret != NSERROR_BAD_ENCODING);
+ NSLOG(netsurf, INFO, "utf8_from_local_encoding failed");
+ free(buf);
+ ro_warn_user("NoMemory", NULL);
+ return true;
}
- mime = content_get_mime_type(object);
+ size = strlen(utf8_buf);
- if (target_url != NULL) {
- target = nsurl_access(target_url);
- }
+ ep = utf8_buf + size;
+ p = utf8_buf;
- ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_ICON,
- icon_buf, true);
- ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_URL,
- url, true);
- ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TARGET,
- target, true);
- ro_gui_set_icon_string(dialog_objinfo, ICON_OBJINFO_TYPE,
- lwc_string_data(mime), true);
+ /* skip leading whitespace */
+ while (isspace(*p)) p++;
- lwc_string_unref(mime);
-}
+ sp = p;
+ while (*p && *p != '\r' && *p != '\n')
+ p += utf8_next(p, ep - p, 0);
+ *p = '\0';
+ if (p > sp)
+ ro_gui_window_launch_url(g, sp);
+
+ free(buf);
+ free(utf8_buf);
+ return true;
+}
-/*
- * User Actions in the browser window
- */
/**
- * Launch a new url in the given window.
- *
- * \param g gui_window to update
- * \param url1 url to be launched
+ * RISC OS browser window operation table
*/
+static struct gui_window_table window_table = {
+ .create = gui_window_create,
+ .destroy = gui_window_destroy,
+ .invalidate = ro_gui_window_invalidate_area,
+ .get_scroll = gui_window_get_scroll,
+ .set_scroll = gui_window_set_scroll,
+ .get_dimensions = gui_window_get_dimensions,
+ .update_extent = gui_window_update_extent,
-void ro_gui_window_launch_url(struct gui_window *g, const char *url1)
-{
- nserror error;
- nsurl *url;
+ .set_title = gui_window_set_title,
+ .set_url = ro_gui_window_set_url,
+ .set_icon = gui_window_set_icon,
+ .set_status = riscos_window_set_status,
+ .set_pointer = gui_window_set_pointer,
+ .place_caret = gui_window_place_caret,
+ .remove_caret = gui_window_remove_caret,
+ .save_link = gui_window_save_link,
+ .drag_start = gui_window_drag_start,
+ .scroll_start = gui_window_scroll_start,
+ .new_content = gui_window_new_content,
+ .start_throbber = gui_window_start_throbber,
+ .stop_throbber = gui_window_stop_throbber,
+ .create_form_select_menu = gui_window_create_form_select_menu,
- if (url1 == NULL)
- return;
+ /* from save */
+ .drag_save_object = gui_drag_save_object,
+ .drag_save_selection =gui_drag_save_selection,
- ro_gui_url_complete_close();
+ /* from textselection */
+ .start_selection = gui_start_selection,
+};
- error = nsurl_create(url1, &url);
- if (error != NSERROR_OK) {
- ro_warn_user(messages_get_errorcode(error), 0);
- } else {
- ro_gui_window_set_url(g, url);
+struct gui_window_table *riscos_window_table = &window_table;
- browser_window_navigate(g->bw, url,
- NULL, BW_NAVIGATE_HISTORY,
- NULL, NULL, NULL);
- nsurl_unref(url);
- }
-}
+/* exported interface documented in riscos/window.h */
+void ro_gui_window_initialise(void)
+{
+ /* Build the browser window menu. */
-/**
- * Perform a Navigate Home action on a browser window.
- *
- * \param *g The browser window to act on.
- */
+ static const struct ns_menu browser_definition = {
+ "NetSurf", {
+ { "Page", BROWSER_PAGE, 0 },
+ { "Page.PageInfo",BROWSER_PAGE_INFO, &dialog_pageinfo },
+ { "Page.Save", BROWSER_SAVE, &dialog_saveas },
+ { "Page.SaveComp", BROWSER_SAVE_COMPLETE, &dialog_saveas },
+ { "Page.Export", NO_ACTION, 0 },
+#ifdef WITH_DRAW_EXPORT
+ { "Page.Export.Draw", BROWSER_EXPORT_DRAW, &dialog_saveas },
+#endif
+#ifdef WITH_PDF_EXPORT
+ { "Page.Export.PDF", BROWSER_EXPORT_PDF, &dialog_saveas },
+#endif
+ { "Page.Export.Text", BROWSER_EXPORT_TEXT, &dialog_saveas },
+ { "Page.SaveURL", NO_ACTION, 0 },
+ { "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, &dialog_saveas },
+ { "Page.SaveURL.URL", BROWSER_SAVE_URL_URL, &dialog_saveas },
+ { "Page.SaveURL.LinkText", BROWSER_SAVE_URL_TEXT, &dialog_saveas },
+ { "_Page.Print", BROWSER_PRINT, &dialog_print },
+ { "Page.NewWindow", BROWSER_NEW_WINDOW, 0 },
+ { "Page.FindText", BROWSER_FIND_TEXT, &dialog_search },
+ { "Page.ViewSrc", BROWSER_VIEW_SOURCE, 0 },
+ { "Object", BROWSER_OBJECT, 0 },
+ { "Object.Object", BROWSER_OBJECT_OBJECT, 0 },
+ { "Object.Object.ObjInfo", BROWSER_OBJECT_INFO, &dialog_objinfo },
+ { "Object.Object.ObjSave", BROWSER_OBJECT_SAVE, &dialog_saveas },
+ { "Object.Object.Export", BROWSER_OBJECT_EXPORT, 0 },
+ { "Object.Object.Export.Sprite", BROWSER_OBJECT_EXPORT_SPRITE, &dialog_saveas },
+#ifdef WITH_DRAW_EXPORT
+ { "Object.Object.Export.ObjDraw", BROWSER_OBJECT_EXPORT_DRAW, &dialog_saveas },
+#endif
+ { "Object.Object.SaveURL", NO_ACTION, 0 },
+ { "Object.Object.SaveURL.URI", BROWSER_OBJECT_SAVE_URL_URI, &dialog_saveas },
+ { "Object.Object.SaveURL.URL", BROWSER_OBJECT_SAVE_URL_URL, &dialog_saveas },
+ { "Object.Object.SaveURL.LinkText", BROWSER_OBJECT_SAVE_URL_TEXT, &dialog_saveas },
+ { "Object.Object.ObjPrint", BROWSER_OBJECT_PRINT, 0 },
+ { "Object.Object.ObjReload", BROWSER_OBJECT_RELOAD, 0 },
+ { "Object.Link", BROWSER_OBJECT_LINK, 0 },
+ { "Object.Link.LinkSave", BROWSER_LINK_SAVE, 0 },
+ { "Object.Link.LinkSave.URI", BROWSER_LINK_SAVE_URI, &dialog_saveas },
+ { "Object.Link.LinkSave.URL", BROWSER_LINK_SAVE_URL, &dialog_saveas },
+ { "Object.Link.LinkSave.LinkText", BROWSER_LINK_SAVE_TEXT, &dialog_saveas },
+ { "_Object.Link.LinkDload", BROWSER_LINK_DOWNLOAD, 0 },
+ { "Object.Link.LinkNew", BROWSER_LINK_NEW_WINDOW, 0 },
+ { "Selection", BROWSER_SELECTION, 0 },
+ { "_Selection.SelSave", BROWSER_SELECTION_SAVE, &dialog_saveas },
+ { "Selection.Copy", BROWSER_SELECTION_COPY, 0 },
+ { "Selection.Cut", BROWSER_SELECTION_CUT, 0 },
+ { "_Selection.Paste", BROWSER_SELECTION_PASTE, 0 },
+ { "Selection.Clear", BROWSER_SELECTION_CLEAR, 0 },
+ { "Selection.SelectAll", BROWSER_SELECTION_ALL, 0 },
+ { "Navigate", NO_ACTION, 0 },
+ { "Navigate.Home", BROWSER_NAVIGATE_HOME, 0 },
+ { "Navigate.Back", BROWSER_NAVIGATE_BACK, 0 },
+ { "Navigate.Forward", BROWSER_NAVIGATE_FORWARD, 0 },
+ { "_Navigate.UpLevel", BROWSER_NAVIGATE_UP, 0 },
+ { "Navigate.Reload", BROWSER_NAVIGATE_RELOAD_ALL, 0 },
+ { "Navigate.Stop", BROWSER_NAVIGATE_STOP, 0 },
+ { "View", NO_ACTION, 0 },
+ { "View.ScaleView", BROWSER_SCALE_VIEW, &dialog_zoom },
+ { "View.Images", NO_ACTION, 0 },
+ { "View.Images.ForeImg", BROWSER_IMAGES_FOREGROUND, 0 },
+ { "View.Images.BackImg", BROWSER_IMAGES_BACKGROUND, 0 },
+ { "View.Toolbars", NO_ACTION, 0 },
+ { "View.Toolbars.ToolButtons", TOOLBAR_BUTTONS, 0 },
+ { "View.Toolbars.ToolAddress", TOOLBAR_ADDRESS_BAR, 0 },
+ { "_View.Toolbars.ToolThrob", TOOLBAR_THROBBER, 0 },
+ { "View.Toolbars.EditToolbar", TOOLBAR_EDIT, 0 },
+ { "_View.Render", NO_ACTION, 0 },
+ { "View.Render.RenderAnims", BROWSER_BUFFER_ANIMS, 0 },
+ { "View.Render.RenderAll", BROWSER_BUFFER_ALL, 0 },
+ { "_View.OptDefault", BROWSER_SAVE_VIEW, 0 },
+ { "View.Window", NO_ACTION, 0 },
+ { "View.Window.WindowSave", BROWSER_WINDOW_DEFAULT, 0 },
+ { "View.Window.WindowStagr", BROWSER_WINDOW_STAGGER, 0 },
+ { "_View.Window.WindowSize", BROWSER_WINDOW_COPY, 0 },
+ { "View.Window.WindowReset", BROWSER_WINDOW_RESET, 0 },
+ { "Utilities", NO_ACTION, 0 },
+ { "Utilities.Hotlist", HOTLIST_SHOW, 0 },
+ { "Utilities.Hotlist.HotlistAdd", HOTLIST_ADD_URL, 0 },
+ { "Utilities.Hotlist.HotlistShow", HOTLIST_SHOW, 0 },
+ { "Utilities.History", HISTORY_SHOW_GLOBAL, 0 },
+ { "Utilities.History.HistLocal", HISTORY_SHOW_LOCAL, 0 },
+ { "Utilities.History.HistGlobal", HISTORY_SHOW_GLOBAL, 0 },
+ { "Utilities.Cookies", COOKIES_SHOW, 0 },
+ { "Utilities.Cookies.ShowCookies", COOKIES_SHOW, 0 },
+ { "Utilities.Cookies.DeleteCookies", COOKIES_DELETE, 0 },
+ { "Help", HELP_OPEN_CONTENTS, 0 },
+ { "Help.HelpContent", HELP_OPEN_CONTENTS, 0 },
+ { "Help.HelpGuide", HELP_OPEN_GUIDE, 0 },
+ { "_Help.HelpInfo", HELP_OPEN_INFORMATION, 0 },
+ { "Help.HelpCredits", HELP_OPEN_CREDITS, 0 },
+ { "_Help.HelpLicence", HELP_OPEN_LICENCE, 0 },
+ { "Help.HelpInter", HELP_LAUNCH_INTERACTIVE, 0 },
+ {NULL, 0, 0}
+ }
+ };
+ ro_gui_browser_window_menu =
+ ro_gui_menu_define_menu(&browser_definition);
+
+}
-void ro_gui_window_action_home(struct gui_window *g)
+
+/* exported interface documented in riscos/window.h */
+nserror
+ro_gui_window_invalidate_area(struct gui_window *g, const struct rect *rect)
{
- static const char *addr = NETSURF_HOMEPAGE;
- nsurl *url;
- nserror error;
+ bool use_buffer;
+ int x0, y0, x1, y1;
+ struct update_box *cur;
+ wimp_window_info info;
+ os_error *error;
- if (g == NULL || g->bw == NULL)
- return;
+ assert(g);
- if (nsoption_charp(homepage_url) != NULL) {
- addr = nsoption_charp(homepage_url);
+ if (rect == NULL) {
+ info.w = g->window;
+ error = xwimp_get_window_info_header_only(&info);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimp_get_window_info_header_only: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_INVALID;
+ }
+
+ error = xwimp_force_redraw(g->window,
+ info.extent.x0, info.extent.y0,
+ info.extent.x1, info.extent.y1);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
}
- error = nsurl_create(addr, &url);
- if (error == NSERROR_OK) {
- error = browser_window_navigate(g->bw,
- url,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
+ x0 = floorf(rect->x0 * 2 * g->scale);
+ y0 = -ceilf(rect->y1 * 2 * g->scale);
+ x1 = ceilf(rect->x1 * 2 * g->scale) + 1;
+ y1 = -floorf(rect->y0 * 2 * g->scale) + 1;
+ use_buffer =
+ (g->option.buffer_everything || g->option.buffer_animations);
+
+ /* try to optimise buffered redraws */
+ if (use_buffer) {
+ for (cur = pending_updates; cur != NULL; cur = cur->next) {
+ if ((cur->g != g) || (!cur->use_buffer)) {
+ continue;
+ }
+ if ((((cur->x0 - x1) < MARGIN) ||
+ ((cur->x1 - x0) < MARGIN)) &&
+ (((cur->y0 - y1) < MARGIN) ||
+ ((cur->y1 - y0) < MARGIN))) {
+ cur->x0 = min(cur->x0, x0);
+ cur->y0 = min(cur->y0, y0);
+ cur->x1 = max(cur->x1, x1);
+ cur->y1 = max(cur->y1, y1);
+ return NSERROR_OK;
+ }
+ }
}
- if (error != NSERROR_OK) {
- ro_warn_user(messages_get_errorcode(error), 0);
+ cur = malloc(sizeof(struct update_box));
+ if (!cur) {
+ NSLOG(netsurf, INFO, "No memory for malloc.");
+ return NSERROR_NOMEM;
}
-}
+ cur->x0 = x0;
+ cur->y0 = y0;
+ cur->x1 = x1;
+ cur->y1 = y1;
+ cur->next = pending_updates;
+ pending_updates = cur;
+ cur->g = g;
+ cur->use_buffer = use_buffer;
+
+ return NSERROR_OK;
+}
-/**
- * Open a new browser window.
- *
- * \param *g The browser window to act on.
- */
-void ro_gui_window_action_new_window(struct gui_window *g)
+/* exported function documented in riscos/window.h */
+nserror ro_gui_window_set_url(struct gui_window *g, nsurl *url)
{
- nserror error;
+ size_t idn_url_l;
+ char *idn_url_s = NULL;
- if (g == NULL || g->bw == NULL)
- return;
+ if (g->toolbar) {
+ if (nsoption_bool(display_decoded_idn) == true) {
+ if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK)
+ idn_url_s = NULL;
+ }
- error = browser_window_create(BW_CREATE_CLONE,
- browser_window_get_url(g->bw),
- NULL, g->bw, NULL);
+ ro_toolbar_set_url(g->toolbar, idn_url_s ? idn_url_s : nsurl_access(url), true, false);
- if (error != NSERROR_OK) {
- ro_warn_user(messages_get_errorcode(error), 0);
+ if (idn_url_s)
+ free(idn_url_s);
+
+ ro_gui_url_complete_start(g->toolbar);
}
-}
+ return NSERROR_OK;
+}
-/**
- * Open a local history pane for a browser window.
- *
- * \param *g The browser window to act on.
- */
-void ro_gui_window_action_local_history(struct gui_window *g)
+/* exported interface documented in riscos/window.h */
+void ro_gui_window_set_scale(struct gui_window *g, float scale)
{
- if (g != NULL && g->bw != NULL)
- ro_gui_history_open(g, true);
+ g->scale = scale;
+ browser_window_set_scale(g->bw, scale, true);
}
-/**
- * Open a save dialogue for a browser window contents.
- *
- * \param *g The browser window to act on.
- * \param save_type The type of save to open.
- */
-
-void ro_gui_window_action_save(struct gui_window *g, gui_save_type save_type)
+/* exported interface documented in riscos/window.h */
+bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
{
- struct hlcache_handle *h;
-
- if (g == NULL || g->bw == NULL || !browser_window_has_content(g->bw))
- return;
-
- h = browser_window_get_content(g->bw);
- if (h == NULL)
- return;
+ os_error *error;
+ os_coord pos;
- ro_gui_save_prepare(save_type, h, NULL, NULL, NULL);
- ro_gui_dialog_open_persistent(g->window, dialog_saveas, true);
-}
+ /* Ignore directories etc. */
+ if (0x1000 <= message->data.data_xfer.file_type)
+ return false;
+ if (!ro_gui_window_to_window_pos(g, message->data.data_xfer.pos.x,
+ message->data.data_xfer.pos.y, &pos))
+ return false;
-/**
- * Open a text search dialogue for a browser window.
- *
- * \param *g The browser window to act on.
- */
+ if (browser_window_drop_file_at_point(g->bw, pos.x, pos.y,
+ message->data.data_xfer.file_name) == false)
+ return false;
-void ro_gui_window_action_search(struct gui_window *g)
-{
- if (g == NULL || g->bw == NULL || !browser_window_can_search(g->bw))
- return;
+ /* send DataLoadAck */
+ message->action = message_DATA_LOAD_ACK;
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE, message, message->sender);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s\n",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
- ro_gui_search_prepare(g->bw);
- ro_gui_dialog_open_persistent(g->window, dialog_search, true);
+ return true;
}
-/**
- * Open a zoom dialogue for a browser window.
- *
- * \param *g The browser window to act on.
- */
-
-void ro_gui_window_action_zoom(struct gui_window *g)
+/* exported interface documented in riscos/window.h */
+void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data)
{
- if (g == NULL)
- return;
+ os_coord pos;
+ struct gui_window *g = (struct gui_window *) data;
- ro_gui_dialog_prepare_zoom(g);
- ro_gui_dialog_open_persistent(g->window, dialog_zoom, true);
+ if (ro_gui_window_to_window_pos(g, pointer->pos.x, pointer->pos.y, &pos))
+ browser_window_mouse_track(g->bw,
+ ro_gui_mouse_drag_state(pointer->buttons,
+ wimp_BUTTON_DOUBLE_CLICK_DRAG),
+ pos.x, pos.y);
}
-/**
- * Add a hotlist entry for a browser window.
- *
- * \param *g The browser window to act on.
- */
-
-static void ro_gui_window_action_add_bookmark(struct gui_window *g)
+/* exported interface documented in riscos/window.h */
+void
+ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi)
{
- nsurl *url;
+ /* sadly there is no 'legal' way to get the sprite into
+ * the Wimp sprite pool other than via a filing system */
+ const char *temp_fname = "Pipe:$._tmpfile";
+ struct browser_window *bw = g->bw;
+ osspriteop_header *overlay = NULL;
+ osspriteop_header *sprite_header;
+ struct bitmap *bitmap;
+ osspriteop_area *area;
+ int width = 34, height = 34;
+ struct hlcache_handle *h;
+ os_error *error;
+ int len, id;
- if (g == NULL || g->bw == NULL || g->toolbar == NULL ||
- browser_window_has_content(g->bw) == false)
- return;
+ assert(bw);
- url = browser_window_get_url(g->bw);
+ h = browser_window_get_content(bw);
+ if (!h) return;
- ro_gui_hotlist_add_page(url);
- ro_toolbar_update_hotlist(g->toolbar);
-}
+ /* if an overlay sprite is defined, locate it and gets its dimensions
+ * so that we can produce a thumbnail with the same dimensions */
+ if (!ro_gui_wimp_get_sprite("ic_netsfxx", &overlay)) {
+ error = xosspriteop_read_sprite_info(osspriteop_PTR,
+ (osspriteop_area *)0x100,
+ (osspriteop_id)overlay, &width, &height, NULL,
+ NULL);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xosspriteop_read_sprite_info: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ overlay = NULL;
+ } else if (sprite_bpp(overlay) != 8) {
+ NSLOG(netsurf, INFO, "overlay sprite is not 8bpp");
+ overlay = NULL;
+ }
+ }
+ /* create the thumbnail sprite */
+ bitmap = riscos_bitmap_create(width, height,
+ BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY);
+ if (!bitmap) {
+ NSLOG(netsurf, INFO, "Thumbnail initialisation failed.");
+ return;
+ }
+ riscos_bitmap_render(bitmap, h);
+ if (overlay) {
+ riscos_bitmap_overlay_sprite(bitmap, overlay);
+ }
+ area = riscos_bitmap_convert_8bpp(bitmap);
+ riscos_bitmap_destroy(bitmap);
+ if (!area) {
+ NSLOG(netsurf, INFO, "Thumbnail conversion failed.");
+ return;
+ }
-/**
- * Remove a hotlist entry for a browser window.
- *
- * \param *g The browser window to act on.
- */
+ /* choose a suitable sprite name */
+ id = 0;
+ while (iconise_used[id])
+ if ((unsigned)++id >= NOF_ELEMENTS(iconise_used)) {
+ id = iconise_next;
+ if ((unsigned)++iconise_next >=
+ NOF_ELEMENTS(iconise_used))
+ iconise_next = 0;
+ break;
+ }
-static void ro_gui_window_action_remove_bookmark(struct gui_window *g)
-{
- nsurl *url;
+ sprite_header = (osspriteop_header *)(area + 1);
+ len = sprintf(sprite_header->name, "ic_netsf%.2d", id);
- if (g == NULL || g->bw == NULL || g->toolbar == NULL ||
- browser_window_has_content(g->bw) == false)
+ error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
+ area, temp_fname);
+ if (error) {
+ NSLOG(netsurf, INFO, "xosspriteop_save_sprite_file: 0x%x:%s",
+ error->errnum, error->errmess);
+ ro_warn_user("MiscError", error->errmess);
+ free(area);
return;
+ }
- url = browser_window_get_url(g->bw);
-
- ro_gui_hotlist_remove_page(url);
-}
+ error = xwimpspriteop_merge_sprite_file(temp_fname);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimpspriteop_merge_sprite_file: 0x%x:%s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ remove(temp_fname);
+ free(area);
+ return;
+ }
+ memcpy(wi->sprite_name, sprite_header->name + 3, len - 2); /* inc NUL */
+ strncpy(wi->title, g->title, sizeof(wi->title));
+ wi->title[sizeof(wi->title) - 1] = '\0';
-/**
- * Open a print dialogue for a browser window.
- *
- * \param *g The browser window to act on.
- */
+ if (wimptextop_string_width(wi->title, 0) > 182) {
+ /* work around bug in Pinboard where it will fail to display
+ * the icon if the text is very wide */
+ if (strlen(wi->title) > 10)
+ wi->title[10] = '\0'; /* pinboard does this anyway */
+ while (wimptextop_string_width(wi->title, 0) > 182)
+ wi->title[strlen(wi->title) - 1] = '\0';
+ }
-void ro_gui_window_action_print(struct gui_window *g)
-{
- if (g == NULL)
- return;
+ wi->size = sizeof(wimp_full_message_window_info);
+ wi->your_ref = wi->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)wi,
+ wi->sender);
+ if (error) {
+ NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x:%s",
+ error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ else {
+ g->iconise_icon = id;
+ iconise_used[id] = true;
+ }
- ro_gui_print_prepare(g);
- ro_gui_dialog_open_persistent(g->window, dialog_print, true);
+ free(area);
}
-/**
- * Open a page info box for a browser window.
- *
- * \param *g The browser window to act on.
- */
-
-void ro_gui_window_action_page_info(struct gui_window *g)
+/* exported interface documented in riscos/window.h */
+bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message)
{
- if (g == NULL || g->bw == NULL ||
- browser_window_has_content(g->bw) == false)
- return;
+ if (message->data.data_xfer.file_type == osfile_TYPE_TEXT &&
+ ro_gui_window_import_text(g,
+ message->data.data_xfer.file_name)) {
+ os_error *error;
- ro_gui_window_prepare_pageinfo(g);
- ro_gui_dialog_open_persistent(g->window, dialog_pageinfo, false);
+ /* send DataLoadAck */
+ message->action = message_DATA_LOAD_ACK;
+ message->your_ref = message->my_ref;
+ error = xwimp_send_message(wimp_USER_MESSAGE, message,
+ message->sender);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimp_send_message: 0x%x: %s\n",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ return true;
+ }
+ return false;
}
-/*
- * Window and Toolbar Redraw and Update
- */
-
-/**
- * Redraws the content for all windows.
- */
-
-void ro_gui_window_redraw_all(void)
+/* exported interface documented in riscos/window.h */
+bool ro_gui_window_check_menu(wimp_menu *menu)
{
- struct gui_window *g;
- for (g = window_list; g; g = g->next)
- gui_window_redraw_window(g);
+ return (ro_gui_browser_window_menu == menu) ? true : false;
}
-/**
- * Remove all pending update boxes for a window
- *
- * \param g gui_window
- */
-void ro_gui_window_remove_update_boxes(struct gui_window *g)
+/* exported interface documented in riscos/window.h */
+void ro_gui_window_redraw_all(void)
{
- struct update_box *cur;
-
- for (cur = pending_updates; cur != NULL; cur = cur->next) {
- if (cur->g == g)
- cur->g = NULL;
+ struct gui_window *g;
+ for (g = window_list; g; g = g->next) {
+ ro_gui_window_invalidate_area(g, NULL);
}
}
-/**
- * Redraw any pending update boxes.
- */
+/* exported interface documented in riscos/window.h */
void ro_gui_window_update_boxes(void)
{
osbool more;
@@ -4158,7 +4601,8 @@ void ro_gui_window_update_boxes(void)
error = xwimp_update_window(&update, &more);
if (error) {
- LOG("xwimp_update_window: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_update_window: 0x%x: %s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
continue;
}
@@ -4191,7 +4635,10 @@ void ro_gui_window_update_boxes(void)
* found. This appears to be a bug in RISC OS. */
if (error && !(use_buffer &&
error->errnum == error_WIMP_GET_RECT)) {
- LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO,
+ "xwimp_get_rectangle: 0x%x: %s",
+ error->errnum,
+ error->errmess);
ro_warn_user("WimpError", error->errmess);
ro_gui_current_redraw_gui = NULL;
continue;
@@ -4210,22 +4657,7 @@ void ro_gui_window_update_boxes(void)
}
-/**
- * callback from core to reformat a window.
- */
-static void riscos_window_reformat(struct gui_window *gw)
-{
- if (gw != NULL) {
- browser_window_reformat(gw->bw, false,
- gw->old_width / 2,
- gw->old_height / 2);
- }
-}
-
-/**
- * Destroy all browser windows.
- */
-
+/* exported interface documented in riscos/window.h */
void ro_gui_window_quit(void)
{
while (window_list) {
@@ -4237,13 +4669,10 @@ void ro_gui_window_quit(void)
}
-/**
- * Animate the "throbbers" of all browser windows.
- */
-
+/* exported interface documented in riscos/window.h */
void ro_gui_throb(void)
{
- struct gui_window *g;
+ struct gui_window *g;
for (g = window_list; g; g = g->next) {
if (!g->active)
@@ -4254,245 +4683,7 @@ void ro_gui_throb(void)
}
-/**
- * Update the toolbar buttons for a given browser window to reflect the
- * current state of its contents.
- *
- * Note that the parameters to this function are arranged so that it can be
- * supplied to the toolbar module as an button state update callback.
- *
- * \param *g The browser window to update.
- */
-
-void ro_gui_window_update_toolbar_buttons(struct gui_window *g)
-{
- struct browser_window *bw;
- struct toolbar *toolbar;
-
- if (g == NULL || g->toolbar == NULL)
- return;
-
- bw = g->bw;
- toolbar = g->toolbar;
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_RELOAD,
- !browser_window_reload_available(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_STOP,
- !browser_window_stop_available(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_BACK,
- !browser_window_back_available(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_FORWARD,
- !browser_window_forward_available(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_UP,
- !browser_window_up_available(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SEARCH,
- !browser_window_can_search(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SCALE,
- !browser_window_has_content(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_PRINT,
- !browser_window_has_content(bw));
-
- ro_toolbar_set_button_shaded_state(toolbar, TOOLBAR_BUTTON_SAVE_SOURCE,
- !browser_window_has_content(bw));
-
- ro_toolbar_update_urlsuggest(toolbar);
-}
-
-
-/**
- * Update a window to reflect a change in toolbar size: used as a callback by
- * the toolbar module when a toolbar height changes.
- *
- * \param *data void pointer the window's gui_window struct
- */
-
-void ro_gui_window_update_toolbar(void *data)
-{
- struct gui_window *g = (struct gui_window *) data;
-
- if (g != NULL)
- gui_window_update_extent(g);
-}
-
-
-/**
- * Save a new toolbar button configuration: used as a callback by the toolbar
- * module when a buttonbar edit has finished.
- *
- * \param *data void pointer to the window's gui_window struct
- * \param *config pointer to a malloc()'d button config string.
- */
-
-void ro_gui_window_save_toolbar_buttons(void *data, char *config)
-{
- nsoption_set_charp(toolbar_browser, config);
- ro_gui_save_options();
-}
-
-
-/**
- * Update a window and its toolbar to reflect a new theme: used as a callback
- * by the toolbar module when a theme change affects a toolbar.
- *
- * \param *data void pointer to the window's gui_window struct
- * \param ok true if the bar still exists; else false.
- */
-
-void ro_gui_window_update_theme(void *data, bool ok)
-{
- struct gui_window *g = (struct gui_window *) data;
-
- if (g != NULL && g->toolbar != NULL) {
- if (ok) {
- gui_window_update_extent(g);
- } else {
- g->toolbar = NULL;
- }
- }
-}
-
-
-/*
- * General Window Support
- */
-
-/**
- * Import text file into window
- *
- * \param g gui window containing textarea
- * \param filename pathname of file to be imported
- * \return true iff successful
- */
-
-bool ro_gui_window_import_text(struct gui_window *g, const char *filename)
-{
- fileswitch_object_type obj_type;
- os_error *error;
- char *buf, *utf8_buf, *sp;
- int size;
- nserror ret;
- const char *ep;
- char *p;
-
- error = xosfile_read_stamped(filename, &obj_type, NULL, NULL,
- &size, NULL, NULL);
- if (error) {
- LOG("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess);
- ro_warn_user("FileError", error->errmess);
- return true; /* was for us, but it didn't work! */
- }
-
- /* Allocate one byte more than needed to ensure that the buffer is
- * always terminated, regardless of file contents.
- */
-
- buf = calloc(size + 1, sizeof(char));
- if (!buf) {
- ro_warn_user("NoMemory", NULL);
- return true;
- }
-
- error = xosfile_load_stamped(filename, (byte*)buf,
- NULL, NULL, NULL, NULL, NULL);
-
- if (error) {
- LOG("xosfile_load_stamped: 0x%x:%s", error->errnum, error->errmess);
- ro_warn_user("LoadError", error->errmess);
- free(buf);
- return true;
- }
-
- ret = utf8_from_local_encoding(buf, size, &utf8_buf);
- if (ret != NSERROR_OK) {
- /* bad encoding shouldn't happen */
- assert(ret != NSERROR_BAD_ENCODING);
- LOG("utf8_from_local_encoding failed");
- free(buf);
- ro_warn_user("NoMemory", NULL);
- return true;
- }
- size = strlen(utf8_buf);
-
- ep = utf8_buf + size;
- p = utf8_buf;
-
- /* skip leading whitespace */
- while (isspace(*p)) p++;
-
- sp = p;
- while (*p && *p != '\r' && *p != '\n')
- p += utf8_next(p, ep - p, 0);
- *p = '\0';
-
- if (p > sp)
- ro_gui_window_launch_url(g, sp);
-
- free(buf);
- free(utf8_buf);
- return true;
-}
-
-
-/**
- * Clones a browser window's options.
- *
- * \param new_gui the new gui window
- * \param old_gui the gui window to clone from, or NULL for default
- */
-
-void ro_gui_window_clone_options(
- struct gui_window *new_gui,
- struct gui_window *old_gui)
-{
- assert(new_gui);
-
- /* Clone the basic options
- */
- if (!old_gui) {
- new_gui->option.buffer_animations = nsoption_bool(buffer_animations);
- new_gui->option.buffer_everything = nsoption_bool(buffer_everything);
- } else {
- new_gui->option = old_gui->option;
- }
-
- /* Set up the toolbar
- */
- if (new_gui->toolbar) {
- ro_toolbar_set_display_buttons(new_gui->toolbar,
- nsoption_bool(toolbar_show_buttons));
- ro_toolbar_set_display_url(new_gui->toolbar,
- nsoption_bool(toolbar_show_address));
- ro_toolbar_set_display_throbber(new_gui->toolbar,
- nsoption_bool(toolbar_show_throbber));
- if ((old_gui) && (old_gui->toolbar)) {
- ro_toolbar_set_display_buttons(new_gui->toolbar,
- ro_toolbar_get_display_buttons(
- old_gui->toolbar));
- ro_toolbar_set_display_url(new_gui->toolbar,
- ro_toolbar_get_display_url(
- old_gui->toolbar));
- ro_toolbar_set_display_throbber(new_gui->toolbar,
- ro_toolbar_get_display_throbber(
- old_gui->toolbar));
- ro_toolbar_process(new_gui->toolbar, -1, true);
- }
- }
-}
-
-
-/**
- * Makes a browser window's options the default.
- *
- * \param gui The riscos gui window to set default options in.
- */
-
+/* exported interface documented in riscos/window.h */
void ro_gui_window_default_options(struct gui_window *gui)
{
if (gui == NULL)
@@ -4520,179 +4711,20 @@ void ro_gui_window_default_options(struct gui_window *gui)
}
-/*
- * Custom Menu Support
- */
-
-/**
- * Prepare or reprepare a form select menu, setting up the menu handle
- * globals in the process.
- *
- * \param g The RISC OS gui window the menu is in.
- * \param control The form control needing a menu.
- * \return true if the menu is OK to be opened; else false.
- */
-
-bool ro_gui_window_prepare_form_select_menu(struct gui_window *g,
- struct form_control *control)
-{
- unsigned int item, entries;
- char *text_convert, *temp;
- struct form_option *option;
- bool reopen = true;
- nserror err;
-
- assert(control);
-
- /* enumerate the entries */
- entries = 0;
- option = form_select_get_option(control, entries);
- while (option != NULL) {
- entries++;
- option = form_select_get_option(control, entries);
- }
-
- if (entries == 0) {
- /* no menu to display */
- ro_gui_menu_destroy();
- return false;
- }
-
- /* free riscos menu if there already is one */
- if ((gui_form_select_menu) && (control != gui_form_select_control)) {
- for (item = 0; ; item++) {
- free(gui_form_select_menu->entries[item].data.
- indirected_text.text);
- if (gui_form_select_menu->entries[item].menu_flags &
- wimp_MENU_LAST)
- break;
- }
- free(gui_form_select_menu->title_data.indirected_text.text);
- free(gui_form_select_menu);
- gui_form_select_menu = 0;
- }
-
- /* allocate new riscos menu */
- if (!gui_form_select_menu) {
- reopen = false;
- gui_form_select_menu = malloc(wimp_SIZEOF_MENU(entries));
- if (!gui_form_select_menu) {
- ro_warn_user("NoMemory", 0);
- ro_gui_menu_destroy();
- return false;
- }
- err = utf8_to_local_encoding(messages_get("SelectMenu"), 0,
- &text_convert);
- if (err != NSERROR_OK) {
- /* badenc should never happen */
- assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_local_encoding failed");
- ro_warn_user("NoMemory", 0);
- ro_gui_menu_destroy();
- return false;
- }
- gui_form_select_menu->title_data.indirected_text.text =
- text_convert;
- ro_gui_menu_init_structure(gui_form_select_menu, entries);
- }
-
- /* initialise menu entries from form control */
- for (item = 0; item < entries; item++) {
- option = form_select_get_option(control, item);
- gui_form_select_menu->entries[item].menu_flags = 0;
- if (option->selected)
- gui_form_select_menu->entries[item].menu_flags =
- wimp_MENU_TICKED;
- if (!reopen) {
-
- /* convert spaces to hard spaces to stop things
- * like 'Go Home' being treated as if 'Home' is a
- * keyboard shortcut and right aligned in the menu.
- */
-
- temp = cnv_space2nbsp(option->text);
- if (!temp) {
- LOG("cnv_space2nbsp failed");
- ro_warn_user("NoMemory", 0);
- ro_gui_menu_destroy();
- return false;
- }
-
- err = utf8_to_local_encoding(temp,
- 0, &text_convert);
- if (err != NSERROR_OK) {
- /* A bad encoding should never happen,
- * so assert this */
- assert(err != NSERROR_BAD_ENCODING);
- LOG("utf8_to_enc failed");
- ro_warn_user("NoMemory", 0);
- ro_gui_menu_destroy();
- return false;
- }
-
- free(temp);
-
- gui_form_select_menu->entries[item].data.indirected_text.text =
- text_convert;
- gui_form_select_menu->entries[item].data.indirected_text.size =
- strlen(gui_form_select_menu->entries[item].
- data.indirected_text.text) + 1;
- }
- }
-
- gui_form_select_menu->entries[0].menu_flags |=
- wimp_MENU_TITLE_INDIRECTED;
- gui_form_select_menu->entries[item - 1].menu_flags |= wimp_MENU_LAST;
-
- return true;
-}
-
-/**
- * Process selections from a form select menu, passing them back to the core.
- *
- * \param *g The browser window affected by the menu.
- * \param *selection The menu selection.
- */
-
-void ro_gui_window_process_form_select_menu(struct gui_window *g,
- wimp_selection *selection)
-{
- assert(g != NULL);
-
- if (selection->items[0] >= 0)
- form_select_process_selection(gui_form_select_control,
- selection->items[0]);
-}
-
-
-/*
- * Window and Toolbar Lookup
- */
-
-/**
- * Convert a RISC OS window handle to a gui_window.
- *
- * \param window RISC OS window handle.
- * \return A pointer to a riscos gui window if found or NULL.
- */
-
+/* exported interface documented in riscos/window.h */
struct gui_window *ro_gui_window_lookup(wimp_w window)
{
struct gui_window *g;
- for (g = window_list; g; g = g->next)
- if (g->window == window)
+ for (g = window_list; g; g = g->next) {
+ if (g->window == window) {
return g;
+ }
+ }
return NULL;
}
-/**
- * Convert a toolbar RISC OS window handle to a gui_window.
- *
- * \param window RISC OS window handle of a toolbar
- * \return pointer to a structure if found, NULL otherwise
- */
-
+/* exported interface documented in riscos/window.h */
struct gui_window *ro_gui_toolbar_lookup(wimp_w window)
{
struct gui_window *g = NULL;
@@ -4710,22 +4742,9 @@ struct gui_window *ro_gui_toolbar_lookup(wimp_w window)
}
-/*
- * Core to RISC OS Conversions
- */
-
-/**
- * Convert x,y screen co-ordinates into window co-ordinates.
- *
- * \param g gui window
- * \param x x ordinate
- * \param y y ordinate
- * \param pos receives position in window co-ordinatates
- * \return true iff conversion successful
- */
-
-bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y,
- os_coord *pos)
+/* exported interface documented in riscos/window.h */
+bool
+ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, os_coord *pos)
{
wimp_window_state state;
os_error *error;
@@ -4735,7 +4754,8 @@ bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y,
state.w = g->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -4745,18 +4765,11 @@ bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y,
}
-/**
- * Convert x,y window co-ordinates into screen co-ordinates.
- *
- * \param g gui window
- * \param x x ordinate
- * \param y y ordinate
- * \param pos receives position in screen co-ordinatates
- * \return true iff conversion successful
- */
-
-bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y,
- os_coord *pos)
+/* exported interface documented in riscos/window.h */
+bool ro_gui_window_to_screen_pos(struct gui_window *g,
+ int x,
+ int y,
+ os_coord *pos)
{
wimp_window_state state;
os_error *error;
@@ -4766,7 +4779,8 @@ bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y,
state.w = g->window;
error = xwimp_get_window_state(&state);
if (error) {
- LOG("xwimp_get_window_state: 0x%x:%s", error->errnum, error->errmess);
+ NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x:%s",
+ error->errnum, error->errmess);
ro_warn_user("WimpError", error->errmess);
return false;
}
@@ -4776,24 +4790,9 @@ bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y,
}
-/*
- * Miscellaneous Functions
- *
- * \TODO -- These items might well belong elsewhere.
- */
-
-/**
- * Returns the state of the mouse buttons and modifiers keys for a
- * mouse action, suitable for passing to the OS-independent
- * browser window/ treeview/ etc code.
- *
- * \param buttons Wimp button state.
- * \param type Wimp work-area/icon type for decoding.
- * \return NetSurf core button state.
- */
-
-browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
- wimp_icon_flags type)
+/* exported interface documented in riscos/window.h */
+enum browser_mouse_state
+ro_gui_mouse_click_state(wimp_mouse_state buttons, wimp_icon_flags type)
{
browser_mouse_state state = 0; /* Blank state with nothing set */
static struct {
@@ -4908,18 +4907,9 @@ browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons,
}
-/**
- * Returns the state of the mouse buttons and modifiers keys whilst
- * dragging, for passing to the OS-independent browser window/ treeview/
- * etc code
- *
- * \param buttons Wimp button state.
- * \param type Wimp work-area/icon type for decoding.
- * \return NetSurf core button state.
- */
-
-browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
- wimp_icon_flags type)
+/* exported interface documented in riscos/window.h */
+browser_mouse_state
+ro_gui_mouse_drag_state(wimp_mouse_state buttons, wimp_icon_flags type)
{
browser_mouse_state state = 0; /* Blank state with nothing set */
@@ -4947,10 +4937,7 @@ browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons,
}
-/**
- * Returns true iff one or more Shift keys is held down
- */
-
+/* exported interface documented in riscos/window.h */
bool ro_gui_shift_pressed(void)
{
int shift = 0;
@@ -4959,10 +4946,7 @@ bool ro_gui_shift_pressed(void)
}
-/**
- * Returns true iff one or more Ctrl keys is held down
- */
-
+/* exported interface documented in riscos/window.h */
bool ro_gui_ctrl_pressed(void)
{
int ctrl = 0;
@@ -4971,10 +4955,7 @@ bool ro_gui_ctrl_pressed(void)
}
-/**
- * Returns true iff one or more Alt keys is held down
- */
-
+/* exported interface documented in riscos/window.h */
bool ro_gui_alt_pressed(void)
{
int alt = 0;
@@ -4982,39 +4963,47 @@ bool ro_gui_alt_pressed(void)
return (alt == 0xff);
}
-static struct gui_window_table window_table = {
- .create = gui_window_create,
- .destroy = gui_window_destroy,
- .redraw = gui_window_redraw_window,
- .update = gui_window_update_box,
- .get_scroll = gui_window_get_scroll,
- .set_scroll = gui_window_set_scroll,
- .get_dimensions = gui_window_get_dimensions,
- .update_extent = gui_window_update_extent,
- .reformat = riscos_window_reformat,
- .set_title = gui_window_set_title,
- .set_url = ro_gui_window_set_url,
- .set_icon = gui_window_set_icon,
- .set_status = riscos_window_set_status,
- .set_pointer = gui_window_set_pointer,
- .place_caret = gui_window_place_caret,
- .remove_caret = gui_window_remove_caret,
- .save_link = gui_window_save_link,
- .drag_start = gui_window_drag_start,
- .scroll_visible = gui_window_scroll_visible,
- .scroll_start = gui_window_scroll_start,
- .new_content = gui_window_new_content,
- .start_throbber = gui_window_start_throbber,
- .stop_throbber = gui_window_stop_throbber,
- .create_form_select_menu = gui_window_create_form_select_menu,
+/* exported interface documented in riscos/window.h */
+void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
+{
+ static gui_pointer_shape curr_pointer = GUI_POINTER_DEFAULT;
+ struct ro_gui_pointer_entry *entry;
+ os_error *error;
- /* from save */
- .drag_save_object = gui_drag_save_object,
- .drag_save_selection =gui_drag_save_selection,
+ if (shape == curr_pointer)
+ return;
- /* from textselection */
- .start_selection = gui_start_selection,
-};
+ assert(shape < sizeof ro_gui_pointer_table /
+ sizeof ro_gui_pointer_table[0]);
-struct gui_window_table *riscos_window_table = &window_table;
+ entry = &ro_gui_pointer_table[shape];
+
+ if (entry->wimp_area) {
+ /* pointer in the Wimp's sprite area */
+ error = xwimpspriteop_set_pointer_shape(entry->sprite_name,
+ 1, entry->xactive, entry->yactive, 0, 0);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xwimpspriteop_set_pointer_shape: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ } else {
+ /* pointer in our own sprite area */
+ error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA,
+ gui_sprites,
+ (osspriteop_id) entry->sprite_name,
+ 1, entry->xactive, entry->yactive, 0, 0);
+ if (error) {
+ NSLOG(netsurf, INFO,
+ "xosspriteop_set_pointer_shape: 0x%x: %s",
+ error->errnum,
+ error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ }
+ }
+
+ curr_pointer = shape;
+}
diff --git a/frontends/riscos/window.h b/frontends/riscos/window.h
index 2e6f6e9aa..0a5bd43c2 100644
--- a/frontends/riscos/window.h
+++ b/frontends/riscos/window.h
@@ -30,10 +30,21 @@ struct nsurl;
extern struct gui_window_table *riscos_window_table;
+/**
+ * Initialise the browser window module and its menus.
+ */
void ro_gui_window_initialise(void);
+
+/**
+ * Check if a particular menu handle is a browser window menu
+ *
+ * \param menu The menu in question.
+ * \return true if this menu is a browser window menu
+ */
bool ro_gui_window_check_menu(wimp_menu *menu);
+
/**
* Set the contents of a window's address bar.
*
@@ -42,5 +53,201 @@ bool ro_gui_window_check_menu(wimp_menu *menu);
*/
nserror ro_gui_window_set_url(struct gui_window *g, struct nsurl *url);
+
+/**
+ * Cause an area of a window to be invalidated
+ *
+ * The specified area of the window should now be considered out of
+ * date. If the entire window is invalidated this simply calls
+ * wimp_force_redraw() otherwise the area is added to a queue of
+ * pending updates which will be processed from a wimp poll allowing
+ * multiple invalidation requests to be agregated.
+ *
+ * \param g The window to update
+ * \param rect The area of the window to update or NULL to redraw entire contents.
+ */
+nserror ro_gui_window_invalidate_area(struct gui_window *g, const struct rect *rect);
+
+
+/**
+ * Set a gui_window's scale
+ */
+void ro_gui_window_set_scale(struct gui_window *g, float scale);
+
+
+/**
+ * Handle Message_DataLoad (file dragged in) for a window.
+ *
+ * If the file was dragged into a form file input, it is used as the value.
+ *
+ * \param g window
+ * \param message Message_DataLoad block
+ * \return true if the load was processed
+ */
+bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message);
+
+
+/**
+ * Handle pointer movements in a browser window.
+ *
+ * \param pointer new mouse position
+ * \param data browser window that the pointer is in
+ */
+void ro_gui_window_mouse_at(wimp_pointer *pointer, void *data);
+
+
+/**
+ * Window is being iconised.
+ *
+ * Create a suitable thumbnail sprite (which, sadly, must be in the
+ * Wimp sprite pool), and return the sprite name and truncated title
+ * to the iconiser
+ *
+ * \param g the gui window being iconised
+ * \param wi the WindowInfo message from the iconiser
+ */
+void ro_gui_window_iconise(struct gui_window *g, wimp_full_message_window_info *wi);
+
+
+/**
+ * Handle Message_DataLoad (file dragged in) for a toolbar
+ *
+ * @todo This belongs in the toolbar module, and should be moved there
+ * once the module is able to usefully handle its own events.
+ *
+ * \param g window
+ * \param message Message_DataLoad block
+ * \return true if the load was processed
+ */
+bool ro_gui_toolbar_dataload(struct gui_window *g, wimp_message *message);
+
+
+/**
+ * Redraws the content for all windows.
+ */
+void ro_gui_window_redraw_all(void);
+
+
+/**
+ * Redraw any pending update boxes.
+ */
+void ro_gui_window_update_boxes(void);
+
+
+/**
+ * Destroy all browser windows.
+ */
+void ro_gui_window_quit(void);
+
+
+/**
+ * Close all browser windows
+ *
+ * no need for a separate fn same operation as quit
+*/
+#define ro_gui_window_close_all ro_gui_window_quit
+
+
+/**
+ * Animate the "throbbers" of all browser windows.
+ */
+void ro_gui_throb(void);
+
+/**
+ * Makes a browser window's options the default.
+ *
+ * \param gui The riscos gui window to set default options in.
+ */
+void ro_gui_window_default_options(struct gui_window *gui);
+
+
+/**
+ * Convert a RISC OS window handle to a gui_window.
+ *
+ * \param window RISC OS window handle.
+ * \return A pointer to a riscos gui window if found or NULL.
+ */
+struct gui_window *ro_gui_window_lookup(wimp_w window);
+
+
+/**
+ * Convert a toolbar RISC OS window handle to a gui_window.
+ *
+ * \param window RISC OS window handle of a toolbar
+ * \return pointer to a structure if found, NULL otherwise
+ */
+struct gui_window *ro_gui_toolbar_lookup(wimp_w window);
+
+
+/**
+ * Convert x,y screen co-ordinates into window co-ordinates.
+ *
+ * \param g gui window
+ * \param x x ordinate
+ * \param y y ordinate
+ * \param pos receives position in window co-ordinatates
+ * \return true iff conversion successful
+ */
+bool ro_gui_window_to_window_pos(struct gui_window *g, int x, int y, os_coord *pos);
+
+
+/**
+ * Convert x,y window co-ordinates into screen co-ordinates.
+ *
+ * \param g gui window
+ * \param x x ordinate
+ * \param y y ordinate
+ * \param pos receives position in screen co-ordinatates
+ * \return true iff conversion successful
+ */
+bool ro_gui_window_to_screen_pos(struct gui_window *g, int x, int y, os_coord *pos);
+
+/**
+ * Returns the state of the mouse buttons and modifiers keys for a
+ * mouse action, suitable for passing to the OS-independent
+ * browser window/ treeview/ etc code.
+ *
+ * \param buttons Wimp button state.
+ * \param type Wimp work-area/icon type for decoding.
+ * \return NetSurf core button state.
+ */
+enum browser_mouse_state ro_gui_mouse_click_state(wimp_mouse_state buttons, wimp_icon_flags type);
+
+
+/**
+ * Returns the state of the mouse buttons and modifiers keys whilst
+ * dragging, for passing to the OS-independent browser window/ treeview/
+ * etc code
+ *
+ * \param buttons Wimp button state.
+ * \param type Wimp work-area/icon type for decoding.
+ * \return NetSurf core button state.
+ */
+enum browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons, wimp_icon_flags type);
+
+
+/**
+ * Returns true iff one or more Shift keys is held down
+ */
+bool ro_gui_shift_pressed(void);
+
+
+/**
+ * Returns true iff one or more Ctrl keys is held down
+ */
+bool ro_gui_ctrl_pressed(void);
+
+
+/**
+ * Returns true iff one or more Alt keys is held down
+ */
+bool ro_gui_alt_pressed(void);
+
+
+/**
+ * Change mouse pointer shape
+ */
+void gui_window_set_pointer(struct gui_window *g, enum gui_pointer_shape shape);
+
#endif
diff --git a/frontends/windows/Makefile b/frontends/windows/Makefile
index 1b93e4cc7..de01ce33a 100644
--- a/frontends/windows/Makefile
+++ b/frontends/windows/Makefile
@@ -15,7 +15,7 @@ $(eval $(call pkg_config_find_and_add,libcares,Cares))
$(eval $(call pkg_config_find_and_add,zlib,ZLib))
# libraries for windows API
-LDFLAGS += -lgnurx -lgdi32 -lcomctl32 -lws2_32 -lmsimg32 -lshlwapi -mwindows
+LDFLAGS += -lgnurx -lgdi32 -lcomctl32 -lws2_32 -lmsimg32 -lshlwapi -lcrypt32 -mwindows
CFLAGS += -U__STRICT_ANSI__ -mwin32
# only windows versions after XP are supported
@@ -50,7 +50,7 @@ S_RESOURCES := windows_resource.o
# sources purely for the windows build
S_FRONTEND := main.c window.c gui.c drawable.c plot.c findfile.c \
font.c bitmap.c about.c prefs.c download.c filetype.c file.c \
- localhistory.c schedule.c windbg.c pointers.c \
+ local_history.c schedule.c windbg.c pointers.c \
corewindow.c hotlist.c cookies.c global_history.c ssl_cert.c
# This is the final source build list
@@ -84,6 +84,7 @@ endif
# installer messages generation
$(OBJROOT)/messages-en: resources/FatMessages
$(VQ)echo "MSGSPLIT: Language: en Filter: win"
+ $(Q)$(RM) $@
$(Q)$(SPLIT_MESSAGES) -l en -p win -f messages -o $@ $<
netsurf-installer.exe: $(EXETARGET) $(WIN_RES_INS_OBJ)
diff --git a/frontends/windows/about.c b/frontends/windows/about.c
index 65c81cd7d..2cd855b55 100644
--- a/frontends/windows/about.c
+++ b/frontends/windows/about.c
@@ -52,7 +52,7 @@ static BOOL init_about_dialog(HWND hwnd)
hFont=CreateFont (26, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
if (hFont != NULL) {
- LOG("Setting font object");
+ NSLOG(netsurf, INFO, "Setting font object");
SendMessage(dlg_itm, WM_SETFONT, (WPARAM)hFont, 0);
}
@@ -85,7 +85,7 @@ static BOOL destroy_about_dialog(HWND hwnd)
if (dlg_itm != NULL) {
hFont = (HFONT)SendMessage(dlg_itm, WM_GETFONT, 0, 0);
if (hFont != NULL) {
- LOG("Destroyed font object");
+ NSLOG(netsurf, INFO, "Destroyed font object");
DeleteObject(hFont);
}
}
@@ -107,12 +107,12 @@ nsws_about_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
case WM_COMMAND:
switch(LOWORD(wparam)) {
case IDOK:
- LOG("OK clicked");
+ NSLOG(netsurf, INFO, "OK clicked");
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
- LOG("Cancel clicked");
+ NSLOG(netsurf, INFO, "Cancel clicked");
EndDialog(hwnd, IDOK);
break;
diff --git a/frontends/windows/bitmap.c b/frontends/windows/bitmap.c
index f60dab613..eed3d3a15 100644
--- a/frontends/windows/bitmap.c
+++ b/frontends/windows/bitmap.c
@@ -52,7 +52,8 @@ void *win32_bitmap_create(int width, int height, unsigned int state)
HBITMAP windib;
uint8_t *pixdata;
- LOG("width %d, height %d, state %u", width, height, state);
+ NSLOG(netsurf, INFO, "width %d, height %d, state %u", width, height,
+ state);
pbmi = calloc(1, sizeof(BITMAPV5HEADER));
if (pbmi == NULL) {
@@ -96,7 +97,7 @@ void *win32_bitmap_create(int width, int height, unsigned int state)
bitmap->opaque = false;
}
- LOG("bitmap %p", bitmap);
+ NSLOG(netsurf, INFO, "bitmap %p", bitmap);
return bitmap;
}
@@ -115,7 +116,7 @@ static unsigned char *bitmap_get_buffer(void *bitmap)
{
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return NULL;
}
@@ -134,7 +135,7 @@ static size_t bitmap_get_rowstride(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
@@ -152,7 +153,7 @@ void win32_bitmap_destroy(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return;
}
@@ -195,11 +196,12 @@ static void bitmap_set_opaque(void *bitmap, bool opaque)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return;
}
- LOG("setting bitmap %p to %s", bm, opaque ? "opaque" : "transparent");
+ NSLOG(netsurf, INFO, "setting bitmap %p to %s", bm,
+ opaque ? "opaque" : "transparent");
bm->opaque = opaque;
}
@@ -216,7 +218,7 @@ static bool bitmap_test_opaque(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return false;
}
@@ -224,11 +226,11 @@ static bool bitmap_test_opaque(void *bitmap)
while (tst-- > 0) {
if (bm->pixdata[(tst << 2) + 3] != 0xff) {
- LOG("bitmap %p has transparency", bm);
+ NSLOG(netsurf, INFO, "bitmap %p has transparency", bm);
return false;
}
}
- LOG("bitmap %p is opaque", bm);
+ NSLOG(netsurf, INFO, "bitmap %p is opaque", bm);
return true;
}
@@ -243,7 +245,7 @@ static bool bitmap_get_opaque(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return false;
}
@@ -255,7 +257,7 @@ static int bitmap_get_width(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
@@ -267,7 +269,7 @@ static int bitmap_get_height(void *bitmap)
struct bitmap *bm = bitmap;
if (bitmap == NULL) {
- LOG("NULL bitmap!");
+ NSLOG(netsurf, INFO, "NULL bitmap!");
return 0;
}
@@ -324,12 +326,12 @@ bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
.plot = &win_plotters
};
- width = min(content_get_width(content), 1024);
+ width = min(max(content_get_width(content), bitmap->width), 1024);
height = ((width * bitmap->height) + (bitmap->width / 2)) /
bitmap->width;
- LOG("bitmap %p for content %p width %d, height %d",
- bitmap, content, width, height);
+ NSLOG(netsurf, INFO, "bitmap %p for content %p width %d, height %d",
+ bitmap, content, width, height);
/* create two memory device contexts to put the bitmaps in */
bufferdc = CreateCompatibleDC(NULL);
diff --git a/frontends/windows/cookies.c b/frontends/windows/cookies.c
index 27949fac1..b3c56da8c 100644
--- a/frontends/windows/cookies.c
+++ b/frontends/windows/cookies.c
@@ -58,6 +58,7 @@ nsw32_cookie_key(struct nsw32_corewindow *nsw32_cw, uint32_t nskey)
return NSERROR_NOT_IMPLEMENTED;
}
+
/**
* callback for mouse action on cookie window
*
@@ -69,18 +70,21 @@ nsw32_cookie_key(struct nsw32_corewindow *nsw32_cw, uint32_t nskey)
*/
static nserror
nsw32_cookie_mouse(struct nsw32_corewindow *nsw32_cw,
- browser_mouse_state mouse_state,
- int x, int y)
+ browser_mouse_state mouse_state,
+ int x, int y)
{
cookie_manager_mouse_action(mouse_state, x, y);
return NSERROR_OK;
}
+
/**
* callback on draw event for cookie window
*
* \param nsw32_cw The nsw32 core window structure.
+ * \param scrollx The horizontal scroll offset.
+ * \param scrolly The vertical scroll offset.
* \param r The rectangle of the window that needs updating.
* \return NSERROR_OK on success otherwise apropriate error code
*/
@@ -102,6 +106,12 @@ nsw32_cookie_draw(struct nsw32_corewindow *nsw32_cw,
}
+/**
+ * callback on close event for cookie window
+ *
+ * \param nsw32_cw The nsw32 core window structure.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
static nserror
nsw32_cookie_close(struct nsw32_corewindow *nsw32_cw)
{
@@ -110,9 +120,11 @@ nsw32_cookie_close(struct nsw32_corewindow *nsw32_cw)
return NSERROR_OK;
}
+
/**
* Creates the window for the cookie tree.
*
+ * \param hInstance The application instance
* \return NSERROR_OK on success else appropriate error code on faliure.
*/
static nserror nsw32_cookie_init(HINSTANCE hInstance)
@@ -124,7 +136,7 @@ static nserror nsw32_cookie_init(HINSTANCE hInstance)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsw32_cookie_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
@@ -169,6 +181,7 @@ nserror nsw32_cookies_present(HINSTANCE hInstance)
return res;
}
+
/* exported interface documented in windows/cookie.h */
nserror nsw32_cookies_finalise(void)
{
diff --git a/frontends/windows/corewindow.c b/frontends/windows/corewindow.c
index 754e0e561..7d88ce7c4 100644
--- a/frontends/windows/corewindow.c
+++ b/frontends/windows/corewindow.c
@@ -155,7 +155,7 @@ nsw32_corewindow_vscroll(struct nsw32_corewindow *nsw32_cw,
SCROLLINFO si; /* current scroll information */
SCROLLINFO usi; /* updated scroll infomation for scrollwindowex */
- LOG("VSCROLL");
+ NSLOG(netsurf, INFO, "VSCROLL");
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
@@ -221,20 +221,105 @@ nsw32_corewindow_vscroll(struct nsw32_corewindow *nsw32_cw,
return 0;
}
+
+static LRESULT
+nsw32_corewindow_hscroll(struct nsw32_corewindow *nsw32_cw,
+ HWND hwnd,
+ WPARAM wparam)
+{
+ SCROLLINFO si; /* current scroll information */
+ SCROLLINFO usi; /* updated scroll infomation for scrollwindowex */
+
+ NSLOG(netsurf, INFO, "VSCROLL");
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ usi = si;
+
+ switch (LOWORD(wparam)) {
+ case SB_LINELEFT:
+ usi.nPos -= 30;
+ break;
+
+ case SB_LINERIGHT:
+ usi.nPos += 30;
+ break;
+
+ case SB_PAGELEFT:
+ usi.nPos -= si.nPage;
+ break;
+
+ case SB_PAGERIGHT:
+ usi.nPos += si.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ usi.nPos = si.nTrackPos;
+ break;
+
+ default:
+ break;
+ }
+
+ if (usi.nPos < si.nMin) {
+ usi.nPos = si.nMin;
+ }
+ if (usi.nPos > si.nMax) {
+ usi.nPos = si.nMax;
+ }
+
+ SetScrollInfo(hwnd, SB_HORZ, &usi, TRUE);
+
+ ScrollWindowEx(hwnd,
+ si.nPos - usi.nPos,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+
+ return 0;
+}
+
+
static LRESULT
nsw32_corewindow_mousedown(struct nsw32_corewindow *nsw32_cw,
+ HWND hwnd,
int x, int y,
browser_mouse_state button)
{
+ SCROLLINFO si; /* scroll information */
+
+ /* get scroll positions */
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ x += si.nPos;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ y += si.nPos;
+
nsw32_cw->mouse(nsw32_cw, button, x, y);
return 0;
}
static LRESULT
nsw32_corewindow_mouseup(struct nsw32_corewindow *nsw32_cw,
+ HWND hwnd,
int x, int y,
browser_mouse_state button)
{
+ SCROLLINFO si; /* scroll information */
+
+ /* get scroll positions */
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ GetScrollInfo(hwnd, SB_HORZ, &si);
+ x += si.nPos;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+ y += si.nPos;
+
nsw32_cw->mouse(nsw32_cw, button, x, y);
return 0;
}
@@ -275,26 +360,29 @@ nsw32_window_corewindow_event_callback(HWND hwnd,
case WM_VSCROLL:
return nsw32_corewindow_vscroll(nsw32_cw, hwnd, wparam);
+ case WM_HSCROLL:
+ return nsw32_corewindow_hscroll(nsw32_cw, hwnd, wparam);
+
case WM_LBUTTONDOWN:
- return nsw32_corewindow_mousedown(nsw32_cw,
+ return nsw32_corewindow_mousedown(nsw32_cw, hwnd,
GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam),
BROWSER_MOUSE_PRESS_1);
case WM_RBUTTONDOWN:
- return nsw32_corewindow_mousedown(nsw32_cw,
+ return nsw32_corewindow_mousedown(nsw32_cw, hwnd,
GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam),
BROWSER_MOUSE_PRESS_2);
case WM_LBUTTONUP:
- return nsw32_corewindow_mouseup(nsw32_cw,
+ return nsw32_corewindow_mouseup(nsw32_cw, hwnd,
GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam),
BROWSER_MOUSE_CLICK_1);
case WM_RBUTTONUP:
- return nsw32_corewindow_mouseup(nsw32_cw,
+ return nsw32_corewindow_mouseup(nsw32_cw, hwnd,
GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam),
BROWSER_MOUSE_CLICK_2);
@@ -307,21 +395,48 @@ nsw32_window_corewindow_event_callback(HWND hwnd,
return DefWindowProc(hwnd, msg, wparam, lparam);
}
+
/**
- * callback from core to request a redraw
+ * callback from core to request an invalidation of a window area.
+ *
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] rect area to redraw or NULL for the entire window area.
+ * \return NSERROR_OK on success or appropriate error code.
*/
-static void
-nsw32_cw_redraw_request(struct core_window *cw, const struct rect *r)
+static nserror
+nsw32_cw_invalidate_area(struct core_window *cw, const struct rect *rect)
{
struct nsw32_corewindow *nsw32_cw = (struct nsw32_corewindow *)cw;
- RECT wr;
+ RECT *redrawrectp = NULL;
+ RECT redrawrect;
+
+ if (rect != NULL) {
+ SCROLLINFO si; /* scroll information */
- wr.left = r->x0;
- wr.top = r->y0;
- wr.right = r->x1;
- wr.bottom = r->y1;
+ /* get scroll positions */
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ GetScrollInfo(nsw32_cw->hWnd, SB_HORZ, &si);
+ redrawrect.left = (long)rect->x0 - si.nPos;
+ redrawrect.right = (long)rect->x1 - si.nPos;
- RedrawWindow(nsw32_cw->hWnd, &wr, NULL, RDW_INVALIDATE | RDW_NOERASE);
+ GetScrollInfo(nsw32_cw->hWnd, SB_VERT, &si);
+ redrawrect.top = (long)rect->y0 - si.nPos;
+ redrawrect.bottom = (long)rect->y1 - si.nPos;
+
+ redrawrectp = &redrawrect;
+ }
+
+ RedrawWindow(nsw32_cw->hWnd,
+ redrawrectp,
+ NULL,
+ RDW_INVALIDATE | RDW_NOERASE);
+
+ return NSERROR_OK;
}
@@ -335,7 +450,7 @@ nsw32_cw_update_size(struct core_window *cw, int width, int height)
nsw32_cw->content_width = width;
nsw32_cw->content_height = height;
- LOG("new content size w:%d h:%d", width, height);
+ NSLOG(netsurf, INFO, "new content size w:%d h:%d", width, height);
update_scrollbars(nsw32_cw);
}
@@ -371,12 +486,12 @@ static void
nsw32_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
{
struct nsw32_corewindow *nsw32_cw = (struct nsw32_corewindow *)cw;
- nsw32_cw->drag_staus = ds;
+ nsw32_cw->drag_status = ds;
}
struct core_window_callback_table nsw32_cw_cb_table = {
- .redraw_request = nsw32_cw_redraw_request,
+ .invalidate = nsw32_cw_invalidate_area,
.update_size = nsw32_cw_update_size,
.scroll_visible = nsw32_cw_scroll_visible,
.get_window_dimensions = nsw32_cw_get_window_dimensions,
@@ -393,6 +508,7 @@ nsw32_corewindow_init(HINSTANCE hInstance,
/* setup the core window callback table */
nsw32_cw->cb_table = &nsw32_cw_cb_table;
+ nsw32_cw->drag_status = CORE_WINDOW_DRAG_NONE;
/* start with the content area being as small as possible */
nsw32_cw->content_width = -1;
@@ -411,7 +527,7 @@ nsw32_corewindow_init(HINSTANCE hInstance,
CS_DBLCLKS;
}
- LOG("creating hInstance %p core window", hInstance);
+ NSLOG(netsurf, INFO, "creating hInstance %p core window", hInstance);
nsw32_cw->hWnd = CreateWindowEx(0,
windowclassname_corewindow,
nsw32_cw->title,
@@ -425,7 +541,7 @@ nsw32_corewindow_init(HINSTANCE hInstance,
hInstance,
NULL);
if (nsw32_cw->hWnd == NULL) {
- LOG("Window create failed");
+ NSLOG(netsurf, INFO, "Window create failed");
return NSERROR_NOMEM;
}
diff --git a/frontends/windows/corewindow.h b/frontends/windows/corewindow.h
index b78c72e8c..cffae3cbd 100644
--- a/frontends/windows/corewindow.h
+++ b/frontends/windows/corewindow.h
@@ -38,7 +38,7 @@ struct nsw32_corewindow {
const char *title;
/** drag status set by core */
- core_window_drag_status drag_staus;
+ core_window_drag_status drag_status;
/** table of callbacks for core window operations */
struct core_window_callback_table *cb_table;
diff --git a/frontends/windows/download.c b/frontends/windows/download.c
index 3a969834e..dfcd2b5a4 100644
--- a/frontends/windows/download.c
+++ b/frontends/windows/download.c
@@ -253,7 +253,8 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui)
strcat(destination, "/");
if (strlen(destination) + strlen(filename) < PATH_MAX - 1)
strcat(destination, filename);
- LOG("download %s [%s] from %s to %s", filename, size, domain, destination);
+ NSLOG(netsurf, INFO, "download %s [%s] from %s to %s", filename,
+ size, domain, destination);
w->title = filename;
w->domain = domain;
w->size = total_size;
@@ -313,7 +314,8 @@ gui_download_window_data(struct gui_download_window *w, const char *data,
struct timeval val;
res = fwrite((void *)data, 1, size, w->file);
if (res != size)
- LOG("file write error %d of %d", size - res, size);
+ NSLOG(netsurf, INFO, "file write error %d of %d", size - res,
+ size);
w->downloaded += res;
w->progress = (unsigned int)(((long long)(w->downloaded) * 10000)
/ w->size);
@@ -327,7 +329,7 @@ gui_download_window_data(struct gui_download_window *w, const char *data,
static void gui_download_window_error(struct gui_download_window *w,
const char *error_msg)
{
- LOG("error %s", error_msg);
+ NSLOG(netsurf, INFO, "error %s", error_msg);
}
static void gui_download_window_done(struct gui_download_window *w)
diff --git a/frontends/windows/drawable.c b/frontends/windows/drawable.c
index cb9429139..f491e0a2a 100644
--- a/frontends/windows/drawable.c
+++ b/frontends/windows/drawable.c
@@ -16,6 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * win32 implementation of drawable window showing browser context
+ */
+
#include <stdbool.h>
#include <stdint.h>
@@ -33,11 +38,12 @@
#include "windows/windbg.h"
#include "windows/plot.h"
#include "windows/window.h"
-#include "windows/localhistory.h"
+#include "windows/local_history.h"
#include "windows/drawable.h"
static const char windowclassname_drawable[] = "nswsdrawablewindow";
+
/**
* Handle wheel scroll messages.
*/
@@ -66,6 +72,7 @@ nsws_drawable_wheel(struct gui_window *gw, HWND hwnd, WPARAM wparam)
return 0;
}
+
/**
* Handle vertical scroll messages.
*/
@@ -76,7 +83,7 @@ nsws_drawable_vscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
SCROLLINFO si;
int mem;
- LOG("VSCROLL %d", gw->requestscrolly);
+ NSLOG(netsurf, INFO, "VSCROLL %d", gw->requestscrolly);
if (gw->requestscrolly != 0)
return 0;
@@ -121,8 +128,8 @@ nsws_drawable_vscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
si.fMask = SIF_POS;
if ((gw->bw != NULL) &&
- (browser_window_get_extents(gw->bw, true,
- &width, &height) == NSERROR_OK)) {
+ (browser_window_get_extents(gw->bw, true,
+ &width, &height) == NSERROR_OK)) {
si.nPos = min(si.nPos, height - gw->height);
}
@@ -130,8 +137,10 @@ nsws_drawable_vscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si);
if (si.nPos != mem) {
- win32_window_set_scroll(gw, gw->scrollx, gw->scrolly +
- gw->requestscrolly + si.nPos - mem);
+ struct rect rect;
+ rect.x0 = rect.x1 = gw->scrollx;
+ rect.y0 = rect.y1 = gw->scrolly + gw->requestscrolly + si.nPos - mem;
+ win32_window_set_scroll(gw, &rect);
}
return 0;
@@ -148,7 +157,7 @@ nsws_drawable_hscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
SCROLLINFO si;
int mem;
- LOG("HSCROLL %d", gw->requestscrollx);
+ NSLOG(netsurf, INFO, "HSCROLL %d", gw->requestscrollx);
if (gw->requestscrollx != 0)
return 0;
@@ -186,22 +195,24 @@ nsws_drawable_hscroll(struct gui_window *gw, HWND hwnd, WPARAM wparam)
si.fMask = SIF_POS;
if ((gw->bw != NULL) &&
- (browser_window_get_extents(gw->bw, true,
- &width, &height) == NSERROR_OK)) {
+ (browser_window_get_extents(gw->bw, true,
+ &width, &height) == NSERROR_OK)) {
si.nPos = min(si.nPos, width - gw->width);
}
si.nPos = max(si.nPos, 0);
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
GetScrollInfo(hwnd, SB_HORZ, &si);
if (si.nPos != mem) {
- win32_window_set_scroll(gw,
- gw->scrollx + gw->requestscrollx + si.nPos - mem,
- gw->scrolly);
+ struct rect rect;
+ rect.x0 = rect.x1 = gw->scrollx + gw->requestscrollx + si.nPos - mem;
+ rect.y0 = rect.y1 = gw->scrolly;
+ win32_window_set_scroll(gw, &rect);
}
return 0;
}
+
/**
* Handle resize events.
*/
@@ -212,6 +223,7 @@ nsws_drawable_resize(struct gui_window *gw)
return 0;
}
+
/**
* Handle key press messages.
*/
@@ -289,7 +301,7 @@ nsws_drawable_key(struct gui_window *gw, HWND hwnd, WPARAM wparam)
break;
}
- if ((i >= 'A') &&
+ if ((i >= 'A') &&
(i <= 'Z') &&
(((!capslock) && (!shift)) || ((capslock) && (shift)))) {
i += 'a' - 'A';
@@ -357,7 +369,8 @@ nsws_drawable_mouseup(struct gui_window *gw,
(gw->bw == NULL))
return 0;
- LOG("state 0x%x, press 0x%x", gw->mouse->state, press);
+ NSLOG(netsurf, INFO, "state 0x%x, press 0x%x", gw->mouse->state,
+ press);
if ((gw->mouse->state & press) != 0) {
gw->mouse->state &= ~press;
gw->mouse->state |= click;
@@ -371,7 +384,10 @@ nsws_drawable_mouseup(struct gui_window *gw,
gw->mouse->state &= ~BROWSER_MOUSE_MOD_3;
if ((gw->mouse->state & click) != 0) {
- LOG("mouse click bw %p, state 0x%x, x %f, y %f", gw->bw, gw->mouse->state, (x + gw->scrollx) / gw->scale, (y + gw->scrolly) / gw->scale);
+ NSLOG(netsurf, INFO,
+ "mouse click bw %p, state 0x%x, x %f, y %f", gw->bw,
+ gw->mouse->state, (x + gw->scrollx) / gw->scale,
+ (y + gw->scrolly) / gw->scale);
browser_window_mouse_click(gw->bw,
gw->mouse->state,
@@ -400,7 +416,7 @@ nsws_drawable_mousedown(struct gui_window *gw,
if ((gw == NULL) ||
(gw->mouse == NULL) ||
(gw->bw == NULL)) {
- nsws_localhistory_close(gw);
+ nsw32_local_history_hide();
return 0;
}
@@ -415,7 +431,9 @@ nsws_drawable_mousedown(struct gui_window *gw,
gw->mouse->pressed_x = (x + gw->scrollx) / gw->scale;
gw->mouse->pressed_y = (y + gw->scrolly) / gw->scale;
- LOG("mouse click bw %p, state %x, x %f, y %f", gw->bw, gw->mouse->state, (x + gw->scrollx) / gw->scale, (y + gw->scrolly) / gw->scale);
+ NSLOG(netsurf, INFO, "mouse click bw %p, state %x, x %f, y %f",
+ gw->bw, gw->mouse->state, (x + gw->scrollx) / gw->scale,
+ (y + gw->scrolly) / gw->scale);
browser_window_mouse_click(gw->bw, gw->mouse->state,
(x + gw->scrollx) / gw->scale,
@@ -424,6 +442,7 @@ nsws_drawable_mousedown(struct gui_window *gw,
return 0;
}
+
/**
* Handle mouse movement messages.
*/
@@ -447,7 +466,8 @@ nsws_drawable_mousemove(struct gui_window *gw, int x, int y)
(abs(x - gw->mouse->pressed_x) >= 5) &&
(abs(y - gw->mouse->pressed_y) >= 5)) {
- LOG("Drag start state 0x%x", gw->mouse->state);
+ NSLOG(netsurf, INFO, "Drag start state 0x%x",
+ gw->mouse->state);
if ((gw->mouse->state & BROWSER_MOUSE_PRESS_1) != 0) {
browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_1,
@@ -480,6 +500,7 @@ nsws_drawable_mousemove(struct gui_window *gw, int x, int y)
return 0;
}
+
/**
* Called when activity occours within the drawable window.
*/
@@ -495,7 +516,8 @@ nsws_window_drawable_event_callback(HWND hwnd,
gw = nsws_get_gui_window(hwnd);
if (gw == NULL) {
- LOG("Unable to find gui window structure for hwnd %p", hwnd);
+ NSLOG(netsurf, INFO,
+ "Unable to find gui window structure for hwnd %p", hwnd);
return DefWindowProc(hwnd, msg, wparam, lparam);
}
@@ -512,9 +534,8 @@ nsws_window_drawable_event_callback(HWND hwnd,
GET_Y_LPARAM(lparam),
BROWSER_MOUSE_PRESS_1);
SetFocus(hwnd);
- nsws_localhistory_close(gw);
+ nsw32_local_history_hide();
return 0;
- break;
case WM_RBUTTONDOWN:
nsws_drawable_mousedown(gw,
@@ -564,12 +585,13 @@ nsws_window_drawable_event_callback(HWND hwnd,
return DefWindowProc(hwnd, msg, wparam, lparam);
}
+
/**
* Create a drawable window.
*/
HWND
-nsws_window_create_drawable(HINSTANCE hinstance,
- HWND hparent,
+nsws_window_create_drawable(HINSTANCE hinstance,
+ HWND hparent,
struct gui_window *gw)
{
HWND hwnd;
@@ -584,7 +606,7 @@ nsws_window_create_drawable(HINSTANCE hinstance,
if (hwnd == NULL) {
win_perror("WindowCreateDrawable");
- LOG("Window creation failed");
+ NSLOG(netsurf, INFO, "Window creation failed");
return NULL;
}
@@ -594,6 +616,7 @@ nsws_window_create_drawable(HINSTANCE hinstance,
return hwnd;
}
+
/**
* Create the drawable window class.
*/
diff --git a/frontends/windows/filetype.c b/frontends/windows/filetype.c
index ed07dd5fc..a5fd9e95e 100644
--- a/frontends/windows/filetype.c
+++ b/frontends/windows/filetype.c
@@ -16,6 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * Fetch operation implementation for win32
+ */
+
#include <stdlib.h>
#include <string.h>
@@ -26,12 +31,15 @@
#include "windows/filetype.h"
/**
- * filetype -- determine the MIME type of a local file
+ * determine the MIME type of a local file.
+ *
+ * \param unix_path The unix style path to the file.
+ * \return The mime type of the file.
*/
static const char *fetch_filetype(const char *unix_path)
{
int l;
- LOG("unix path %s", unix_path);
+ NSLOG(netsurf, INFO, "unix path %s", unix_path);
l = strlen(unix_path);
if (2 < l && strcasecmp(unix_path + l - 3, "css") == 0)
return "text/css";
@@ -52,6 +60,7 @@ static const char *fetch_filetype(const char *unix_path)
return "text/html";
}
+/** win32 fetch operation table */
static struct gui_fetch_table fetch_table = {
.filetype = fetch_filetype,
};
diff --git a/frontends/windows/findfile.c b/frontends/windows/findfile.c
index e1c9595eb..e665530ba 100644
--- a/frontends/windows/findfile.c
+++ b/frontends/windows/findfile.c
@@ -99,7 +99,7 @@ char *nsws_find_resource(char *buf, const char *filename, const char *def)
char t[PATH_MAX];
if (cdir != NULL) {
- LOG("Found Home %s", cdir);
+ NSLOG(netsurf, INFO, "Found Home %s", cdir);
strcpy(t, cdir);
strcat(t, "/.netsurf/");
strcat(t, filename);
@@ -126,7 +126,7 @@ char *nsws_find_resource(char *buf, const char *filename, const char *def)
getcwd(t, PATH_MAX - SLEN("\\res\\") - strlen(filename));
strcat(t, "\\res\\");
strcat(t, filename);
- LOG("looking in %s", t);
+ NSLOG(netsurf, INFO, "looking in %s", t);
if ((realpath(t, buf) != NULL) && (access(buf, R_OK) == 0))
return buf;
diff --git a/frontends/windows/font.c b/frontends/windows/font.c
index f50ba6e9e..7389bd8c1 100644
--- a/frontends/windows/font.c
+++ b/frontends/windows/font.c
@@ -19,7 +19,7 @@
/**
* \file
- * Windows font handling implementation.
+ * Windows font handling and character encoding implementation.
*/
#include "utils/config.h"
@@ -38,36 +38,57 @@
HWND font_hwnd;
-nserror utf8_to_font_encoding(const struct font_desc* font,
- const char *string,
- size_t len,
- char **result)
+/* exported interface documented in windows/font.h */
+nserror
+utf8_to_font_encoding(const struct font_desc* font,
+ const char *string,
+ size_t len,
+ char **result)
{
return utf8_to_enc(string, font->encoding, len, result);
}
-static nserror utf8_to_local_encoding(const char *string,
- size_t len,
- char **result)
+
+/**
+ * Convert a string to UCS2 from UTF8
+ *
+ * \param[in] string source string
+ * \param[in] len source string length
+ * \param[out] result The UCS2 string
+ */
+static nserror
+utf8_to_local_encoding(const char *string, size_t len, char **result)
{
return utf8_to_enc(string, "UCS-2", len, result);
}
-static nserror utf8_from_local_encoding(const char *string, size_t len,
- char **result)
+
+/**
+ * Convert a string to UTF8 from local encoding
+ *
+ * \param[in] string source string
+ * \param[in] len source string length
+ * \param[out] result The UTF8 string
+ */
+static nserror
+utf8_from_local_encoding(const char *string, size_t len, char **result)
{
assert(string && result);
- if (len == 0)
+ if (len == 0) {
len = strlen(string);
+ }
*result = strndup(string, len);
- if (!(*result))
+ if (!(*result)) {
return NSERROR_NOMEM;
+ }
return NSERROR_OK;
}
+
+/* exported interface documented in windows/font.h */
HFONT get_font(const plot_font_style_t *style)
{
char *face = NULL;
@@ -99,7 +120,7 @@ HFONT get_font(const plot_font_style_t *style)
int nHeight = -10;
HDC hdc = GetDC(font_hwnd);
- nHeight = -MulDiv(style->size, GetDeviceCaps(hdc, LOGPIXELSY), 72 * FONT_SIZE_SCALE);
+ nHeight = -MulDiv(style->size, GetDeviceCaps(hdc, LOGPIXELSY), 72 * PLOT_STYLE_SCALE);
ReleaseDC(font_hwnd, hdc);
HFONT font = CreateFont(
@@ -122,16 +143,18 @@ HFONT get_font(const plot_font_style_t *style)
free(face);
if (font == NULL) {
- if (style->family == PLOT_FONT_FAMILY_MONOSPACE)
+ if (style->family == PLOT_FONT_FAMILY_MONOSPACE) {
font = (HFONT) GetStockObject(ANSI_FIXED_FONT);
- else
+ } else {
font = (HFONT) GetStockObject(ANSI_VAR_FONT);
+ }
}
if (font == NULL)
font = (HFONT) GetStockObject(SYSTEM_FONT);
return font;
}
+
/**
* Measure the width of a string.
*
@@ -139,13 +162,13 @@ HFONT get_font(const plot_font_style_t *style)
* \param[in] string UTF-8 string to measure
* \param[in] length length of string, in bytes
* \param[out] width updated to width of string[0..length)
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
static nserror
win32_font_width(const plot_font_style_t *style,
- const char *string,
- size_t length,
- int *width)
+ const char *string,
+ size_t length,
+ int *width)
{
HDC hdc;
HFONT font;
@@ -184,15 +207,15 @@ win32_font_width(const plot_font_style_t *style,
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
static nserror
win32_font_position(const plot_font_style_t *style,
- const char *string,
- size_t length,
- int x,
- size_t *char_offset,
- int *actual_x)
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
{
HDC hdc;
HFONT font;
@@ -211,8 +234,8 @@ win32_font_position(const plot_font_style_t *style,
if ((GetTextExtentExPointA(hdc, string, length, x, &offset, NULL,&s) != 0) &&
(GetTextExtentPoint32A(hdc, string, offset, &s) != 0)) {
- *char_offset = (size_t)offset;
- *actual_x = s.cx;
+ *char_offset = (size_t)offset;
+ *actual_x = s.cx;
} else {
ret = NSERROR_UNKNOWN;
}
@@ -235,7 +258,7 @@ win32_font_position(const plot_font_style_t *style,
* \param x width available
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*
* On exit, [char_offset == 0 ||
* string[char_offset] == ' ' ||
@@ -243,16 +266,21 @@ win32_font_position(const plot_font_style_t *style,
*/
static nserror
win32_font_split(const plot_font_style_t *style,
- const char *string,
- size_t length,
- int x,
- size_t *char_offset,
- int *actual_x)
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
{
int c_off;
nserror ret = NSERROR_UNKNOWN;
- if (win32_font_position(style, string, length, x, char_offset, actual_x)) {
+ if (win32_font_position(style,
+ string,
+ length,
+ x,
+ char_offset,
+ actual_x) == NSERROR_OK) {
c_off = *char_offset;
if (*char_offset == length) {
ret = NSERROR_OK;
@@ -271,21 +299,26 @@ win32_font_split(const plot_font_style_t *style,
}
}
- success = win32_font_width(style, string, *char_offset, actual_x);
+ success = win32_font_width(style,
+ string,
+ *char_offset,
+ actual_x);
if (success) {
ret = NSERROR_OK;
}
}
}
-/*
- LOG("ret %d Split %u chars at %ipx: Split at char %i (%ipx) - %.*s",
- ret, length, x, *char_offset, *actual_x, *char_offset, string);
-*/
+
+ NSLOG(netsurf, DEEPDEBUG,
+ "ret %d Split %u chars at %ipx: Split at char %i (%ipx) - %.*s",
+ ret, length, x, *char_offset, *actual_x, *char_offset, string);
+
return ret;
}
+/** win32 font operations table */
static struct gui_layout_table layout_table = {
.width = win32_font_width,
.position = win32_font_position,
@@ -294,7 +327,7 @@ static struct gui_layout_table layout_table = {
struct gui_layout_table *win32_layout_table = &layout_table;
-
+/** win32 utf8 encoding operations table */
static struct gui_utf8_table utf8_table = {
.utf8_to_local = utf8_to_local_encoding,
.local_to_utf8 = utf8_from_local_encoding,
diff --git a/frontends/windows/font.h b/frontends/windows/font.h
index a1077e041..ec2c262ff 100644
--- a/frontends/windows/font.h
+++ b/frontends/windows/font.h
@@ -38,10 +38,15 @@ struct font_desc {
struct gui_layout_table *win32_layout_table;
struct gui_utf8_table *win32_utf8_table;
-extern nserror utf8_to_font_encoding(const struct font_desc* font,
- const char *string,
- size_t len,
- char **result);
+/**
+ * convert from utf-8 to win32 font encoding.
+ *
+ * \param[in] font font descriptor
+ * \param[in] string source utf-8 string
+ * \param[in] len The length of the utf-8 data
+ * \param[out] result The reencoded string.
+ */
+extern nserror utf8_to_font_encoding(const struct font_desc* font, const char *string, size_t len, char **result);
/**
* generate a win32 font handle from a generic font style
diff --git a/frontends/windows/global_history.c b/frontends/windows/global_history.c
index 0ef09632d..dcc75ba21 100644
--- a/frontends/windows/global_history.c
+++ b/frontends/windows/global_history.c
@@ -18,7 +18,7 @@
/**
* \file
- * Implementation of win32 cookie manager.
+ * Implementation of win32 global history interface.
*/
#include <stdint.h>
@@ -81,6 +81,8 @@ nsw32_global_history_mouse(struct nsw32_corewindow *nsw32_cw,
* callback on draw event for global_history window
*
* \param nsw32_cw The nsw32 core window structure.
+ * \param scrollx The horizontal scroll offset.
+ * \param scrolly The vertical scroll offset.
* \param r The rectangle of the window that needs updating.
* \return NSERROR_OK on success otherwise apropriate error code
*/
@@ -124,7 +126,7 @@ static nserror nsw32_global_history_init(HINSTANCE hInstance)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsw32_global_history_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
diff --git a/frontends/windows/gui.c b/frontends/windows/gui.c
index f5808de86..890bfae42 100644
--- a/frontends/windows/gui.c
+++ b/frontends/windows/gui.c
@@ -17,6 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * win32 gui implementation.
+ */
+
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -47,6 +52,7 @@ HINSTANCE hinst;
static bool win32_quit = false;
+/* exported interface documented in gui.h */
void win32_set_quit(bool q)
{
win32_quit = q;
@@ -60,7 +66,7 @@ void win32_run(void)
int timeout; /* timeout in miliseconds */
UINT timer_id = 0;
- LOG("Starting messgae dispatcher");
+ NSLOG(netsurf, INFO, "Starting messgae dispatcher");
while (!win32_quit) {
/* run the scheduler and discover how long to wait for
@@ -98,7 +104,7 @@ void win32_run(void)
nserror win32_warning(const char *warning, const char *detail)
{
size_t len = 1 + ((warning != NULL) ? strlen(messages_get(warning)) :
- 0) + ((detail != 0) ? strlen(detail) : 0);
+ 0) + ((detail != 0) ? strlen(detail) : 0);
char message[len];
snprintf(message, len, messages_get(warning), detail);
MessageBox(NULL, message, "Warning", MB_ICONWARNING);
@@ -110,8 +116,8 @@ nserror win32_warning(const char *warning, const char *detail)
/**
* Core asks front end for clipboard contents.
*
- * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
- * \param length Byte length of UTF-8 text in buffer
+ * \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
+ * \param length Byte length of UTF-8 text in buffer
*/
static void gui_get_clipboard(char **buffer, size_t *length)
{
@@ -122,7 +128,7 @@ static void gui_get_clipboard(char **buffer, size_t *length)
clipboard_handle = GetClipboardData(CF_TEXT);
if (clipboard_handle != NULL) {
content = GlobalLock(clipboard_handle);
- LOG("pasting %s", content);
+ NSLOG(netsurf, INFO, "pasting %s", content);
GlobalUnlock(clipboard_handle);
}
}
@@ -137,7 +143,7 @@ static void gui_get_clipboard(char **buffer, size_t *length)
* \param n_styles Number of text run styles in array
*/
static void gui_set_clipboard(const char *buffer, size_t length,
- nsclipboard_styles styles[], int n_styles)
+ nsclipboard_styles styles[], int n_styles)
{
/* TODO: Implement this */
HANDLE hnew;
@@ -169,5 +175,3 @@ static struct gui_clipboard_table clipboard_table = {
};
struct gui_clipboard_table *win32_clipboard_table = &clipboard_table;
-
-
diff --git a/frontends/windows/hotlist.c b/frontends/windows/hotlist.c
index c184619bf..e8dd90b34 100644
--- a/frontends/windows/hotlist.c
+++ b/frontends/windows/hotlist.c
@@ -85,6 +85,8 @@ nsw32_hotlist_mouse(struct nsw32_corewindow *nsw32_cw,
* callback on draw event for hotlist window
*
* \param nsw32_cw The nsw32 core window structure.
+ * \param scrollx The horizontal scroll offset.
+ * \param scrolly The vertical scroll offset.
* \param r The rectangle of the window that needs updating.
* \return NSERROR_OK on success otherwise apropriate error code
*/
@@ -128,7 +130,7 @@ static nserror nsw32_hotlist_init(HINSTANCE hInstance)
return NSERROR_OK;
}
- ncwin = malloc(sizeof(struct nsw32_hotlist_window));
+ ncwin = calloc(1, sizeof(*ncwin));
if (ncwin == NULL) {
return NSERROR_NOMEM;
}
@@ -182,7 +184,7 @@ nserror nsw32_hotlist_finalise(void)
return NSERROR_OK;
}
- res = hotlist_fini(nsoption_charp(hotlist_path));
+ res = hotlist_fini();
if (res == NSERROR_OK) {
res = nsw32_corewindow_fini(&hotlist_window->core);
DestroyWindow(hotlist_window->core.hWnd);
diff --git a/frontends/windows/local_history.c b/frontends/windows/local_history.c
new file mode 100644
index 000000000..722d365e7
--- /dev/null
+++ b/frontends/windows/local_history.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of win32 local history interface.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
+#include "desktop/local_history.h"
+
+#include "windows/plot.h"
+#include "windows/corewindow.h"
+#include "windows/local_history.h"
+
+
+struct nsw32_local_history_window {
+ struct nsw32_corewindow core;
+
+ struct local_history_session *session;
+};
+
+static struct nsw32_local_history_window *local_history_window = NULL;
+
+/**
+ * callback for keypress on local_history window
+ *
+ * \param nsw32_cw The nsw32 core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsw32_local_history_key(struct nsw32_corewindow *nsw32_cw, uint32_t nskey)
+{
+ struct nsw32_local_history_window *lhw;
+
+ lhw = (struct nsw32_local_history_window *)nsw32_cw;
+
+ if (local_history_keypress(lhw->session,nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+/**
+ * callback for mouse action on local_history window
+ *
+ * \param nsw32_cw The nsw32 core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsw32_local_history_mouse(struct nsw32_corewindow *nsw32_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct nsw32_local_history_window *lhw;
+
+ lhw = (struct nsw32_local_history_window *)nsw32_cw;
+
+ local_history_mouse_action(lhw->session, mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+/**
+ * callback on draw event for local_history window
+ *
+ * \param nsw32_cw The nsw32 core window structure.
+ * \param scrollx The horizontal scroll offset.
+ * \param scrolly The vertical scroll offset.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsw32_local_history_draw(struct nsw32_corewindow *nsw32_cw,
+ int scrollx,
+ int scrolly,
+ struct rect *r)
+{
+ struct nsw32_local_history_window *lhw;
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &win_plotters
+ };
+
+ lhw = (struct nsw32_local_history_window *)nsw32_cw;
+
+ local_history_redraw(lhw->session, -scrollx, -scrolly, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+
+static nserror
+nsw32_local_history_close(struct nsw32_corewindow *nsw32_cw)
+{
+ ShowWindow(nsw32_cw->hWnd, SW_HIDE);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Creates the window for the local_history tree.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror
+nsw32_local_history_init(HINSTANCE hInstance,
+ struct browser_window *bw,
+ struct nsw32_local_history_window **win_out)
+{
+ struct nsw32_local_history_window *ncwin;
+ nserror res;
+
+ if ((*win_out) != NULL) {
+ res = local_history_set((*win_out)->session, bw);
+ return res;
+ }
+
+ ncwin = calloc(1, sizeof(*ncwin));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ ncwin->core.title = "NetSurf Local History";
+ ncwin->core.draw = nsw32_local_history_draw;
+ ncwin->core.key = nsw32_local_history_key;
+ ncwin->core.mouse = nsw32_local_history_mouse;
+ ncwin->core.close = nsw32_local_history_close;
+
+ res = nsw32_corewindow_init(hInstance, NULL, &ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = local_history_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ bw,
+ &ncwin->session);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ *win_out = ncwin;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in windows/local_history.h */
+nserror
+nsw32_local_history_present(HWND hWndParent, struct browser_window *bw)
+{
+ nserror res;
+ HINSTANCE hInstance;
+ RECT parentr;
+ int width, height;
+ int margin = 50;
+
+ hInstance = (HINSTANCE)GetWindowLongPtr(hWndParent, GWLP_HINSTANCE);
+
+ res = nsw32_local_history_init(hInstance, bw, &local_history_window);
+ if (res == NSERROR_OK) {
+ GetWindowRect(hWndParent, &parentr);
+
+ /* resize history widget ensureing the drawing area is
+ * no larger than parent window
+ */
+ res = local_history_get_size(local_history_window->session,
+ &width,
+ &height);
+ width += margin;
+ height += margin;
+ if ((parentr.right - parentr.left - margin) < width) {
+ width = parentr.right - parentr.left - margin;
+ }
+ if ((parentr.bottom - parentr.top - margin) < height) {
+ height = parentr.bottom - parentr.top - margin;
+ }
+ SetWindowPos(local_history_window->core.hWnd,
+ HWND_TOP,
+ parentr.left + (margin/2),
+ parentr.top + (margin/2),
+ width,
+ height,
+ SWP_SHOWWINDOW);
+ }
+ return res;
+}
+
+
+/* exported interface documented in windows/local_history.h */
+nserror nsw32_local_history_hide(void)
+{
+ nserror res = NSERROR_OK;
+
+ if (local_history_window != NULL) {
+ ShowWindow(local_history_window->core.hWnd, SW_HIDE);
+
+ res = local_history_set(local_history_window->session, NULL);
+ }
+
+ return res;
+}
+
+/* exported interface documented in windows/local_history.h */
+nserror nsw32_local_history_finalise(void)
+{
+ nserror res;
+
+ if (local_history_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = local_history_fini(local_history_window->session);
+ if (res == NSERROR_OK) {
+ res = nsw32_corewindow_fini(&local_history_window->core);
+ DestroyWindow(local_history_window->core.hWnd);
+ free(local_history_window);
+ local_history_window = NULL;
+ }
+
+ return res;
+}
diff --git a/frontends/cocoa/apple_image.h b/frontends/windows/local_history.h
index 11248a6fb..a6e2180b9 100644
--- a/frontends/cocoa/apple_image.h
+++ b/frontends/windows/local_history.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,24 +16,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * Interface to win32 local history manager using nsw32 core window
+ */
-#ifndef _NETSURF_COCOA_APPLE_IMAGE_H_
-#define _NETSURF_COCOA_APPLE_IMAGE_H_
-
-#include "utils/config.h"
-#include "utils/errors.h"
-
-#ifdef WITH_APPLE_IMAGE
+#ifndef NETSURF_WINDOWS_LOCAL_HISTORY_H
+#define NETSURF_WINDOWS_LOCAL_HISTORY_H
/**
- * Initialise apple image handlers instead of generic core ones.
+ * make the local history window visible.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
*/
-nserror apple_image_init(void);
+nserror nsw32_local_history_present(HWND hWndParent, struct browser_window *bw);
-#else
-
-#define apple_image_init() NSERROR_OK
+/**
+ * hide the local history window.
+ */
+nserror nsw32_local_history_hide(void);
-#endif /* WITH_APPLE_IMAGE */
+/**
+ * Destroys the local history window and performs any other necessary cleanup
+ * actions.
+ */
+nserror nsw32_local_history_finalise(void);
#endif
diff --git a/frontends/windows/localhistory.c b/frontends/windows/localhistory.c
deleted file mode 100644
index ae3b7f521..000000000
--- a/frontends/windows/localhistory.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "utils/config.h"
-
-#include <windows.h>
-#include <windowsx.h>
-#include <commctrl.h>
-
-#include "desktop/browser_history.h"
-#include "netsurf/plotters.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-
-#include "windows/window.h"
-#include "windows/localhistory.h"
-#include "windows/gui.h"
-#include "windows/plot.h"
-#include "windows/resourceid.h"
-#include "windows/windbg.h"
-
-static const char windowclassname_localhistory[] = "nswslocalhistorywindow";
-
-struct nsws_localhistory {
- HWND hwnd; /**< the window handle */
- int width; /**< the width of the memory history */
- int height; /**< the height of the memory history */
- int guiwidth; /**< the width of the history window */
- int guiheight; /**< the height of the history window */
- int vscroll; /**< the vertical scroll location */
- int hscroll; /**< the horizontal scroll location */
-};
-
-
-static void
-nsws_localhistory_scroll_check(struct nsws_localhistory *l,
- struct gui_window *gw)
-{
- SCROLLINFO si;
-
- if ((gw->bw == NULL) || (l->hwnd == NULL))
- return;
-
- browser_window_history_size(gw->bw, &(l->width), &(l->height));
-
- si.cbSize = sizeof(si);
- si.fMask = SIF_ALL;
- si.nMin = 0;
- si.nMax = l->height;
- si.nPage = l->guiheight;
- si.nPos = 0;
- SetScrollInfo(l->hwnd, SB_VERT, &si, TRUE);
-
- si.nMax = l->width;
- si.nPage = l->guiwidth;
- SetScrollInfo(l->hwnd, SB_HORZ, &si, TRUE);
- if (l->guiheight >= l->height)
- l->vscroll = 0;
- if (l->guiwidth >= l->width)
- l->hscroll = 0;
- SendMessage(l->hwnd, WM_PAINT, 0, 0);
-}
-
-
-static void
-nsws_localhistory_up(struct nsws_localhistory *l, struct gui_window *gw)
-{
- HDC tmp_hdc;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &win_plotters
- };
-
- LOG("gui window %p", gw);
-
- l->vscroll = 0;
- l->hscroll = 0;
-
- if (gw->bw != NULL) {
- /* set global HDC for the plotters */
- tmp_hdc = plot_hdc;
- plot_hdc = GetDC(l->hwnd);
-
- browser_window_history_redraw(gw->bw, &ctx);
-
- ReleaseDC(l->hwnd, plot_hdc);
-
- plot_hdc = tmp_hdc;
- }
-
- nsws_localhistory_scroll_check(l, gw);
-}
-
-
-void nsws_localhistory_close(struct gui_window *w)
-{
- struct nsws_localhistory *l = gui_window_localhistory(w);
- if (l != NULL)
- CloseWindow(l->hwnd);
-}
-
-
-static LRESULT CALLBACK
-nsws_localhistory_event_callback(HWND hwnd, UINT msg,
- WPARAM wparam, LPARAM lparam)
-{
- int x,y;
- struct gui_window *gw;
-
- LOG_WIN_MSG(hwnd, msg, wparam, lparam);
-
- gw = nsws_get_gui_window(hwnd);
- if (gw == NULL) {
- LOG("Unable to find gui window structure for hwnd %p", hwnd);
- return DefWindowProc(hwnd, msg, wparam, lparam);
- }
-
- switch(msg) {
-
- case WM_CREATE:
- nsws_localhistory_scroll_check(gw->localhistory, gw);
- break;
-
- case WM_SIZE:
- gw->localhistory->guiheight = HIWORD(lparam);
- gw->localhistory->guiwidth = LOWORD(lparam);
- nsws_localhistory_scroll_check(gw->localhistory, gw);
- break;
-
- case WM_LBUTTONUP:
- if (gw->bw == NULL)
- break;
-
- x = GET_X_LPARAM(lparam);
- y = GET_Y_LPARAM(lparam);
-
- if (browser_window_history_click(gw->bw,
- gw->localhistory->hscroll + x,
- gw->localhistory->vscroll + y,
- false)) {
- DestroyWindow(hwnd);
- }
-
- break;
-
- case WM_MOUSEMOVE:
- x = GET_X_LPARAM(lparam);
- y = GET_Y_LPARAM(lparam);
- return DefWindowProc(hwnd, msg, wparam, lparam);
- break;
-
-
- case WM_VSCROLL:
- {
- SCROLLINFO si;
- int mem;
- si.cbSize = sizeof(si);
- si.fMask = SIF_ALL;
- GetScrollInfo(hwnd, SB_VERT, &si);
- mem = si.nPos;
- switch (LOWORD(wparam)) {
- case SB_TOP:
- si.nPos = si.nMin;
- break;
- case SB_BOTTOM:
- si.nPos = si.nMax;
- break;
- case SB_LINEUP:
- si.nPos -= 30;
- break;
- case SB_LINEDOWN:
- si.nPos += 30;
- break;
- case SB_PAGEUP:
- si.nPos -= gw->localhistory->guiheight;
- break;
- case SB_PAGEDOWN:
- si.nPos += gw->localhistory->guiheight;
- break;
- case SB_THUMBTRACK:
- si.nPos = si.nTrackPos;
- break;
- default:
- break;
- }
- si.nPos = min(si.nPos, gw->localhistory->height);
- si.nPos = min(si.nPos, 0);
- si.fMask = SIF_POS;
- SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
- GetScrollInfo(hwnd, SB_VERT, &si);
- if (si.nPos != mem) {
- gw->localhistory->vscroll += si.nPos - mem;
- ScrollWindowEx(hwnd, 0, -(si.nPos - mem), NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
- }
- break;
- }
-
- case WM_HSCROLL:
- {
- SCROLLINFO si;
- int mem;
-
- si.cbSize = sizeof(si);
- si.fMask = SIF_ALL;
- GetScrollInfo(hwnd, SB_HORZ, &si);
- mem = si.nPos;
-
- switch (LOWORD(wparam)) {
- case SB_LINELEFT:
- si.nPos -= 30;
- break;
- case SB_LINERIGHT:
- si.nPos += 30;
- break;
- case SB_PAGELEFT:
- si.nPos -= gw->localhistory->guiwidth;
- break;
- case SB_PAGERIGHT:
- si.nPos += gw->localhistory->guiwidth;
- break;
- case SB_THUMBTRACK:
- si.nPos = si.nTrackPos;
- break;
- default:
- break;
- }
- si.nPos = min(si.nPos, gw->localhistory->width);
- si.nPos = max(si.nPos, 0);
- si.fMask = SIF_POS;
- SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
- GetScrollInfo(hwnd, SB_HORZ, &si);
- if (si.nPos != mem) {
- gw->localhistory->hscroll += si.nPos - mem;
- ScrollWindowEx(hwnd, -(si.nPos - mem), 0, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
- }
- break;
- }
-
- case WM_PAINT: {
- PAINTSTRUCT ps;
- HDC hdc, tmp_hdc;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &win_plotters
- };
-
- hdc = BeginPaint(hwnd, &ps);
- if (gw->bw != NULL) {
- /* set global HDC for the plotters */
- tmp_hdc = plot_hdc;
- plot_hdc = hdc;
-
- browser_window_history_redraw_rectangle(gw->bw,
- gw->localhistory->hscroll + ps.rcPaint.left,
- gw->localhistory->vscroll + ps.rcPaint.top,
- gw->localhistory->hscroll + (ps.rcPaint.right - ps.rcPaint.left),
- gw->localhistory->vscroll + (ps.rcPaint.bottom - ps.rcPaint.top),
- ps.rcPaint.left,
- ps.rcPaint.top, &ctx);
-
- plot_hdc = tmp_hdc;
-
- }
- EndPaint(hwnd, &ps);
-
- break;
- }
-
- case WM_CLOSE:
- DestroyWindow(hwnd);
- return 1;
-
- case WM_DESTROY:
- free(gw->localhistory);
- gw->localhistory = NULL;
- break;
-
- default:
- return DefWindowProc(hwnd, msg, wparam, lparam);
-
- }
- return 0;
-}
-
-
-/* exported method documented in windows/localhistory.h */
-struct nsws_localhistory *nsws_window_create_localhistory(struct gui_window *gw)
-{
- struct nsws_localhistory *localhistory;
- INITCOMMONCONTROLSEX icc;
- int margin = 50;
- RECT r;
-
- LOG("gui window %p", gw);
-
- /* if we already have a window, just update and re-show it */
- if (gw->localhistory != NULL) {
- nsws_localhistory_up(gw->localhistory, gw);
- UpdateWindow(gw->localhistory->hwnd);
- ShowWindow(gw->localhistory->hwnd, SW_SHOWNORMAL);
- return gw->localhistory;
- }
-
- localhistory = calloc(1, sizeof(struct nsws_localhistory));
-
- if (localhistory == NULL) {
- return NULL;
- }
- gw->localhistory = localhistory;
-
- localhistory->width = 0;
- localhistory->height = 0;
-
- if (gw->bw != NULL) {
- browser_window_history_size(gw->bw,
- &(localhistory->width),
- &(localhistory->height));
- }
-
- GetWindowRect(gw->main, &r);
- SetWindowPos(gw->main, HWND_NOTOPMOST, 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE);
-
- localhistory->guiwidth = min(r.right - r.left - margin,
- localhistory->width + margin);
- localhistory->guiheight = min(r.bottom - r.top - margin,
- localhistory->height + margin);
-
- icc.dwSize = sizeof(icc);
- icc.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
-#if WINVER > 0x0501
- icc.dwICC |= ICC_STANDARD_CLASSES;
-#endif
- InitCommonControlsEx(&icc);
-
- LOG("creating local history window for hInstance %p", hinst);
- localhistory->hwnd = CreateWindow(windowclassname_localhistory,
- "NetSurf History",
- WS_THICKFRAME |
- WS_HSCROLL |
- WS_VSCROLL |
- WS_CLIPCHILDREN |
- WS_CLIPSIBLINGS |
- WS_SYSMENU |
- CS_DBLCLKS,
- r.left + margin/2,
- r.top + margin/2,
- localhistory->guiwidth,
- localhistory->guiheight,
- NULL,
- NULL,
- hinst,
- NULL);
-
- /* set the gui window associated with this browser */
- SetProp(localhistory->hwnd, TEXT("GuiWnd"), (HANDLE)gw);
-
- LOG("gui_window %p width %d height %d hwnd %p",
- gw, localhistory->guiwidth, localhistory->guiheight,
- localhistory->hwnd);
-
- nsws_localhistory_up(localhistory, gw);
- UpdateWindow(localhistory->hwnd);
- ShowWindow(localhistory->hwnd, SW_SHOWNORMAL);
-
- return localhistory;
-}
-
-
-/* exported method documented in windows/localhistory.h */
-nserror
-nsws_create_localhistory_class(HINSTANCE hinstance) {
- nserror ret = NSERROR_OK;
- WNDCLASSEX w;
-
- /* localhistory window */
- w.cbSize = sizeof(WNDCLASSEX);
- w.style = 0;
- w.lpfnWndProc = nsws_localhistory_event_callback;
- w.cbClsExtra = 0;
- w.cbWndExtra = 0;
- w.hInstance = hinstance;
- w.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
- w.hCursor = LoadCursor(NULL, IDC_ARROW);
- w.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- w.lpszMenuName = NULL;
- w.lpszClassName = windowclassname_localhistory;
- w.hIconSm = LoadIcon(hinstance, MAKEINTRESOURCE(IDR_NETSURF_ICON));
-
- if (RegisterClassEx(&w) == 0) {
- win_perror("DrawableClass");
- ret = NSERROR_INIT_FAILED;
- }
-
- return ret;
-}
diff --git a/frontends/windows/localhistory.h b/frontends/windows/localhistory.h
deleted file mode 100644
index b0ad07491..000000000
--- a/frontends/windows/localhistory.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
-*
-* This file is part of NetSurf, http://www.netsurf-browser.org/
-*
-* NetSurf is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; version 2 of the License.
-*
-* NetSurf is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _NETSURF_WINDOWS_LOCALHISTORY_H_
-#define _NETSURF_WINDOWS_LOCALHISTORY_H_
-
-struct nsws_localhistory;
-
-void nsws_localhistory_open(struct gui_window *gw);
-void nsws_localhistory_close(struct gui_window *gw);
-
-/* creates localhistory window */
-struct nsws_localhistory *nsws_window_create_localhistory(struct gui_window *gw);
-
-nserror nsws_create_localhistory_class(HINSTANCE hinstance);
-
-#endif
diff --git a/frontends/windows/main.c b/frontends/windows/main.c
index 442c71b06..a3a7c2b39 100644
--- a/frontends/windows/main.c
+++ b/frontends/windows/main.c
@@ -46,7 +46,7 @@
#include "windows/corewindow.h"
#include "windows/ssl_cert.h"
#include "windows/download.h"
-#include "windows/localhistory.h"
+#include "windows/local_history.h"
#include "windows/window.h"
#include "windows/schedule.h"
#include "windows/font.h"
@@ -99,7 +99,7 @@ static nserror get_config_home(char **config_home_out)
*config_home_out = strdup(adPath);
- LOG("using config path \"%s\"", *config_home_out);
+ NSLOG(netsurf, INFO, "using config path \"%s\"", *config_home_out);
return NSERROR_OK;
}
@@ -343,15 +343,16 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
/* Locate the correct user configuration directory path */
ret = get_config_home(&nsw32_config_home);
if (ret != NSERROR_OK) {
- LOG("Unable to locate a configuration directory.");
+ NSLOG(netsurf, INFO,
+ "Unable to locate a configuration directory.");
nsw32_config_home = NULL;
}
/* Initialise user options */
ret = nsw32_option_init(&argc, argv);
if (ret != NSERROR_OK) {
- LOG("Options failed to initialise (%s)\n",
- messages_get_errorcode(ret));
+ NSLOG(netsurf, INFO, "Options failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
return 1;
}
@@ -365,17 +366,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
/* common initialisation */
ret = netsurf_init(NULL);
if (ret != NSERROR_OK) {
- LOG("NetSurf failed to initialise");
+ NSLOG(netsurf, INFO, "NetSurf failed to initialise");
return 1;
}
urldb_load(nsoption_charp(url_file));
urldb_load_cookies(nsoption_charp(cookie_file));
- hotlist_init(nsoption_charp(hotlist_path));
+ hotlist_init(nsoption_charp(hotlist_path),
+ nsoption_charp(hotlist_path));
ret = nsws_create_main_class(hInstance);
ret = nsws_create_drawable_class(hInstance);
- ret = nsws_create_localhistory_class(hInstance);
ret = nsw32_create_corewindow_class(hInstance);
ret = nsws_create_cert_verify_class(hInstance);
@@ -392,7 +393,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
addr = NETSURF_HOMEPAGE;
}
- LOG("calling browser_window_create");
+ NSLOG(netsurf, INFO, "calling browser_window_create");
ret = nsurl_create(addr, &url);
if (ret == NSERROR_OK) {
@@ -418,5 +419,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
/* finalise options */
nsoption_finalise(nsoptions, nsoptions_default);
+ /* finalise logging */
+ nslog_finalise();
+
return 0;
}
diff --git a/frontends/windows/plot.c b/frontends/windows/plot.c
index fd2961957..4d9096d75 100644
--- a/frontends/windows/plot.c
+++ b/frontends/windows/plot.c
@@ -17,6 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * win32 plotter implementation.
+ */
+
#include "utils/config.h"
#include <sys/types.h>
#include <stdint.h>
@@ -36,458 +41,23 @@
#include "windows/gui.h"
#include "windows/plot.h"
-
-/* set NSWS_PLOT_DEBUG to 0 for no debugging, 1 for debugging */
-/* #define NSWS_PLOT_DEBUG */
-
-#ifdef NSWS_PLOT_DEBUG
-#define PLOT_LOG(x...) LOG(x)
-#else
-#define PLOT_LOG(x...) ((void) 0)
-#endif
-
HDC plot_hdc;
-static RECT plot_clip; /* currently set clipping rectangle */
-
-static bool clip(const struct rect *clip)
-{
- PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1);
-
- plot_clip.left = clip->x0;
- plot_clip.top = clip->y0;
- plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */
- plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */
-
- return true;
-}
-
-static bool line(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- /* windows 0x00bbggrr */
- DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type ==
- PLOT_OP_TYPE_DOT) ? PS_DOT :
- (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH:
- 0);
- LOGBRUSH lb = {BS_SOLID, col, 0};
- HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (bak == NULL) {
- DeleteObject(pen);
- DeleteObject(clipregion);
- return false;
- }
-/*
- RECT r;
- r.left = x0;
- r.top = y0;
- r.right = x1;
- r.bottom = y1;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- MoveToEx(plot_hdc, x0, y0, (LPPOINT) NULL);
-
- LineTo(plot_hdc, x1, y1);
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, bak);
-
- DeleteObject(pen);
- DeleteObject(clipregion);
-
- return true;
-}
-
-static bool rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- PLOT_LOG("rectangle from %d,%d to %d,%d", x0, y0, x1, y1);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- x1++;
- y1++;
-
- COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- DWORD penstyle = PS_GEOMETRIC |
- (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT :
- (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH :
- (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL :
- 0)));
- LOGBRUSH lb = {BS_SOLID, pencol, 0};
- LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0};
- if (style->fill_type == PLOT_OP_TYPE_NONE)
- lb1.lbStyle = BS_HOLLOW;
-
- HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
- if (pen == NULL) {
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateBrushIndirect(&lb1);
- if (brush == NULL) {
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
- if (brushbak == NULL) {
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
-
- SelectClipRgn(plot_hdc, clipregion);
-
- Rectangle(plot_hdc, x0, y0, x1, y1);
-
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- SelectClipRgn(plot_hdc, NULL);
- DeleteObject(pen);
- DeleteObject(brush);
- DeleteObject(clipregion);
-
- return true;
-}
-
-
-static bool polygon(const int *p, unsigned int n, const plot_style_t *style)
-{
- PLOT_LOG("polygon %d points", n);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- POINT points[n];
- unsigned int i;
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF);
- COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HPEN penbak = SelectObject(plot_hdc, pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateSolidBrush(brushcol);
- if (brush == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brushbak = SelectObject(plot_hdc, brush);
- if (brushbak == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
- SetPolyFillMode(plot_hdc, WINDING);
- for (i = 0; i < n; i++) {
- points[i].x = (long) p[2 * i];
- points[i].y = (long) p[2 * i + 1];
-
- PLOT_LOG("%ld,%ld ", points[i].x, points[i].y);
- }
-
- SelectClipRgn(plot_hdc, clipregion);
-
- if (n >= 2)
- Polygon(plot_hdc, points, n);
-
- SelectClipRgn(plot_hdc, NULL);
-
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
- DeleteObject(brush);
-
- return true;
-}
-
-
-static bool text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *style)
-{
- PLOT_LOG("words %s at %d,%d", text, x, y);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- HFONT fontbak, font = get_font(style);
- if (font == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- int wlen;
- SIZE s;
- LPWSTR wstring;
- fontbak = (HFONT) SelectObject(plot_hdc, font);
- GetTextExtentPoint(plot_hdc, text, length, &s);
-
-/*
- RECT r;
- r.left = x;
- r.top = y - (3 * s.cy) / 4;
- r.right = x + s.cx;
- r.bottom = y + s.cy / 4;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT);
- if ((style->background & 0xFF000000) != 0x01000000)
- /* 100% alpha */
- SetBkColor(plot_hdc, (DWORD) (style->background & 0x00FFFFFF));
- SetBkMode(plot_hdc, TRANSPARENT);
- SetTextColor(plot_hdc, (DWORD) (style->foreground & 0x00FFFFFF));
-
- wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0);
- wstring = malloc(2 * (wlen + 1));
- if (wstring == NULL) {
- return false;
- }
- MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen);
- TextOutW(plot_hdc, x, y, wstring, wlen);
-
- SelectClipRgn(plot_hdc, NULL);
- free(wstring);
- font = SelectObject(plot_hdc, fontbak);
- DeleteObject(clipregion);
- DeleteObject(font);
-
- return true;
-}
-
-static bool disc(int x, int y, int radius, const plot_style_t *style)
-{
- PLOT_LOG("disc at %d,%d radius %d", x, y, radius);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour)
- & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateSolidBrush(col);
- if (brush == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
- if (brushbak == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
-/*
- RECT r;
- r.left = x - radius;
- r.top = y - radius;
- r.right = x + radius;
- r.bottom = y + radius;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- if (style->fill_type == PLOT_OP_TYPE_NONE)
- Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
- x - radius, y - radius,
- x - radius, y - radius);
- else
- Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius);
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
- DeleteObject(brush);
-
- return true;
-}
-
-static bool arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style)
-{
- PLOT_LOG("arc centre %d,%d radius %d from %d to %d", x, y, radius,
- angle1, angle2);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
-
- int q1, q2;
- double a1=1.0, a2=1.0, b1=1.0, b2=1.0;
- q1 = (int) ((angle1 + 45) / 90) - 45;
- q2 = (int) ((angle2 + 45) / 90) - 45;
- while (q1 > 4)
- q1 -= 4;
- while (q2 > 4)
- q2 -= 4;
- while (q1 <= 0)
- q1 += 4;
- while (q2 <= 0)
- q2 += 4;
- angle1 = ((angle1 + 45) % 90) - 45;
- angle2 = ((angle2 + 45) % 90) - 45;
+/** currently set clipping rectangle */
+static RECT plot_clip;
- switch(q1) {
- case 1:
- a1 = 1.0;
- b1 = -tan((M_PI / 180) * angle1);
- break;
- case 2:
- b1 = -1.0;
- a1 = -tan((M_PI / 180) * angle1);
- break;
- case 3:
- a1 = -1.0;
- b1 = tan((M_PI / 180) * angle1);
- break;
- case 4:
- b1 = 1.0;
- a1 = tan((M_PI / 180) * angle1);
- break;
- }
- switch(q2) {
- case 1:
- a2 = 1.0;
- b2 = -tan((M_PI / 180) * angle2);
- break;
- case 2:
- b2 = -1.0;
- a2 = -tan((M_PI / 180) * angle2);
- break;
- case 3:
- a2 = -1.0;
- b2 = tan((M_PI / 180) * angle2);
- break;
- case 4:
- b2 = 1.0;
- a2 = tan((M_PI / 180) * angle2);
- break;
- }
-
-/*
- RECT r;
- r.left = x - radius;
- r.top = y - radius;
- r.right = x + radius;
- r.bottom = y + radius;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
- x + (int)(a1 * radius), y + (int)(b1 * radius),
- x + (int)(a2 * radius), y + (int)(b2 * radius));
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, penbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
-
- return true;
-}
-
-static bool
+/**
+ * bitmap helper to plot a solid block of colour
+ *
+ * \param col colour to plot with
+ * \param x the x coordinate to plot at
+ * \param y the y coordinate to plot at
+ * \param width the width of block to plot
+ * \param height the height to plot
+ * \return NSERROR_OK on sucess else error code.
+ */
+static nserror
plot_block(COLORREF col, int x, int y, int width, int height)
{
HRGN clipregion;
@@ -499,24 +69,24 @@ plot_block(COLORREF col, int x, int y, int width, int height)
(y >= plot_clip.bottom) ||
((y + height) < plot_clip.top)) {
/* Image completely outside clip region */
- return true;
- }
+ return NSERROR_OK;
+ }
/* ensure the plot HDC is set */
if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
}
clipregion = CreateRectRgnIndirect(&plot_clip);
if (clipregion == NULL) {
- return false;
+ return NSERROR_INVALID;
}
SelectClipRgn(plot_hdc, clipregion);
/* Saving the original pen object */
- original = SelectObject(plot_hdc,GetStockObject(DC_PEN));
+ original = SelectObject(plot_hdc,GetStockObject(DC_PEN));
SelectObject(plot_hdc, GetStockObject(DC_PEN));
SelectObject(plot_hdc, GetStockObject(DC_BRUSH));
@@ -528,15 +98,28 @@ plot_block(COLORREF col, int x, int y, int width, int height)
DeleteObject(clipregion);
- return true;
+ return NSERROR_OK;
}
-/* blunt force truma way of achiving alpha blended plotting */
-static bool
-plot_alpha_bitmap(HDC hdc,
- struct bitmap *bitmap,
- int x, int y,
+
+/**
+ * plot an alpha blended bitmap
+ *
+ * blunt force truma way of achiving alpha blended plotting
+ *
+ * \param hdc drawing cotext
+ * \param bitmap bitmap to render
+ * \param x x coordinate to plot at
+ * \param y y coordinate to plot at
+ * \param width The width to plot the bitmap into
+ * \param height The height to plot the bitmap into
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+static nserror
+plot_alpha_bitmap(HDC hdc,
+ struct bitmap *bitmap,
+ int x, int y,
int width, int height)
{
#ifdef WINDOWS_GDI_ALPHA_WORKED
@@ -545,15 +128,17 @@ plot_alpha_bitmap(HDC hdc,
bool bltres;
bmihdc = CreateCompatibleDC(hdc);
SelectObject(bmihdc, bitmap->windib);
- bltres = AlphaBlend(hdc,
- x, y,
+ bltres = AlphaBlend(hdc,
+ x, y,
width, height,
bmihdc,
- 0, 0,
+ 0, 0,
bitmap->width, bitmap->height,
blnd);
DeleteDC(bmihdc);
- return bltres;
+ if (!bltres) {
+ return NSERROR_INVALID;
+ }
#else
HDC Memhdc;
BITMAPINFOHEADER bmih;
@@ -564,21 +149,25 @@ plot_alpha_bitmap(HDC hdc,
BITMAPINFO *bmi;
HBITMAP MemBMh;
- PLOT_LOG("%p bitmap %d,%d width %d height %d", bitmap, x, y, width, height);
- PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom);
+ NSLOG(plot, DEEPDEBUG, "%p bitmap %d,%d width %d height %d",
+ bitmap, x, y, width, height);
+ NSLOG(plot, DEEPDEBUG, "clipped %ld,%ld to %ld,%ld",
+ plot_clip.left, plot_clip.top,
+ plot_clip.right, plot_clip.bottom);
Memhdc = CreateCompatibleDC(hdc);
if (Memhdc == NULL) {
- return false;
+ return NSERROR_INVALID;
}
- if ((bitmap->width != width) ||
+ if ((bitmap->width != width) ||
(bitmap->height != height)) {
- PLOT_LOG("scaling from %d,%d to %d,%d",
- bitmap->width, bitmap->height, width, height);
+ NSLOG(plot, DEEPDEBUG, "scaling from %d,%d to %d,%d",
+ bitmap->width, bitmap->height, width, height);
bitmap = bitmap_scale(bitmap, width, height);
- if (bitmap == NULL)
- return false;
+ if (bitmap == NULL) {
+ return NSERROR_INVALID;
+ }
isscaled = true;
}
@@ -586,14 +175,14 @@ plot_alpha_bitmap(HDC hdc,
(bitmap->width * bitmap->height * 4));
if (bmi == NULL) {
DeleteDC(Memhdc);
- return false;
+ return NSERROR_INVALID;
}
MemBMh = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height);
if (MemBMh == NULL){
free(bmi);
DeleteDC(Memhdc);
- return false;
+ return NSERROR_INVALID;
}
/* save 'background' data for alpha channel work */
@@ -655,7 +244,7 @@ plot_alpha_bitmap(HDC hdc,
}
}
SetDIBitsToDevice(hdc, x, y, bitmap->width, bitmap->height,
- 0, 0, 0, bitmap->height,
+ 0, 0, 0, bitmap->height,
(const void *) bmi->bmiColors,
bmi, DIB_RGB_COLORS);
@@ -667,16 +256,27 @@ plot_alpha_bitmap(HDC hdc,
free(bmi);
DeleteObject(MemBMh);
DeleteDC(Memhdc);
- return true;
#endif
+
+ return NSERROR_OK;
}
-static bool
+/**
+ * Internal bitmap plotting
+ *
+ * \param bitmap The bitmap to plot
+ * \param x x coordinate to plot at
+ * \param y y coordinate to plot at
+ * \param width The width to plot the bitmap into
+ * \param height The height to plot the bitmap into
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+static nserror
plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
{
- int bltres;
HRGN clipregion;
+ nserror res = NSERROR_OK;
/* Bail early if we can */
if ((x >= plot_clip.right) ||
@@ -684,25 +284,26 @@ plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
(y >= plot_clip.bottom) ||
((y + height) < plot_clip.top)) {
/* Image completely outside clip region */
- return true;
- }
+ return NSERROR_OK;
+ }
/* ensure the plot HDC is set */
if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
}
clipregion = CreateRectRgnIndirect(&plot_clip);
if (clipregion == NULL) {
- return false;
+ return NSERROR_INVALID;
}
SelectClipRgn(plot_hdc, clipregion);
if (bitmap->opaque) {
+ int bltres;
/* opaque bitmap */
- if ((bitmap->width == width) &&
+ if ((bitmap->width == width) &&
(bitmap->height == height)) {
/* unscaled */
bltres = SetDIBitsToDevice(plot_hdc,
@@ -717,36 +318,549 @@ plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
} else {
/* scaled */
SetStretchBltMode(plot_hdc, COLORONCOLOR);
- bltres = StretchDIBits(plot_hdc,
- x, y,
+ bltres = StretchDIBits(plot_hdc,
+ x, y,
width, height,
- 0, 0,
+ 0, 0,
bitmap->width, bitmap->height,
- bitmap->pixdata,
- (BITMAPINFO *)bitmap->pbmi,
- DIB_RGB_COLORS,
+ bitmap->pixdata,
+ (BITMAPINFO *)bitmap->pbmi,
+ DIB_RGB_COLORS,
SRCCOPY);
}
+ /* check to see if GDI operation failed */
+ if (bltres == 0) {
+ res = NSERROR_INVALID;
+ }
+ NSLOG(plot, DEEPDEBUG, "bltres = %d", bltres);
} else {
/* Bitmap with alpha.*/
- bltres = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height);
+ res = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height);
}
- PLOT_LOG("bltres = %d", bltres);
+ DeleteObject(clipregion);
+
+ return res;
+}
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ NSLOG(plot, DEEPDEBUG, "clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1);
+
+ plot_clip.left = clip->x0;
+ plot_clip.top = clip->y0;
+ plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */
+ plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y,
+ int radius, int angle1, int angle2)
+{
+ NSLOG(plot, DEEPDEBUG, "arc centre %d,%d radius %d from %d to %d", x, y, radius,
+ angle1, angle2);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+
+ int q1, q2;
+ double a1=1.0, a2=1.0, b1=1.0, b2=1.0;
+ q1 = (int) ((angle1 + 45) / 90) - 45;
+ q2 = (int) ((angle2 + 45) / 90) - 45;
+ while (q1 > 4)
+ q1 -= 4;
+ while (q2 > 4)
+ q2 -= 4;
+ while (q1 <= 0)
+ q1 += 4;
+ while (q2 <= 0)
+ q2 += 4;
+ angle1 = ((angle1 + 45) % 90) - 45;
+ angle2 = ((angle2 + 45) % 90) - 45;
+
+ switch(q1) {
+ case 1:
+ a1 = 1.0;
+ b1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 2:
+ b1 = -1.0;
+ a1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 3:
+ a1 = -1.0;
+ b1 = tan((M_PI / 180) * angle1);
+ break;
+ case 4:
+ b1 = 1.0;
+ a1 = tan((M_PI / 180) * angle1);
+ break;
+ }
+
+ switch(q2) {
+ case 1:
+ a2 = 1.0;
+ b2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 2:
+ b2 = -1.0;
+ a2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 3:
+ a2 = -1.0;
+ b2 = tan((M_PI / 180) * angle2);
+ break;
+ case 4:
+ b2 = 1.0;
+ a2 = tan((M_PI / 180) * angle2);
+ break;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x + (int)(a1 * radius), y + (int)(b1 * radius),
+ x + (int)(a2 * radius), y + (int)(b2 * radius));
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
DeleteObject(clipregion);
+ DeleteObject(pen);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ NSLOG(plot, DEEPDEBUG, "disc at %d,%d radius %d", x, y, radius);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour)
+ & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateSolidBrush(col);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
- return true;
+ SelectClipRgn(plot_hdc, clipregion);
+ if (style->fill_type == PLOT_OP_TYPE_NONE) {
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x - radius, y - radius,
+ x - radius, y - radius);
+ } else {
+ Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius);
+ }
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return NSERROR_OK;
}
-static bool
-windows_plot_bitmap(int x, int y,
- int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
+{
+ NSLOG(plot, DEEPDEBUG, "from %d,%d to %d,%d",
+ line->x0, line->y0, line->x1, line->y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ /* windows 0x00bbggrr */
+ DWORD penstyle = PS_GEOMETRIC |
+ ((style->stroke_type == PLOT_OP_TYPE_DOT) ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH:
+ 0);
+ LOGBRUSH lb = {BS_SOLID, col, 0};
+ HPEN pen = ExtCreatePen(penstyle,
+ plot_style_fixed_to_int(style->stroke_width),
+ &lb, 0, NULL);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (bak == NULL) {
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ MoveToEx(plot_hdc, line->x0, line->y0, (LPPOINT) NULL);
+
+ LineTo(plot_hdc, line->x1, line->y1);
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, bak);
+
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
+{
+ NSLOG(plot, DEEPDEBUG, "rectangle from %d,%d to %d,%d",
+ rect->x0, rect->y0, rect->x1, rect->y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ DWORD penstyle = PS_GEOMETRIC |
+ (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH :
+ (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL :
+ 0)));
+ LOGBRUSH lb = {BS_SOLID, pencol, 0};
+ LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0};
+ if (style->fill_type == PLOT_OP_TYPE_NONE)
+ lb1.lbStyle = BS_HOLLOW;
+
+ HPEN pen = ExtCreatePen(penstyle,
+ plot_style_fixed_to_int(style->stroke_width),
+ &lb, 0, NULL);
+ if (pen == NULL) {
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateBrushIndirect(&lb1);
+ if (brush == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ /* windows GDI call coordinates are inclusive */
+ Rectangle(plot_hdc, rect->x0, rect->y0, rect->x1 + 1, rect->y1 + 1);
+
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ SelectClipRgn(plot_hdc, NULL);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ DeleteObject(clipregion);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param style Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
+{
+ NSLOG(plot, DEEPDEBUG, "polygon %d points", n);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ POINT points[n];
+ unsigned int i;
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HPEN penbak = SelectObject(plot_hdc, pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateSolidBrush(brushcol);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brushbak = SelectObject(plot_hdc, brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
+ SetPolyFillMode(plot_hdc, WINDING);
+ for (i = 0; i < n; i++) {
+ points[i].x = (long) p[2 * i];
+ points[i].y = (long) p[2 * i + 1];
+
+ NSLOG(plot, DEEPDEBUG, "%ld,%ld ", points[i].x, points[i].y);
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (n >= 2) {
+ Polygon(plot_hdc, points, n);
+ }
+
+ SelectClipRgn(plot_hdc, NULL);
+
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6])
+{
+ NSLOG(plot, DEEPDEBUG, "path unimplemented");
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
int xf,yf;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
@@ -754,16 +868,16 @@ windows_plot_bitmap(int x, int y,
/* Bail early if we can */
- PLOT_LOG("Plotting %p at %d,%d by %d,%d",bitmap, x,y,width,height);
+ NSLOG(plot, DEEPDEBUG, "Plotting %p at %d,%d by %d,%d",bitmap, x,y,width,height);
if (bitmap == NULL) {
- LOG("Passed null bitmap!");
- return true;
+ NSLOG(netsurf, INFO, "Passed null bitmap!");
+ return NSERROR_OK;
}
/* check if nothing to plot */
if (width == 0 || height == 0)
- return true;
+ return NSERROR_OK;
/* x and y define coordinate of top left of of the initial explicitly
* placed tile. The width and height are the image scaling and the
@@ -775,9 +889,13 @@ windows_plot_bitmap(int x, int y,
/* Not repeating at all, so just plot it */
if ((bitmap->width == 1) && (bitmap->height == 1)) {
if ((*(bitmap->pixdata + 3) & 0xff) == 0) {
- return true;
+ return NSERROR_OK;
}
- return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, x, y, x + width, y + height);
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ x,
+ y,
+ x + width,
+ y + height);
} else {
return plot_bitmap(bitmap, x, y, width, height);
@@ -788,41 +906,47 @@ windows_plot_bitmap(int x, int y,
* of the area. Can only be done when image is fully opaque. */
if ((bitmap->width == 1) && (bitmap->height == 1)) {
if ((*(COLORREF *)bitmap->pixdata & 0xff000000) != 0) {
- return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
- plot_clip.left,
- plot_clip.top,
- plot_clip.right,
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
plot_clip.bottom);
}
}
/* Optimise tiled plots of bitmaps scaled to 1x1 by replacing with
* a flat fill of the area. Can only be done when image is fully
- * opaque. */
+ * opaque.
+ */
if ((width == 1) && (height == 1)) {
if (bitmap->opaque) {
/** TODO: Currently using top left pixel. Maybe centre
* pixel or average value would be better. */
- return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
- plot_clip.left,
- plot_clip.top,
- plot_clip.right,
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
plot_clip.bottom);
}
}
- PLOT_LOG("Tiled plotting %d,%d by %d,%d",x,y,width,height);
- PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom);
+ NSLOG(plot, DEEPDEBUG, "Tiled plotting %d,%d by %d,%d", x, y, width, height);
+ NSLOG(plot, DEEPDEBUG, "clipped %ld,%ld to %ld,%ld",
+ plot_clip.left, plot_clip.top,
+ plot_clip.right, plot_clip.bottom);
/* get left most tile position */
- if (repeat_x)
+ if (repeat_x) {
for (; x > plot_clip.left; x -= width);
+ }
/* get top most tile position */
- if (repeat_y)
+ if (repeat_y) {
for (; y > plot_clip.top; y -= height);
+ }
- PLOT_LOG("repeat from %d,%d to %ld,%ld", x, y, plot_clip.right, plot_clip.bottom);
+ NSLOG(plot, DEEPDEBUG, "repeat from %d,%d to %ld,%ld",
+ x, y, plot_clip.right, plot_clip.bottom);
/* tile down and across to extents */
for (xf = x; xf < plot_clip.right; xf += width) {
@@ -833,25 +957,86 @@ windows_plot_bitmap(int x, int y,
break;
}
if (!repeat_x)
- break;
+ break;
}
- return true;
+ return NSERROR_OK;
}
-static bool flush(void)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- PLOT_LOG("flush unimplemented");
- return true;
-}
+ NSLOG(plot, DEEPDEBUG, "words %s at %d,%d", text, x, y);
-static bool path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- PLOT_LOG("path unimplemented");
- return true;
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ NSLOG(netsurf, INFO, "HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ HFONT fontbak, font = get_font(fstyle);
+ if (font == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ int wlen;
+ SIZE s;
+ LPWSTR wstring;
+ fontbak = (HFONT) SelectObject(plot_hdc, font);
+ GetTextExtentPoint(plot_hdc, text, length, &s);
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT);
+ if ((fstyle->background & 0xFF000000) != 0x01000000) {
+ /* 100% alpha */
+ SetBkColor(plot_hdc, (DWORD) (fstyle->background & 0x00FFFFFF));
+ }
+ SetBkMode(plot_hdc, TRANSPARENT);
+ SetTextColor(plot_hdc, (DWORD) (fstyle->foreground & 0x00FFFFFF));
+
+ wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0);
+ wstring = malloc(2 * (wlen + 1));
+ if (wstring == NULL) {
+ return NSERROR_INVALID;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen);
+ TextOutW(plot_hdc, x, y, wstring, wlen);
+
+ SelectClipRgn(plot_hdc, NULL);
+ free(wstring);
+ font = SelectObject(plot_hdc, fontbak);
+ DeleteObject(clipregion);
+ DeleteObject(font);
+
+ return NSERROR_OK;
}
+
+/**
+ * win32 API plot operation table
+ */
const struct plotter_table win_plotters = {
.rectangle = rectangle,
.line = line,
@@ -860,8 +1045,7 @@ const struct plotter_table win_plotters = {
.text = text,
.disc = disc,
.arc = arc,
- .bitmap = windows_plot_bitmap,
- .flush = flush,
+ .bitmap = bitmap,
.path = path,
.option_knockout = true,
};
diff --git a/frontends/windows/prefs.c b/frontends/windows/prefs.c
index 03414ee9f..591b57426 100644
--- a/frontends/windows/prefs.c
+++ b/frontends/windows/prefs.c
@@ -16,6 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * win32 preferences dialog implementation.
+ */
+
#include "utils/config.h"
#include <windows.h>
@@ -31,9 +36,19 @@
#include "windows/resourceid.h"
#include "windows/windbg.h"
+/** Preferences dialog width */
#define NSWS_PREFS_WINDOW_WIDTH 600
+/** Preferences dialog height */
#define NSWS_PREFS_WINDOW_HEIGHT 400
+
+/**
+ * Prepare preferences dialog font tab
+ *
+ * \param fontfamily The font family
+ * \param parent The parent window win32 handle
+ * \return The selected font or NULL on error
+ */
static CHOOSEFONT *nsws_prefs_font_prepare(int fontfamily, HWND parent)
{
CHOOSEFONT *cf = malloc(sizeof(CHOOSEFONT));
@@ -81,6 +96,15 @@ static CHOOSEFONT *nsws_prefs_font_prepare(int fontfamily, HWND parent)
return cf;
}
+
+/**
+ * Update value in spinner control when it is changed
+ *
+ * \param sub The window handle of the spinner control
+ * \param change The amount the control changed by
+ * \param minval The minimum allowed value of the control
+ * \param maxval The maximum allowed value of the control
+ */
static void change_spinner(HWND sub, double change, double minval, double maxval)
{
char *temp, number[6];
@@ -90,8 +114,9 @@ static void change_spinner(HWND sub, double change, double minval, double maxval
len = SendMessage(sub, WM_GETTEXTLENGTH, 0, 0);
temp = malloc(len + 1);
- if (temp == NULL)
+ if (temp == NULL) {
return;
+ }
SendMessage(sub, WM_GETTEXT, (WPARAM)(len + 1), (LPARAM) temp);
@@ -101,17 +126,29 @@ static void change_spinner(HWND sub, double change, double minval, double maxval
value = max(value, minval);
value = min(value, maxval);
- if ((change == 1.0) || (change == -1.0))
+ if ((change == 1.0) || (change == -1.0)) {
snprintf(number, 6, "%.0f", value);
- else
+ } else {
snprintf(number, 6, "%.1f", value);
+ }
SendMessage(sub, WM_SETTEXT, 0, (LPARAM)number);
}
+/**
+ * Handle messages to the appearance preference dialog
+ *
+ * \param hwnd The win32 handle of the appearance dialog
+ * \param msg The message code
+ * \param wparam The message w parameter
+ * \param lParam The message l parameter
+ * \return result appropriate for message
+ */
static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
- UINT msg, WPARAM wparam, LPARAM lParam)
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lParam)
{
int len;
char *temp, number[6];
@@ -192,7 +229,7 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
/* animation */
sub = GetDlgItem(hwnd, IDC_PREFS_NOANIMATION);
SendMessage(sub, BM_SETCHECK, (WPARAM)((nsoption_bool(animate_images))
- ? BST_UNCHECKED : BST_CHECKED), 0);
+ ? BST_UNCHECKED : BST_CHECKED), 0);
if (nsoption_int(minimum_gif_delay) != 0) {
sub = GetDlgItem(hwnd, IDC_PREFS_ANIMATIONDELAY);
@@ -222,13 +259,13 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
if (temp != NULL) {
SendMessage(sub, WM_GETTEXT, (WPARAM)
(len + 1), (LPARAM) temp);
- nsoption_set_int(font_min_size,
+ nsoption_set_int(font_min_size,
(int)(10 * strtod(temp, NULL)));
free(temp);
}
/* animation */
- nsoption_set_bool(animate_images,
+ nsoption_set_bool(animate_images,
(IsDlgButtonChecked(hwnd, IDC_PREFS_NOANIMATION) == BST_CHECKED) ? true : false);
@@ -259,7 +296,7 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
case IDC_PREFS_ANIMATIONDELAY_SPIN:
change_spinner(GetDlgItem(hwnd, IDC_PREFS_ANIMATIONDELAY), 0.1 * ud->iDelta, 0.1, 100.0);
return TRUE;
-
+
}
}
break;
@@ -267,7 +304,8 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
case WM_COMMAND:
- LOG("WM_COMMAND Identifier 0x%x",LOWORD(wparam));
+ NSLOG(netsurf, INFO, "WM_COMMAND Identifier 0x%x",
+ LOWORD(wparam));
switch(LOWORD(wparam)) {
case IDC_PREFS_PROXYTYPE:
@@ -276,8 +314,8 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
SendMessage(sub, CB_GETCURSEL, 0, 0) - 1);
nsoption_set_bool(http_proxy,
(nsoption_int(http_proxy_auth) != -1));
- nsoption_set_int(http_proxy_auth,
- nsoption_int(http_proxy_auth) +
+ nsoption_set_int(http_proxy_auth,
+ nsoption_int(http_proxy_auth) +
(nsoption_bool(http_proxy)) ? 0 : 1);
break;
@@ -288,7 +326,7 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
}
if (ChooseFont(cf) == TRUE) {
- nsoption_set_charp(font_sans,
+ nsoption_set_charp(font_sans,
strdup(cf->lpLogFont->lfFaceName));
}
@@ -390,12 +428,12 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
break;
}
- case IDC_PREFS_FONTDEF:
+ case IDC_PREFS_FONTDEF:
sub = GetDlgItem(hwnd, IDC_PREFS_FONTDEF);
nsoption_set_int(font_default,
SendMessage(sub, CB_GETCURSEL, 0, 0) + 1);
break;
-
+
}
break;
@@ -403,8 +441,20 @@ static BOOL CALLBACK options_appearance_dialog_handler(HWND hwnd,
return FALSE;
}
+
+/**
+ * Handle messages to the connections preference dialog
+ *
+ * \param hwnd The win32 handle of the connections dialog
+ * \param msg The message code
+ * \param wparam The message w parameter
+ * \param lParam The message l parameter
+ * \return result appropriate for message
+ */
static BOOL CALLBACK options_connections_dialog_handler(HWND hwnd,
- UINT msg, WPARAM wparam, LPARAM lParam)
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lParam)
{
int len;
char *temp, number[6];
@@ -562,8 +612,20 @@ static BOOL CALLBACK options_connections_dialog_handler(HWND hwnd,
return FALSE;
}
+
+/**
+ * Handle messages to the general preference dialog
+ *
+ * \param hwnd The win32 handle of the general dialog
+ * \param msg The message code
+ * \param wparam The message w parameter
+ * \param lParam The message l parameter
+ * \return result appropriate for message
+ */
static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
- UINT msg, WPARAM wparam, LPARAM lParam)
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lParam)
{
HWND sub;
@@ -577,21 +639,21 @@ static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
/* Display images */
sub = GetDlgItem(hwnd, IDC_PREFS_IMAGES);
- SendMessage(sub, BM_SETCHECK,
- (WPARAM) ((nsoption_bool(suppress_images)) ?
- BST_CHECKED : BST_UNCHECKED), 0);
+ SendMessage(sub, BM_SETCHECK,
+ (WPARAM) ((nsoption_bool(suppress_images)) ?
+ BST_CHECKED : BST_UNCHECKED), 0);
/* advert blocking */
sub = GetDlgItem(hwnd, IDC_PREFS_ADVERTS);
- SendMessage(sub, BM_SETCHECK,
- (WPARAM) ((nsoption_bool(block_advertisements)) ?
- BST_CHECKED : BST_UNCHECKED), 0);
+ SendMessage(sub, BM_SETCHECK,
+ (WPARAM) ((nsoption_bool(block_advertisements)) ?
+ BST_CHECKED : BST_UNCHECKED), 0);
/* Referrer sending */
sub = GetDlgItem(hwnd, IDC_PREFS_REFERER);
- SendMessage(sub, BM_SETCHECK,
+ SendMessage(sub, BM_SETCHECK,
(WPARAM)((nsoption_bool(send_referer)) ?
- BST_CHECKED : BST_UNCHECKED), 0);
+ BST_CHECKED : BST_UNCHECKED), 0);
break;
case WM_NOTIFY:
@@ -602,8 +664,8 @@ static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
if (sub != NULL) {
int text_length;
char *text;
- text_length = SendMessage(sub,
- WM_GETTEXTLENGTH, 0, 0);
+ text_length = SendMessage(sub,
+ WM_GETTEXTLENGTH, 0, 0);
text = malloc(text_length + 1);
if (text != NULL) {
SendMessage(sub, WM_GETTEXT,
@@ -616,19 +678,20 @@ static BOOL CALLBACK options_general_dialog_handler(HWND hwnd,
nsoption_set_bool(suppress_images,
(IsDlgButtonChecked(hwnd, IDC_PREFS_IMAGES) == BST_CHECKED) ? true : false);
- nsoption_set_bool(block_advertisements, (IsDlgButtonChecked(hwnd,
- IDC_PREFS_ADVERTS) == BST_CHECKED) ? true : false);
+ nsoption_set_bool(block_advertisements,
+ (IsDlgButtonChecked(hwnd, IDC_PREFS_ADVERTS) == BST_CHECKED) ? true : false);
- nsoption_set_bool(send_referer, (IsDlgButtonChecked(hwnd,
- IDC_PREFS_REFERER) == BST_CHECKED) ? true : false);
+ nsoption_set_bool(send_referer,
+ (IsDlgButtonChecked(hwnd, IDC_PREFS_REFERER) == BST_CHECKED) ? true : false);
break;
-
+
}
}
return FALSE;
}
+
/* exported interface documented in windows/prefs.h */
nserror nsws_prefs_save(void)
{
@@ -644,6 +707,7 @@ nserror nsws_prefs_save(void)
return res;
}
+
/* exported interface documented in windows/prefs.h */
void nsws_prefs_dialog_init(HINSTANCE hinst, HWND parent)
{
diff --git a/frontends/windows/res/adblock.css b/frontends/windows/res/adblock.css
index ff2485622..0d12aaa7c 120000
--- a/frontends/windows/res/adblock.css
+++ b/frontends/windows/res/adblock.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
+../../../resources/adblock.css \ No newline at end of file
diff --git a/frontends/windows/res/ca-bundle.crt b/frontends/windows/res/ca-bundle.crt
index 0b0e416ad..1187fa51a 120000
--- a/frontends/windows/res/ca-bundle.crt
+++ b/frontends/windows/res/ca-bundle.crt
@@ -1 +1 @@
-../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
+../../../resources/ca-bundle \ No newline at end of file
diff --git a/frontends/windows/res/credits.html b/frontends/windows/res/credits.html
index 1ba17392b..b43a1a06c 120000
--- a/frontends/windows/res/credits.html
+++ b/frontends/windows/res/credits.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
+../../../resources/en/credits.html \ No newline at end of file
diff --git a/frontends/windows/res/default.css b/frontends/windows/res/default.css
index a8579eb7c..fa3ae6c26 120000
--- a/frontends/windows/res/default.css
+++ b/frontends/windows/res/default.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
+../../../resources/default.css \ No newline at end of file
diff --git a/frontends/windows/res/internal.css b/frontends/windows/res/internal.css
index 17f9f1504..5583a9811 120000
--- a/frontends/windows/res/internal.css
+++ b/frontends/windows/res/internal.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
+../../../resources/internal.css \ No newline at end of file
diff --git a/frontends/windows/res/licence.html b/frontends/windows/res/licence.html
index 147dd6db2..c0c1e6630 120000
--- a/frontends/windows/res/licence.html
+++ b/frontends/windows/res/licence.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
+../../../resources/en/licence.html \ No newline at end of file
diff --git a/frontends/windows/res/netsurf.png b/frontends/windows/res/netsurf.png
index 905512c25..d0ab72a5e 120000
--- a/frontends/windows/res/netsurf.png
+++ b/frontends/windows/res/netsurf.png
@@ -1 +1 @@
-../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
+../../../resources/netsurf.png \ No newline at end of file
diff --git a/frontends/windows/res/quirks.css b/frontends/windows/res/quirks.css
index 88aabe48c..1e752cb9e 120000
--- a/frontends/windows/res/quirks.css
+++ b/frontends/windows/res/quirks.css
@@ -1 +1 @@
-../../../!NetSurf/Resources/Quirks,f79 \ No newline at end of file
+../../../resources/quirks.css \ No newline at end of file
diff --git a/frontends/windows/res/welcome.html b/frontends/windows/res/welcome.html
index 28362130a..d5220f90a 120000
--- a/frontends/windows/res/welcome.html
+++ b/frontends/windows/res/welcome.html
@@ -1 +1 @@
-../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
+../../../resources/en/welcome.html \ No newline at end of file
diff --git a/frontends/windows/schedule.c b/frontends/windows/schedule.c
index eae6c1d63..76358ec68 100644
--- a/frontends/windows/schedule.c
+++ b/frontends/windows/schedule.c
@@ -25,12 +25,6 @@
#include "windows/schedule.h"
-#ifdef DEBUG_SCHEDULER
-#define SRLOG(x...) LOG(x)
-#else
-#define SRLOG(x...) ((void) 0)
-#endif
-
/* linked list of scheduled callbacks */
static struct nscallback *schedule_list = NULL;
@@ -66,7 +60,7 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
return NSERROR_OK;
}
- SRLOG("removing %p, %p", callback, p);
+ NSLOG(schedule, DEBUG, "removing %p, %p", callback, p);
cur_nscb = schedule_list;
prev_nscb = NULL;
@@ -76,8 +70,11 @@ static nserror schedule_remove(void (*callback)(void *p), void *p)
(cur_nscb->p == p)) {
/* item to remove */
- SRLOG("callback entry %p removing %p(%p)",
- cur_nscb, cur_nscb->callback, cur_nscb->p);
+ NSLOG(schedule, DEBUG,
+ "callback entry %p removing %p(%p)",
+ cur_nscb,
+ cur_nscb->callback,
+ cur_nscb->p);
/* remove callback */
unlnk_nscb = cur_nscb;
@@ -118,7 +115,8 @@ nserror win32_schedule(int ival, void (*callback)(void *p), void *p)
return NSERROR_NOMEM;
}
- SRLOG("adding callback %p for %p(%p) at %d cs",
+ NSLOG(schedule, DEBUG,
+ "adding callback %p for %p(%p) at %d cs",
nscb, callback, p, ival);
gettimeofday(&nscb->tv, NULL);
@@ -168,8 +166,11 @@ schedule_run(void)
prev_nscb->next = unlnk_nscb->next;
}
- SRLOG("callback entry %p running %p(%p)",
- unlnk_nscb, unlnk_nscb->callback, unlnk_nscb->p);
+ NSLOG(schedule, DEBUG,
+ "callback entry %p running %p(%p)",
+ unlnk_nscb,
+ unlnk_nscb->callback,
+ unlnk_nscb->p);
/* call callback */
unlnk_nscb->callback(unlnk_nscb->p);
@@ -201,8 +202,9 @@ schedule_run(void)
/* make returned time relative to now */
timersub(&nexttime, &tv, &rettime);
- SRLOG("returning time to next event as %ldms",
- (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
+ NSLOG(schedule, DEBUG,
+ "returning time to next event as %ldms",
+ (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000));
/* return next event time in milliseconds (24days max wait) */
return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
@@ -216,12 +218,16 @@ void list_schedule(void)
gettimeofday(&tv, NULL);
- LOG("schedule list at %ld:%ld", tv.tv_sec, tv.tv_usec);
+ NSLOG(netsurf, INFO, "schedule list at %ld:%ld", tv.tv_sec, tv.tv_usec);
cur_nscb = schedule_list;
while (cur_nscb != NULL) {
- LOG("Schedule %p at %ld:%ld", cur_nscb, cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec);
+ NSLOG(netsurf, INFO,
+ "Schedule %p at %ld:%ld",
+ cur_nscb,
+ cur_nscb->tv.tv_sec,
+ cur_nscb->tv.tv_usec);
cur_nscb = cur_nscb->next;
}
}
diff --git a/frontends/windows/ssl_cert.c b/frontends/windows/ssl_cert.c
index 72d1d3b55..4db061626 100644
--- a/frontends/windows/ssl_cert.c
+++ b/frontends/windows/ssl_cert.c
@@ -41,13 +41,18 @@
/* spacing and sizes for dialog elements from
* https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486(v=vs.85).aspx#sizingandspacing
*/
+/** dialog margin */
#define DLG_MRGN 11
+/** warning icon height */
#define WRN_ICO_H 32
+/** comand button width */
#define CMD_BTN_W 75
+/** command button height */
#define CMD_BTN_H 23
static const char windowclassname_sslcert[] = "nswssslcertwindow";
+/** win32 ssl certificate view context */
struct nsw32_sslcert_window {
struct nsw32_corewindow core;
@@ -65,15 +70,15 @@ struct nsw32_sslcert_window {
/** warning text handle */
HWND hTxt;
-
};
+
/**
- * callback for keypress on hotlist window
+ * callback for keypress on ssl certificate window
*
* \param nsw32_cw The nsw32 core window structure.
* \param nskey The netsurf key code
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
static nserror
nsw32_sslcert_viewer_key(struct nsw32_corewindow *nsw32_cw, uint32_t nskey)
@@ -89,19 +94,20 @@ nsw32_sslcert_viewer_key(struct nsw32_corewindow *nsw32_cw, uint32_t nskey)
return NSERROR_NOT_IMPLEMENTED;
}
+
/**
- * callback for mouse action on hotlist window
+ * callback for mouse action on ssl certificate window
*
* \param nsw32_cw The nsw32 core window structure.
* \param mouse_state netsurf mouse state on event
* \param x location of event
* \param y location of event
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
static nserror
nsw32_sslcert_viewer_mouse(struct nsw32_corewindow *nsw32_cw,
- browser_mouse_state mouse_state,
- int x, int y)
+ browser_mouse_state mouse_state,
+ int x, int y)
{
struct nsw32_sslcert_window *crtvrfy_win;
@@ -113,12 +119,15 @@ nsw32_sslcert_viewer_mouse(struct nsw32_corewindow *nsw32_cw,
return NSERROR_OK;
}
+
/**
- * callback on draw event for hotlist window
+ * callback on draw event for ssl certificate window
*
* \param nsw32_cw The nsw32 core window structure.
+ * \param scrollx The horizontal scroll offset.
+ * \param scrolly The vertical scroll offset.
* \param r The rectangle of the window that needs updating.
- * \return NSERROR_OK on success otherwise apropriate error code
+ * \return NSERROR_OK on success otherwise appropriate error code
*/
static nserror
nsw32_sslcert_viewer_draw(struct nsw32_corewindow *nsw32_cw,
@@ -144,6 +153,12 @@ nsw32_sslcert_viewer_draw(struct nsw32_corewindow *nsw32_cw,
}
+/**
+ * callback on close event for ssl certificate window
+ *
+ * \param nsw32_cw The nsw32 core window structure.
+ * \return NSERROR_OK on success otherwise appropriate error code
+ */
static nserror
nsw32_sslcert_viewer_close(struct nsw32_corewindow *nsw32_cw)
{
@@ -155,10 +170,10 @@ nsw32_sslcert_viewer_close(struct nsw32_corewindow *nsw32_cw)
/* exported interface documented in nsw32/ssl_cert.h */
nserror nsw32_cert_verify(struct nsurl *url,
- const struct ssl_cert_info *certs,
- unsigned long num,
- nserror (*cb)(bool proceed, void *pw),
- void *cbpw)
+ const struct ssl_cert_info *certs,
+ unsigned long num,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
{
struct nsw32_sslcert_window *ncwin;
nserror res;
@@ -176,7 +191,7 @@ nserror nsw32_cert_verify(struct nsurl *url,
return res;
}
- LOG("creating hInstance %p SSL window", hinst);
+ NSLOG(netsurf, INFO, "creating hInstance %p SSL window", hinst);
ncwin->hWnd = CreateWindowEx(0,
windowclassname_sslcert,
"SSL Certificate viewer",
@@ -193,7 +208,7 @@ nserror nsw32_cert_verify(struct nsurl *url,
hinst,
NULL);
if (ncwin->hWnd == NULL) {
- LOG("Window create failed");
+ NSLOG(netsurf, INFO, "Window create failed");
return NSERROR_NOMEM;
}
@@ -260,17 +275,17 @@ nserror nsw32_cert_verify(struct nsurl *url,
NULL,
NULL);
ncwin->hTxt = CreateWindowEx(0,
- "STATIC",
- "NetSurf failed to verify the authenticity of an SSL certificate. Verify the certificate details",
- WS_VISIBLE | WS_CHILD | SS_LEFT,
- DLG_MRGN + WRN_ICO_H + DLG_MRGN,
- DLG_MRGN + 5,
- 400,
- WRN_ICO_H - 5,
- ncwin->hWnd,
- NULL,
- NULL,
- NULL);
+ "STATIC",
+ "NetSurf failed to verify the authenticity of an SSL certificate. Verify the certificate details",
+ WS_VISIBLE | WS_CHILD | SS_LEFT,
+ DLG_MRGN + WRN_ICO_H + DLG_MRGN,
+ DLG_MRGN + 5,
+ 400,
+ WRN_ICO_H - 5,
+ ncwin->hWnd,
+ NULL,
+ NULL,
+ NULL);
SendMessage(ncwin->hTxt, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE,0));
SetProp(ncwin->hWnd, TEXT("CertWnd"), (HANDLE)ncwin);
@@ -280,8 +295,12 @@ nserror nsw32_cert_verify(struct nsurl *url,
return NSERROR_OK;
}
+
/**
* position and size ssl cert window widgets.
+ *
+ * \param hwnd The win32 handle of the window
+ * \param certwin The certificate viewer context
*/
static void
nsw32_window_ssl_cert_size(HWND hwnd, struct nsw32_sslcert_window *certwin)
@@ -318,6 +337,13 @@ nsw32_window_ssl_cert_size(HWND hwnd, struct nsw32_sslcert_window *certwin)
TRUE);
}
+
+/**
+ * Destroy a certificate viewing window
+ *
+ * \param crtwin The certificate viewer context
+ * \return NSERROR_OK on success otherwise appropriate error code
+ */
static nserror nsw32_crtvrfy_destroy(struct nsw32_sslcert_window *crtwin)
{
nserror res;
@@ -331,25 +357,29 @@ static nserror nsw32_crtvrfy_destroy(struct nsw32_sslcert_window *crtwin)
return res;
}
+
/**
- * handle command message on main browser window
+ * handle command message on ssl certificate viewing window.
*
- * \param hwnd The win32 window handle
- * \param gw win32 gui window
+ * \param hwnd The win32 window handle.
+ * \param crtwin certificate window context.
* \param notification_code notifiction code
* \param identifier notification identifier
* \param ctrl_window The win32 control window handle
- * \return apropriate response for command
+ * \return appropriate response for command
*/
static LRESULT
nsw32_window_ssl_cert_command(HWND hwnd,
- struct nsw32_sslcert_window *crtwin,
- int notification_code,
- int identifier,
- HWND ctrl_window)
+ struct nsw32_sslcert_window *crtwin,
+ int notification_code,
+ int identifier,
+ HWND ctrl_window)
{
- LOG("notification_code %x identifier %x ctrl_window %p",
- notification_code, identifier, ctrl_window);
+ NSLOG(netsurf, INFO,
+ "notification_code %x identifier %x ctrl_window %p",
+ notification_code,
+ identifier,
+ ctrl_window);
switch(identifier) {
case IDC_SSLCERT_BTN_ACCEPT:
@@ -368,6 +398,7 @@ nsw32_window_ssl_cert_command(HWND hwnd,
return 0; /* control message handled */
}
+
/**
* callback for SSL certificate window win32 events
*
@@ -378,9 +409,9 @@ nsw32_window_ssl_cert_command(HWND hwnd,
*/
static LRESULT CALLBACK
nsw32_window_ssl_cert_event_callback(HWND hwnd,
- UINT msg,
- WPARAM wparam,
- LPARAM lparam)
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lparam)
{
struct nsw32_sslcert_window *crtwin;
crtwin = GetProp(hwnd, TEXT("CertWnd"));
@@ -410,6 +441,7 @@ nsw32_window_ssl_cert_event_callback(HWND hwnd,
return DefWindowProc(hwnd, msg, wparam, lparam);
}
+
/* exported interface documented in nsw32/ssl_cert.h */
nserror nsws_create_cert_verify_class(HINSTANCE hInstance)
{
diff --git a/frontends/windows/windbg.h b/frontends/windows/windbg.h
index b2d8640f4..6cd9f97f8 100644
--- a/frontends/windows/windbg.h
+++ b/frontends/windows/windbg.h
@@ -24,11 +24,13 @@
const char *msg_num_to_name(int msg);
void win_perror(const char *lpszFunction);
-#define LOG_WIN_MSG(h, m, w, l) \
- if (((m) != WM_SETCURSOR) && \
- ((m) != WM_MOUSEMOVE) && \
- ((m) != WM_NCHITTEST) && \
- ((m) != WM_ENTERIDLE)) \
- LOG("%s, hwnd %p, w 0x%x, l 0x%Ix", msg_num_to_name(m), h, w, l);
+#define LOG_WIN_MSG(h, m, w, l) \
+ if (((m) != WM_SETCURSOR) && \
+ ((m) != WM_MOUSEMOVE) && \
+ ((m) != WM_NCHITTEST) && \
+ ((m) != WM_ENTERIDLE)) \
+ NSLOG(netsurf, INFO, \
+ "%s, hwnd %p, w 0x%x, l 0x%Ix", \
+ msg_num_to_name(m), h, w, l)
#endif
diff --git a/frontends/windows/window.c b/frontends/windows/window.c
index 94dc7c10e..90d076812 100644
--- a/frontends/windows/window.c
+++ b/frontends/windows/window.c
@@ -49,7 +49,7 @@
#include "windows/drawable.h"
#include "windows/font.h"
#include "windows/prefs.h"
-#include "windows/localhistory.h"
+#include "windows/local_history.h"
#include "windows/hotlist.h"
#include "windows/cookies.h"
#include "windows/global_history.h"
@@ -75,7 +75,7 @@ static int open_windows = 0;
* Obtain the DPI of the display.
*
* \param hwnd A win32 window handle to get the DPI for
- * \return The DPI of the device teh window is displayed on.
+ * \return The DPI of the device the window is displayed on.
*/
static int get_window_dpi(HWND hwnd)
{
@@ -88,7 +88,7 @@ static int get_window_dpi(HWND hwnd)
ReleaseDC(hwnd, hdc);
- LOG("FIX DPI %d", dpi);
+ NSLOG(netsurf, INFO, "FIX DPI %d", dpi);
return dpi;
}
@@ -99,7 +99,7 @@ static int get_window_dpi(HWND hwnd)
*
* \param gw gui window context.
*/
-static void nsws_window_set_accels(struct gui_window *w)
+static void nsws_window_set_accels(struct gui_window *gw)
{
int i, nitems = 13;
ACCEL accels[nitems];
@@ -137,7 +137,7 @@ static void nsws_window_set_accels(struct gui_window *w)
accels[12].fVirt = FVIRTKEY;
accels[12].cmd = IDM_VIEW_FULLSCREEN;
- w->acceltable = CreateAcceleratorTable(accels, nitems);
+ gw->acceltable = CreateAcceleratorTable(accels, nitems);
}
@@ -163,7 +163,9 @@ static HWND nsws_window_create(HINSTANCE hInstance, struct gui_window *gw)
gw->mainmenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU_MAIN));
gw->rclick = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU_CONTEXT));
- LOG("creating hInstance %p GUI window %p", hInstance, gw);
+ NSLOG(netsurf, INFO,
+ "creating hInstance %p GUI window %p",
+ hInstance, gw);
hwnd = CreateWindowEx(0,
windowclassname_main,
"NetSurf Browser",
@@ -181,7 +183,7 @@ static HWND nsws_window_create(HINSTANCE hInstance, struct gui_window *gw)
NULL);
if (hwnd == NULL) {
- LOG("Window create failed");
+ NSLOG(netsurf, INFO, "Window create failed");
return NULL;
}
@@ -194,9 +196,10 @@ static HWND nsws_window_create(HINSTANCE hInstance, struct gui_window *gw)
(nsoption_int(window_height) >= 100) &&
(nsoption_int(window_x) >= 0) &&
(nsoption_int(window_y) >= 0)) {
- LOG("Setting Window position %d,%d %d,%d",
- nsoption_int(window_x), nsoption_int(window_y),
- nsoption_int(window_width), nsoption_int(window_height));
+ NSLOG(netsurf, INFO,
+ "Setting Window position %d,%d %d,%d",
+ nsoption_int(window_x), nsoption_int(window_y),
+ nsoption_int(window_width), nsoption_int(window_height));
SetWindowPos(hwnd, HWND_TOP,
nsoption_int(window_x),
nsoption_int(window_y),
@@ -223,51 +226,54 @@ static HWND nsws_window_create(HINSTANCE hInstance, struct gui_window *gw)
*/
static LRESULT
nsws_window_toolbar_command(struct gui_window *gw,
- int notification_code,
- int identifier,
- HWND ctrl_window)
+ int notification_code,
+ int identifier,
+ HWND ctrl_window)
{
- LOG("notification_code %d identifier %d ctrl_window %p",
- notification_code, identifier, ctrl_window);
+ NSLOG(netsurf, INFO,
+ "notification_code %d identifier %d ctrl_window %p",
+ notification_code,
+ identifier,
+ ctrl_window);
switch(identifier) {
case IDC_MAIN_URLBAR:
switch (notification_code) {
case EN_CHANGE:
- LOG("EN_CHANGE");
+ NSLOG(netsurf, INFO, "EN_CHANGE");
break;
case EN_ERRSPACE:
- LOG("EN_ERRSPACE");
+ NSLOG(netsurf, INFO, "EN_ERRSPACE");
break;
case EN_HSCROLL:
- LOG("EN_HSCROLL");
+ NSLOG(netsurf, INFO, "EN_HSCROLL");
break;
case EN_KILLFOCUS:
- LOG("EN_KILLFOCUS");
+ NSLOG(netsurf, INFO, "EN_KILLFOCUS");
break;
case EN_MAXTEXT:
- LOG("EN_MAXTEXT");
+ NSLOG(netsurf, INFO, "EN_MAXTEXT");
break;
case EN_SETFOCUS:
- LOG("EN_SETFOCUS");
+ NSLOG(netsurf, INFO, "EN_SETFOCUS");
break;
case EN_UPDATE:
- LOG("EN_UPDATE");
+ NSLOG(netsurf, INFO, "EN_UPDATE");
break;
case EN_VSCROLL:
- LOG("EN_VSCROLL");
+ NSLOG(netsurf, INFO, "EN_VSCROLL");
break;
default:
- LOG("Unknown notification_code");
+ NSLOG(netsurf, INFO, "Unknown notification_code");
break;
}
break;
@@ -421,7 +427,7 @@ nsws_window_urlbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
case WM_DESTROY:
hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
if (hFont != NULL) {
- LOG("Destroyed font object");
+ NSLOG(netsurf, INFO, "Destroyed font object");
DeleteObject(hFont);
}
@@ -446,7 +452,7 @@ nsws_window_urlbar_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
/**
* create a urlbar and message handler
*
- * Create an Edit control for enerting urls
+ * Create an Edit control for entering urls
*
* \param hInstance The application instance handle.
* \param hWndParent The containing window.
@@ -491,8 +497,8 @@ nsws_window_urlbar_create(HINSTANCE hInstance,
/* subclass the message handler */
urlproc = (WNDPROC)SetWindowLongPtr(hwnd,
- GWLP_WNDPROC,
- (LONG_PTR)nsws_window_urlbar_callback);
+ GWLP_WNDPROC,
+ (LONG_PTR)nsws_window_urlbar_callback);
/* save the real handler */
SetProp(hwnd, TEXT("OrigMsgProc"), (HANDLE)urlproc);
@@ -502,12 +508,13 @@ nsws_window_urlbar_create(HINSTANCE hInstance,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, "Arial");
if (hFont != NULL) {
- LOG("Setting font object");
+ NSLOG(netsurf, INFO, "Setting font object");
SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, 0);
}
- LOG("Created url bar hwnd:%p, x:%d, y:%d, w:%d, h:%d",
- hwnd, urlx, urly, urlwidth, urlheight);
+ NSLOG(netsurf, INFO,
+ "Created url bar hwnd:%p, x:%d, y:%d, w:%d, h:%d", hwnd, urlx,
+ urly, urlwidth, urlheight);
return hwnd;
}
@@ -548,7 +555,7 @@ nsws_window_throbber_create(HINSTANCE hInstance,
NULL);
nsws_find_resource(avi, "throbber.avi", "windows/res/throbber.avi");
- LOG("setting throbber avi as %s", avi);
+ NSLOG(netsurf, INFO, "setting throbber avi as %s", avi);
Animate_Open(hwnd, avi);
if (gw->throbbing) {
Animate_Play(hwnd, 0, -1, -1);
@@ -576,7 +583,8 @@ get_imagelist(HINSTANCE hInstance, int resid, int bsize, int bcnt)
HIMAGELIST hImageList;
HBITMAP hScrBM;
- LOG("resource id %d, bzize %d, bcnt %d", resid, bsize, bcnt);
+ NSLOG(netsurf, INFO, "resource id %d, bzize %d, bcnt %d", resid,
+ bsize, bcnt);
hImageList = ImageList_Create(bsize, bsize,
ILC_COLOR24 | ILC_MASK, 0,
@@ -654,8 +662,8 @@ nsws_window_create_toolbar(HINSTANCE hInstance,
/* subclass the message handler */
toolproc = (WNDPROC)SetWindowLongPtr(hWndToolbar,
- GWLP_WNDPROC,
- (LONG_PTR)nsws_window_toolbar_callback);
+ GWLP_WNDPROC,
+ (LONG_PTR)nsws_window_toolbar_callback);
/* save the real handler */
SetProp(hWndToolbar, TEXT("OrigMsgProc"), (HANDLE)toolproc);
@@ -754,7 +762,7 @@ nsws_window_create_statusbar(HINSTANCE hInstance,
static void nsws_update_edit(struct gui_window *w)
{
browser_editor_flags editor_flags = (w->bw == NULL) ?
- BW_EDITOR_NONE : browser_window_get_editor_flags(w->bw);
+ BW_EDITOR_NONE : browser_window_get_editor_flags(w->bw);
bool paste, copy, del;
bool sel = (editor_flags & BW_EDITOR_CAN_COPY);
@@ -809,11 +817,12 @@ static void nsws_update_edit(struct gui_window *w)
*
* \param gw win32 frontends graphical window.
* \param hwnd The win32 window handle
- * \param int x The x coordinate of the event.
- * \param y the y cooordiante of the event.
+ * \param x The x coordinate of the event.
+ * \param y the y coordinate of the event.
+ * \return true if menu displayed else false
*/
static bool
-nsws_ctx_menu(struct gui_window *w, HWND hwnd, int x, int y)
+nsws_ctx_menu(struct gui_window *gw, HWND hwnd, int x, int y)
{
RECT rc; /* client area of window */
POINT pt = { x, y }; /* location of mouse click */
@@ -827,8 +836,8 @@ nsws_ctx_menu(struct gui_window *w, HWND hwnd, int x, int y)
/* If the position is in the client area, display a shortcut menu. */
if (PtInRect(&rc, pt)) {
ClientToScreen(hwnd, &pt);
- nsws_update_edit(w);
- TrackPopupMenu(GetSubMenu(w->rclick, 0),
+ nsws_update_edit(gw);
+ TrackPopupMenu(GetSubMenu(gw->rclick, 0),
TPM_CENTERALIGN | TPM_TOPALIGN,
x,
y,
@@ -878,21 +887,40 @@ static void nsws_window_update_forward_back(struct gui_window *w)
MAKELONG((back ? TBSTATE_ENABLED :
TBSTATE_INDETERMINATE), 0));
}
+ nsw32_local_history_hide();
}
/**
- * redraw the whole window
+ * Invalidate an area of a win32 browser window
*
- * \param gw win32 frontends graphical window.
+ * \param gw The netsurf window being invalidated.
+ * \param rect area to redraw or NULL for entrire window area.
+ * \return NSERROR_OK or appropriate error code.
*/
-static void win32_window_redraw_window(struct gui_window *gw)
+static nserror
+win32_window_invalidate_area(struct gui_window *gw, const struct rect *rect)
{
- /* LOG("gw:%p", gw); */
- if (gw != NULL) {
- RedrawWindow(gw->drawingarea, NULL, NULL,
- RDW_INVALIDATE | RDW_NOERASE);
+ RECT *redrawrectp = NULL;
+ RECT redrawrect;
+
+ assert(gw != NULL);
+
+ if (rect != NULL) {
+ redrawrectp = &redrawrect;
+
+ redrawrect.left = (long)rect->x0 - (gw->scrollx / gw->scale);
+ redrawrect.top = (long)rect->y0 - (gw->scrolly / gw->scale);
+ redrawrect.right =(long)rect->x1;
+ redrawrect.bottom = (long)rect->y1;
+
}
+ RedrawWindow(gw->drawingarea,
+ redrawrectp,
+ NULL,
+ RDW_INVALIDATE | RDW_NOERASE);
+
+ return NSERROR_OK;
}
@@ -904,7 +932,7 @@ static void win32_window_redraw_window(struct gui_window *gw)
*/
static void nsws_set_scale(struct gui_window *gw, float scale)
{
- int x, y;
+ struct rect rect;
assert(gw != NULL);
@@ -912,8 +940,8 @@ static void nsws_set_scale(struct gui_window *gw, float scale)
return;
}
- x = gw->scrollx;
- y = gw->scrolly;
+ rect.x0 = rect.x1 = gw->scrollx;
+ rect.y0 = rect.y1 = gw->scrolly;
gw->scale = scale;
@@ -921,8 +949,8 @@ static void nsws_set_scale(struct gui_window *gw, float scale)
browser_window_set_scale(gw->bw, scale, true);
}
- win32_window_redraw_window(gw);
- win32_window_set_scroll(gw, x, y);
+ win32_window_invalidate_area(gw, NULL);
+ win32_window_set_scroll(gw, &rect);
}
@@ -963,10 +991,10 @@ static nserror win32_open_new_window(struct gui_window *gw)
*
* \param hwnd The win32 window handle
* \param gw win32 gui window
- * \param notification_code notifiction code
+ * \param notification_code notification code
* \param identifier notification identifier
* \param ctrl_window The win32 control window handle
- * \return apropriate response for command
+ * \return appropriate response for command
*/
static LRESULT
nsws_window_command(HWND hwnd,
@@ -977,8 +1005,11 @@ nsws_window_command(HWND hwnd,
{
nserror ret;
- LOG("notification_code %x identifier %x ctrl_window %p",
- notification_code, identifier, ctrl_window);
+ NSLOG(netsurf, INFO,
+ "notification_code %x identifier %x ctrl_window %p",
+ notification_code,
+ identifier,
+ ctrl_window);
switch(identifier) {
@@ -1053,7 +1084,7 @@ nsws_window_command(HWND hwnd,
HANDLE h = GetClipboardData(CF_TEXT);
if (h != NULL) {
char *content = GlobalLock(h);
- LOG("pasting %s\n", content);
+ NSLOG(netsurf, INFO, "pasting %s\n", content);
GlobalUnlock(h);
}
CloseClipboard();
@@ -1129,7 +1160,7 @@ nsws_window_command(HWND hwnd,
break;
case IDM_NAV_LOCALHISTORY:
- gw->localhistory = nsws_window_create_localhistory(gw);
+ nsw32_local_history_present(gw->main, gw->bw);
break;
case IDM_NAV_GLOBALHISTORY:
@@ -1217,7 +1248,7 @@ nsws_window_command(HWND hwnd,
browser_window_debug(gw->bw, CONTENT_DEBUG_REDRAW);
/* TODO: This should only redraw, not reformat.
* (Layout doesn't change, so reformat is a waste of time) */
- browser_window_reformat(gw->bw, false, gw->width, gw->height);
+ browser_window_schedule_reformat(gw->bw);
}
break;
@@ -1256,7 +1287,7 @@ nsws_window_command(HWND hwnd,
int len = SendMessage(gw->urlbar, WM_GETTEXTLENGTH, 0, 0);
char addr[len + 1];
SendMessage(gw->urlbar, WM_GETTEXT, (WPARAM)(len + 1), (LPARAM)addr);
- LOG("launching %s\n", addr);
+ NSLOG(netsurf, INFO, "launching %s\n", addr);
if (nsurl_create(addr, &url) != NSERROR_OK) {
win32_warning("NoMemory", 0);
@@ -1286,14 +1317,14 @@ nsws_window_command(HWND hwnd,
/**
* Get the scroll position of a win32 browser window.
*
- * \param g gui_window
- * \param sx receives x ordinate of point at top-left of window
- * \param sy receives y ordinate of point at top-left of window
+ * \param gw gui_window
+ * \param sx receives x ordinate of point at top-left of window
+ * \param sy receives y ordinate of point at top-left of window
* \return true iff successful
*/
static bool win32_window_get_scroll(struct gui_window *gw, int *sx, int *sy)
{
- LOG("get scroll");
+ NSLOG(netsurf, INFO, "get scroll");
if (gw == NULL)
return false;
@@ -1311,7 +1342,7 @@ static bool win32_window_get_scroll(struct gui_window *gw, int *sx, int *sy)
* \param hwnd The win32 window handle
* \param wparam The w win32 parameter
* \param lparam The l win32 parameter
- * \return apropriate response for resize
+ * \return appropriate response for resize
*/
static LRESULT
nsws_window_resize(struct gui_window *gw,
@@ -1319,7 +1350,6 @@ nsws_window_resize(struct gui_window *gw,
WPARAM wparam,
LPARAM lparam)
{
- int x, y;
RECT rstatus, rtool;
if ((gw->toolbar == NULL) ||
@@ -1332,7 +1362,6 @@ nsws_window_resize(struct gui_window *gw,
GetClientRect(gw->toolbar, &rtool);
GetWindowRect(gw->statusbar, &rstatus);
- win32_window_get_scroll(gw, &x, &y);
gw->width = LOWORD(lparam);
gw->height = HIWORD(lparam) - (rtool.bottom - rtool.top) - (rstatus.bottom - rstatus.top);
@@ -1346,7 +1375,7 @@ nsws_window_resize(struct gui_window *gw,
}
nsws_window_update_forward_back(gw);
- win32_window_set_scroll(gw, x, y);
+ browser_window_update(gw->bw, false);
if (gw->toolbar != NULL) {
SendMessage(gw->toolbar, TB_SETSTATE,
@@ -1392,7 +1421,8 @@ nsws_window_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
gw = nsws_get_gui_window(hwnd);
if (gw == NULL) {
- LOG("Unable to find gui window structure for hwnd %p", hwnd);
+ NSLOG(netsurf, INFO,
+ "Unable to find gui window structure for hwnd %p", hwnd);
return DefWindowProc(hwnd, msg, wparam, lparam);
}
@@ -1417,6 +1447,7 @@ nsws_window_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
case WM_NCDESTROY:
RemoveProp(hwnd, TEXT("GuiWnd"));
+ nsw32_local_history_hide();
browser_window_destroy(gw->bw);
if (--open_windows <= 0) {
win32_set_quit(true);
@@ -1444,7 +1475,7 @@ win32_window_create(struct browser_window *bw,
{
struct gui_window *gw;
- LOG("Creating gui window for browser window %p", bw);
+ NSLOG(netsurf, INFO, "Creating gui window for browser window %p", bw);
gw = calloc(1, sizeof(struct gui_window));
if (gw == NULL) {
@@ -1465,7 +1496,7 @@ win32_window_create(struct browser_window *bw,
gw->mouse = malloc(sizeof(struct browser_mouse));
if (gw->mouse == NULL) {
free(gw);
- LOG("Unable to allocate mouse state");
+ NSLOG(netsurf, INFO, "Unable to allocate mouse state");
return NULL;
}
gw->mouse->gui = gw;
@@ -1485,8 +1516,12 @@ win32_window_create(struct browser_window *bw,
gw->statusbar = nsws_window_create_statusbar(hinst, gw->main, gw);
gw->drawingarea = nsws_window_create_drawable(hinst, gw->main, gw);
- LOG("new window: main:%p toolbar:%p statusbar %p drawingarea %p",
- gw->main, gw->toolbar, gw->statusbar, gw->drawingarea);
+ NSLOG(netsurf, INFO,
+ "new window: main:%p toolbar:%p statusbar %p drawingarea %p",
+ gw->main,
+ gw->toolbar,
+ gw->statusbar,
+ gw->drawingarea);
font_hwnd = gw->drawingarea;
open_windows++;
@@ -1522,32 +1557,6 @@ static void win32_window_destroy(struct gui_window *w)
/**
- * Cause redraw of part of a win32 window.
- *
- * \param gw win32 gui window
- * \param rect area to redraw
- */
-static void
-win32_window_update(struct gui_window *gw, const struct rect *rect)
-{
- if (gw == NULL)
- return;
-
- RECT redrawrect;
-
- redrawrect.left = (long)rect->x0 - (gw->scrollx / gw->scale);
- redrawrect.top = (long)rect->y0 - (gw->scrolly / gw->scale);
- redrawrect.right =(long)rect->x1;
- redrawrect.bottom = (long)rect->y1;
-
- RedrawWindow(gw->drawingarea,
- &redrawrect,
- NULL,
- RDW_INVALIDATE | RDW_NOERASE);
-}
-
-
-/**
* Find the current dimensions of a win32 browser window's content area.
*
* \param gw gui_window to measure
@@ -1555,18 +1564,17 @@ win32_window_update(struct gui_window *gw, const struct rect *rect)
* \param height receives height of window
* \param scaled whether to return scaled values
*/
-static void
+static nserror
win32_window_get_dimensions(struct gui_window *gw,
int *width, int *height,
bool scaled)
{
- if (gw == NULL)
- return;
-
- LOG("get dimensions %p w=%d h=%d", gw, gw->width, gw->height);
-
*width = gw->width;
*height = gw->height;
+
+ NSLOG(netsurf, INFO, "gw:%p w=%d h=%d", gw, *width, *height);
+
+ return NSERROR_OK;
}
@@ -1583,19 +1591,6 @@ static void win32_window_update_extent(struct gui_window *w)
/**
- * callback from core to reformat a win32 window.
- *
- * \param gw The win32 gui window to reformat.
- */
-static void win32_window_reformat(struct gui_window *gw)
-{
- if (gw != NULL) {
- browser_window_reformat(gw->bw, false, gw->width, gw->height);
- }
-}
-
-
-/**
* set win32 browser window title
*
* \param w the win32 gui window.
@@ -1603,24 +1598,29 @@ static void win32_window_reformat(struct gui_window *gw)
*/
static void win32_window_set_title(struct gui_window *w, const char *title)
{
- if (w == NULL)
+ char *fulltitle;
+
+ if (w == NULL) {
return;
- LOG("%p, title %s", w, title);
- char *fulltitle = malloc(strlen(title) +
- SLEN(" - NetSurf") + 1);
+ }
+
+ NSLOG(netsurf, INFO, "%p, title %s", w, title);
+ fulltitle = malloc(strlen(title) + SLEN(" - NetSurf") + 1);
if (fulltitle == NULL) {
win32_warning("NoMemory", 0);
return;
}
+
strcpy(fulltitle, title);
strcat(fulltitle, " - NetSurf");
+
SendMessage(w->main, WM_SETTEXT, 0, (LPARAM)fulltitle);
free(fulltitle);
}
/**
- * Set the navigation url is a win32 browser window.
+ * Set the navigation url in a win32 browser window.
*
* \param gw window to update.
* \param url The url to use as icon.
@@ -1688,13 +1688,13 @@ win32_window_place_caret(struct gui_window *w, int x, int y,
/**
* Remove the win32 input focus from window
*
- * \param g window with caret
+ * \param gw window with caret
*/
-static void win32_window_remove_caret(struct gui_window *w)
+static void win32_window_remove_caret(struct gui_window *gw)
{
- if (w == NULL)
+ if (gw == NULL)
return;
- HideCaret(w->drawingarea);
+ HideCaret(gw->drawingarea);
}
@@ -1770,13 +1770,11 @@ static void win32_window_stop_throbber(struct gui_window *w)
static struct gui_window_table window_table = {
.create = win32_window_create,
.destroy = win32_window_destroy,
- .redraw = win32_window_redraw_window,
- .update = win32_window_update,
+ .invalidate = win32_window_invalidate_area,
.get_scroll = win32_window_get_scroll,
.set_scroll = win32_window_set_scroll,
.get_dimensions = win32_window_get_dimensions,
.update_extent = win32_window_update_extent,
- .reformat = win32_window_reformat,
.set_title = win32_window_set_title,
.set_url = win32_window_set_url,
@@ -1797,7 +1795,7 @@ struct gui_window *nsws_get_gui_window(HWND hwnd)
struct gui_window *gw = NULL;
HWND phwnd = hwnd;
- /* scan the window hierachy for gui window */
+ /* scan the window hierarchy for gui window */
while (phwnd != NULL) {
gw = GetProp(phwnd, TEXT("GuiWnd"));
if (gw != NULL)
@@ -1848,84 +1846,101 @@ bool nsws_window_go(HWND hwnd, const char *urltxt)
/* exported interface documented in windows/window.h */
-void win32_window_set_scroll(struct gui_window *w, int sx, int sy)
+nserror win32_window_set_scroll(struct gui_window *gw, const struct rect *rect)
{
SCROLLINFO si;
- nserror err;
+ nserror res;
int height;
int width;
POINT p;
- if ((w == NULL) || (w->bw == NULL))
- return;
-
- err = browser_window_get_extents(w->bw, true, &width, &height);
- if (err != NSERROR_OK) {
- return;
+ if ((gw == NULL) || (gw->bw == NULL)) {
+ return NSERROR_BAD_PARAMETER;
}
- /*LOG("scroll sx,sy:%d,%d x,y:%d,%d w.h:%d,%d",sx,sy,w->scrollx,w->scrolly, width,height);*/
+ res = browser_window_get_extents(gw->bw, true, &width, &height);
+ if (res != NSERROR_OK) {
+ return res;
+ }
- /* The resulting gui window scroll must remain withn the
+ /* The resulting gui window scroll must remain within the
* windows bounding box.
*/
- if (sx < 0) {
- w->requestscrollx = -w->scrollx;
- } else if (sx > (width - w->width)) {
- w->requestscrollx = (width - w->width) - w->scrollx;
+ if (rect->x0 < 0) {
+ gw->requestscrollx = -gw->scrollx;
+ } else if (rect->x0 > (width - gw->width)) {
+ gw->requestscrollx = (width - gw->width) - gw->scrollx;
} else {
- w->requestscrollx = sx - w->scrollx;
+ gw->requestscrollx = rect->x0 - gw->scrollx;
}
- if (sy < 0) {
- w->requestscrolly = -w->scrolly;
- } else if (sy > (height - w->height)) {
- w->requestscrolly = (height - w->height) - w->scrolly;
+ if (rect->y0 < 0) {
+ gw->requestscrolly = -gw->scrolly;
+ } else if (rect->y0 > (height - gw->height)) {
+ gw->requestscrolly = (height - gw->height) - gw->scrolly;
} else {
- w->requestscrolly = sy - w->scrolly;
+ gw->requestscrolly = rect->y0 - gw->scrolly;
}
- /*LOG("requestscroll x,y:%d,%d", w->requestscrollx, w->requestscrolly);*/
+ NSLOG(netsurf, DEEPDEBUG,
+ "requestscroll x,y:%d,%d",
+ gw->requestscrollx, gw->requestscrolly);
/* set the vertical scroll offset */
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = height - 1;
- si.nPage = w->height;
- si.nPos = max(w->scrolly + w->requestscrolly, 0);
- si.nPos = min(si.nPos, height - w->height);
- SetScrollInfo(w->drawingarea, SB_VERT, &si, TRUE);
- /*LOG("SetScrollInfo VERT min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos);*/
+ si.nPage = gw->height;
+ si.nPos = max(gw->scrolly + gw->requestscrolly, 0);
+ si.nPos = min(si.nPos, height - gw->height);
+ SetScrollInfo(gw->drawingarea, SB_VERT, &si, TRUE);
+ NSLOG(netsurf, DEEPDEBUG,
+ "SetScrollInfo VERT min:%d max:%d page:%d pos:%d",
+ si.nMin, si.nMax, si.nPage, si.nPos);
/* set the horizontal scroll offset */
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = width -1;
- si.nPage = w->width;
- si.nPos = max(w->scrollx + w->requestscrollx, 0);
- si.nPos = min(si.nPos, width - w->width);
- SetScrollInfo(w->drawingarea, SB_HORZ, &si, TRUE);
- /*LOG("SetScrollInfo HORZ min:%d max:%d page:%d pos:%d", si.nMin, si.nMax, si.nPage, si.nPos);*/
+ si.nPage = gw->width;
+ si.nPos = max(gw->scrollx + gw->requestscrollx, 0);
+ si.nPos = min(si.nPos, width - gw->width);
+ SetScrollInfo(gw->drawingarea, SB_HORZ, &si, TRUE);
+ NSLOG(netsurf, DEEPDEBUG,
+ "SetScrollInfo HORZ min:%d max:%d page:%d pos:%d",
+ si.nMin, si.nMax, si.nPage, si.nPos);
/* Set caret position */
GetCaretPos(&p);
- HideCaret(w->drawingarea);
- SetCaretPos(p.x - w->requestscrollx, p.y - w->requestscrolly);
- ShowCaret(w->drawingarea);
+ HideCaret(gw->drawingarea);
+ SetCaretPos(p.x - gw->requestscrollx, p.y - gw->requestscrolly);
+ ShowCaret(gw->drawingarea);
RECT r, redraw;
r.top = 0;
- r.bottom = w->height + 1;
+ r.bottom = gw->height + 1;
r.left = 0;
- r.right = w->width + 1;
- ScrollWindowEx(w->drawingarea, - w->requestscrollx, - w->requestscrolly, &r, NULL, NULL, &redraw, SW_INVALIDATE);
- /*LOG("ScrollWindowEx %d, %d", - w->requestscrollx, - w->requestscrolly);*/
- w->scrolly += w->requestscrolly;
- w->scrollx += w->requestscrollx;
- w->requestscrollx = 0;
- w->requestscrolly = 0;
+ r.right = gw->width + 1;
+ ScrollWindowEx(gw->drawingarea,
+ - gw->requestscrollx,
+ - gw->requestscrolly,
+ &r,
+ NULL,
+ NULL,
+ &redraw,
+ SW_INVALIDATE);
+ NSLOG(netsurf, DEEPDEBUG,
+ "ScrollWindowEx %d, %d",
+ - gw->requestscrollx,
+ - gw->requestscrolly);
+
+ gw->scrolly += gw->requestscrolly;
+ gw->scrollx += gw->requestscrollx;
+ gw->requestscrollx = 0;
+ gw->requestscrolly = 0;
+ return NSERROR_OK;
}
@@ -1966,12 +1981,3 @@ HWND gui_window_main_window(struct gui_window *w)
return NULL;
return w->main;
}
-
-
-/* exported interface documented in windows/window.h */
-struct nsws_localhistory *gui_window_localhistory(struct gui_window *w)
-{
- if (w == NULL)
- return NULL;
- return w->localhistory;
-}
diff --git a/frontends/windows/window.h b/frontends/windows/window.h
index d927c2899..3cdb9aefe 100644
--- a/frontends/windows/window.h
+++ b/frontends/windows/window.h
@@ -73,6 +73,7 @@ struct gui_window {
struct gui_window *next, *prev; /**< global linked list */
};
+struct rect;
/**
* Obtain gui window structure from window handle.
@@ -91,13 +92,17 @@ struct gui_window *nsws_get_gui_window(HWND hwnd);
bool nsws_window_go(HWND hwnd, const char *urltxt);
/**
- * scroll the window
+ * Set the scroll position of a win32 browser window.
*
- * \param w The win32 gui window to scroll.
- * \param sx the new 'absolute' horizontal scroll location
- * \param sy the new 'absolute' vertical scroll location
+ * Scrolls the viewport to ensure the specified rectangle of the
+ * content is shown. The win32 implementation scrolls the contents so
+ * the specified point in the content is at the top of the viewport.
+ *
+ * \param gw The win32 gui window to scroll.
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or apropriate error code.
*/
-void win32_window_set_scroll(struct gui_window *w, int sx, int sy);
+nserror win32_window_set_scroll(struct gui_window *gw, const struct rect *rect);
/**
* Create the main browser window class.
diff --git a/include/netsurf/bitmap.h b/include/netsurf/bitmap.h
index e54bdff85..a85efce99 100644
--- a/include/netsurf/bitmap.h
+++ b/include/netsurf/bitmap.h
@@ -154,7 +154,7 @@ struct gui_bitmap_table {
*
* \param bitmap The bitmap to save
* \param path The path to save the bitmap to.
- * \param flags Flags affectin the save.
+ * \param flags Flags affecting the save.
*/
bool (*save)(void *bitmap, const char *path, unsigned flags);
diff --git a/include/netsurf/browser_window.h b/include/netsurf/browser_window.h
index 482dcb92c..439b0785d 100644
--- a/include/netsurf/browser_window.h
+++ b/include/netsurf/browser_window.h
@@ -43,6 +43,9 @@ struct rect;
struct redraw_context;
enum content_debug;
+/**
+ * type of browser window drag in progess
+ */
typedef enum {
DRAGGING_NONE,
DRAGGING_SELECTION,
@@ -113,7 +116,10 @@ enum browser_window_nav_flags {
* A transaction is unverifiable if the user does not
* have that option.
*/
- BW_NAVIGATE_UNVERIFIABLE = (1 << 2)
+ BW_NAVIGATE_UNVERIFIABLE = (1 << 2),
+
+ /** suppress initial history updates (used by back/fwd/etc) */
+ BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE = (1 << 3)
};
/**
@@ -194,14 +200,27 @@ bool browser_window_up_available(struct browser_window *bw);
nserror browser_window_navigate_up(struct browser_window *bw, bool new_window);
/**
- * Get a browser window's URL.
+ * Access a browser window's URL. This URL is always without any fragment.
*
* \param bw browser window
* \return pointer to nsurl. Doesn't create a ref for caller.
*
* \note guaranteed to return a valid nsurl ptr, never returns NULL.
*/
-struct nsurl* browser_window_get_url(struct browser_window *bw);
+struct nsurl* browser_window_access_url(struct browser_window *bw);
+
+/**
+ * Access a browser window's URL.
+ *
+ * \param[in] bw browser window
+ * \param[in] fragment Whether to include any URL fragment.
+ * \param[out] url_out Returns a ref to the URL on success.
+ * \return NSERROR_OK, or appropriate error otherwise.
+ */
+nserror browser_window_get_url(
+ struct browser_window *bw,
+ bool fragment,
+ struct nsurl** url_out);
/**
* Get the title of a browser_window.
@@ -293,16 +312,23 @@ void browser_window_reload(struct browser_window *bw, bool all);
*/
void browser_window_destroy(struct browser_window *bw);
+
/**
* Reformat a browser window contents to a new width or height.
*
+ * This API is not safe to call from all contexts and care must be used.
+ *
+ * \warning This API is generally only useful within the browser core
+ * and is only exposed for historical reasons. A frontend almost
+ * certianly actually wants browser_window_schedule_reformat() and not
+ * this.
+ *
* \param bw The browser window to reformat.
* \param background Reformat in the background.
* \param width new width
* \param height new height
*/
-void browser_window_reformat(struct browser_window *bw, bool background,
- int width, int height);
+void browser_window_reformat(struct browser_window *bw, bool background, int width, int height);
/**
@@ -408,6 +434,7 @@ void browser_window_mouse_click(struct browser_window *bw,
void browser_window_mouse_track(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
+
/**
* Locate a browser window in the specified stack according.
*
@@ -420,21 +447,28 @@ struct browser_window *browser_window_find_target(
struct browser_window *bw, const char *target,
browser_mouse_state mouse);
+
/**
- * Cause the frontends reformat entry to be called in safe context.
+ * Reformat the browser window contents in a safe context.
*
- * The browser_window_reformat call cannot safely be called from some
- * contexts, this call allows for the reformat to happen from a safe
+ * The browser_window_reformat() call cannot safely be called from some
+ * contexts, This interface allows for the reformat to happen from a safe
* top level context.
*
- * The callback is frontend provided as the context information (size
- * etc.) about the windowing toolkit is only available to the
- * frontend.
+ * The reformat uses the window table get_dimensions() callback as the
+ * correct viewport dimensions are only available to the frontend.
+ *
+ * \param bw The browser window to reformat the content of.
+ * \return NSERROR_OK on success else appropriate error code.
*/
nserror browser_window_schedule_reformat(struct browser_window *bw);
-
+/**
+ * callback for select menu widget
+ *
+ * \todo This API needs investigating
+ */
void browser_select_menu_callback(void *client_data,
int x, int y, int width, int height);
@@ -554,26 +588,6 @@ void browser_window_get_position(struct browser_window *bw, bool root,
*/
void browser_window_set_position(struct browser_window *bw, int x, int y);
-/**
- * Scroll the browser window to display the passed area
- *
- * \param bw browser window to scroll
- * \param rect area to display
- */
-void browser_window_scroll_visible(struct browser_window *bw,
- const struct rect *rect);
-
-/**
- * Set scroll offsets for a browser window.
- *
- * \param bw The browser window
- * \param x The x scroll offset to set
- * \param y The y scroll offset to set
- *
- * \todo Do we really need this and browser_window_scroll_visible?
- * Ditto for gui_window_* variants.
- */
-void browser_window_set_scroll(struct browser_window *bw, int x, int y);
/**
* Set drag type for a browser window, and inform front end
diff --git a/include/netsurf/content_type.h b/include/netsurf/content_type.h
index b3d574309..ef654cd70 100644
--- a/include/netsurf/content_type.h
+++ b/include/netsurf/content_type.h
@@ -23,8 +23,8 @@
* The content enumerations are defined here.
*/
-#ifndef _NETSURF_CONTENT_TYPE_H_
-#define _NETSURF_CONTENT_TYPE_H_
+#ifndef NETSURF_CONTENT_TYPE_H
+#define NETSURF_CONTENT_TYPE_H
/** Debugging dump operations */
enum content_debug {
diff --git a/include/netsurf/core_window.h b/include/netsurf/core_window.h
index b6b012049..77d220b9c 100644
--- a/include/netsurf/core_window.h
+++ b/include/netsurf/core_window.h
@@ -20,7 +20,7 @@
* \file
* Interface to core window handling.
*
- * This provides a generallised API for frontends to implement which
+ * This provides a generalised API for frontends to implement which
* allows them to provide a single implementation for general window
* operations on their platform.
*
@@ -35,6 +35,9 @@
struct core_window;
struct rect;
+/**
+ * drag status passed to drag_status callback
+ */
typedef enum {
CORE_WINDOW_DRAG_NONE,
CORE_WINDOW_DRAG_SELECTION,
@@ -42,15 +45,28 @@ typedef enum {
CORE_WINDOW_DRAG_MOVE
} core_window_drag_status;
-/** Callbacks to achieve various core window functionality. */
+/**
+ * Callbacks to achieve various core window functionality.
+ */
struct core_window_callback_table {
/**
- * Request a redraw of the window
+ * Invalidate an area of a window.
*
- * \param[in] cw the core window object
- * \param[in] r rectangle to redraw
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated. It is expected that the windowing system will
+ * then subsequently cause redraw/expose operations as
+ * necessary.
+ *
+ * \note the frontend should not attempt to actually start the
+ * redraw operations as a result of this callback because the
+ * core redraw functions may already be threaded.
+ *
+ * \param[in] cw The core window to invalidate.
+ * \param[in] rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
*/
- void (*redraw_request)(struct core_window *cw, const struct rect *r);
+ nserror (*invalidate)(struct core_window *cw, const struct rect *rect);
/**
* Update the limits of the window
diff --git a/include/netsurf/mouse.h b/include/netsurf/mouse.h
index 1b16998a9..999f5a5b3 100644
--- a/include/netsurf/mouse.h
+++ b/include/netsurf/mouse.h
@@ -79,7 +79,10 @@ typedef enum browser_mouse_state {
/** 2nd modifier key pressed (eg. Ctrl) */
BROWSER_MOUSE_MOD_2 = (1 << 12),
/** 3rd modifier key pressed (eg. Alt) */
- BROWSER_MOUSE_MOD_3 = (1 << 13)
+ BROWSER_MOUSE_MOD_3 = (1 << 13),
+
+ /** pointer leaving window */
+ BROWSER_MOUSE_LEAVE = (1 << 14),
} browser_mouse_state;
diff --git a/include/netsurf/plot_style.h b/include/netsurf/plot_style.h
index 30db3663e..f1b617231 100644
--- a/include/netsurf/plot_style.h
+++ b/include/netsurf/plot_style.h
@@ -25,6 +25,8 @@
#define NETSURF_PLOT_STYLE_H
#include <stdint.h>
+#include <stdint.h>
+#include <libwapcaplet/libwapcaplet.h>
#include "netsurf/types.h"
/** light grey widget base colour */
@@ -36,8 +38,26 @@
/** Transparent colour value. */
#define NS_TRANSPARENT 0x01000000
-/** Scaling factor for font sizes */
-#define FONT_SIZE_SCALE 1024
+/** 22:10 fixed point */
+#define PLOT_STYLE_RADIX (10)
+
+/** Scaling factor for plot styles */
+#define PLOT_STYLE_SCALE (1 << PLOT_STYLE_RADIX)
+
+/* type for fixed point numbers */
+typedef int32_t plot_style_fixed;
+
+/* Convert an int to fixed point */
+#define plot_style_int_to_fixed(v) ((v) << PLOT_STYLE_RADIX)
+
+/* Convert fixed point to int */
+#define plot_style_fixed_to_int(v) ((v) >> PLOT_STYLE_RADIX)
+
+/* Convert fixed point to float */
+#define plot_style_fixed_to_float(v) (((float)v) / PLOT_STYLE_SCALE)
+
+/* Convert fixed point to double */
+#define plot_style_fixed_to_double(v) (((double)v) / PLOT_STYLE_SCALE)
/**
* Type of plot operation
@@ -55,7 +75,7 @@ typedef enum {
*/
typedef struct plot_style_s {
plot_operation_type_t stroke_type; /**< Stroke plot type */
- int stroke_width; /**< Width of stroke, in pixels */
+ plot_style_fixed stroke_width; /**< Width of stroke, in pixels */
colour stroke_colour; /**< Colour of stroke */
plot_operation_type_t fill_type; /**< Fill plot type */
colour fill_colour; /**< Colour of fill */
@@ -89,8 +109,14 @@ typedef enum {
* Font style for plotting
*/
typedef struct plot_font_style {
+ /**
+ * Array of pointers to font families.
+ *
+ * May be NULL. Array is NULL terminated.
+ */
+ lwc_string * const * families;
plot_font_generic_family_t family; /**< Generic family to plot with */
- int size; /**< Font size, in points * FONT_SIZE_SCALE */
+ plot_style_fixed size; /**< Font size, in pt */
int weight; /**< Font weight: value in range [100,900] as per CSS */
plot_font_flags_t flags; /**< Font flags */
colour background; /**< Background colour to blend to, if appropriate */
diff --git a/include/netsurf/plotters.h b/include/netsurf/plotters.h
index 88cbbe560..2fd507aa5 100644
--- a/include/netsurf/plotters.h
+++ b/include/netsurf/plotters.h
@@ -31,6 +31,7 @@
struct bitmap;
struct rect;
+struct plotter_table;
typedef unsigned long bitmap_flags_t;
#define BITMAPF_NONE 0
@@ -44,50 +45,45 @@ enum path_command {
PLOTTER_PATH_BEZIER,
};
-/** Set of target specific plotting functions.
- *
- * The functions are:
- * arc - Plots an arc, around (x,y), from anticlockwise from angle1 to
- * angle2. Angles are measured anticlockwise from horizontal, in
- * degrees.
- * disc - Plots a circle, centered on (x,y), which is optionally filled.
- * line - Plots a line from (x0,y0) to (x1,y1). Coordinates are at
- * centre of line width/thickness.
- * path - Plots a path consisting of cubic Bezier curves. Line colour is
- * given by c and fill colour is given by fill.
- * polygon - Plots a filled polygon with straight lines between points.
- * The lines around the edge of the ploygon are not plotted. The
- * polygon is filled with the non-zero winding rule.
- * rectangle - Plots a rectangle outline. The line can be solid, dotted or
- * dashed. Top left corner at (x0,y0) and rectangle has given
- * width and height.
- * fill - Plots a filled rectangle. Top left corner at (x0,y0), bottom
- * right corner at (x1,y1). Note: (x0,y0) is inside filled area,
- * but (x1,y1) is below and to the right. See diagram below.
- * clip - Sets a clip rectangle for subsequent plots.
- * text - Plots text. (x,y) is the coordinate of the left hand side of
- * the text's baseline. The text is UTF-8 encoded. The colour, c,
- * is the colour of the text. Background colour, bg, may be used
- * optionally to attempt to provide anti-aliased text without
- * screen reads. Font information is provided in the style.
- * bitmap - Tiled plot of a bitmap image. (x,y) gives the top left
- * coordinate of an explicitly placed tile. From this tile the
- * image can repeat in all four directions -- up, down, left and
- * right -- to the extents given by the current clip rectangle.
- * The bitmap_flags say whether to tile in the x and y
- * directions. If not tiling in x or y directions, the single
- * image is plotted. The width and height give the dimensions
- * the image is to be scaled to.
- * group_start - Start of a group of objects. Used when plotter implements
- * export to a vector graphics file format. (Optional.)
- * group_end - End of the most recently started group. (Optional.)
- * flush - Only used internally by the knockout code. Should be NULL in
- * any front end display plotters or export plotters.
- *
- * Plotter options:
- * option_knockout - Optimisation particularly for unaccelerated screen
- * redraw. It tries to avoid plotting to the same area
- * more than once. See desktop/knockout.c
+/**
+ * Redraw context
+ */
+struct redraw_context {
+ /**
+ * Redraw to show interactive features.
+ *
+ * Active features include selections etc.
+ *
+ * \note Should be off for printing.
+ */
+ bool interactive;
+
+ /**
+ * Render background images.
+ *
+ * \note May want it off for printing.
+ */
+ bool background_images;
+
+ /**
+ * Current plot operation table
+ *
+ * \warning must be assigned before use.
+ */
+ const struct plotter_table *plot;
+
+ /**
+ * Private context.
+ *
+ * Private context allows callers to pass context through to
+ * plot operations without using a global.
+ */
+ void *priv;
+};
+
+
+/**
+ * Plotter operations table.
*
* Coordinates are from top left of canvas and (0,0) is the top left grid
* denomination. If a "fill" is drawn from (0,0) to (4,3), the result is:
@@ -101,61 +97,235 @@ enum path_command {
* 2 |#|#|#|#| |
* +-+-+-+-+-+-
* 3 | | | | | |
+ *
*/
struct plotter_table {
- /* clipping operations */
- bool (*clip)(const struct rect *clip);
-
- /* shape primatives */
- bool (*arc)(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle);
- bool (*disc)(int x, int y, int radius, const plot_style_t *pstyle);
- bool (*line)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
- bool (*rectangle)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
- bool (*polygon)(const int *p, unsigned int n, const plot_style_t *pstyle);
-
- /* complex path (for SVG) */
- bool (*path)(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6]);
-
- /* Image */
- bool (*bitmap)(int x, int y, int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags);
+ /**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*clip)(
+ const struct redraw_context *ctx,
+ const struct rect *clip);
/**
- * Text.
+ * Plots an arc
*
- * \param x x coordinate
- * \param y y coordinate
- * \param text UTF-8 string to plot
- * \param length length of string, in bytes
- * \param fstyle plot style for this text
- * \return true on success, false on error and error reported
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
*/
- bool (*text)(int x, int y, const char *text, size_t length,
- const plot_font_style_t *fstyle);
+ nserror (*arc)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x,
+ int y,
+ int radius,
+ int angle1,
+ int angle2);
- /* optional callbacks */
- bool (*group_start)(const char *name); /**< optional, may be NULL */
- bool (*group_end)(void); /**< optional, may be NULL */
- bool (*flush)(void); /**< optional, may be NULL */
+ /**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the circle plot.
+ * \param x The x coordinate of the circle.
+ * \param y The y coordinate of the circle.
+ * \param radius The radius of the circle.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*disc)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ int x,
+ int y,
+ int radius);
- /* flags */
- bool option_knockout; /**< set if knockout rendering is required */
-};
+ /**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*line)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *line);
+ /**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*rectangle)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const struct rect *rectangle);
-/* Redraw context */
-struct redraw_context {
- /** Redraw to show interactive features, such as active selections
- * etc. Should be off for printing. */
- bool interactive;
+ /**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*polygon)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const int *p,
+ unsigned int n);
- /** Render background images. May want it off for printing. */
- bool background_images;
+ /**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*path)(
+ const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ const float transform[6]);
- /** Current plotters, must be assigned before use. */
- const struct plotter_table *plot;
+ /**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*bitmap)(
+ const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags);
+
+ /**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*text)(
+ const struct redraw_context *ctx,
+ const plot_font_style_t *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length);
+
+ /**
+ * Start of a group of objects.
+ *
+ * optional, may be NULL. Used when plotter implements export
+ * to a vector graphics file format.
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*group_start)(
+ const struct redraw_context *ctx,
+ const char *name);
+
+ /**
+ * End of the most recently started group.
+ *
+ * optional, may be NULL
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*group_end)(
+ const struct redraw_context *ctx);
+
+ /**
+ * Only used internally by the knockout code. Must be NULL in
+ * any front end display plotters or export plotters.
+ *
+ * \param ctx The current redraw context.
+ * \return NSERROR_OK on success else error code.
+ */
+ nserror (*flush)(
+ const struct redraw_context *ctx);
+
+ /* flags */
+ /**
+ * flag to enable knockout rendering.
+ *
+ * Optimisation particularly for unaccelerated screen
+ * redraw. It tries to avoid plotting to the same area more
+ * than once. See desktop/knockout.c
+ */
+ bool option_knockout;
};
#endif
diff --git a/include/netsurf/url_db.h b/include/netsurf/url_db.h
index be2c656ff..217cf8fcd 100644
--- a/include/netsurf/url_db.h
+++ b/include/netsurf/url_db.h
@@ -96,15 +96,6 @@ void urldb_iterate_entries(bool (*callback)(struct nsurl *url, const struct url_
/**
- * Retrieve thumbnail data for given URL
- *
- * \param url Absolute URL to search for
- * \return Pointer to thumbnail data, or NULL if not found.
- */
-struct bitmap *urldb_get_thumbnail(struct nsurl *url);
-
-
-/**
* Find data for an URL.
*
* \param url Absolute URL to look for
diff --git a/include/netsurf/window.h b/include/netsurf/window.h
index b88736807..53d9b30f2 100644
--- a/include/netsurf/window.h
+++ b/include/netsurf/window.h
@@ -23,8 +23,8 @@
* operations.
*/
-#ifndef _NETSURF_WINDOW_H_
-#define _NETSURF_WINDOW_H_
+#ifndef NETSURF_WINDOW_H
+#define NETSURF_WINDOW_H
typedef enum gui_save_type {
GUI_SAVE_SOURCE,
@@ -50,10 +50,13 @@ typedef enum {
GDRAGGING_OTHER
} gui_drag_type;
+/**
+ * Window creation control flags.
+ */
typedef enum {
- GW_CREATE_NONE = 0, /* New window */
- GW_CREATE_CLONE = (1 << 0), /* Clone existing window */
- GW_CREATE_TAB = (1 << 1) /* In same window as existing */
+ GW_CREATE_NONE = 0, /**< New window */
+ GW_CREATE_CLONE = (1 << 0), /**< Clone existing window */
+ GW_CREATE_TAB = (1 << 1) /**< Create tab in same window as existing */
} gui_window_create_flags;
struct browser_window;
@@ -76,20 +79,31 @@ struct gui_window_table {
/**
* Create and open a gui window for a browsing context.
*
- * \param bw bw to create gui_window for
- * \param existing an existing gui_window, may be NULL
- * \param flags flags for gui window creation
- * \return gui window, or NULL on error
+ * The implementing front end must create a context suitable
+ * for it to display a window referred to as the "gui window".
+ *
+ * The frontend will be expected to request the core redraw
+ * areas of the gui window which have become invalidated
+ * either from toolkit expose events or as a result of a
+ * invalidate() call.
+ *
+ * Most core operations used by the frontend concerning browser
+ * windows require passing the browser window context therefor
+ * the gui window must include a reference to the browser
+ * window passed here.
*
* If GW_CREATE_CLONE flag is set existing is non-NULL.
*
- * Front end's gui_window must include a reference to the
- * browser window passed in the bw param.
+ * \param bw The core browsing context associated with the gui window
+ * \param existing An existing gui_window, may be NULL.
+ * \param flags flags to control the gui window creation.
+ * \return gui window, or NULL on error.
*/
struct gui_window *(*create)(struct browser_window *bw,
struct gui_window *existing,
gui_window_create_flags flags);
+
/**
* Destroy previously created gui window
*
@@ -97,54 +111,74 @@ struct gui_window_table {
*/
void (*destroy)(struct gui_window *gw);
+
/**
- * Force a redraw of the entire contents of a window.
+ * Invalidate an area of a window.
*
- * @todo this API should be merged with update.
+ * The specified area of the window should now be considered
+ * out of date. If the area is NULL the entire window must be
+ * invalidated. It is expected that the windowing system will
+ * then subsequently cause redraw/expose operations as
+ * necessary.
*
- * \param g gui_window to redraw
- */
- void (*redraw)(struct gui_window *g);
-
- /**
- * Redraw an area of a window.
+ * \note the frontend should not attempt to actually start the
+ * redraw operations as a result of this callback because the
+ * core redraw functions may already be threaded.
*
- * \param g gui_window
- * \param rect area to redraw
+ * \param gw The gui window to invalidate.
+ * \param rect area to redraw or NULL for the entire window area
+ * \return NSERROR_OK on success or appropriate error code
*/
- void (*update)(struct gui_window *g, const struct rect *rect);
+ nserror (*invalidate)(struct gui_window *gw, const struct rect *rect);
+
/**
* Get the scroll position of a browser window.
*
- * \param g gui_window
- * \param sx receives x ordinate of point at top-left of window
- * \param sy receives y ordinate of point at top-left of window
+ * \param gw The gui window to obtain the scroll position from.
+ * \param sx receives x ordinate of point at top-left of window
+ * \param sy receives y ordinate of point at top-left of window
* \return true iff successful
*/
- bool (*get_scroll)(struct gui_window *g, int *sx, int *sy);
+ bool (*get_scroll)(struct gui_window *gw, int *sx, int *sy);
+
/**
* Set the scroll position of a browser window.
*
- * \param g gui_window to scroll
- * \param sx point to place at top-left of window
- * \param sy point to place at top-left of window
+ * scrolls the viewport to ensure the specified rectangle of
+ * the content is shown.
+ * If the rectangle is of zero size i.e. x0 == x1 and y0 == y1
+ * the contents will be scrolled so the specified point in the
+ * content is at the top of the viewport.
+ * If the size of the rectangle is non zero the frontend may
+ * add padding or centre the defined area or it may simply
+ * align as in the zero size rectangle
+ *
+ * \param gw The gui window to scroll.
+ * \param rect The rectangle to ensure is shown.
+ * \return NSERROR_OK on success or appropriate error code.
*/
- void (*set_scroll)(struct gui_window *g, int sx, int sy);
+ nserror (*set_scroll)(struct gui_window *gw, const struct rect *rect);
+
/**
* Find the current dimensions of a browser window's content area.
*
- * @todo The implementations of this are buggy and its only
- * used from frames code.
+ * This is used to determine the actual available drawing size
+ * in pixels. This allows contents that can be dynamically
+ * reformatted, such as HTML, to better use the available
+ * space.
*
- * \param g gui_window to measure
- * \param width receives width of window
+ * \param gw The gui window to measure content area of.
+ * \param width receives width of window
* \param height receives height of window
* \param scaled whether to return scaled values
+ * \return NSERROR_OK on success and width and height updated
+ * else error code.
*/
- void (*get_dimensions)(struct gui_window *g, int *width, int *height, bool scaled);
+ nserror (*get_dimensions)(struct gui_window *gw, int *width, int *height, bool scaled);
+
/**
* Update the extent of the inside of a browser window to that of the
@@ -153,21 +187,9 @@ struct gui_window_table {
* @todo this is used to update scroll bars does it need
* renaming? some frontends (windows) do not even implement it.
*
- * \param g gui_window to update the extent of
- */
- void (*update_extent)(struct gui_window *g);
-
- /**
- * Reformat a window.
- *
- * This is used to perform reformats when the page contents
- * require reformatting. The reformat is requested using
- * browser_window_schedule_reformat and occurs via a scheduled
- * callback hence from top level context.
- *
- * \param g gui_window to reformat.
+ * \param gw The gui window to update the extent of.
*/
- void (*reformat)(struct gui_window *g);
+ void (*update_extent)(struct gui_window *gw);
/* Optional entries */
@@ -175,10 +197,10 @@ struct gui_window_table {
/**
* Set the title of a window.
*
- * \param g window to update
- * \param title new window title
+ * \param gw The gui window to set title of.
+ * \param title new window title
*/
- void (*set_title)(struct gui_window *g, const char *title);
+ void (*set_title)(struct gui_window *gw, const char *title);
/**
* Set the navigation url.
@@ -264,20 +286,6 @@ struct gui_window_table {
*/
nserror (*save_link)(struct gui_window *g, struct nsurl *url, const char *title);
- /**
- * Scrolls the specified area of a browser window into view.
- *
- * @todo investigate if this can be merged with set_scroll
- * which is what the default implementation used by most
- * toolkits uses.
- *
- * \param g gui_window to scroll
- * \param x0 left point to ensure visible
- * \param y0 bottom point to ensure visible
- * \param x1 right point to ensure visible
- * \param y1 top point to ensure visible
- */
- void (*scroll_visible)(struct gui_window *g, int x0, int y0, int x1, int y1);
/**
* Starts drag scrolling of a browser window
@@ -289,28 +297,50 @@ struct gui_window_table {
/**
* Called when the gui_window has new content.
*
- * \param g the gui_window that has new content
+ * \param gw The gui window that has new content
*/
- void (*new_content)(struct gui_window *g);
+ void (*new_content)(struct gui_window *gw);
/**
* create a form select menu
+ *
+ * \param gw The gui window to open select menu form gadget in.
+ * \param control The form control gadget handle.
*/
void (*create_form_select_menu)(struct gui_window *gw, struct form_control *control);
/**
* Called when file chooser gadget is activated
+ *
+ * \param gw The gui window to open file chooser in.
+ * \param hl The content of the object.
+ * \param gadget The form control gadget handle.
*/
- void (*file_gadget_open)(struct gui_window *g, struct hlcache_handle *hl, struct form_control *gadget);
+ void (*file_gadget_open)(struct gui_window *gw, struct hlcache_handle *hl, struct form_control *gadget);
- /** object dragged to window*/
- void (*drag_save_object)(struct gui_window *g, struct hlcache_handle *c, gui_save_type type);
+ /**
+ * object dragged to window
+ *
+ * \param gw The gui window to save dragged object of.
+ * \param c The content of the object.
+ * \param type the type of save.
+ */
+ void (*drag_save_object)(struct gui_window *gw, struct hlcache_handle *c, gui_save_type type);
- /** drag selection save */
- void (*drag_save_selection)(struct gui_window *g, const char *selection);
+ /**
+ * drag selection save
+ *
+ * \param gw The gui window to save dragged selection of.
+ * \param selection The selection to save.
+ */
+ void (*drag_save_selection)(struct gui_window *gw, const char *selection);
- /** selection started */
- void (*start_selection)(struct gui_window *g);
+ /**
+ * selection started
+ *
+ * \param gw The gui window to start selection in.
+ */
+ void (*start_selection)(struct gui_window *gw);
};
#endif
diff --git a/render/Makefile b/render/Makefile
deleted file mode 100644
index 148c2c39d..000000000
--- a/render/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# Render sources
-
-S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
- font.c form.c imagemap.c layout.c search.c table.c textplain.c \
- html.c html_css.c html_css_fetcher.c html_script.c \
- html_interaction.c html_redraw.c html_forms.c html_object.c
-
-
-S_RENDER := $(addprefix render/,$(S_RENDER))
diff --git a/render/textplain.h b/render/textplain.h
deleted file mode 100644
index 6a88c3470..000000000
--- a/render/textplain.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Content for text/plain (interface).
- */
-
-#ifndef _NETSURF_RENDER_TEXTPLAIN_H_
-#define _NETSURF_RENDER_TEXTPLAIN_H_
-
-#include <stddef.h>
-#include "netsurf/mouse.h"
-
-struct content;
-struct hlcache_handle;
-struct http_parameter;
-struct rect;
-
-nserror textplain_init(void);
-
-/* access to lines for text selection and searching */
-unsigned long textplain_line_count(struct content *c);
-size_t textplain_size(struct content *c);
-
-size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
-void textplain_coords_from_range(struct content *c,
- unsigned start, unsigned end, struct rect *r);
-char *textplain_get_line(struct content *c, unsigned lineno,
- size_t *poffset, size_t *plen);
-int textplain_find_line(struct content *c, unsigned offset);
-char *textplain_get_raw_data(struct content *c,
- unsigned start, unsigned end, size_t *plen);
-struct browser_window *textplain_get_browser_window(struct content *c);
-
-#endif
diff --git a/resources/FatMessages b/resources/FatMessages
index ead95fc06..de8eed6ad 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -36,8 +36,10 @@
# Globals
en.all.NetSurf:NetSurf
-en.all.NetSurfCopyright:© 2003-2016 The NetSurf Developers
-nl.all.NetSurfCopyright:© 2003-2016 De NetSurf-ontwikkelaars
+en.all.NetSurfCopyright:© 2003-2017 The NetSurf Developers
+de.all.NetSurfCopyright:© 2003-2017 die NetSurf Entwickler
+nl.all.NetSurfCopyright:© 2003-2017 De NetSurf-ontwikkelaars
+it.all.NetSurfCopyright:© 2003-2017 A cura degli sviluppatori di NetSurf
# Menus
@@ -49,6 +51,7 @@ nl.all.NetSurfCopyright:© 2003-2016 De NetSurf-ontwikkelaars
# Iconbar menu
#
en.all.Info:Info
+de.all.Info:Information
fr.all.Info:Information
nl.all.Info:Informatie
en.ro.AppHelpNoShortcut:Help...
@@ -524,12 +527,12 @@ nl.all.Selection:Selectie
en.ro.SelectAll:Select all ^A
de.ro.SelectAll:Alles auswählen ^A
fr.ro.SelectAll:Tout sélectionner ^A
-it.ro.SelectAll:Seleziona Tutto ^A
+it.ro.SelectAll:Seleziona tutto ^A
nl.ro.SelectAll:Selecteer alles ^A
en.ro.Clear:Clear selection ^Z
de.ro.Clear:Auswahl aufheben ^Z
fr.ro.Clear:Effacer la sélection ^Z
-it.ro.Clear:Cancella selezione ^Z
+it.ro.Clear:Annulla selezione ^Z
nl.ro.Clear:Deselecteer ^Z
en.ro.Copy:Copy to clipboard ^C
de.ro.Copy:Auswahl kopieren ^C
@@ -615,7 +618,7 @@ nl.all.Link:Koppeling
en.all.All:All
de.all.All:Alles
fr.all.All:Tout
-it.all.All:Tutte
+it.all.All:Tutti
nl.all.All:Alles
en.all.Folders:Directories
de.all.Folders:Verzeichnisse
@@ -670,12 +673,12 @@ nl.all.ProxyNoAuth:Eenvoudige proxy
en.all.ProxyBasic:Basic authentication
de.all.ProxyBasic:mit Authentifizierung
fr.all.ProxyBasic:Authentification de base
-it.all.ProxyBasic:Autentificato di base
+it.all.ProxyBasic:Autentificazione base
nl.all.ProxyBasic:Basisauthenticatie
en.all.ProxyNTLM:NTLM authentication
de.all.ProxyNTLM:NTLM Authentifizierung
fr.all.ProxyNTLM:Authentification NTLM
-it.all.ProxyNTLM:Autentificato NTLM
+it.all.ProxyNTLM:Autentificazione NTLM
nl.all.ProxyNTLM:NTLM-authenticatie
#
# Fonts pane
@@ -814,7 +817,7 @@ nl.all.PasteNS:Plak in
en.all.SelectAllNS:Select all
de.all.SelectAllNS:Alles auswählen
fr.all.SelectAllNS:Sélectionner tout
-it.all.SelectAllNS:Seleziona Tutto
+it.all.SelectAllNS:Seleziona tutto
nl.all.SelectAllNS:Selecteer alles
en.all.ClearNS:Clear selection
de.all.ClearNS:Auswahl rückgängig
@@ -969,7 +972,7 @@ nl.ami.SaveIFF:Bewaar als IFF...
en.all.SaveComplete:Save complete...
de.all.SaveComplete:Speichern abgeschlossen...
fr.all.SaveComplete:Enregistrement terminé...
-it.all.SaveComplete:Salva Tutto...
+it.all.SaveComplete:Salva tutto...
nl.all.SaveComplete:Bewaar alles...
en.all.Close:Close
de.all.Close:Schließen
@@ -979,7 +982,7 @@ nl.all.Close:Sluit
en.ami.CloseInactive:Close inactive tabs
de.ami.CloseInactive:Close inactive tabs
fr.ami.CloseInactive:Close inactive tabs
-it.ami.CloseInactive:Close inactive tabs
+it.ami.CloseInactive:Chiudi schede inattive
nl.ami.CloseInactive:Close inactive tabs
en.all.ObjShow:Show object
de.all.ObjShow:Zeige Objekt
@@ -1283,6 +1286,7 @@ nl.all.TreeviewLabelFolder:Map:
# Cookie Manager field values
#
en.all.CookieManagerSession:Session
+it.all.CookieManagerSession:Sessione
en.all.CookieManagerHTTPS:Secure hosts via https only
de.all.CookieManagerHTTPS:Secure hosts via https only
fr.all.CookieManagerHTTPS:Hôtes sécurisés via https uniquement
@@ -1322,7 +1326,7 @@ nl.all.NewFolderName:Nieuwe map
en.all.NoTitle:<No title>
de.all.NoTitle:<No title>
fr.all.NoTitle:<Sans titre>
-it.all.NoTitle:<Nessun titolo>
+it.all.NoTitle:<Senza titolo>
nl.all.NoTitle:<Naamloos>
@@ -1343,12 +1347,12 @@ nl.all.TreeHotlist:NetSurf-favorieten
en.ami.NetSurfDesc:Small as a mouse, fast as a cheetah and available for free. NetSurf is a multi-platform web browser.
fr.ami.NetSurfDesc:Petit comme une souris, rapide comme un guépard. NetSurf est un navigateur Web multi-plate-forme libre.
-it.ami.NetSurfDesc:Piccolo come un mouse, veloce come un ghepardo. NetSurf è un browser web opensource e multi-piattaforma.
+it.ami.NetSurfDesc:Piccolo come un mouse e veloce come un ghepardo! NetSurf, il browser web opensource e multi-piattaforma
nl.ami.NetSurfDesc:Klein als een muis, snel als een cheetah en gratis beschikbaar. NetSurf is een multi-platform webbrowser.
en.gtk.AboutDesc:NetSurf is a small and fast web browser.
fr.gtk.AboutDesc:NetSurf est un navigateur Web multi-plate-forme libre.
-it.gtk.AboutDesc:NetSurf è un browser web opensource e multi-piattaforma.
+it.gtk.AboutDesc:NetSurf, il browser web opensource e multi-piattaforma
nl.gtk.AboutDesc:NetSurf is een kleine, snelle webbrowser met open broncode.
# Hotlist user interface tokens
@@ -1391,7 +1395,7 @@ nl.all.EditFolder:Hernoem map
en.all.HotlistHomepage:NetSurf homepage
de.all.HotlistHomepage:NetSurf Homepage
fr.all.HotlistHomepage:Page d'accueil de NetSurf
-it.all.HotlistHomepage:Home Page di NetSurf
+it.all.HotlistHomepage:Pagina iniziale di NetSurf
nl.all.HotlistHomepage:NetSurf-startpagina
en.all.HotlistDocumentation:Documentation
de.all.HotlistDocumentation:Dokumentation
@@ -1451,32 +1455,32 @@ fr.all.DateYesterday:Hier
it.all.DateYesterday:Ieri
nl.all.DateYesterday:Gisteren
en.all.Date2Days:Two days ago
-de.all.Date2Days:2 days ago
+de.all.Date2Days:vor 2 Tagen
fr.all.Date2Days:Il y a deux jours
it.all.Date2Days:2 giorni fa
nl.all.Date2Days:2 dagen geleden
en.all.Date3Days:Three days ago
-de.all.Date3Days:3 days ago
+de.all.Date3Days:vor 3 Tagen
fr.all.Date3Days:Il y a trois jours
it.all.Date3Days:3 giorni fa
nl.all.Date3Days:3 dagen geleden
en.all.Date4Days:Four days ago
-de.all.Date4Days:4 days ago
+de.all.Date4Days:vor 4 Tagen
fr.all.Date4Days:Il y a quatre jours
it.all.Date4Days:4 giorni fa
nl.all.Date4Days:4 dagen geleden
en.all.Date5Days:Five days ago
-de.all.Date5Days:5 days ago
+de.all.Date5Days:vor 5 Tagen
fr.all.Date5Days:Il y a cinq jours
it.all.Date5Days:5 giorni fa
nl.all.Date5Days:5 dagen geleden
en.all.Date6Days:Six days ago
-de.all.Date6Days:6 days ago
+de.all.Date6Days:vor 6 Tagen
fr.all.Date6Days:Il y a six jours
it.all.Date6Days:6 giorni fa
nl.all.Date6Days:6 dagen geleden
en.all.Date1Week:A week ago
-de.all.Date1Week:A week ago
+de.all.Date1Week:vor einer Woche
fr.all.Date1Week:Il y a une semaine
it.all.Date1Week:1 settimana fa
nl.all.Date1Week:Een week geleden
@@ -1564,6 +1568,11 @@ nl.all.Abort:Breek af
# This section contains tokens which are used in the Amiga
# download window.
#
+en.ami.amiDownloading:NetSurf: Downloading...
+de.ami.amiDownloading:NetSurf: Downloading...
+fr.ami.amiDownloading:NetSurf: Downloading...
+it.ami.amiDownloading:NetSurf: Scaricamento...
+nl.ami.amiDownloading:NetSurf: Downloading...
en.ami.amiDownload:%ld of %ld bytes downloaded
de.ami.amiDownload:%ld von %ld Bytes heruntergeladen
fr.ami.amiDownload:%ld of %ld bytes downloaded
@@ -1736,17 +1745,17 @@ fr.gtk.gtkplainSave:Enregistrer sans mise en forme
it.gtk.gtkplainSave:Salva come testo
nl.gtk.gtkplainSave:Als tekst bewaren
en.gtk.gtkcompleteSave:Save webpage complete - select an empty directory
-de.gtk.gtkcompleteSave:Save webpage complete - select an empty directory
+de.gtk.gtkcompleteSave:Seite komplett speichern - ein leeres Verzeichnis wählen
fr.gtk.gtkcompleteSave:Enregistrer page web complète - sélectioner un dossier vide
it.gtk.gtkcompleteSave:Salva l'intera pagina web - seleziona una directory vuota
nl.gtk.gtkcompleteSave:Complete webpagina bewaren - selecteer een lege map
en.gtk.gtkSaveConfirm:File saved
-de.gtk.gtkSaveConfirm:File saved
+de.gtk.gtkSaveConfirm:Datei gespeichert
fr.gtk.gtkSaveConfirm:Fichier enregistré
it.gtk.gtkSaveConfirm:File salvato
nl.gtk.gtkSaveConfirm:Bestand bewaard
en.gtk.gtkSaveCancelled:File not saved
-de.gtk.gtkSaveCancelled:File not saved
+de.gtk.gtkSaveCancelled:Datei nicht gespeichert
fr.gtk.gtkSaveCancelled:Fichier pas enregistré
it.gtk.gtkSaveCancelled:File non salvato
nl.gtk.gtkSaveCancelled:Bestand is niet bewaard
@@ -1792,7 +1801,7 @@ nl.gtk.gtkNavigate:_Ga
en.gtk.gtkTools:_Tools
de.gtk.gtkTools:_Tools
fr.gtk.gtkTools:Ou_tils
-it.gtk.gtkTools:_Tools
+it.gtk.gtkTools:_Strumenti
nl.gtk.gtkTools:E_xtra
en.gtk.gtkHelp:_Help
de.gtk.gtkHelp:_Hilfe
@@ -1805,51 +1814,26 @@ de.gtk.gtkNewTab:Neuer _Tab
fr.gtk.gtkNewTab:Nouvel _Onglet
it.gtk.gtkNewTab:Nuova _scheda
nl.gtk.gtkNewTab:Nieuw _Tabblad
-en.gtk.gtkNewTabAccel:<ctrl>t
-de.gtk.gtkNewTabAccel:<ctrl>t
-fr.gtk.gtkNewTabAccel:<ctrl>t
-it.gtk.gtkNewTabAccel:<ctrl>t
-nl.gtk.gtkNewTabAccel:<ctrl>t
en.gtk.gtkNewWindow:_New Window
de.gtk.gtkNewWindow:_Neues Fenster
fr.gtk.gtkNewWindow:_Nouvelle Fenêtre
it.gtk.gtkNewWindow:_Nuova finestra
nl.gtk.gtkNewWindow:_Nieuw venster
-en.gtk.gtkNewWindowAccel:<ctrl>n
-de.gtk.gtkNewWindowAccel:<ctrl>n
-fr.gtk.gtkNewWindowAccel:<ctrl>n
-it.gtk.gtkNewWindowAccel:<ctrl>n
-nl.gtk.gtkNewWindowAccel:<ctrl>n
en.gtk.gtkOpenFile:_Open File
de.gtk.gtkOpenFile:Datei öffnen
fr.gtk.gtkOpenFile:_Ouvrir un fichier
it.gtk.gtkOpenFile:_Apri file
nl.gtk.gtkOpenFile:Bestand _openen
-en.gtk.gtkOpenFileAccel:<ctrl>o
-de.gtk.gtkOpenFileAccel:<ctrl>o
-fr.gtk.gtkOpenFileAccel:<ctrl>o
-it.gtk.gtkOpenFileAccel:<ctrl>o
-nl.gtk.gtkOpenFileAccel:<ctrl>o
en.gtk.gtkCloseWindow:_Close Window
de.gtk.gtkCloseWindow:Fenster schließen
fr.gtk.gtkCloseWindow:_Fermer la fenêtre
it.gtk.gtkCloseWindow:_Chiudi finestra
nl.gtk.gtkCloseWindow:_Venster sluiten
-en.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-de.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-fr.gtk.gtkCloseWindowAccel:<ctrl><maj>w
-it.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-nl.gtk.gtkCloseWindowAccel:<ctrl><shift>w
en.gtk.gtkSavePage:Save Page…
de.gtk.gtkSavePage:Seite speichern..
fr.gtk.gtkSavePage:Enregistrer la Page...
it.gtk.gtkSavePage:Salva pagina...
nl.gtk.gtkSavePage:Pagina bewaren...
-en.gtk.gtkSavePageAccel:<ctrl>s
-de.gtk.gtkSavePageAccel:<ctrl>s
-fr.gtk.gtkSavePageAccel:<ctrl>s
-it.gtk.gtkSavePageAccel:<ctrl>s
-nl.gtk.gtkSavePageAccel:<ctrl>s
en.gtk.gtkExport:Export
de.gtk.gtkExport:Exportieren
fr.gtk.gtkExport:Exporter
@@ -1880,62 +1864,32 @@ de.gtk.gtkPrintPreview:Druckvorschau...
fr.gtk.gtkPrintPreview:Aperçu avant impression...
it.gtk.gtkPrintPreview:Anteprima di stampa...
nl.gtk.gtkPrintPreview:Afdruk_voorbeeld...
-en.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-de.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-fr.gtk.gtkPrintPreviewAccel:<ctrl><maj>p
-it.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-nl.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
en.gtk.gtkPrint:Print…
de.gtk.gtkPrint:Drucken...
fr.gtk.gtkPrint:Imprimer...
it.gtk.gtkPrint:Stampa...
nl.gtk.gtkPrint:Af_drukken...
-en.gtk.gtkPrintAccel:<ctrl>p
-de.gtk.gtkPrintAccel:<ctrl>p
-fr.gtk.gtkPrintAccel:<ctrl>p
-it.gtk.gtkPrintAccel:<ctrl>p
-nl.gtk.gtkPrintAccel:<ctrl>p
en.gtk.gtkQuitMenu:_Quit
de.gtk.gtkQuitMenu:Beenden
fr.gtk.gtkQuitMenu:_Quitter
it.gtk.gtkQuitMenu:_Esci
nl.gtk.gtkQuitMenu:A_fsluiten
-en.gtk.gtkQuitMenuAccel:<ctrl>q
-de.gtk.gtkQuitMenuAccel:<ctrl>q
-fr.gtk.gtkQuitMenuAccel:<ctrl>q
-it.gtk.gtkQuitMenuAccel:<ctrl>q
-nl.gtk.gtkQuitMenuAccel:<ctrl>q
en.gtk.gtkCut:Cu_t
de.gtk.gtkCut:Ausschneiden
fr.gtk.gtkCut:Cou_per
it.gtk.gtkCut:Ta_glia
nl.gtk.gtkCut:K_nippen
-en.gtk.gtkCutAccel:<ctrl>x
-de.gtk.gtkCutAccel:<ctrl>x
-fr.gtk.gtkCutAccel:<ctrl>x
-it.gtk.gtkCutAccel:<ctrl>x
-nl.gtk.gtkCutAccel:<ctrl>x
en.gtk.gtkCopy:_Copy
de.gtk.gtkCopy:Kopieren
fr.gtk.gtkCopy:_Copier
it.gtk.gtkCopy:_Copia
nl.gtk.gtkCopy:_Kopiëren
-en.gtk.gtkCopyAccel:<ctrl>c
-de.gtk.gtkCopyAccel:<ctrl>c
-fr.gtk.gtkCopyAccel:<ctrl>c
-it.gtk.gtkCopyAccel:<ctrl>c
-nl.gtk.gtkCopyAccel:<ctrl>c
en.gtk.gtkPaste:_Paste
de.gtk.gtkPaste:Einfügen
fr.gtk.gtkPaste:C_oller
it.gtk.gtkPaste:_Incolla
nl.gtk.gtkPaste:_Plakken
-en.gtk.gtkPasteAccel:<ctrl>v
-de.gtk.gtkPasteAccel:<ctrl>v
-fr.gtk.gtkPasteAccel:<ctrl>v
-it.gtk.gtkPasteAccel:<ctrl>v
-nl.gtk.gtkPasteAccel:<ctrl>v
en.gtk.gtkDelete:_Delete
de.gtk.gtkDelete:Löschen
fr.gtk.gtkDelete:_Supprimer
@@ -1946,21 +1900,11 @@ de.gtk.gtkSelectAll:_Alles auswählen
fr.gtk.gtkSelectAll:_Tout sélectionner
it.gtk.gtkSelectAll:Seleziona _Tutto
nl.gtk.gtkSelectAll:_Alles selecteren
-en.gtk.gtkSelectAllAccel:<ctrl>a
-de.gtk.gtkSelectAllAccel:<ctrl>a
-fr.gtk.gtkSelectAllAccel:<ctrl>a
-it.gtk.gtkSelectAllAccel:<ctrl>a
-nl.gtk.gtkSelectAllAccel:<ctrl>a
en.gtk.gtkFind:_Find…
de.gtk.gtkFind:_Finden..
fr.gtk.gtkFind:_Rechercher...
it.gtk.gtkFind:_Trova...
nl.gtk.gtkFind:_Zoeken...
-en.gtk.gtkFindAccel:<ctrl>f
-de.gtk.gtkFindAccel:<ctrl>f
-fr.gtk.gtkFindAccel:<ctrl>f
-it.gtk.gtkFindAccel:<ctrl>f
-nl.gtk.gtkFindAccel:<ctrl>f
en.gtk.gtkPreferences:P_references
de.gtk.gtkPreferences:Einstellungen
fr.gtk.gtkPreferences:P_références
@@ -1972,21 +1916,11 @@ de.gtk.gtkStop:_Stop
fr.gtk.gtkStop:_Arrêter
it.gtk.gtkStop:_Stoppa
nl.gtk.gtkStop:_Stoppen
-en.gtk.gtkStopAccel:Escape
-de.gtk.gtkStopAccel:Escape
-fr.gtk.gtkStopAccel:Échap
-it.gtk.gtkStopAccel:Escape
-nl.gtk.gtkStopAccel:Escape
en.gtk.gtkReload:_Reload
de.gtk.gtkReload:Neu laden
fr.gtk.gtkReload:_Actualiser
it.gtk.gtkReload:_Ricarica
nl.gtk.gtkReload:Ver_nieuwen
-en.gtk.gtkReloadAccel:F5
-de.gtk.gtkReloadAccel:F5
-fr.gtk.gtkReloadAccel:F5
-it.gtk.gtkReloadAccel:F5
-nl.gtk.gtkReloadAccel:F5
en.gtk.gtkScaleView:_Scale View
de.gtk.gtkScaleView:Ansicht skalieren
fr.gtk.gtkScaleView:_Zoom
@@ -1997,51 +1931,26 @@ de.gtk.gtkZoomPlus:Here_inzoomen
fr.gtk.gtkZoomPlus:Zoom _avant
it.gtk.gtkZoomPlus:_Incrementa zoom
nl.gtk.gtkZoomPlus:_Inzoomen
-en.gtk.gtkZoomPlusAccel:<ctrl>plus
-de.gtk.gtkZoomPlusAccel:<ctrl>plus
-fr.gtk.gtkZoomPlusAccel:<ctrl>+
-it.gtk.gtkZoomPlusAccel:<ctrl>più
-nl.gtk.gtkZoomPlusAccel:<ctrl>plus
en.gtk.gtkZoomMinus:Zoom _out
de.gtk.gtkZoomMinus:Herausz_oomen
fr.gtk.gtkZoomMinus:Z_oom arrière
it.gtk.gtkZoomMinus:_Diminuisci zoom
nl.gtk.gtkZoomMinus:_Uitzoomen
-en.gtk.gtkZoomMinusAccel:<ctrl>minus
-de.gtk.gtkZoomMinusAccel:<ctrl>minus
-fr.gtk.gtkZoomMinusAccel:<ctrl>-
-it.gtk.gtkZoomMinusAccel:<ctrl>meno
-nl.gtk.gtkZoomMinusAccel:<ctrl>minus
en.gtk.gtkZoomNormal:_Normal size
de.gtk.gtkZoomNormal:_Normalgröße
fr.gtk.gtkZoomNormal:_Taille Normale
it.gtk.gtkZoomNormal:Dimensione _normale
nl.gtk.gtkZoomNormal:_Originele grootte
-en.gtk.gtkZoomNormalAccel:<ctrl>0
-de.gtk.gtkZoomNormalAccel:<ctrl>0
-fr.gtk.gtkZoomNormalAccel:<ctrl>0
-it.gtk.gtkZoomNormalAccel:<ctrl>0
-nl.gtk.gtkZoomNormalAccel:<ctrl>0
en.gtk.gtkFullScreen:_Fullscreen
de.gtk.gtkFullScreen:_Vollbild
fr.gtk.gtkFullScreen:_Plein écran
it.gtk.gtkFullScreen:_Tutto schermo
nl.gtk.gtkFullScreen:_Volledig scherm
-en.gtk.gtkFullScreenAccel:F11
-de.gtk.gtkFullScreenAccel:F11
-fr.gtk.gtkFullScreenAccel:F11
-it.gtk.gtkFullScreenAccel:F11
-nl.gtk.gtkFullScreenAccel:F11
en.gtk.gtkPageSource:Page S_ource
-de.gtk.gtkPageSource: Q_uelltext Anzeigen
+de.gtk.gtkPageSource: Q_uelltext anzeigen
fr.gtk.gtkPageSource:Code s_ource de la page
it.gtk.gtkPageSource:Mostra s_orgente
nl.gtk.gtkPageSource:Pagina_bron
-en.gtk.gtkPageSourceAccel:<ctrl>U
-de.gtk.gtkPageSourceAccel:<ctrl>U
-fr.gtk.gtkPageSourceAccel:<ctrl>U
-it.gtk.gtkPageSourceAccel:<ctrl>U
-nl.gtk.gtkPageSourceAccel:<ctrl>U
en.gtk.gtkImages:_Images
de.gtk.gtkImages:B_ilder
fr.gtk.gtkImages:_Images
@@ -2087,11 +1996,6 @@ de.gtk.gtkDownloads:_Downloads...
fr.gtk.gtkDownloads:_Téléchargements...
it.gtk.gtkDownloads:_Trasferimenti...
nl.gtk.gtkDownloads:_Downloads...
-en.gtk.gtkDownloadsAccel:<ctrl>j
-de.gtk.gtkDownloadsAccel:<ctrl>j
-fr.gtk.gtkDownloadsAccel:<ctrl>j
-it.gtk.gtkDownloadsAccel:<ctrl>j
-nl.gtk.gtkDownloadsAccel:<ctrl>j
en.gtk.gtkSaveWindowSize:S_ave Window Size
de.gtk.gtkSaveWindowSize:Fenstergröße _speichern
fr.gtk.gtkSaveWindowSize:E_nregistrer la taille de la fenêtre
@@ -2100,7 +2004,7 @@ nl.gtk.gtkSaveWindowSize:Vensteromvang ops_laan
en.gtk.gtkDeveloper:De_veloper
de.gtk.gtkDeveloper:De_veloper
fr.gtk.gtkDeveloper:Dé_veloppeur
-it.gtk.gtkDeveloper:De_veloper
+it.gtk.gtkDeveloper:S_viluppatore
nl.gtk.gtkDeveloper:_Internet ontwikkeling
en.gtk.gtkToggleDebugging:T_oggle debug rendering
de.gtk.gtkToggleDebugging:T_oggle debug rendering
@@ -2123,122 +2027,62 @@ de.gtk.gtkBack:_Zurück
fr.gtk.gtkBack:_Précédent
it.gtk.gtkBack:_Indietro
nl.gtk.gtkBack:_Terug
-en.gtk.gtkBackAccel:<alt>Left
-de.gtk.gtkBackAccel:<alt>Left
-fr.gtk.gtkBackAccel:<alt>Gauche
-it.gtk.gtkBackAccel:<alt>Sinistra
-nl.gtk.gtkBackAccel:<alt>Linkerpijltoets
en.gtk.gtkForward:_Forward
de.gtk.gtkForward:_Vorwärts
fr.gtk.gtkForward:_Suivant
it.gtk.gtkForward:_Avanti
nl.gtk.gtkForward:_Vooruit
-en.gtk.gtkForwardAccel:<alt>Right
-de.gtk.gtkForwardAccel:<alt>Right
-fr.gtk.gtkForwardAccel:<alt>Droit
-it.gtk.gtkForwardAccel:<alt>Destra
-nl.gtk.gtkForwardAccel:<alt>Rechterpijltoets
en.gtk.gtkHome:_Home
de.gtk.gtkHome:_Startseite
fr.gtk.gtkHome:_Accueil
it.gtk.gtkHome:_Home
nl.gtk.gtkHome:_Beginpagina
-en.gtk.gtkHomeAccel:<alt>Down
-de.gtk.gtkHomeAccel:<alt>Down
-fr.gtk.gtkHomeAccel:<alt>Bas
-it.gtk.gtkHomeAccel:<alt>Giù
-nl.gtk.gtkHomeAccel:<alt>Pijl omlaag
en.gtk.gtkLocalHistory:_Local History…
de.gtk.gtkLocalHistory:_Lokaler Verlauf
fr.gtk.gtkLocalHistory:Historique _local
it.gtk.gtkLocalHistory:Cronologia _locale
nl.gtk.gtkLocalHistory:Vensterge_schiedenis
-en.gtk.gtkLocalHistoryAccel:<ctrl>h
-de.gtk.gtkLocalHistoryAccel:<ctrl>h
-fr.gtk.gtkLocalHistoryAccel:<ctrl>h
-it.gtk.gtkLocalHistoryAccel:<ctrl>h
-nl.gtk.gtkLocalHistoryAccel:<ctrl>h
en.gtk.gtkGlobalHistory:_Global History…
de.gtk.gtkGlobalHistory:_Globaler Verlauf
fr.gtk.gtkGlobalHistory:Historique _global
it.gtk.gtkGlobalHistory:Cronologia _globale
nl.gtk.gtkGlobalHistory:Browser_geschiedenis
-en.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-de.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-fr.gtk.gtkGlobalHistoryAccel:<ctrl><maj>h
-it.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-nl.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
en.gtk.gtkAddBookMarks:_Add to Bookmarks…
de.gtk.gtkAddBookMarks:_Lesezeichen hinzufügen..
fr.gtk.gtkAddBookMarks:_Ajouter un marque-page..
it.gtk.gtkAddBookMarks:_Aggiungi ai segnalibri...
nl.gtk.gtkAddBookMarks:_Aan bladwijzers toevoegen...
-en.gtk.gtkAddBookMarksAccel:<ctrl>d
-de.gtk.gtkAddBookMarksAccel:<ctrl>d
-fr.gtk.gtkAddBookMarksAccel:<ctrl>d
-it.gtk.gtkAddBookMarksAccel:<ctrl>d
-nl.gtk.gtkAddBookMarksAccel:<ctrl>d
en.gtk.gtkShowBookMarks:_Show Bookmarks…
de.gtk.gtkShowBookMarks:Le_sezeichen anzeigen..
fr.gtk.gtkShowBookMarks:_Montrer les marques-pages...
it.gtk.gtkShowBookMarks:_Mostra segnalibri...
nl.gtk.gtkShowBookMarks:Bladwijzers _beheren...
-en.gtk.gtkShowBookMarksAccel:F6
-de.gtk.gtkShowBookMarksAccel:F6
-fr.gtk.gtkShowBookMarksAccel:F6
-it.gtk.gtkShowBookMarksAccel:F6
-nl.gtk.gtkShowBookMarksAccel:F6
en.gtk.gtkShowCookies:Show _Cookies…
-de.gtk.gtkShowCookies:Show _Cookies..
+de.gtk.gtkShowCookies:Zeige _Cookies…
fr.gtk.gtkShowCookies:Afficher _cookies...
it.gtk.gtkShowCookies:Mostra _cookie...
nl.gtk.gtkShowCookies:_Cookies beheren...
-en.gtk.gtkShowCookiesAccel:F9
-de.gtk.gtkShowCookiesAccel:F9
-fr.gtk.gtkShowCookiesAccel:F9
-it.gtk.gtkShowCookiesAccel:F9
-nl.gtk.gtkShowCookiesAccel:F9
en.gtk.gtkOpenLocation:_Open Location…
de.gtk.gtkOpenLocation:_Ort öffnen..
fr.gtk.gtkOpenLocation:_Ouvrir un site..
it.gtk.gtkOpenLocation:_Apri indirizzo...
nl.gtk.gtkOpenLocation:Locatie _openen..
-en.gtk.gtkOpenLocationAccel:<ctrl>l
-de.gtk.gtkOpenLocationAccel:<ctrl>l
-fr.gtk.gtkOpenLocationAccel:<ctrl>l
-it.gtk.gtkOpenLocationAccel:<ctrl>l
-nl.gtk.gtkOpenLocationAccel:<ctrl>l
en.gtk.gtkNextTab:_Next tab
de.gtk.gtkNextTab:_Nächster Tab
fr.gtk.gtkNextTab:O_nglet suivant
it.gtk.gtkNextTab:Scheda _successiva
nl.gtk.gtkNextTab:Vol_gende tabblad
-en.gtk.gtkNextTabAccel:<ctrl>Right
-de.gtk.gtkNextTabAccel:<ctrl>Right
-fr.gtk.gtkNextTabAccel:<ctrl>Droit
-it.gtk.gtkNextTabAccel:<ctrl>Destra
-nl.gtk.gtkNextTabAccel:<ctrl>Rechterpijltoets
en.gtk.gtkPrevTab:_Previous tab
-de.gtk.gtkPrevTab:_Vorheriger tab
+de.gtk.gtkPrevTab:_Vorheriger Tab
fr.gtk.gtkPrevTab:Onglet _précédent
it.gtk.gtkPrevTab:Scheda _precedente
nl.gtk.gtkPrevTab:Vo_rige tabblad
-en.gtk.gtkPrevTabAccel:<ctrl>Left
-de.gtk.gtkPrevTabAccel:<ctrl>Left
-fr.gtk.gtkPrevTabAccel:<ctrl>Gauche
-it.gtk.gtkPrevTabAccel:<ctrl>Sinistra
-nl.gtk.gtkPrevTabAccel:<ctrl>Linkerpijltoets
en.gtk.gtkCloseTab:_Close tab
de.gtk.gtkCloseTab:Tab s_chliessen
fr.gtk.gtkCloseTab:_Fermer l'onglet
it.gtk.gtkCloseTab:_Chiudi scheda
nl.gtk.gtkCloseTab:Tabblad _sluiten
-en.gtk.gtkCloseTabAccel:<ctrl>w
-de.gtk.gtkCloseTabAccel:<ctrl>w
-fr.gtk.gtkCloseTabAccel:<ctrl>w
-it.gtk.gtkCloseTabAccel:<ctrl>w
-nl.gtk.gtkCloseTabAccel:<ctrl>w
en.gtk.gtkContents:_Contents…
de.gtk.gtkContents:_Inhalt
@@ -2248,22 +2092,22 @@ nl.gtk.gtkContents:_Inhoud
en.gtk.gtkGuide:User _guide…
de.gtk.gtkGuide:H_andbuch
fr.gtk.gtkGuide:_Guide utilisateur
-it.gtk.gtkGuide:_Guida in linea
+it.gtk.gtkGuide:_Guida in linea...
nl.gtk.gtkGuide:Gebruiks_aanwijzing...
en.gtk.gtkUserInformation:User _information…
de.gtk.gtkUserInformation:Benutzer_information
fr.gtk.gtkUserInformation:_Information utilisateur
-it.gtk.gtkUserInformation:Informazioni _utente
+it.gtk.gtkUserInformation:Informazioni _utente...
nl.gtk.gtkUserInformation:Gebruikers_informatie...
en.gtk.gtkAbout:_About…
de.gtk.gtkAbout:Ü_ber
fr.gtk.gtkAbout:_A propos...
-it.gtk.gtkAbout:_Informazioni
+it.gtk.gtkAbout:_Informazioni...
nl.gtk.gtkAbout:_Programma-informatie...
en.gtk.gtkCustomize:Customise…
-de.gtk.gtkCustomize:Customise..
+de.gtk.gtkCustomize:Anpassen…
fr.gtk.gtkCustomize:Personnaliser...
it.gtk.gtkCustomize:Personalizza...
nl.gtk.gtkCustomize:Aanpassen...
@@ -2283,14 +2127,14 @@ fr.gtk.gtkSavelink:Enregistrer li_en
it.gtk.gtkSavelink:Salva Lin_k
nl.gtk.gtkSavelink:_Koppeling opslaan als...
en.gtk.gtkBookmarklink:Bookmark _Link
-de.gtk.gtkBookmarklink:Bookmark _Link
+de.gtk.gtkBookmarklink:_Link als Bookmark
fr.gtk.gtkBookmarklink:Marquer _Lien
-it.gtk.gtkBookmarklink:Bookmark _Link
+it.gtk.gtkBookmarklink:A_ggiungi ai segnalibri
nl.gtk.gtkBookmarklink:B_ladwijzer voor de koppeling maken
en.gtk.gtkCopylink:Copy link loc_ation
-de.gtk.gtkCopylink:Copy link loc_ation
+de.gtk.gtkCopylink:Link_adresse kopieren
fr.gtk.gtkCopylink:_Copier le lien
-it.gtk.gtkCopylink:Copy link loc_ation
+it.gtk.gtkCopylink:Copia in_dirizzo link
nl.gtk.gtkCopylink:Koppelingsloc_atie kopiëren
@@ -2329,376 +2173,496 @@ nl.gtk.gtkThemeAdd:Thema is succesvol toegevoegd
# GTK preferences dialog
en.gtk.preferencesTitle:Netsurf Preferences
+de.gtk.preferencesTitle:Netsurf Einstellungen
fr.gtk.preferencesTitle:Préférences de Netsurf
nl.gtk.preferencesTitle:Netsurf-voorkeuren
# Main tab
en.gtk.preferencesMainTabtitle:Main
+de.gtk.preferencesMainTabtitle:Allgemein
fr.gtk.preferencesMainTabtitle:Accueil/Principal
nl.gtk.preferencesMainTabtitle:Algemeen
en.gtk.preferencesStartup:<b>Startup</b>
+de.gtk.preferencesStartup:<b>Starten</b>
fr.gtk.preferencesStartup:<b>Démarrage</b>
nl.gtk.preferencesStartup:<b>Opstarten</b>
en.gtk.preferencesStartupPage:Page:
+de.gtk.preferencesStartupPage:Seite:
fr.gtk.preferencesStartupPage:Page:
nl.gtk.preferencesStartupPage:Pagina:
en.gtk.preferencesStartupPageTooltip:The default startup page
+de.gtk.preferencesStartupPageTooltip:Die Standard Startseite
fr.gtk.preferencesStartupPageTooltip:La page de démarrage par défaut
nl.gtk.preferencesStartupPageTooltip:De standaard startpagina
en.gtk.preferencesStartupPageDefault:Use Default Page
+de.gtk.preferencesStartupPageDefault:Standard Seite nutzen
fr.gtk.preferencesStartupPageDefault:Utiliser la page par défaut
nl.gtk.preferencesStartupPageDefault:Standaard herstellen
en.gtk.preferencesStartupPageCurrent:Use Current Page
+de.gtk.preferencesStartupPageCurrent:aktuelle Seite nehmen
fr.gtk.preferencesStartupPageCurrent:Utiliser la page en cours
nl.gtk.preferencesStartupPageCurrent:Huidige pagina gebruiken
en.gtk.preferencesSearch:<b>Search</b>
+de.gtk.preferencesSearch:<b>Suchen</b>
fr.gtk.preferencesSearch:<b>Recherche</b>
nl.gtk.preferencesSearch:<b>Zoeken</b>
en.gtk.preferencesSearchURLBar:Search from URL bar
+de.gtk.preferencesSearchURLBar:Adressleiste zum Suchen
fr.gtk.preferencesSearchURLBar:Recherche depuis la barre d'URL
nl.gtk.preferencesSearchURLBar:Standaardzoekmachine
en.gtk.preferencesSearchProvider:Provider:
+de.gtk.preferencesSearchProvider:Anbieter:
fr.gtk.preferencesSearchProvider:Fournisseur :
nl.gtk.preferencesSearchProvider:Zoeken met:
en.gtk.preferencesSearchProviderTooltip:The default web search provider
+de.gtk.preferencesSearchProviderTooltip:Voreingestellter Suchanbieter
fr.gtk.preferencesSearchProviderTooltip:Le fournisseur de recherche sur le web par défaut
nl.gtk.preferencesSearchProviderTooltip:Kies de standaardzoekmachine. NetSurf gebruikt deze in de zoekbalk.
en.gtk.preferencesDownloads:<b>Downloads</b>
+de.gtk.preferencesDownloads:<b>Downloads</b>
fr.gtk.preferencesDownloads:<b>Téléchargements</b>
nl.gtk.preferencesDownloads:<b>Downloads</b>
en.gtk.preferencesDownloadsRemove:Remove download from list when complete
+de.gtk.preferencesDownloadsRemove:abgeschlossene Downloads auslisten
fr.gtk.preferencesDownloadsRemove:Retirer le téléchargement de la liste une fois terminé
nl.gtk.preferencesDownloadsRemove:Downloadvermeldingen verwijderen
en.gtk.preferencesDownloadsConfirm:Confirm before overwriting files
+de.gtk.preferencesDownloadsConfirm:Überschreiben bestätigen
fr.gtk.preferencesDownloadsConfirm:Confirmer avant d'écraser des fichiers
nl.gtk.preferencesDownloadsConfirm:Overschrijven van bestand bevestigen
en.gtk.preferencesDownloadsLocation:Location:
+de.gtk.preferencesDownloadsLocation:Zielort:
fr.gtk.preferencesDownloadsLocation:Emplacement :
nl.gtk.preferencesDownloadsLocation:Bestanden opslaan in:
en.gtk.preferencesDownloadsLocationTooltip:The default location downloaded files are put
+de.gtk.preferencesDownloadsLocationTooltip:Speicherort für Downloads
fr.gtk.preferencesDownloadsLocationTooltip:L'emplacement par défaut des fichiers téléchargés sont mis
nl.gtk.preferencesDownloadsLocationTooltip:De standaardplaats waar gedownloade bestanden worden opgeslagen
# Appearance tab
en.gtk.preferencesAppearanceTabtitle:Appearance
+de.gtk.preferencesAppearanceTabtitle:Aussehen
fr.gtk.preferencesAppearanceTabtitle:Apparence
nl.gtk.preferencesAppearanceTabtitle:Vormgeving
en.gtk.preferencesThemes:<b>Themes</b>
+de.gtk.preferencesThemes:<b>Themen</b>
fr.gtk.preferencesThemes:<b>Thèmes</b>
nl.gtk.preferencesThemes:<b>Thema's</b>
en.gtk.preferencesThemesAdd:Add Theme...
+de.gtk.preferencesThemesAdd:Thema hinzu...
fr.gtk.preferencesThemesAdd:Ajouter thème...
nl.gtk.preferencesThemesAdd:Thema toevoegen...
en.gtk.preferencesTabs:<b>Tabs</b>
+de.gtk.preferencesTabs:<b>Tabs</b>
fr.gtk.preferencesTabs:<b>Onglets</b>
nl.gtk.preferencesTabs:<b>Tabbladen</b>
en.gtk.preferencesTabsAlways:Always show tab bar
+de.gtk.preferencesTabsAlways:Tableiste immer anzeigen
fr.gtk.preferencesTabsAlways:Toujours afficher la barre d'onglet
nl.gtk.preferencesTabsAlways:De tabbladenwerkbalk verbergen wanneer slechts één tabblad is geopend
en.gtk.preferencesTabsSwitch:Switch to newly opened tabs immediately
+de.gtk.preferencesTabsSwitch:neue Tabs sofort in Vordergrund
fr.gtk.preferencesTabsSwitch:Passer à l'onglet nouvellement ouvert immédiatement
nl.gtk.preferencesTabsSwitch:Naar vanuit koppeling geopende nieuwe tabbladen schakelen
en.gtk.preferencesTabsNewly:Newly opened tabs are blank
+de.gtk.preferencesTabsNewly:neue Tabs als leere Seite
fr.gtk.preferencesTabsNewly:Onglet récemment ouvert est vièrge
nl.gtk.preferencesTabsNewly:Geopende nieuwe tabbladen zijn leeg inplaats van de startpagina
en.gtk.preferencesTabsPosition:Position:
+de.gtk.preferencesTabsPosition:Position:
fr.gtk.preferencesTabsPosition:Position :
nl.gtk.preferencesTabsPosition:Positie in venster:
en.gtk.preferencesTools:<b>Tools</b>
+de.gtk.preferencesTools:<b>Tools</b>
fr.gtk.preferencesTools:<b>Outils</b>
nl.gtk.preferencesTools:<b>Ontwikkelaarshulpmiddelen</b>
en.gtk.preferencesDeveloperView:Open developer views in a
+de.gtk.preferencesDeveloperView:Entwickleransicht öffnen in
fr.gtk.preferencesDeveloperView:Vues de développement s'ouvrent dans
nl.gtk.preferencesDeveloperView:Informatie voor ontwikkelaars openen in
en.gtk.preferencesDeveloperViewWindow:Window
+de.gtk.preferencesDeveloperViewWindow:Fenster
fr.gtk.preferencesDeveloperViewWindow:un fenêtre
nl.gtk.preferencesDeveloperViewWindow:Venster
en.gtk.preferencesDeveloperViewTab:Tab
+de.gtk.preferencesDeveloperViewTab:Tab
fr.gtk.preferencesDeveloperViewTab:un onglet
nl.gtk.preferencesDeveloperViewTab:Tabblad
en.gtk.preferencesDeveloperViewEditor:Editor
+de.gtk.preferencesDeveloperViewEditor:Editor
fr.gtk.preferencesDeveloperViewEditor:Éditeur
nl.gtk.preferencesDeveloperViewEditor:Tekst-editor
en.gtk.preferencesURLbar:<b>URLbar</b>
+de.gtk.preferencesURLbar:<b>Adressleiste</b>
fr.gtk.preferencesURLbar:<b>Barre URL</b>
nl.gtk.preferencesURLbar:<b>Locatiebalk</b>
en.gtk.preferencesURLbarDisplay:Display recently visited URLs as you type
+de.gtk.preferencesURLbarDisplay:benutzte URLs während Eingabe zeigen
fr.gtk.preferencesURLbarDisplay:Afficher les URL visités récemment lorsque vous tapez
nl.gtk.preferencesURLbarDisplay:Automatisch aanvullen vanuit de browsergeschiedenis tijdens het typen
en.gtk.preferencesToolbar:<b>Toolbar</b>
+de.gtk.preferencesToolbar:<b>Knopfleiste</b>
fr.gtk.preferencesToolbar:<b>Barre d'outils</b>
nl.gtk.preferencesToolbar:<b>Werkbalk</b>
en.gtk.preferencesToolbarButtons:Buttons:
+de.gtk.preferencesToolbarButtons:Gestalt:
fr.gtk.preferencesToolbarButtons:Boutons :
nl.gtk.preferencesToolbarButtons:Knoppen:
# Theme list
en.gtk.preferencesThemeTypeDefault:Default
+de.gtk.preferencesThemeTypeDefault:Standard
fr.gtk.preferencesThemeTypeDefault:Défaut
nl.gtk.preferencesThemeTypeDefault:Standaard
# Tab position list
en.gtk.preferencesTabLocTop:Top
+de.gtk.preferencesTabLocTop:Oben
fr.gtk.preferencesTabLocTop:Haut
nl.gtk.preferencesTabLocTop:Bovenaan
en.gtk.preferencesTabLocLeft:Left
+de.gtk.preferencesTabLocLeft:Links
fr.gtk.preferencesTabLocLeft:Gauche
nl.gtk.preferencesTabLocLeft:Links
en.gtk.preferencesTabLocBottom:Bottom
+de.gtk.preferencesTabLocBottom:Unten
fr.gtk.preferencesTabLocBottom:Bas
nl.gtk.preferencesTabLocBottom:Onderaan
en.gtk.preferencesTabLocRight:Right
+de.gtk.preferencesTabLocRight:Rechts
fr.gtk.preferencesTabLocRight:Droite
nl.gtk.preferencesTabLocRight:Rechts
# button list
en.gtk.preferencesButtonTypeSmall:Small Icons
+de.gtk.preferencesButtonTypeSmall:Kleine Icons
fr.gtk.preferencesButtonTypeSmall:Petites icônes
nl.gtk.preferencesButtonTypeSmall:Kleine pictogrammen
en.gtk.preferencesButtonTypeLarge:Large Icons
+de.gtk.preferencesButtonTypeLarge:Große Icons
fr.gtk.preferencesButtonTypeLarge:Grandes icônes
nl.gtk.preferencesButtonTypeLarge:Grote pictogrammen
en.gtk.preferencesButtonTypeLargeText:Large Icons and Text
+de.gtk.preferencesButtonTypeLargeText:Große Icons mit Text
fr.gtk.preferencesButtonTypeLargeText:Grandes icônes et texte
nl.gtk.preferencesButtonTypeLargeText:Grote pictogrammen en tekst
en.gtk.preferencesButtonTypeText:Text only
+de.gtk.preferencesButtonTypeText:Text ohne Icons
fr.gtk.preferencesButtonTypeText:Texte uniquement
nl.gtk.preferencesButtonTypeText:Alleen tekst
# content tab
en.gtk.preferencesContentTabtitle:Content
+de.gtk.preferencesContentTabtitle:Inhalte
fr.gtk.preferencesContentTabtitle:Contenu
nl.gtk.preferencesContentTabtitle:Inhoud
en.gtk.preferencesControl:<b>Control</b>
+de.gtk.preferencesControl:<b>Steuerung</b>
fr.gtk.preferencesControl:<b>Contrôle</b>
nl.gtk.preferencesControl:<b>Opties</b>
en.gtk.preferencesControlPrevent:Prevent pop-up windows
+de.gtk.preferencesControlPrevent:Pop-Up Fenster blocken
fr.gtk.preferencesControlPrevent:Empêcher fenêtres pop-up
nl.gtk.preferencesControlPrevent:Pop-upvensters blokkeren
en.gtk.preferencesControlHide:Hide Adverts
+de.gtk.preferencesControlHide:Werbung unterdrücken
fr.gtk.preferencesControlHide:Cacher les publicités
nl.gtk.preferencesControlHide:Advertenties verbergen
en.gtk.preferencesControlEnable:Enable JavaScript
+de.gtk.preferencesControlEnable:JavaScript einschalten
fr.gtk.preferencesControlEnable:Activer JavaScript
nl.gtk.preferencesControlEnable:JavaScript inschakelen
en.gtk.preferencesControlDisable:Disable plug-ins
+de.gtk.preferencesControlDisable:Plug-Ins abschalten
fr.gtk.preferencesControlDisable:Désactiver modules externes
nl.gtk.preferencesControlDisable:Plug-ins uitschakelen
en.gtk.preferencesControlHigh:High quality image scaling
+de.gtk.preferencesControlHigh:Bildskalierung hoher Qualität
fr.gtk.preferencesControlHigh:Haute qualité d'image redimensionnée
nl.gtk.preferencesControlHigh:Schalen op hoge beeldkwaliteit
en.gtk.preferencesControlLoad:Load and display
+de.gtk.preferencesControlLoad:laden und anzeigen
fr.gtk.preferencesControlLoad:Charger et visualiser
nl.gtk.preferencesControlLoad:Laad en toon
en.gtk.preferencesAnimation:<b>Animation</b>
+de.gtk.preferencesAnimation:<b>Animation</b>
fr.gtk.preferencesAnimation:<b>Animation</b>
nl.gtk.preferencesAnimation:<b>Animaties</b>
en.gtk.preferencesAnimationEnable:Enable
+de.gtk.preferencesAnimationEnable:zulassen
fr.gtk.preferencesAnimationEnable:Activer
nl.gtk.preferencesAnimationEnable:Ingeschakeld
en.gtk.preferencesAnimationMinimum:Minimum time between frames:
+de.gtk.preferencesAnimationMinimum:minimale Zeit zwischen Frames:
fr.gtk.preferencesAnimationMinimum:Temps minimal entre cadres/frames/images/photo :
nl.gtk.preferencesAnimationMinimum:Minimum tijd tussen opeenvolgende animatiebeelden:
en.gtk.preferencesAnimationMinimumTooltip:Do not update animations any more often than this.
+de.gtk.preferencesAnimationMinimumTooltip:Animation nicht öfter als so aktualisieren
fr.gtk.preferencesAnimationMinimumTooltip:Ne pas mettre à jour les animations plus souvent que cela.
nl.gtk.preferencesAnimationMinimumTooltip:Animaties niet vaker actualiseren dan dit.
en.gtk.preferencesFonts:<b>Fonts</b>
+de.gtk.preferencesFonts:<b>Fonts</b>
fr.gtk.preferencesFonts:<b>Fontes/Polices</b>
nl.gtk.preferencesFonts:<b>Lettertypen</b>
en.gtk.preferencesFontsDefault:Default
+de.gtk.preferencesFontsDefault:Standard
fr.gtk.preferencesFontsDefault:Défaut
nl.gtk.preferencesFontsDefault:Standaard
en.gtk.preferencesFontsSize:Size
+de.gtk.preferencesFontsSize:Größe
fr.gtk.preferencesFontsSize:Taille
nl.gtk.preferencesFontsSize:Grootte
en.gtk.preferencesFontsSizeTooltip:The base-line font size to use.
+de.gtk.preferencesFontsSizeTooltip:Die Standardgröße für Basisschriften.
fr.gtk.preferencesFontsSizeTooltip:La taille de la fonte/police de base à utiliser.
nl.gtk.preferencesFontsSizeTooltip:Het standaardlettertype te gebruiken voor webpagina's.
en.gtk.preferencesFontsPreview:_Preview
+de.gtk.preferencesFontsPreview:Vorschau
fr.gtk.preferencesFontsPreview:A_perçu
nl.gtk.preferencesFontsPreview:_Voorbeeld
en.gtk.preferencesLanguage:<b>Language</b>
+de.gtk.preferencesLanguage:<b>Sprache</b>
fr.gtk.preferencesLanguage:<b>Langue</b>
nl.gtk.preferencesLanguage:<b>Talen</b>
en.gtk.preferencesLanguagePreferred:Preferred language:
+de.gtk.preferencesLanguagePreferred:bevorzugte Sprache:
fr.gtk.preferencesLanguagePreferred:Langue préférée :
nl.gtk.preferencesLanguagePreferred:Voorkeurtaal:
en.gtk.preferencesLanguagePreferredTooltip:The preferred language for web pages
+de.gtk.preferencesLanguagePreferredTooltip:Die gewünschte Sprache für Webseiten
fr.gtk.preferencesLanguagePreferredTooltip:La langue préférée pour les pages Web
nl.gtk.preferencesLanguagePreferredTooltip:De voorkeurtaal voor webpagina's
# Image loading list
en.gtk.preferencesImageLoadBoth:foreground and background images
+de.gtk.preferencesImageLoadBoth:Vorder- und Hintergrundbilder
fr.gtk.preferencesImageLoadBoth:Images d'avant-plan et d'arrière-plan
nl.gtk.preferencesImageLoadBoth:voorgrond- en achtergrondafbeeldingen
en.gtk.preferencesImageLoadFore:foreground images
+de.gtk.preferencesImageLoadFore:Vordergrundbilder
fr.gtk.preferencesImageLoadFore:Images d'avant-plan
nl.gtk.preferencesImageLoadFore:voorgrondafbeeldingen
en.gtk.preferencesImageLoadBack:background images
+de.gtk.preferencesImageLoadBack:Hintergrundbilder
fr.gtk.preferencesImageLoadBack:Images d'arrière-plan
nl.gtk.preferencesImageLoadBack:achtergrondafbeeldingen
en.gtk.preferencesImageLoadNone:no images
+de.gtk.preferencesImageLoadNone:Keine Bidlder
fr.gtk.preferencesImageLoadNone:pas d'images
nl.gtk.preferencesImageLoadNone:geen afbeeldingen
# font type list
en.gtk.preferencesFonttypeSans:Sans-serif
+de.gtk.preferencesFonttypeSans:Sans-serif
fr.gtk.preferencesFonttypeSans:Sans-serif
nl.gtk.preferencesFonttypeSans:Schreefloos
en.gtk.preferencesFonttypeSerif:Serif
+de.gtk.preferencesFonttypeSerif:Serif
fr.gtk.preferencesFonttypeSerif:Serif
nl.gtk.preferencesFonttypeSerif:Met schreef
en.gtk.preferencesFonttypeMonospace:Monospace
+de.gtk.preferencesFonttypeMonospace:Monospace
fr.gtk.preferencesFonttypeMonospace:Monospace
nl.gtk.preferencesFonttypeMonospace:Monospace
en.gtk.preferencesFonttypeCursive:Cursive
+de.gtk.preferencesFonttypeCursive:Kursiv
fr.gtk.preferencesFonttypeCursive:Cursive
nl.gtk.preferencesFonttypeCursive:Cursief
en.gtk.preferencesFonttypeFantasy:Fantasy
+de.gtk.preferencesFonttypeFantasy:Fantasy
fr.gtk.preferencesFonttypeFantasy:Fantasy
nl.gtk.preferencesFonttypeFantasy:Fantasie
en.gtk.preferencesPrivacyTabtitle:Privacy
+de.gtk.preferencesPrivacyTabtitle:Privates
fr.gtk.preferencesPrivacyTabtitle:Confidentialité
nl.gtk.preferencesPrivacyTabtitle:Privacy
en.gtk.preferencesGeneral:<b>General</b>
+de.gtk.preferencesGeneral:<b>Generelles</b>
fr.gtk.preferencesGeneral:<b>Général</b>
nl.gtk.preferencesGeneral:<b>Algemeen</b>
en.gtk.preferencesGeneralReferral:Enable referral submission
+de.gtk.preferencesGeneralReferral:Referenzen erlauben
fr.gtk.preferencesGeneralReferral:Permettre l'envoi du referer en entête
nl.gtk.preferencesGeneralReferral:Referentie versturen inschakelen
en.gtk.preferencesGeneralDNT:Enable sending "Do Not Track" request
+de.gtk.preferencesGeneralDNT:Webseiten sollen nicht nachverfolgen dürfen
fr.gtk.preferencesGeneralDNT:Activer l'envoi d'une requête "Ne pas suivre à la trace"
nl.gtk.preferencesGeneralDNT:Websites laten weten dat gebruiker niet gevolgd wil worden
en.gtk.preferencesHistory:<b>History</b>
+de.gtk.preferencesHistory:<b>History</b>
fr.gtk.preferencesHistory:<b>Historque</b>
nl.gtk.preferencesHistory:<b>Geschiedenis</b>
en.gtk.preferencesHistoryShow:Local history shows URL in tooltip
+de.gtk.preferencesHistoryShow:History (lokal) zeigt die URL in der Hilfe an
fr.gtk.preferencesHistoryShow:Historique local dans une infobulle
nl.gtk.preferencesHistoryShow:Venstergeschiedenis toont webadres in een tipkader
en.gtk.preferencesHistoryRemember:Remember browsing history for up to
+de.gtk.preferencesHistoryRemember:History merken für bis zu
fr.gtk.preferencesHistoryRemember:Conserver l'historique de navigation pendant
nl.gtk.preferencesHistoryRemember:Browsergeschiedenis onthouden voor
en.gtk.preferencesHistoryDays:days
+de.gtk.preferencesHistoryDays:Tage(n)
fr.gtk.preferencesHistoryDays:jours
nl.gtk.preferencesHistoryDays:dag(en)
en.gtk.preferencesCache:<b>Cache</b>
+de.gtk.preferencesCache:<b>Cache</b>
fr.gtk.preferencesCache:<b>Cache</b>
nl.gtk.preferencesCache:<b>Buffer</b>
en.gtk.preferencesCacheMemory:Memory cache size
+de.gtk.preferencesCacheMemory:RAM Cache
fr.gtk.preferencesCacheMemory:Taille du cache mémoire
nl.gtk.preferencesCacheMemory:Grootte geheugenbuffer
en.gtk.preferencesCacheDisc:Disc cache size
+de.gtk.preferencesCacheDisc:Festplatten Cache
fr.gtk.preferencesCacheDisc:Taille du cache disque
nl.gtk.preferencesCacheDisc:Grootte schijfbuffer
en.gtk.preferencesCacheExpire:Expire cache entries after
+de.gtk.preferencesCacheExpire:Einträge verfallen nach
fr.gtk.preferencesCacheExpire:Les entrées du cache expirent après un délai de
nl.gtk.preferencesCacheExpire:Buffergegevens vervallen na
en.gtk.preferencesCacheMaintenance:Maintenance
+de.gtk.preferencesCacheMaintenance:Aufräumen
fr.gtk.preferencesCacheMaintenance:Maintenance
nl.gtk.preferencesCacheMaintenance:Onderhoud
en.gtk.preferencesCacheDays:days
+de.gtk.preferencesCacheDays:Tage(n)
fr.gtk.preferencesCacheDays:jours
nl.gtk.preferencesCacheDays:dag(en)
en.gtk.preferencesNetworkTabtitle:Network
+de.gtk.preferencesNetworkTabtitle:Netzwerk
fr.gtk.preferencesNetworkTabtitle:Réseau
nl.gtk.preferencesNetworkTabtitle:Netwerk
en.gtk.preferencesProxy:<b>HTTP Proxy</b>
+de.gtk.preferencesProxy:<b>HTTP Proxy</b>
fr.gtk.preferencesProxy:<b>Proxy HTTP</b>
nl.gtk.preferencesProxy:<b>HTTP-proxy</b>
en.gtk.preferencesProxyType:Proxy type
+de.gtk.preferencesProxyType:Proxytyp
fr.gtk.preferencesProxyType:Type de Proxy
nl.gtk.preferencesProxyType:Proxy-type
en.gtk.preferencesProxyHost:Host
+de.gtk.preferencesProxyHost:Host
fr.gtk.preferencesProxyHost:Hôte
nl.gtk.preferencesProxyHost:Proxy-server
en.gtk.preferencesProxyUsername:Username
+de.gtk.preferencesProxyUsername:Benutzer
fr.gtk.preferencesProxyUsername:Nom d'utilisateur
nl.gtk.preferencesProxyUsername:Gebruikersnaam
en.gtk.preferencesProxyPassword:Password
+de.gtk.preferencesProxyPassword:Passwort
fr.gtk.preferencesProxyPassword:Mot de passe
nl.gtk.preferencesProxyPassword:Wachtwoord
en.gtk.preferencesProxyNoproxy:No Proxy For
+de.gtk.preferencesProxyNoproxy:Kein Proxy für
fr.gtk.preferencesProxyNoproxy:Pas de proxy pour
nl.gtk.preferencesProxyNoproxy:Geen proxy voor
en.gtk.preferencesProxyTypeTooltip:The type of HTTP proxy server.
+de.gtk.preferencesProxyTypeTooltip:Der Type des HTTP Proxy-Servers.
fr.gtk.preferencesProxyTypeTooltip:Le type de serveur proxy HTTP.
nl.gtk.preferencesProxyTypeTooltip:Het type van de HTTP-proxy-server.
en.gtk.preferencesProxyHostTooltip:Host name of your proxy server.
+de.gtk.preferencesProxyHostTooltip:Hostname des Proxy-Servers.
fr.gtk.preferencesProxyHostTooltip:Nom d'hôte du serveur proxy.
nl.gtk.preferencesProxyHostTooltip:Adres van de proxy-server.
en.gtk.preferencesProxyPortTooltip:Port number to connect to on proxy server.
+de.gtk.preferencesProxyPortTooltip:Portnummer für die Verbindung zum Proxy.
fr.gtk.preferencesProxyPortTooltip:Le numéro de port pour se connecter au serveur proxy.
nl.gtk.preferencesProxyPortTooltip:Poortnummer om te verbinden met de proxy-server.
en.gtk.preferencesProxyUsernameTooltip:Username to access the proxy.
+de.gtk.preferencesProxyUsernameTooltip:Username für die Verbindung zum Proxy.
fr.gtk.preferencesProxyUsernameTooltip:Nom d'utilisateur pour accéder au proxy.
nl.gtk.preferencesProxyUsernameTooltip:Gebruikersnaam voor toegang tot de proxy.
en.gtk.preferencesProxyNoproxyTooltip:Comma separated list of host names that should not be proxied.
+de.gtk.preferencesProxyNoproxyTooltip:Liste von Hosts, die kein Proxy sein sollen. Komma trennt Einträge.
fr.gtk.preferencesProxyNoproxyTooltip:Liste des noms d'hôtes séparés par des virgules qui ne devraient pas être traitées par le proxy.
nl.gtk.preferencesProxyNoproxyTooltip:Lijst van ip-adressen of servernamen die niet via de proxy mogen lopen, gescheiden door komma's.
en.gtk.preferencesFetching:<b>Fetching</b>
+de.gtk.preferencesFetching:<b>Daten holen (Fetch)</b>
fr.gtk.preferencesFetching:<b>Connexions</b>
nl.gtk.preferencesFetching:<b>Verbindingen</b>
en.gtk.preferencesFetchingMax:Maximum fetchers
+de.gtk.preferencesFetchingMax:Verbindungen maximal
fr.gtk.preferencesFetchingMax:Nombre maximum de connexions
nl.gtk.preferencesFetchingMax:Maximum aantal
en.gtk.preferencesFetchingPerhost:Fetches per host
+de.gtk.preferencesFetchingPerhost:Verbindungen pro Host
fr.gtk.preferencesFetchingPerhost:Nombre de connexions par hôte
nl.gtk.preferencesFetchingPerhost:Aantal verbindingen per server
en.gtk.preferencesFetchingCached:Cached connections
+de.gtk.preferencesFetchingCached:gepufferte Verbindungen
fr.gtk.preferencesFetchingCached:Connexions en cache
nl.gtk.preferencesFetchingCached:Gebufferde verbindingen
en.gtk.preferencesFetchingMaxTooltip:Maximum number of concurrent items to fetch at once.
+de.gtk.preferencesFetchingMaxTooltip:Maximale Anzahl paralleler Verbindungen.
fr.gtk.preferencesFetchingMaxTooltip:Nombre maximum d'éléments simultanés à récupérer
nl.gtk.preferencesFetchingMaxTooltip:Maximum aantal verbindingen die simultaan items ophalen.
en.gtk.preferencesFetchingPerhostTooltip:Maximum number of item fetches per web server.
+de.gtk.preferencesFetchingPerhostTooltip:Maximale Zahl je Webserver.
fr.gtk.preferencesFetchingPerhostTooltip:Nombre maximum d'élément à extrair pour chaque serveur Web.
nl.gtk.preferencesFetchingPerhostTooltip:Maximum aantal verbinden per webserver.
en.gtk.preferencesFetchingCachedTooltip:Number of connections to keep in case they are needed again.
+de.gtk.preferencesFetchingCachedTooltip:Zahl offengehaltener Verbindungen für den Fall, daß sie nochmal benötigt werden.
fr.gtk.preferencesFetchingCachedTooltip:Nombre de connexions à maintenir dans le cas où elles seront nécessaires à nouveau.
nl.gtk.preferencesFetchingCachedTooltip:Aantal verbindingen te bufferen voor het geval ze zijn weer nodig.
# Proxy type list
en.gtk.preferencesProxyTypeDirect:Direct connection
+de.gtk.preferencesProxyTypeDirect:Direktverbindung
fr.gtk.preferencesProxyTypeDirect:Connexion directe
nl.gtk.preferencesProxyTypeDirect:Directe verbinding
en.gtk.preferencesProxyTypeManual:Manual with no authentication
+de.gtk.preferencesProxyTypeManual:Manuell ohne Authentifizierung
fr.gtk.preferencesProxyTypeManual:Manuel sans authentification
nl.gtk.preferencesProxyTypeManual:Handmatig zonder authenticatie
en.gtk.preferencesProxyTypeBasic:Manual with basic authentication
+de.gtk.preferencesProxyTypeBasic:Manuell mit einfacher Prüfung
fr.gtk.preferencesProxyTypeBasic:Manuel avec authentification basique
nl.gtk.preferencesProxyTypeBasic:Handmatig met basisauthenticatie
en.gtk.preferencesProxyTypeNLTM:Manual with - authentication
+de.gtk.preferencesProxyTypeNLTM:Manuell mit - Authentifizierung
fr.gtk.preferencesProxyTypeNLTM:Manuel avec l'authentification NTLM
nl.gtk.preferencesProxyTypeNLTM:Handmatig via NTLM-authenticatie
en.gtk.preferencesProxyTypeSystem:System settings
+de.gtk.preferencesProxyTypeSystem:System
fr.gtk.preferencesProxyTypeSystem:Paramètres du système
nl.gtk.preferencesProxyTypeSystem:Systeeminstellingen
en.gtk.preferencesPDFTabtitle:PDF
+de.gtk.preferencesPDFTabtitle:PDF (Dokumente)
fr.gtk.preferencesPDFTabtitle:PDF
nl.gtk.preferencesPDFTabtitle:PDF-uitvoer
en.gtk.preferencesAppearance:<b>Appearance</b>
+de.gtk.preferencesAppearance:<b>Aussehen</b>
fr.gtk.preferencesAppearance:<b>Apparence</b>
nl.gtk.preferencesAppearance:<b>Opmaak</b>
en.gtk.preferencesAppearanceImages:No images in output
+de.gtk.preferencesAppearanceImages:Bilder unterdrücken
fr.gtk.preferencesAppearanceImages:Aucune image de rendu/restituée
nl.gtk.preferencesAppearanceImages:Geen afbeeldingen in uitvoer
en.gtk.preferencesAppearanceBackground:No background images in output
+de.gtk.preferencesAppearanceBackground:keine Hintergrundbilder
fr.gtk.preferencesAppearanceBackground:Aucune image d'arrière-plan de rendu/restituée
nl.gtk.preferencesAppearanceBackground:Geen achtergrondafbeeldingen in uitvoer
en.gtk.preferencesAppearanceScalefit:Scale output to fit page
+de.gtk.preferencesAppearanceScalefit:Ausgabe auf Seitengröße skalieren
fr.gtk.preferencesAppearanceScalefit:Adapter à la page
nl.gtk.preferencesAppearanceScalefit:Uitvoer passend maken aan pagina
en.gtk.preferencesAppearanceScale:Scale output
+de.gtk.preferencesAppearanceScale:Skalierung
fr.gtk.preferencesAppearanceScale:Adapter
nl.gtk.preferencesAppearanceScale:Schaal
en.gtk.preferencesMargins:<b>Margins</b>
+de.gtk.preferencesMargins:<b>Ränder</b>
fr.gtk.preferencesMargins:<b>Marges</b>
nl.gtk.preferencesMargins:<b>Marges</b>
en.gtk.preferencesMarginsMeasurements:measurements in mm
+de.gtk.preferencesMarginsMeasurements:Messen in mm
fr.gtk.preferencesMarginsMeasurements:Mesures en mm
nl.gtk.preferencesMarginsMeasurements:eenheden in millimeters
en.gtk.preferencesGeneration:<b>Generation</b>
+de.gtk.preferencesGeneration:<b>Erstellung</b>
fr.gtk.preferencesGeneration:<b>Generation</b>
nl.gtk.preferencesGeneration:<b>Genereren</b>
en.gtk.preferencesGenerationCompressed:Output is compressed
+de.gtk.preferencesGenerationCompressed:Ausgabe komprimieren
fr.gtk.preferencesGenerationCompressed:La restitution est compressée
nl.gtk.preferencesGenerationCompressed:Uitvoer wordt gecomprimeerd
en.gtk.preferencesGenerationPassword:Output has a password
+de.gtk.preferencesGenerationPassword:Dokument hat Passwort
fr.gtk.preferencesGenerationPassword:La restitution possède un mot de passe
nl.gtk.preferencesGenerationPassword:Uitvoer wordt met wachtwoord beveiligd
@@ -3130,7 +3094,7 @@ nl.all.FrameDrag:frames aan het aanpassen
en.all.Not2xx:Server returned an error
de.all.Not2xx:Server meldet Fehler zurück
fr.all.Not2xx:Le serveur a renvoyé une erreur
-it.all.Not2xx:Il Server ha riportato un errore
+it.all.Not2xx:Il server ha riportato un errore
nl.all.Not2xx:Server meldt een fout
en.all.InvalidURL:The address <em>%s</em> could not be understood.
de.all.InvalidURL:Die Adresse <em>%s</em> konnte nicht ausgewertet werden.
@@ -3217,7 +3181,7 @@ nl.all.NoMemory:NetSurf heeft gebrek aan voldoende geheugen. Maak wat geheugen v
en.ro.LongURL:The URL for this page is too long for NetSurf to display.
de.ro.LongURL:The URL for this page is too long for NetSurf to display.
fr.ro.LongURL:The URL for this page is too long for NetSurf to display.
-it.ro.LongURL:The URL for this page is too long for NetSurf to display.
+it.ro.LongURL:L'URL di questa pagina è troppo lungo per essere visualizzato su NetSurf.
nl.ro.LongURL:Het adres van deze pagina is te lang voor NetSurf om te kunnen tonen.
en.ro.FontBadInst:An error occurred when initialising fonts due to the presence of obsolete copies of the ROM fonts on disc. NetSurf will exit and launch a program which will attempt to fix this.
de.ro.FontBadInst:Font-Initialisierung fehlerhaft. Obsolete Kopien von ROM Fonts auf dem lokalem Speichermedium. Fehlerbehebung startet.
@@ -3307,7 +3271,7 @@ nl.all.EncNotRec:Codeertype is niet herkend.
en.all.FileOpenError:could not open file '%s'
de.all.FileOpenError:Datei ist nicht zu öffnen: '%s'
fr.all.FileOpenError:ne parvient pas à ouvrir le fichier '%s'
-it.all.FileOpenError:impossibile aprire il file '%s'
+it.all.FileOpenError:Impossibile aprire il file '%s'
nl.all.FileOpenError:kan bestand '%s' niet openen
en.all.DirectoryError:directory '%s' already exists
de.all.DirectoryError:Verzeichnis '%s' existiert bereits.
@@ -3316,6 +3280,7 @@ it.all.DirectoryError:La directory '%s' è già esistente
nl.all.DirectoryError:map '%s' bestaat reeds
en.ro.SprIsNull:Unable to convert image to sprite
+de.ro.SprIsNull:Bild nicht in Sprite konvertierbar
nl.ro.SprIsNull:Afbeelding kan niet worden omgezet in een sprite.
# Error messages for Amiga version only
@@ -3325,22 +3290,22 @@ fr.ami.CompError:Unable to open
it.ami.CompError:Impossibile aprire
nl.ami.CompError:Niet te openen
en.ami.BMConvErr:NetSurf requires guigfx.library to display images in this mode
-de.ami.BMConvErr:NetSurf requires guigfx.library to display images in this mode
+de.ami.BMConvErr:NetSurf benötigt die guigfx.library für Bilder in diesem Mode
fr.ami.BMConvErr:NetSurf requires guigfx.library to display images in this mode
-it.ami.BMConvErr:NetSurf requires guigfx.library to display images in this mode
+it.ami.BMConvErr:NetSurf richiede guigfx.library per la visualizzazione delle immagini in questa modalità
nl.ami.BMConvErr:NetSurf requires guigfx.library to display images in this mode
en.ami.MultiTabClose:Are you sure you want to close multiple tabs?
-de.ami.MultiTabClose:Are you sure you want to close multiple tabs?
+de.ami.MultiTabClose:Wirklich mehrere Tabs schließen?
fr.ami.MultiTabClose:Are you sure you want to close multiple tabs?
it.ami.MultiTabClose:Sono rimaste aperte più schede, sei sicuro di voler uscire da NetSurf?
nl.ami.MultiTabClose:Er zijn meerdere tabbladen geopend. Tabbladen allemaal sluiten?
en.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
-de.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
+de.ami.TCPIPShutdown:Der TCP/IP Stack geht grad' zur Hölle und reißt Netsurf mit sich. In genau 5 Sekunden - es sei denn, der Shutdown wird abgebrochen.
fr.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
it.ami.TCPIPShutdown:Lo stack TCP/IP ha dato segnale di essere in procinto di arresto, NetSurf verrà chiuso. NetSurf si chiuderà entro 5 secondi a meno che lo shutdown non venga interrotto.
nl.ami.TCPIPShutdown:De TCP/IP-stack meldt dat deze wordt afgesloten waardoor NetSurf gestopt moet worden. NetSurf zal stoppen in 5 seconden, tenzij het afsluiten wordt afgebroken.
en.ami.AbortShutdown:Abort shutdown
-de.ami.AbortShutdown:Abort shutdown
+de.ami.AbortShutdown:Shutdown abbrechen
fr.ami.AbortShutdown:Abort shutdown
it.ami.AbortShutdown:Interrompi lo shutdown
nl.ami.AbortShutdown:Afsluiten afbreken
@@ -3368,9 +3333,9 @@ fr.all.OverwriteFile:Un fichier portant ce nom existe déjà et serait perdu.
it.all.OverwriteFile:Un file con questo nome è già esistente, continuare comporterà la sovrascrittura del file originale.
nl.all.OverwriteFile:Een bestand met deze naam bestaat al en zal door deze actie overschreven worden.
en.all.RemoveHotlist:Are you sure you wish to remove this address from the hotlist?
-de.all.RemoveHotlist:Are you sure you wish to remove this address from the hotlist?
+de.all.RemoveHotlist:Adresse wirklich aus der Hotlist entfernen?
fr.all.RemoveHotlist:Êtes-vous sûr de vouloir supprimer l'adresse de la liste critique?
-it.all.RemoveHotlist:Are you sure you wish to remove this address from the hotlist?
+it.all.RemoveHotlist:Sei sicuro di voler rimuovere questo indirizzo dai segnalibri?
nl.all.RemoveHotlist:Zeker weten dat dit adres uit de favorietenlijst verwijderd moet worden?
# Page fetching
@@ -3408,12 +3373,12 @@ fr.all.Redirecting:Redirection en cours...
it.all.Redirecting:redirezione in corso...
nl.all.Redirecting:doorverwijzen...
en.all.Loading:Loading
-de.all.Loading:Loading
+de.all.Loading:Laden
fr.all.Loading:Chargement
it.all.Loading:Caricamento della pagina...
nl.all.Loading:laden
en.all.Fetching:Fetching data
-de.all.Fetching:Ladevorgänge
+de.all.Fetching:Daten holen
fr.all.Fetching:Récupération des données
it.all.Fetching:Ricezione
nl.all.Fetching:ophalen
@@ -3433,7 +3398,7 @@ fr.all.Done:Terminé
it.all.Done:Completato
nl.all.Done:klaar
en.all.Stopped:Stopped
-de.all.Stopped:Stopped
+de.all.Stopped:Angehalten
fr.all.Stopped:Arrêté
it.all.Stopped:Interrotto
nl.all.Stopped:gestopt
@@ -3476,12 +3441,15 @@ fr.all.ParsingFail:L'analyse syntaxique du document a échoué.
it.all.ParsingFail:Analisi del documento fallita.
nl.all.ParsingFail:fout bij ontleden van dit document.
en.all.CSSGeneric:Error processing CSS
+de.all.CSSGeneric:CSS Auswertung klappt nicht
fr.all.CSSGeneric:Erreur lors du traitement CSS
nl.all.CSSGeneric:fout bij het verwerken van de CSS
+it.all.CSSGeneric:Errore nell'elaborazione del CSS
en.all.CSSBase:Base stylesheet failed to load
fr.all.CSSBase:Échec de chargement de la feuille de style de base
nl.all.CSSBase:basisstijlblad kan niet worden geladen
+it.all.CSSBase:Impossibile caricare il foglio di stile base
en.all.BadGIF:Reading GIF failed.
de.all.BadGIF:Lesen einer GIF Datei fehlgeschlagen.
@@ -3634,7 +3602,7 @@ nl.all.HTTP407:Authenticatie op de proxy-server verplicht
en.all.HTTP408:Request timeout
de.all.HTTP408:Request timeout
fr.all.HTTP408:Délai de requête trop long
-it.all.HTTP408:Richiesta TimeOut
+it.all.HTTP408:Timeout della richiesta
nl.all.HTTP408:Aanvraagtijd verstreken
en.all.HTTP409:Conflict
de.all.HTTP409:Conflict
@@ -3704,7 +3672,7 @@ nl.all.HTTP503:Dienst niet beschikbaar
en.all.HTTP504:Gateway timeout
de.all.HTTP504:Gateway timeout
fr.all.HTTP504:Délai passerelle expiré
-it.all.HTTP504:TimeOut Gateway
+it.all.HTTP504:Timeout Gateway
nl.all.HTTP504:Aanvraagtijd bij Gateway verstreken
en.all.HTTP505:HTTP version not supported
de.all.HTTP505:HTTP version not supported
@@ -3918,14 +3886,14 @@ fr.all.DontReplace:Ne pas remplacer le fichier
it.all.DontReplace:Non sostituire
nl.all.DontReplace:Annuleer bewaaractie
en.all.Remove:Remove address
-de.all.Remove:Remove address
+de.all.Remove:Adresse entfernen
fr.all.Remove:Enlever/retirer une adresse
-it.all.Remove:Remove address
+it.all.Remove:Rimuovi indirizzo
nl.all.Remove:Verwijder adres
en.all.DontRemove:Don't remove
-de.all.DontRemove:Don't remove
+de.all.DontRemove:Behalten
fr.all.DontRemove:Ne pas enlever/retirer
-it.all.DontRemove:Don't remove
+it.all.DontRemove:Non rimuovere
nl.all.DontRemove:Niet verwijderen
en.all.obj:object
de.all.obj:Objekt
@@ -3953,9 +3921,9 @@ fr.all.OK:OK
it.all.OK:OK
nl.all.OK:OK
en.ami.More:More
-de.ami.More:More
+de.ami.More:Mehr
fr.ami.More:More
-it.ami.More:More
+it.ami.More:Di più
nl.ami.More:Meer
@@ -4042,12 +4010,12 @@ nl.ro.HelpToolbar16:Dit is de Activiteitsindicator.|MDeze indicator beweegt zola
en.ro.HelpToolbarFav:\TFavicon: a small logo supplied by the current site, if available.
de.ro.HelpToolbarFav:\TFavicon: a small logo supplied by the current site, if available.
fr.ro.HelpToolbarFav:\TFavicon: a small logo supplied by the current site, if available.
-it.ro.HelpToolbarFav:\TFavicon: a small logo supplied by the current site, if available.
+it.ro.HelpToolbarFav:\TFavicon: un piccolo logo fornito dal sito, se disponibile.
nl.ro.HelpToolbarFav:Dit is het websitesymbool: een kleine logo dat meegeleverd wordt met de website, voorzover beschikbaar.
en.ro.HelpToolbarHot:\Thotlist indicator: if lit, the current address is in the hotlist.|M\Sto add the current address to the hotlist.|M\Ato remove the current address from the hotlist.
de.ro.HelpToolbarHot:\Thotlist indicator: if lit, the current address is in the hotlist.|M\Sto add the current address to the hotlist.|M\Ato remove the current address from the hotlist.
fr.ro.HelpToolbarHot:\Thotlist indicator: if lit, the current address is in the hotlist.|M\Sto add the current address to the hotlist.|M\Ato remove the current address from the hotlist.
-it.ro.HelpToolbarHot:\Thotlist indicator: if lit, the current address is in the hotlist.|M\Sto add the current address to the hotlist.|M\Ato remove the current address from the hotlist.
+it.ro.HelpToolbarHot:\Tindicatore segnalibri: se acceso significa che il corrente indirizzo è presente nei segnalibri.|M\Sper aggiungere il corrente indirizzo ai segnalibri.|M\Aper rimuovere il corrente indirizzo dai segnalibri.
nl.ro.HelpToolbarHot:Dit is de favorietenindicator: wanneer deze oplicht, staat het webadres al in de favorietenlijst.|MKlik met KIES om het adres aan de favorietenlijst toe te voegen.|MKlik met PASAAN om het adres uit de favorietenlijst te verwijderen.
en.ro.HelpStatus0:\Tstatus bar resizer.|MDrag to alter the size of the status bar.
@@ -4175,7 +4143,7 @@ nl.ro.HelpBrowserMenu0-6:Klik met KIES om deze pagina in een nieuw browservenste
en.ro.HelpBrowserMenu0-7:\Rsearch for instances of a string of text on the page.
de.ro.HelpBrowserMenu0-7:Erlaubt das Suchen einer Zeichenkette im Text des aktuellen Browserfensters.
fr.ro.HelpBrowserMenu0-7:\Rchercher un fragment de texte sur la page.
-it.ro.HelpBrowserMenu0-7:\Rcerca una stringa di testo all'interno della pagina web
+it.ro.HelpBrowserMenu0-7:\Rcerca una stringa di testo all'interno della pagina
nl.ro.HelpBrowserMenu0-7:Verplaats de muispijl naar rechts om een stuk tekst binnen de pagina op te zoeken.
en.ro.HelpBrowserMenu0-8:\Sview the source code of the current page in a text editor.
de.ro.HelpBrowserMenu0-8:Lädt den Quellcode der Seite in einen Editor.
@@ -4185,12 +4153,12 @@ nl.ro.HelpBrowserMenu0-8:Klik met KIES om de broncode van deze pagina in een tek
en.ro.HelpBrowserMenu1:\Rsee the options relating to the current item.
de.ro.HelpBrowserMenu1:Untermenü Objekt.|MMenöpunkte beziehen sich auf das aktuelle Objekt.
fr.ro.HelpBrowserMenu1:\Rvoir les options correspondant à l'objet courant.
-it.ro.HelpBrowserMenu1:\Rmostra opzioni relative al corrente oggetto
+it.ro.HelpBrowserMenu1:\Rmostra opzioni relative all'oggetto corrente.
nl.ro.HelpBrowserMenu1:Verplaats de muispijl naar rechts om de mogelijkheden bij dit item te tonen.
en.ro.HelpBrowserMenu1-0-0:\Rsee information about the current item.
de.ro.HelpBrowserMenu1-0-0:Informationen zum aktuellen Objekt zeigen.
fr.ro.HelpBrowserMenu1-0-0:\Rvoir les informations sur l'objet en cours.
-it.ro.HelpBrowserMenu1-0-0:\Rmostra informazioni relative al corrente oggetto
+it.ro.HelpBrowserMenu1-0-0:\Rmostra informazioni relative all'oggetto corrente.
nl.ro.HelpBrowserMenu1-0-0:Verplaats de muispijl naar rechts om informatie over dit item te tonen.
en.ro.HelpBrowserMenu1-0-1:\Rsave the current item.
de.ro.HelpBrowserMenu1-0-1:Abspeichern des Objektes (Original).
@@ -4215,22 +4183,22 @@ nl.ro.HelpBrowserMenu1-0-2-1:Verplaats de muispijl naar rechts om de afbeelding
en.ro.HelpBrowserMenu1-0-3:\Rsave the address of the current item.
de.ro.HelpBrowserMenu1-0-3:Die Adresse des Objektes speichern.
fr.ro.HelpBrowserMenu1-0-3:\Rsauver l'adresse de l'objet courant.
-it.ro.HelpBrowserMenu1-0-3:\Rsalva l'indirizzo del corrente oggetto
+it.ro.HelpBrowserMenu1-0-3:\Rsalva l'indirizzo dell'oggetto corrente.
nl.ro.HelpBrowserMenu1-0-3:Verplaats de muispijl naar rechts om het adres van dit item te bewaren.
en.ro.HelpBrowserMenu1-0-3-0:\Rsave the current item's address in Acorn URI format.
de.ro.HelpBrowserMenu1-0-3-0:Speichert die Adresse des Objektes im Acorn URI Format.
fr.ro.HelpBrowserMenu1-0-3-0:\Rsauver l'adresse de l'objet courant au format Acorn URI.
-it.ro.HelpBrowserMenu1-0-3-0:\Rsalva l'indirizzo del corrente oggetto nel formato Acorn URI
+it.ro.HelpBrowserMenu1-0-3-0:\Rsalva l'indirizzo dell'oggetto corrente nel formato Acorn URI
nl.ro.HelpBrowserMenu1-0-3-0:Verplaats de muispijl naar rechts om het adres van dit item in AcornURI-vorm te bewaren.
en.ro.HelpBrowserMenu1-0-3-1:\Rsave the current item's address in Ant URL format.
de.ro.HelpBrowserMenu1-0-3-1:Speichert die Adresse des Objektes im Ant URL Format.
fr.ro.HelpBrowserMenu1-0-3-1:\Rsauver l'adresse de l'objet courant au format Ant URL.
-it.ro.HelpBrowserMenu1-0-3-1:\Rsalva l'indirizzo del corrente oggetto nel formato Ant URL
+it.ro.HelpBrowserMenu1-0-3-1:\Rsalva l'indirizzo dell'oggetto corrente nel formato Ant URL
nl.ro.HelpBrowserMenu1-0-3-1:Verplaats de muispijl naar rechts om het adres van dit item in AntURL-vorm te bewaren.
en.ro.HelpBrowserMenu1-0-3-2:\Rsave the current item's address as plain text.
de.ro.HelpBrowserMenu1-0-3-2:Speichert die Adresse des Objektes als Text.
fr.ro.HelpBrowserMenu1-0-3-2:\Rsauver l'adresse de l'objet courant en texte simple.
-it.ro.HelpBrowserMenu1-0-3-2:\Rsalva l'indirizzo del corrente oggetto come file di testo
+it.ro.HelpBrowserMenu1-0-3-2:\Rsalva l'indirizzo dell'oggetto corrente come file di testo
nl.ro.HelpBrowserMenu1-0-3-2:Verplaats de muispijl naar rechts om het adres van dit item als platte tekst te bewaren.
en.ro.HelpBrowserMenu1-0-4:\Sreload all the items on this page.
de.ro.HelpBrowserMenu1-0-4:Anklicken mit AUSWAHL um alle Objekte der Seite erneut zu laden.
@@ -4240,7 +4208,7 @@ nl.ro.HelpBrowserMenu1-0-4:Klik met KIES om alle items van deze pagina opnieuw o
en.ro.HelpBrowserMenu1-1:\Rsee the options relating to the current link.
de.ro.HelpBrowserMenu1-1:Optionen für den aktuellen Verweis
fr.ro.HelpBrowserMenu1-1:\Rsee the options relating to the current link.
-it.ro.HelpBrowserMenu1-1:\Rmostra opzioni relative al corrente link
+it.ro.HelpBrowserMenu1-1:\Rmostra opzioni relative al link corrente.
nl.ro.HelpBrowserMenu1-1:Verplaats de muispijl naar rechts om de mogelijkheden bij deze koppeling te tonen.
en.ro.HelpBrowserMenu1-1-0:\Rsave the current link.
de.ro.HelpBrowserMenu1-1-0:Die Adresse des aktuellen Verweises abspeichern.
@@ -4275,7 +4243,7 @@ nl.ro.HelpBrowserMenu1-1-2:Klik met KIES om deze koppeling in een nieuw browserv
en.ro.HelpBrowserMenu2:\Rsee the selection options.
de.ro.HelpBrowserMenu2:Optionen für die manuell markierten Webseitenbereiche
fr.ro.HelpBrowserMenu2:\Rsee the selection options.
-it.ro.HelpBrowserMenu2:\Rmostra opzioni di selezione
+it.ro.HelpBrowserMenu2:\Rmostra le opzioni di selezione
nl.ro.HelpBrowserMenu2:Verplaats de muispijl naar rechts om de selectiemogelijkheden te tonen.
en.ro.HelpBrowserMenu2-0:\Rsave the current selection.
de.ro.HelpBrowserMenu2-0:Die aktuell markierten Bereiche abspeichern.
@@ -4300,12 +4268,12 @@ nl.ro.HelpBrowserMenu2-3:Klik met KIES om de tekst van het klembord hier in te v
en.ro.HelpBrowserMenu2-4:\Sdeselect the current selection.
de.ro.HelpBrowserMenu2-4:\Sdeselect the current selection.
fr.ro.HelpBrowserMenu2-4:\Sdeselect the current selection.
-it.ro.HelpBrowserMenu2-4:\Sdeselect the current selection.
+it.ro.HelpBrowserMenu2-4:\Sdeseleziona la selezione corrente.
nl.ro.HelpBrowserMenu2-4:Klik met KIES om de gekozen selectie te deselecteren.
en.ro.HelpBrowserMenu2-5:\Sselect all text on the current page, without the contents of text input fields.|MWhen the carret is at a text input field, all text in that field is selected.
de.ro.HelpBrowserMenu2-5:\Sselect all text on the current page, without the contents of text input fields.|MWhen the carret is at a text input field, all text in that field is selected.
fr.ro.HelpBrowserMenu2-5:\Sselect all text on the current page, without the contents of text input fields.|MWhen the carret is at a text input field, all text in that field is selected.
-it.ro.HelpBrowserMenu2-5:\Sselect all text on the current page, without the contents of text input fields.|MWhen the carret is at a text input field, all text in that field is selected.
+it.ro.HelpBrowserMenu2-5:\Sseleziona tutto il testo della pagina corrente escludendo i contenuti di testo nei campi di input.|MQualora il caret sia in un campo di inserimento testo allora verrà selezionato tutto il testo in quel campo.
nl.ro.HelpBrowserMenu2-5:Klik met KIES om alle tekst op de pagina, uitgezonderd de invoervelden te selecteren.|MWanneer het inlasteken in een invoerveld staat, wordt alle tekst in het veld geselecteerd.
en.ro.HelpBrowserMenu3:\Rsee the navigation options.
de.ro.HelpBrowserMenu3:Untermenü Navigieren.
@@ -4335,7 +4303,7 @@ nl.ro.HelpBrowserMenu3-3:Klik met KIES om 1 niveau omhoog te gaan in de websiteh
en.ro.HelpBrowserMenu3-4:\Sfetch the current page again.
de.ro.HelpBrowserMenu3-4:Lädt die aktuelle Seite erneut.|MDie Seite wird aktualisiert. Ältere Informationen zu dieser Seite, die noch im lokalen Zwischenpuffer gespeichert sind, werden dabei überschrieben.
fr.ro.HelpBrowserMenu3-4:\Srecommencer le chargement de la page courante.
-it.ro.HelpBrowserMenu3-4:\Sottieni nuovamente la corrente pagina.
+it.ro.HelpBrowserMenu3-4:\Sottieni nuovamente la pagina corrente.
nl.ro.HelpBrowserMenu3-4:Klik met KIES om deze pagina opnieuw op te halen.
en.ro.HelpBrowserMenu3-5:\Sstop NetSurf from continuing to load this page.
de.ro.HelpBrowserMenu3-5:Unterbricht den Ladevorgang und alle anderen Prozesse im aktuellen Browserfenster.
@@ -4360,7 +4328,7 @@ nl.ro.HelpBrowserMenu4-1:Verplaats de muispijl naar rechts om de afbeeldingsmoge
en.ro.HelpBrowserMenu4-1-0:\Stoggle the display of foreground images.
de.ro.HelpBrowserMenu4-1-0:\Stoggle the display of foreground images.
fr.ro.HelpBrowserMenu4-1-0:\Stoggle the display of foreground images.
-it.ro.HelpBrowserMenu4-1-0:\Stoggle the display of foreground images.
+it.ro.HelpBrowserMenu4-1-0:\SAlterna la visualizzazione delle immagini in primo piano.
nl.ro.HelpBrowserMenu4-1-0:Klik met KIES om het tonen van voorgrondafbeeldingen aan of uit te zetten.
en.ro.HelpBrowserMenu4-1-1:\Stoggle the display of background images.
de.ro.HelpBrowserMenu4-1-1:Schaltet Hintergrundbilder ein/aus.
@@ -4405,12 +4373,12 @@ nl.ro.HelpBrowserMenu4-3:Verplaats de muispijl naar rechts om de pagina-opbouwme
en.ro.HelpBrowserMenu4-3-0:\Stoggle whether animations are not displayed until all calculations are complete.
de.ro.HelpBrowserMenu4-3-0:Schaltet das Puffern von Objekten ein/aus.|MNachzuzeichnende Objekte, z.B. Bildanimationen oder Textbereiche, werden zwischengespeichert um Flackern zu vermeiden.
fr.ro.HelpBrowserMenu4-3-0:\Sdécider si les animations sont affichées quand tous les calculs sont terminés (ou avant).
-it.ro.HelpBrowserMenu4-3-0:\Simposta la non visualizzazione delle animazioni fino al completamento dei calcoli.
+it.ro.HelpBrowserMenu4-3-0:\Simposta la non visualizzazione delle animazioni fino al completamento della procedura di calcolo.
nl.ro.HelpBrowserMenu4-3-0:Klik met KIES om animaties pas te tonen, nadat alle opgehaalde paginagegevens zijn verwerkt, aan of uit te zetten.
en.ro.HelpBrowserMenu4-3-1:\Stoggle whether everything is not displayed until all calculations are complete.
de.ro.HelpBrowserMenu4-3-1:Schaltet das Puffern der gesamten Seitenberechnung ein/aus.|MDie komplette Seite wird nach Berechnung und Aufbau zwischengespeichert. Das ist vorteilhaft bei großen Hintergrundbildern und vielen sich überschneidenden Seitenelementen.
fr.ro.HelpBrowserMenu4-3-1:\Sdécider si tout doit être affiché quand tous les calculs sont terminés (ou avant).
-it.ro.HelpBrowserMenu4-3-1:\Simposta la non visualizzazione di tutto il processo fino al completamento dei calcoli.
+it.ro.HelpBrowserMenu4-3-1:\Simposta la non visualizzazione di tutto il processo fino al completamento della procedura di calcolo.
nl.ro.HelpBrowserMenu4-3-1:Klik met KIES om het niet eerder tonen van de gehele pagina, nadat alle opgehaalde paginagegevens zijn verwerkt aan of uit te zetten.
en.ro.HelpBrowserMenu4-4:\Smake your local display options the default options for NetSurf.
de.ro.HelpBrowserMenu4-4:Übernimmt die vorgenommenen Anzeigeeinstellungen als globale Standardwerte für die Darstellung aller weiteren Seiten.
@@ -4465,7 +4433,7 @@ nl.ro.HelpBrowserMenu5-0-1:Klik met KIES om de favorietenlijst te openen.
en.ro.HelpBrowserMenu5-1:\Rview the history options.
de.ro.HelpBrowserMenu5-1:Zugriff auf die History Funktionen.|MIn die History werden bereits besuchte Webseiten eingetragen. Dies erlaubt das einfache Wiederfinden einmal gesehener Web-Inhalte.
fr.ro.HelpBrowserMenu5-1:\Rview the history options.
-it.ro.HelpBrowserMenu5-1:\Rmostra opzioni della cronologia
+it.ro.HelpBrowserMenu5-1:\Rmostra le opzioni della cronologia
nl.ro.HelpBrowserMenu5-1:Verplaats de muispijl naar rechts om de geschiedenismogelijkheden te tonen.
en.ro.HelpBrowserMenu5-1-0:\Sopen the local history \w.
de.ro.HelpBrowserMenu5-1-0:Anklicken mit AUSWAHL öffnet das Fenster mit der lokalen History.|MIn der lokalen History werden alle Webseiten notiert, die mit dem aktuellen Browserfenster bereits besucht worden waren.
@@ -4490,12 +4458,12 @@ nl.ro.HelpBrowserMenu5-2-0:Klik met KIES om het cookiesbeheervenster te openen.
en.ro.HelpBrowserMenu5-2-1:\Sdelete all stored cookies.
de.ro.HelpBrowserMenu5-2-1:\Sdelete all stored cookies.
fr.ro.HelpBrowserMenu5-2-1:\Sdelete all stored cookies.
-it.ro.HelpBrowserMenu5-2-1:\Sdelete all stored cookies.
+it.ro.HelpBrowserMenu5-2-1:\Scancella tutti i cookie salvati.
nl.ro.HelpBrowserMenu5-2-1:Klik met KIES om alle opgeslagen cookies te verwijderen.
en.ro.HelpBrowserMenu6:\Rsee the help resources available.
de.ro.HelpBrowserMenu6:Untermenü Hilfe.|MZeigt Informationen zu und über NetSurf.
fr.ro.HelpBrowserMenu6:\Rvoir l'aide disponible.
-it.ro.HelpBrowserMenu6:\Rmostra documentazione disponibile
+it.ro.HelpBrowserMenu6:\Rmostra la documentazione disponibile
nl.ro.HelpBrowserMenu6:Verplaats de muispijl naar rechts om extra hulp en informatie te raadplegen, indien deze beschikbaar is.
en.ro.HelpBrowserMenu6-0:\Sopen the documentation contents page in a new \w.
de.ro.HelpBrowserMenu6-0:Öffnet die NetSurf Dokumentation in einem neuen Browserfenster.
@@ -4595,12 +4563,12 @@ nl.ro.HelpScaleView3:Klik met KIES om de schaal met 10% per keer te vergroten.
en.ro.HelpScaleView5:Choose whether all frames will also be scaled.
de.ro.HelpScaleView5:Choose whether all frames will also be scaled.
fr.ro.HelpScaleView5:Choose whether all frames will also be scaled.
-it.ro.HelpScaleView5:Choose whether all frames will also be scaled.
+it.ro.HelpScaleView5:Scegli se scalare anche tutti i frame.
nl.ro.HelpScaleView5:Selecteer de optie optie om ook de bijbehorende frames mee te schalen.
en.ro.HelpScaleView7:\Scancel changes.|MThe current scale will not be changed.
de.ro.HelpScaleView7:Klicken mit AUSWAHL um die Skalierung nicht durchzuführen.|MDas Dialogfenster wird geschlossen.|MDie Darstellung der Seite wird unverändert beibehalten.
fr.ro.HelpScaleView7:\Sannuler les changements.|ML'échelle en cours ne sera pas modifiée.
-it.ro.HelpScaleView7:\Sannulla tutte le modifiche.|MLa corrente scala non verrà modificata.
+it.ro.HelpScaleView7:\Sannulla tutte le modifiche.|MLa scala corrente non verrà modificata.
nl.ro.HelpScaleView7:Klik met KIES om dit venster te sluiten zonder dat de gemaakte wijzigingen worden ingesteld.|MDeze schaal wordt niet gewijzigd.
en.ro.HelpScaleView8:\Schange the view to the scale you have chosen.
de.ro.HelpScaleView8:Klicken mit AUSWAHL um die Seite skaliert darzustellen.|MDie Seite wird in der gewählten Vergrößerung angezeigt.
@@ -4625,28 +4593,28 @@ nl.ro.HelpSearch1:Kies of een zoekopdracht rekening moet houden met hoofd- en kl
en.ro.HelpSearch2:\Smove to the next match.
de.ro.HelpSearch2:Klicken mit AUSWAHL findet den nächsten Treffer.
fr.ro.HelpSearch2:\Schercher l'occurence suivante.
-it.ro.HelpSearch2:\Smove to the next match.
+it.ro.HelpSearch2:\Spassa alla prossima occorrenza
nl.ro.HelpSearch2:Klik met KIES om naar de volgende gevonden zoekreeks te gaan.
en.ro.HelpSearch3:\Smove to the previous match.
de.ro.HelpSearch3:Klicken mit AUSWAHL sucht rückwärts im Text.
fr.ro.HelpSearch3:\Schercher l'occurence précédente.
-it.ro.HelpSearch3:\Smove to the previous match.
+it.ro.HelpSearch3:\Spassa alla precedente occorrenza
nl.ro.HelpSearch3:Klik met KIES om naar de vorige gevonden zoekreeks te gaan.
en.ro.HelpSearch4:\Sstop searching and close this \w.
de.ro.HelpSearch4:Klicken mit AUSWAHL bricht die Suche ab und schließt das Fenster.
fr.ro.HelpSearch4:\Sarrêter la recherche et fermer cette fenêtre.
-it.ro.HelpSearch4:\Sstop searching and close this \w.
+it.ro.HelpSearch4:\Sinterrompi la ricerca e chiudi \w.
nl.ro.HelpSearch4:Klik met KIES om het zoeken te stoppen en dit venster te sluiten.
en.ro.HelpHotFolder:Use this \w to set the directory name.
de.ro.HelpHotFolder:Dieses Fenster verwenden, um den Verzeichnis-Namen festzulegen.
fr.ro.HelpHotFolder:Utiliser cette \w pour définir le nom de répertoire.
-it.ro.HelpHotFolder:Use this \w to set the directory name.
+it.ro.HelpHotFolder:Usa questa \w per impostare il nome della directory.
nl.ro.HelpHotFolder:Gebruik dit venster om de mapnaam in te voeren.
en.ro.HelpHotEntry:Use this \w to set the entry details.
de.ro.HelpHotEntry:Dieses Fenster verwenden, um die Details des Eintrages festzulegen.
fr.ro.HelpHotEntry:Utiliser cette \w pour définir les détails de cette entrée.
-it.ro.HelpHotEntry:Use this \w to set the entry details.
+it.ro.HelpHotEntry:Usa questa \w per impostare i dettagli dell'immissione.
nl.ro.HelpHotEntry:Gebruik dit om details van dit item in te voeren.
en.ro.HelpHotlist:\Thotlist management window.
de.ro.HelpHotlist:Das ist das Hotlist Fenster.
@@ -4676,28 +4644,28 @@ nl.ro.HelpHotlist3:Klik met KIES om de details van dit item te verbergen.
en.ro.HelpHotlist4:\Sselect this directory.|MDouble-click \s to open this directory.
de.ro.HelpHotlist4:Klicken mit AUSWAHL markiert dieses Verzeichnis.|MDoppelklicken um das Verzeichnis zu öffnen.
fr.ro.HelpHotlist4:\Ssélectionner ce répertoire.|MDouble-cliquer \s pour ouvrir ce répertoire.
-it.ro.HelpHotlist4:\Sselect this directory.|MDouble-click \s to open this directory.
+it.ro.HelpHotlist4:\Sseleziona questa directory.|MDoppio-click \s per aprire questa directory.
nl.ro.HelpHotlist4:Klik met KIES om deze map te selecteren.|MDubbelklik met KIES om deze map te openen en alle bijbehorende items uit te klappen.
en.ro.HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
de.ro.HelpHotlist5:Klicken mit AUSWAHL markiert diesen Eintrag.|MDoppelklicken öffnet diesen Eintrag in einem neuen Browserfenster.
fr.ro.HelpHotlist5:\Ssélectionner cette entrée.|MDouble-cliquer \s pour lancer cette URL.
-it.ro.HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
+it.ro.HelpHotlist5:\Sseleziona questo elemento.|MDoppio-click \s per avviare questo URL.
nl.ro.HelpHotlist5:Klik met KIES om dit item te selecteren.|MDubbelklik met om de inhoud van dit adres in een nieuw browservenster te openen.
en.ro.HelpHotlist6:Release the mouse buttons to complete your selection.
de.ro.HelpHotlist6:Maustasten loslassen, um die Auswahl abzuschließen.
fr.ro.HelpHotlist6:Lâcher les boutons de souris pour terminer votre sélection.
-it.ro.HelpHotlist6:Release the mouse buttons to complete your selection.
+it.ro.HelpHotlist6:Rilascia il pulsante dei mouse per completare la selezione.
nl.ro.HelpHotlist6:Laat de muisknop(pen) los om de selectie af te ronden.
en.ro.HelpHotlist7:Release the mouse buttons to move the selection.
de.ro.HelpHotlist7:Maustasten loslassen, um das Verschieben auszuführen.
fr.ro.HelpHotlist7:Lâcher les boutons de souris pour déplacer votre sélection.
-it.ro.HelpHotlist7:Release the mouse buttons to move the selection.
+it.ro.HelpHotlist7:Rilascia il pulsante del mouse per spostare la selezione.
nl.ro.HelpHotlist7:Laat de muisknop(pen) los om de selectie te kunnen verplaatsen.
en.ro.HelpHotToolbar0:\Tdelete button.|M\Sdelete the current selection.
de.ro.HelpHotToolbar0:Löscht die markierten Einträge und Verzeichnisse.
fr.ro.HelpHotToolbar0:\Tle bouton Supprimer.|M\Ssupprimer la sélection courante.
-it.ro.HelpHotToolbar0:\Tdelete button.|M\Sdelete the current selection.
+it.ro.HelpHotToolbar0:\Tcancella pulsante.|M\Scancella la selezione corrente.
nl.ro.HelpHotToolbar0:Dit is de Verwijder-knop.|MKlik met KIES om deze selectie te verwijderen.
en.ro.HelpHotToolbar1:\Texpand entries button.|M\Sexpand all addresses in the hotlist.|M\Acollapse all addresses in the hotlist.|MExpanded addresses show additional details, such as a visit counter.
de.ro.HelpHotToolbar1:Expandiert Einträge.|MKlicken mit AUSWAHL expandiert alle / alle markierten Einträge.|MKlicken mit SPEZIAL faltet alle / alle markierten Einträge zusammen.|MBei expandierten Einträgen werden zusätzliche Informationen angezeigt.
@@ -4712,12 +4680,12 @@ nl.ro.HelpHotToolbar2:Dit is de Open map-knop.|MKlik met KIES om alle mappen in
en.ro.HelpHotToolbar3:\Tlaunch button.|M\Slaunch the current selection.
de.ro.HelpHotToolbar3:Lädt alle markierten Einträge in jeweils ein neues Browserfenster.
fr.ro.HelpHotToolbar3:\Tle bouton de lancement.|M\Slancer (ouvrir) la sélection en cours.
-it.ro.HelpHotToolbar3:\Tlaunch button.|M\Slaunch the current selection.
+it.ro.HelpHotToolbar3:\Tpulsante di avvio.|M\Savvia la selezione corrente.
nl.ro.HelpHotToolbar3:Dit is de Ga naar-knop.|MKlik met KIES om alle pagina's in deze selectie in nieuwe browservensters te openen.
en.ro.HelpHotToolbar4:\Tcreate button.|M\Screate a new directory.
de.ro.HelpHotToolbar4:Erzeugt neue Einträge oder Verzeichnisse.|MKlicken mit AUSWAHL erstellt ein neues Verzeichnis.
fr.ro.HelpHotToolbar4:\Tle bouton Créer.|M\Scréer un nouveau répertoire.
-it.ro.HelpHotToolbar4:\Tcreate button.|M\Screate a new directory.
+it.ro.HelpHotToolbar4:\Tcrea pulsante.|M\Screa una nuova directory.
nl.ro.HelpHotToolbar4:Dit is de Nieuwe map-knop.|MKlik met KIES om een nieuwe map aan te maken.
en.ro.HelpHotlistMenu0:\Rperform an operation on the hotlist.
@@ -4748,7 +4716,7 @@ nl.ro.HelpHotlistMenu0-1:Verplaats de muispijl naar rechts om de favorietenlijst
en.ro.HelpHotlistMenu0-2:\Rexpand items within the hotlist.
de.ro.HelpHotlistMenu0-2:Öffnen von Verzeichnissen und Anzeigen von Zusatzinformationen.
fr.ro.HelpHotlistMenu0-2:\Rdéployer les items dans la liste des favoris.
-it.ro.HelpHotlistMenu0-2:\Rexpand items within the hotlist.
+it.ro.HelpHotlistMenu0-2:\Respandi gli elementi all'interno del segnalibro.
nl.ro.HelpHotlistMenu0-2:Verplaats de muispijl naar rechts om bepaalde items in de favorietenlijst uit te klappen.
en.ro.HelpHotlistMenu0-2-0:\Sopen all directories and show all entry details.
de.ro.HelpHotlistMenu0-2-0:Öffnet alle Verzeichnisse und zeigt zu Einträgen die Zusatzinformationen an.
@@ -4768,12 +4736,12 @@ nl.ro.HelpHotlistMenu0-2-2:Klik met KIES om alle details van de favorieten te to
en.ro.HelpHotlistMenu0-3:\Rcollapse items within the hotlist.
de.ro.HelpHotlistMenu0-3:Schließen von Verzeichnissen und Ausblenden der Zusatzinformationen.
fr.ro.HelpHotlistMenu0-3:\Rregrouper les items dans la liste des favoris.
-it.ro.HelpHotlistMenu0-3:\Rcollapse items within the hotlist.
+it.ro.HelpHotlistMenu0-3:\Rraggruppa gli elementi all'interno del segnalibro.
nl.ro.HelpHotlistMenu0-3:Verplaats de muispijl naar rechts om bepaalde items in de favorietenlijst in te klappen.
en.ro.HelpHotlistMenu0-3-0:\Sclose all directories and hide all entry details.
de.ro.HelpHotlistMenu0-3-0:Schließt alle Verzeichnisse und versteckt die Zusatzinformationen bei Einträgen.
fr.ro.HelpHotlistMenu0-3-0:\Sfermer tous les répertoires et cacher les détails sur les entrées.
-it.ro.HelpHotlistMenu0-3-0:\Sclose all directories and hide all entry details.
+it.ro.HelpHotlistMenu0-3-0:\Schiudi tutte le directory e nascondi tutti i dettagli delle immissioni.
nl.ro.HelpHotlistMenu0-3-0:Klik met KIES om alle mappen te sluiten en alle details in de favorietenlijst te verbergen.
en.ro.HelpHotlistMenu0-3-1:\Sclose all directories.
de.ro.HelpHotlistMenu0-3-1:Schließt alle Verzeichnisse.
@@ -4803,12 +4771,12 @@ nl.ro.HelpHotlistMenu0-4-1:Klik met KIES om de aanpasmodus van de gereedschapbal
en.ro.HelpHotlistMenu1:\Roperate on the current selection.
de.ro.HelpHotlistMenu1:Untermenü Auswahl. Bearbeiten der markierten Hotlist Elemente.
fr.ro.HelpHotlistMenu1:\Ragir sur la sélection en cours.
-it.ro.HelpHotlistMenu1:\Roperate on the current selection.
+it.ro.HelpHotlistMenu1:\Ropera nella selezione corrente.
nl.ro.HelpHotlistMenu1:Verplaats de muispijl naar rechts om een operatie op deze selectie uit te voeren.
en.ro.HelpHotlistMenu1-0:\Redit the current item.
de.ro.HelpHotlistMenu1-0:Ändern des markierten Elementes in der Hotlist.
fr.ro.HelpHotlistMenu1-0:\Rééditer l'item en cours.
-it.ro.HelpHotlistMenu1-0:\Redit the current item.
+it.ro.HelpHotlistMenu1-0:\Rmodifica l'oggetto corrente.
nl.ro.HelpHotlistMenu1-0:Klik met KIES om de naam van dit item te wijzigen
en.ro.HelpHotlistMenu1-1:\Slaunch the current selection.
de.ro.HelpHotlistMenu1-1:Öffnet markierte Einträge in je einem neuen Browserfenster.
@@ -4839,7 +4807,7 @@ nl.ro.HelpHotlistMenu3:Klik met KIES om alle geselecteerde items te deselecteren
en.ro.HelpGHistory:\Tglobal history window.
de.ro.HelpGHistory:Das ist das Fenster der globalen History.
fr.ro.HelpGHistory:\Tla fenêtre d'historique global.
-it.ro.HelpGHistory:\Tfinestra cronologia globale.
+it.ro.HelpGHistory:\Tfinestra della cronologia globale.
nl.ro.HelpGHistory:Dit venster toont de browsergeschiedenis.
en.ro.HelpGHistoryToolbar0:\Tdelete button.|M\Sdelete the current selection.
de.ro.HelpGHistoryToolbar0:Entfernt markierte Bereiche.|MAnklicken mit AUSWAHL löscht die vorher markierten Bereiche aus der History.
@@ -4870,17 +4838,17 @@ nl.ro.HelpGHistoryMenu0:Verplaats de muispijl naar rechts om een operatie uit te
en.ro.HelpGHistoryMenu0-0:\Rexport global history as an HTML file.
de.ro.HelpGHistoryMenu0-0:Speichert die History (global) als HTML Datei.
fr.ro.HelpGHistoryMenu0-0:\Rexporter l'historique global en fichier HTML.
-it.ro.HelpGHistoryMenu0-0:\Rexport global history as an HTML file.
+it.ro.HelpGHistoryMenu0-0:\Resporta la cronologia globale come file HTML.
nl.ro.HelpGHistoryMenu0-0:Verplaats de muispijl naar rechts om de browsergeschiedenis te exporteren als een HTML-bestand.
en.ro.HelpGHistoryMenu0-1:\Rexpand items within global history.
de.ro.HelpGHistoryMenu0-1:Mehr Information anzeigen
fr.ro.HelpGHistoryMenu0-1:\Rdéployer les items de l'historique global.
-it.ro.HelpGHistoryMenu0-1:\Rexpand items within global history.
+it.ro.HelpGHistoryMenu0-1:\Respandi gli elementi all'interno della cronologia globale.
nl.ro.HelpGHistoryMenu0-1:Verplaats de muispijl naar rechts om bepaalde items in de browsergeschiedenis uit te klappen.
en.ro.HelpGHistoryMenu0-1-0:\Sopen all directories and show all entry details.
de.ro.HelpGHistoryMenu0-1-0:Öffnet alle Verzeichnisse und zeigt die Details der Einträge an.
fr.ro.HelpGHistoryMenu0-1-0:\Souvrir tous les répertoires et donner le détail de toutes les entrées.
-it.ro.HelpGHistoryMenu0-1-0:\Sapri tutte le directory e mostra in dettaglio tutte le immissioni
+it.ro.HelpGHistoryMenu0-1-0:\Sapri tutte le directory e mostra in dettaglio tutte le immissioni.
nl.ro.HelpGHistoryMenu0-1-0:Klik met KIES om alle mappen te openen en alle itemdetails te tonen.
en.ro.HelpGHistoryMenu0-1-1:\Sopen all directories.
de.ro.HelpGHistoryMenu0-1-1:Öffnet alle Verzeichnisse.
@@ -4895,7 +4863,7 @@ nl.ro.HelpGHistoryMenu0-1-2:Klik met KIES om alle itemdetails te tonen.
en.ro.HelpGHistoryMenu0-2:\Rcollapse items within global history.
de.ro.HelpGHistoryMenu0-2:Weniger Information anzeigen
fr.ro.HelpGHistoryMenu0-2:\Rregrouper les items de l'historique global.
-it.ro.HelpGHistoryMenu0-2:\Rcollapse items within global history.
+it.ro.HelpGHistoryMenu0-2:\Rraggruppa gli elementi all'interno della cronologia globale.
nl.ro.HelpGHistoryMenu0-2:Verplaats de muispijl naar rechts om bepaalde items in de browsergeschiedenis in te klappen.
en.ro.HelpGHistoryMenu0-2-0:\Sclose all directories and hide all entry details.
de.ro.HelpGHistoryMenu0-2-0:Schließt alle Verzeichnisse und versteckt die Details der Einträge.
@@ -4987,12 +4955,12 @@ nl.ro.HelpCookiesMenu0:Verplaats de muispijl naar rechts om een operatie uit te
en.ro.HelpCookiesMenu0-0:\Rexpand items within the cookie list.
de.ro.HelpCookiesMenu0-0:Menü zum Expandieren der Einträge der Liste.
fr.ro.HelpCookiesMenu0-0:\Rdéployer les items dans la liste de cookies.
-it.ro.HelpCookiesMenu0-0:\Rexpand items within the cookie list.
+it.ro.HelpCookiesMenu0-0:\Respandi gli elementi all'interno della lista dei cookie.
nl.ro.HelpCookiesMenu0-0:Verplaats de muispijl naar rechts om bepaalde items in het cookiesbeheervenster uit te klappen.
en.ro.HelpCookiesMenu0-0-0:\Sopen all directories and show all cookie details.
de.ro.HelpCookiesMenu0-0-0:Klicken mit AUSWAHL öffnet alle Verzeichnisse und zeigt Details zu allen angezeigten Cookies.
fr.ro.HelpCookiesMenu0-0-0:\Souvrir tous les répertoires et montrer le détail de tous les cookies.
-it.ro.HelpCookiesMenu0-0-0:\Sapri tutte le directory e mostra i dettagli di tutti i cookie
+it.ro.HelpCookiesMenu0-0-0:\Sapri tutte le directory e mostra in dettaglio tutti i cookie
nl.ro.HelpCookiesMenu0-0-0:Klik met KIES om alle mappen te openen en alle cookiedetails te tonen.
en.ro.HelpCookiesMenu0-0-1:\Sopen all directories.
de.ro.HelpCookiesMenu0-0-1:Klicken mit AUSWAHL öffnet alle Verzeichnisse.
@@ -5002,12 +4970,12 @@ nl.ro.HelpCookiesMenu0-0-1:Klik met KIES om alle mappen te openen en de bijbehor
en.ro.HelpCookiesMenu0-0-2:\Sshow all cookie details.
de.ro.HelpCookiesMenu0-0-2:Klicken mit AUSWAHL zeigt Details zu allen angezeigten Cookies.
fr.ro.HelpCookiesMenu0-0-2:\Smontrer le détail de tous les cookies.
-it.ro.HelpCookiesMenu0-0-2:\Smostra tutti i cookie in dettaglio
+it.ro.HelpCookiesMenu0-0-2:\Smostra in dettaglio tutti i cookie
nl.ro.HelpCookiesMenu0-0-2:Klik met KIES om alle cookiedetails te tonen.
en.ro.HelpCookiesMenu0-1:\Rcollapse items within the cookie list.
de.ro.HelpCookiesMenu0-1:Menü zum Schließen der Einträge der Liste.
fr.ro.HelpCookiesMenu0-1:\Rregrouper les items dans la liste de cookies.
-it.ro.HelpCookiesMenu0-1:\Rcollapse items within the cookie list.
+it.ro.HelpCookiesMenu0-1:\Rragguppa gli elementi all'interno della lista dei cookie.
nl.ro.HelpCookiesMenu0-1:Verplaats de muispijl naar rechts om bepaalde items in het cookiesbeheervenster in te klappen.
en.ro.HelpCookiesMenu0-1-0:\Sclose all directories and hide all cookie details.
de.ro.HelpCookiesMenu0-1-0:Klicken mit AUSWAHL schließt alle Verzeichnisse und versteckt die Cookiedetails.
@@ -5052,7 +5020,7 @@ nl.ro.HelpCookiesMenu1-0:Klik met KIES om deze geselecteerde cookies te verwijde
en.ro.HelpCookiesMenu2:\Sselect all the items in the cookie list.
de.ro.HelpCookiesMenu2:Klicken mit AUSWAHL markiert alle Cookies als gewählt.
fr.ro.HelpCookiesMenu2:\Ssélectionner tous les items dans la liste de cookies.
-it.ro.HelpCookiesMenu2:\Sseleziona tutti gli oggetti nella lista dei cookie.
+it.ro.HelpCookiesMenu2:\Sseleziona tutti gli oggetti dalla lista dei cookie.
nl.ro.HelpCookiesMenu2:Klik met KIES om alle cookies in het cookiesbeheervenster te selecteren.
en.ro.HelpCookiesMenu3:\Sdeselect all selected items.
de.ro.HelpCookiesMenu3:Klicken mit AUSWAHL macht alle Markierungen rückgängig.
@@ -5063,14 +5031,14 @@ nl.ro.HelpCookiesMenu3:Klik met KIES om alle geselecteerde items te deselecteren
en.ro.HelpAppInfo:\TNetSurf information \w.|MSee the about page for the contributor list and credits.
de.ro.HelpAppInfo:Das ist das Info-Fenster zu NetSurf.|MGenauere Angaben zu den Autoren, Grafikern, Übersetzern, genutzten Libraries etc. gibt es bei "Über NetSurf" im Untermenü Hilfe eines Browserfensters.
fr.ro.HelpAppInfo:\Tla \w d'information de NetSurf.|MVoir la page "À propos de" pour une liste des contributeurs et les remerciements.
-it.ro.HelpAppInfo:\TNetSurf information \w.|MSee the about page for the contributor list and credits.
+it.ro.HelpAppInfo:\TInformazioni su NetSurf \w.|MMostra la pagina delle informazioni e la lista dei ringraziamenti.
nl.ro.HelpAppInfo:Dit is het NetSurf-informatievenster.|MOpen de Bijdragen-pagina voor de lijst met degenen die bijdroegen aan het NetSurf-project.
en.ro.HelpConfigure:\Tconfiguration \w for NetSurf
de.ro.HelpConfigure:Dies ist das Konfigurationsfenster von NetSurf.
fr.ro.HelpConfigure:\Tla fenêtre de configuration pour Netsurf
-it.ro.HelpConfigure:\Tconfiguration \w for NetSurf
+it.ro.HelpConfigure:\Tconfigurazione \w per NetSurf
nl.ro.HelpConfigure:Dit is het NetSurf-instellingenvenster.
en.ro.HelpConfigure0:Cache configuration tool
de.ro.HelpConfigure0:Cachespeicher konfigurieren
@@ -5120,18 +5088,18 @@ nl.ro.HelpConfigure8:Thema-instellingen.|MKlik op dit symbool om een weergavethe
en.ro.HelpConfigure9:Security and Privacy configuration tool
de.ro.HelpConfigure9:Sicherheitseinstellungen und Privatsphäre
fr.ro.HelpConfigure9:Outil de configuration de la sécurité et de la confidentialité
-it.ro.HelpConfigure9:Strumento di configurazione della Sicurezza e Privacy
+it.ro.HelpConfigure9:Strumento di configurazione per Sicurezza e la Privacy
nl.ro.HelpConfigure9:Veiligheid en Privacy-instellingen|MKlik op dit symbool om de veiligheids- en privacyinstellingen aan te passen.
en.ro.HelpCacheConfig:\Tcache configuration \w.
de.ro.HelpCacheConfig:Das ist das Fenster der Cache-Konfiguration.
fr.ro.HelpCacheConfig:\Tla fenêtre de configuration du cache.
-it.ro.HelpCacheConfig:\Tcache configuration \w.
+it.ro.HelpCacheConfig:\Tconfigurazione della cache \w.
nl.ro.HelpCacheConfig:Diverse bufferinstelligen kunnen in dit venster gewijzigd worden.
en.ro.HelpCacheConfig3:\Tamount of memory to be used for caching content.
de.ro.HelpCacheConfig3:Speichergröße, die verwendet wird um Inhalte zwischenzuspeichern.
fr.ro.HelpCacheConfig3:\Tla quantité de mémoire à utiliser pour le contenu du cache.
-it.ro.HelpCacheConfig3:\Tamount of memory to be used for caching content.
+it.ro.HelpCacheConfig3:\Tquantità di memoria da usare per il contenuto della cache.
nl.ro.HelpCacheConfig3:Dit invoerveld toont de hoeveelheid geheugen die wordt gebruikt om de pagina-inhoud te bufferen.
en.ro.HelpCacheConfig4:\Sreduce the amount of memory.
de.ro.HelpCacheConfig4:Klicken mit AUSWAHL verringert die Größe des Cachespeichers.
@@ -5146,7 +5114,7 @@ nl.ro.HelpCacheConfig5:Klik met KIES om de geheugenruimte groter te maken.
en.ro.HelpCacheConfig10:\Tamount of disc space to be used for caching content between sessions.
de.ro.HelpCacheConfig10:\Tamount of disc space to be used for caching content between sessions.
fr.ro.HelpCacheConfig10:\Tamount of disc space to be used for caching content between sessions.
-it.ro.HelpCacheConfig10:\Tamount of disc space to be used for caching content between sessions.
+it.ro.HelpCacheConfig10:\Tquantità di spazio su disco da usare per il contenuto della cache tra le sessioni.
nl.ro.HelpCacheConfig10:Dit invoerveld toont de hoeveelheid schijfruimte die wordt gebruikt om de pagina-inhoud tussen sessies te bufferen.
en.ro.HelpCacheConfig11:\Sreduce the amount of memory.
de.ro.HelpCacheConfig11:Klicken mit AUSWAHL verringert die Größe des Cachespeichers.
@@ -5166,12 +5134,12 @@ nl.ro.HelpCacheConfig15:Dit is het maximum aantal dagen dat de gebufferde pagina
en.ro.HelpCacheConfig16:\Sreduce the number of days.
de.ro.HelpCacheConfig16:\Sreduce the number of days.
fr.ro.HelpCacheConfig16:\Sreduce the number of days.
-it.ro.HelpCacheConfig16:\Sreduce the number of days.
+it.ro.HelpCacheConfig16:\Sriduce il numero di giorni.
nl.ro.HelpCacheConfig16:Klik met KIES om het aantal dagen te verlagen.
en.ro.HelpCacheConfig17:\Sincrease the number of days.
de.ro.HelpCacheConfig17:\Sincrease the number of days.
fr.ro.HelpCacheConfig17:\Sincrease the number of days.
-it.ro.HelpCacheConfig17:\Sincrease the number of days.
+it.ro.HelpCacheConfig17:\Saumenta il numero di giorni.
nl.ro.HelpCacheConfig17:Klik met KIES om het aantal dagen te verhogen.
en.ro.HelpCacheConfig19:\Sreset the Cache options back to their default values.
de.ro.HelpCacheConfig19:Stellt die Standardeinstellungen wieder her.
@@ -5192,7 +5160,7 @@ nl.ro.HelpCacheConfig21:Klik met KIES om de gemaakte wijzigingen te bewaren en d
en.ro.HelpConnectConfig:\Tconnection configuration \w
de.ro.HelpConnectConfig:Das ist das Fenster zur Einstellung der Parameter für die Netzanbindung.
fr.ro.HelpConnectConfig:\Tla fenêtre de configuration de connexion.
-it.ro.HelpConnectConfig:\Tconnection configuration \w
+it.ro.HelpConnectConfig:\Tconfigurazione della connessione \w
nl.ro.HelpConnectConfig:Diverse verbindingsinstellingen kunnen in dit venster gewijzigd worden.
en.ro.HelpConnectConfig3:\Tcurrently selected proxy type.|MUse the menu to select a proxy type.
de.ro.HelpConnectConfig3:Aktuell gewählter Proxytyp.|MMit dem Menü kann ein anderer Typ eingestellt werden.
@@ -5257,17 +5225,17 @@ nl.ro.HelpConnectConfig22:Klik met KIES om het maximaal aantal simultaan uit te
en.ro.HelpConnectConfig24:\Tmaximum number of persistent connections.
de.ro.HelpConnectConfig24:Das ist die Maximalzahl aufrechtzuerhaltender Verbindungen.
fr.ro.HelpConnectConfig24:\Tle nombre maximum de connexions persistantes.
-it.ro.HelpConnectConfig24:\Tmaximum number of persistent connections.
+it.ro.HelpConnectConfig24:\Tnumero massimo di connessioni persistenti.
nl.ro.HelpConnectConfig24:Dit is het maximum aantal langdurige verbindingen.
en.ro.HelpConnectConfig25:\Sreduce the maximum number of persistent connections.
de.ro.HelpConnectConfig25:Klicken mit AUSWAHL verringert die Maximalzahl offengehaltener Verbindungen.
fr.ro.HelpConnectConfig25:\Sréduire le nombre maximum de connexions persistantes.
-it.ro.HelpConnectConfig25:\Sreduce the maximum number of persistent connections.
+it.ro.HelpConnectConfig25:\Sriduci il numero massimo di connessioni persistenti.
nl.ro.HelpConnectConfig25:Klik met KIES om het maximum aantal langdurige verbindingen te verlagen.
en.ro.HelpConnectConfig26:\Sincrease the maximum number of persistent connections.
de.ro.HelpConnectConfig26:Klicken mit AUSWAHL vergrößert die Maximalzahl offengehaltener Verbindungen.
fr.ro.HelpConnectConfig26:\Saugmenter le nombre maximum de connexions persistantes.
-it.ro.HelpConnectConfig26:\Sincrease the maximum number of persistent connections.
+it.ro.HelpConnectConfig26:\Saumenta il numero massimo di connessioni persistenti.
nl.ro.HelpConnectConfig26:Klik met KIES om het maximum aantal langdurige verbindingen te verhogen.
en.ro.HelpConnectConfig27:\Sreset the Connection options back to their default values.
de.ro.HelpConnectConfig27:Stellt die Standardeinstellungen wieder her.
@@ -5288,7 +5256,7 @@ nl.ro.HelpConnectConfig29:Klik met KIES om de gemaakte wijzigingen te bewaren en
en.ro.HelpContentConfig:\Tcontent configuration \w
de.ro.HelpContentConfig:Fenster zur Einstellung des Browserverhaltens bei bestimmten Seiteninhalten
fr.ro.HelpContentConfig:\Tla fenêtre de configuration du Contenu
-it.ro.HelpContentConfig:\Tcontent configuration \w
+it.ro.HelpContentConfig:\Tconfigurazione dei contenuti \w
nl.ro.HelpContentConfig:Het gedrag van de browser kan in dit venster gewijzigd worden.
en.ro.HelpContentConfig2:This indicates whether NetSurf will attempt to block advertisements on web pages|MIn rare circumstances, this option may cause valid content to be blocked too.
de.ro.HelpContentConfig2:Stellt ein, ob NetSurf versuchen soll, die auf Webseiten eingeblendete Werbung automatisch zu unterdrücken.|MIn seltenen Fällen wird dadurch jedoch auch 'echter' Seiteninhalt geblockt.
@@ -5333,7 +5301,7 @@ nl.ro.HelpContentConfig11:Deze optie geeft aan of het uitvoeren van JavaScript-s
en.ro.HelpFontConfig:\Tfont configuration \w
de.ro.HelpFontConfig:Konfigurationsfenster zur Einstellung der verwendeten Schriftarten
fr.ro.HelpFontConfig:\Tla fenêtre de configuration de Fontes
-it.ro.HelpFontConfig:\Tfont configuration \w
+it.ro.HelpFontConfig:\Tconfigurazione dei font \w
nl.ro.HelpFontConfig:De instellingen voor de verschillende tekststijlen kunnen in dit venster gewijzigd worden.
en.ro.HelpFontConfig3:\Tcurrently selected sans-serif font.|MNetSurf will use this font wherever a web page specifies a sans-serif typeface.
de.ro.HelpFontConfig3:Das ist die aktuell gewählte Schriftart für Sans-serif.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Sans-serif vorgegeben wird.
@@ -5408,7 +5376,7 @@ nl.ro.HelpFontConfig24:Klik met KIES om de standaardlettergrootte te verkleinen
en.ro.HelpFontConfig25:\Sincrease the default font size.
de.ro.HelpFontConfig25:Klicken mit AUSWAHL vergrößert die Standardfontgröße.
fr.ro.HelpFontConfig25:\Saugmenter la taille de fonte.
-it.ro.HelpFontConfig25:\Saumenta la dimensione del font predefinito
+it.ro.HelpFontConfig25:\Saumenta la dimensione del font predefinita
nl.ro.HelpFontConfig25:Klik met KIES om de standaardlettergrootte te vergroten.
en.ro.HelpFontConfig28:You can enter a minimum font size here.|MNetSurf will not allow web pages to display smaller text than this.
de.ro.HelpFontConfig28:Hier kann eine minimale Schriftgröße eingestellt werden.|MNetSurf wird keine Darstellung von noch kleineren Schriften zulassen.
@@ -5444,12 +5412,12 @@ nl.ro.HelpFontConfig34:Klik met KIES om de gemaakte wijzigingen te bewaren en di
en.ro.HelpHomeConfig:\Thome page configuration \w
de.ro.HelpHomeConfig:Homepage Konfiguration
fr.ro.HelpHomeConfig:\Tla fenêtre de configuration de Page d'accueil
-it.ro.HelpHomeConfig:\Thome page configuration \w
+it.ro.HelpHomeConfig:\Tconfigurazione della pagina iniziale \w
nl.ro.HelpHomeConfig:De begin/startpagina kan in dit venster gewijzigd worden.
en.ro.HelpHomeConfig3:You can enter a default home page address here.
de.ro.HelpHomeConfig3:Hier kann die Webadresse der Homepage eingegeben werden.
fr.ro.HelpHomeConfig3:Vous pouvez entrer ici une page d'accueil par défaut.
-it.ro.HelpHomeConfig3:You can enter a default home page address here.
+it.ro.HelpHomeConfig3:Puoi inserire l'indirizzo della pagina iniziale qui.
nl.ro.HelpHomeConfig3:Voer hier een standaard begin-/startpagina-adres in.
en.ro.HelpHomeConfig4:\Sselect a recently typed URL.|MThese addresses have recently been typed into a NetSurf browser \w's URL bar.
de.ro.HelpHomeConfig4:Klicken mit AUSWAHL zur schnellen Auswahl einer Adresse.|MDie angezeigten Adressen wurden in letzter Zeit in die Adressleiste eines Browserfensters eingegeben.
@@ -5480,7 +5448,7 @@ nl.ro.HelpHomeConfig8:Klik met KIES om de gemaakte wijzigingen te bewaren en dit
en.ro.HelpImageConfig:\Timage configuration \w
de.ro.HelpImageConfig:Das ist das Fenster zur Konfiguration der Bilddarstellungsoptionen.
fr.ro.HelpImageConfig:\Tla fenêtre de configuration d'Image
-it.ro.HelpImageConfig:\Timage configuration \w
+it.ro.HelpImageConfig:\Tconfigurazione della immagini \w
nl.ro.HelpImageConfig:De verwerking van afbeeldingen kan in dit venster gewijzigd worden.
en.ro.HelpImageConfig3:\Tcurrently selected foreground image quality.
de.ro.HelpImageConfig3:Das ist die aktuell gewählte Qualität für die Darstellung der Vordergrundbilder.
@@ -5515,12 +5483,12 @@ nl.ro.HelpImageConfig12:In dit veld kan de minimumtijd ingevoerd worden tussen d
en.ro.HelpImageConfig13:\Sreduce the minimum time between animation frames.
de.ro.HelpImageConfig13:Klicken mit AUSWAHL verkleinert die minimale Wartezeit zwischen aufeinanderfolgenden Einzelbildern einer Animation.
fr.ro.HelpImageConfig13:\Sréduire le temps minimum entre deux images d'animation.
-it.ro.HelpImageConfig13:\Sreduce the minimum time between animation frames.
+it.ro.HelpImageConfig13:\Sriduce il tempo di intervallo minimo tra i frame di animazione.
nl.ro.HelpImageConfig13:Klik met KIES om de minimumtijd tussen animatie-afbeeldingen te verkleinen.
en.ro.HelpImageConfig14:\Sincrease the minimum time between animation frames.
de.ro.HelpImageConfig14:Klicken mit AUSWAHL vergrößert die minimale Wartezeit zwischen aufeinanderfolgenden Einzelbildern einer Animation.
fr.ro.HelpImageConfig14:\Saugmenter le temps minimum entre deux images d'animation.
-it.ro.HelpImageConfig14:\Sincrease the minimum time between animation frames.
+it.ro.HelpImageConfig14:\Saumenta il tempo di intervallo minimo tra i frame di animazione.
nl.ro.HelpImageConfig14:Klik met KIES om de minimumtijd tussen animatie-afbeeldingen te vergroten.
en.ro.HelpImageConfig16:This indicates whether NetSurf will disable animations on web pages.|MWhen animations are disabled, NetSurf will show the first frame as a static image.
de.ro.HelpImageConfig16:Erlaubt das Abschalten der Animationsdarstellung auf Webseiten.|MSind die Animationen abgeschaltet, wird von NetSurf lediglich das erste Einzelbild der Animationsfolge als einfaches Bild angezeigt.
@@ -5546,7 +5514,7 @@ nl.ro.HelpImageConfig19:Klik met KIES om de gemaakte wijzigingen te bewaren en d
en.ro.HelpInterfaceConfig:\Tinterface configuration \w
de.ro.HelpInterfaceConfig:Fenster zur Einstellung des Programmverhaltens in ausgewählten Situationen
fr.ro.HelpInterfaceConfig:\Tla fenêtre de configuration d'interface
-it.ro.HelpInterfaceConfig:\Tinterface configuration \w
+it.ro.HelpInterfaceConfig:\Tconfigurazione dell'interfaccia \w
nl.ro.HelpInterfaceConfig:De interface-instellingen kunnen in dit venster gewijzigd worden.
en.ro.HelpInterfaceConfig2:This indicates whether NetSurf will strip file extensions when saving files to disc.
de.ro.HelpInterfaceConfig2:Beim Abspeichern von Dateien auf einen Datenträger werden die Dateinamenserweiterungen (Extensions) aus dem Dateinamen entfernt.
@@ -5589,12 +5557,12 @@ fr.ro.HelpInterfaceConfig13:\Ssauver ces réglages et fermer la fenêtre.|M\Asau
it.ro.HelpInterfaceConfig13:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpInterfaceConfig13:Klik met KIES om de gemaakte wijzigingen te bewaren en dit venster te sluiten.|MKlikken met PASAAN heeft hetzelfde effect, alleen wordt het huidige venster dan niet gesloten.
en.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
-de.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
+de.ro.HelpInterfaceConfig16:Erlaubt das Benutzen eines externen Programmes zur Verwaltung der Hotlist.
fr.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
it.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
nl.ro.HelpInterfaceConfig16:Deze optie geeft aan of de favorietenlijst via een extern programma (indien beschikbaar) beheerd mogen worden.
en.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
-de.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
+de.ro.HelpInterfaceConfig18:\Tder Pfad zu einer Anwendung, die die Hotlist verwalten kann.
fr.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
it.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
nl.ro.HelpInterfaceConfig18:Voer in dit invoerveld het pad in van een extern programma dat de favorietenlijst mag beheren.
@@ -5602,17 +5570,17 @@ nl.ro.HelpInterfaceConfig18:Voer in dit invoerveld het pad in van een extern pro
en.ro.HelpLanguageConfig:\Tlanguage configuration \w
de.ro.HelpLanguageConfig:Konfigurationsfenster für die Spracheinstellungen
fr.ro.HelpLanguageConfig:\Tfenêtre de configuration de langue.
-it.ro.HelpLanguageConfig:\Tlanguage configuration \w
+it.ro.HelpLanguageConfig:\Tconfigurazione della lingua \w
nl.ro.HelpLanguageConfig:Diverse taalinstellingen kunnen in dit venster gewijzigd worden.
en.ro.HelpLanguageConfig3:\Tcurrently selected interface language.|MThe interface language is the language used for NetSurf's messages and dialogue boxes.
-de.ro.HelpLanguageConfig3:Das ist die aktuell eingestellte Sprache für die Bedienoberfläche.|MDiese Sprache wird genutzt, um NetSurf's Meldungen und die Texte der Dialogboxen und Menüs darzustellen.
+de.ro.HelpLanguageConfig3:Das ist die aktuell eingestellte Sprache für die Bedienoberfläche.|MDiese Sprache wird genutzt, um NetSurf's Meldungen, Texte der Dialogboxen, Menüs darzustellen.
fr.ro.HelpLanguageConfig3:\Tla langue d'interface sélectionnée actuellement.|MLa langue d'interface est la langue utilisée pour les messages et les boîtes de dialogue de Netsurf.
it.ro.HelpLanguageConfig3:\Tcurrently selected interface language.|MThe interface language is the language used for NetSurf's messages and dialogue boxes.
nl.ro.HelpLanguageConfig3:Dit is momenteel de geselecteerde gebruikersinterfacetaal.|MDe interfacetaal is de taal voor de melding- en dialoogvensters.
en.ro.HelpLanguageConfig4:\Sselect an interface language.
de.ro.HelpLanguageConfig4:Klicken mit AUSWAHL zum Auswählen einer Oberflächensprache.
fr.ro.HelpLanguageConfig4:\Schoisir une langue d'interface.
-it.ro.HelpLanguageConfig4:\Sselect an interface language.
+it.ro.HelpLanguageConfig4:\Sseleziona un'interfaccia di lingua.
nl.ro.HelpLanguageConfig4:Klik met KIES om de gebruikersinterfacetaal te kiezen.
en.ro.HelpLanguageConfig6:\Tcurrently selected web page language.|MIf a web site provides a choice of languages, NetSurf will request the page in your preferred language.
de.ro.HelpLanguageConfig6:Das ist die aktuelle Sprache zur Anzeige auf Webseiten.|MWenn eine Webseite die Darstellung in verschiedenen Sprachen anbietet, wird NetSurf die Webseite in der hier eingestellten bevorzugten Sprache abrufen.
@@ -5622,7 +5590,7 @@ nl.ro.HelpLanguageConfig6:Dit is momenteel de geselecteerde webpaginataal.|MWann
en.ro.HelpLanguageConfig7:\Sselect a preferred web page language.
de.ro.HelpLanguageConfig7:Klicken mit AUSWAHL zum Auswählen einer Webseitensprache.
fr.ro.HelpLanguageConfig7:\Schoisir une langue de page web préférée.
-it.ro.HelpLanguageConfig7:\Sselect a preferred web page language.
+it.ro.HelpLanguageConfig7:\Sseleziona una lingua preferita per le pagine web.
nl.ro.HelpLanguageConfig7:Klik met KIES om de gewenste webpaginataal te kiezen.
en.ro.HelpLanguageConfig8:\Sreset the Language options back to their default values.
de.ro.HelpLanguageConfig8:Stellt die Standardeinstellungen wieder her.
@@ -5643,7 +5611,7 @@ nl.ro.HelpLanguageConfig10:Klik met KIES om de gemaakte wijzigingen te bewaren e
en.ro.HelpSecurityConfig:\Tsecurity configuration \w
de.ro.HelpSecurityConfig:Fenster zur Konfiguration der Sicherheitseinstellungen
fr.ro.HelpSecurityConfig:\Tla fenêtre de configuration de sécurité
-it.ro.HelpSecurityConfig:\Tsecurity configuration \w
+it.ro.HelpSecurityConfig:\Tconfigurazione di sicurezza \w
nl.ro.HelpSecurityConfig:De privacy- en veiligheidsinstellingen kunnen in dit venster gewijzigd worden.
en.ro.HelpSecurityConfig2:This indicates whether NetSurf will send site referral information to web servers.|MWhen this is enabled NetSurf will tell the web server of a new page the address of the site you came from, after following a link.
de.ro.HelpSecurityConfig2:NetSurf sendet Seitenreferenzinformationen an Webserver.|MIst diese Option gewählt, schickt NetSurf an den Server einer neuen Webseite die Adresse der Seite von der aus die aktuelle über einen Link aufgerufen wurde.
@@ -5658,12 +5626,12 @@ nl.ro.HelpSecurityConfig6:In dit veld kan de tijdsduur ingevoerd worden, dat ite
en.ro.HelpSecurityConfig7:\Sreduce the global history duration.
de.ro.HelpSecurityConfig7:Klicken mit AUSWAHL verkürzt die Aufbewahrungszeit von Seiten in der globalen History.
fr.ro.HelpSecurityConfig7:\Sréduire la durée de l'historique global.
-it.ro.HelpSecurityConfig7:\Sreduce the global history duration.
+it.ro.HelpSecurityConfig7:\Sriduce la durata della cronologia globale.
nl.ro.HelpSecurityConfig7:Klik met KIES om de tijdsduur van de browsergeschiedenis per dag te verminderen.
en.ro.HelpSecurityConfig8:\Sincrease the global history duration.
de.ro.HelpSecurityConfig8:Klicken mit AUSWAHL verlängert die Aufbewahrungszeit von Seiten in der globalen History.
fr.ro.HelpSecurityConfig8:\Saugmenter la durée de l'historique global.
-it.ro.HelpSecurityConfig8:\Sincrease the global history duration.
+it.ro.HelpSecurityConfig8:\Saumenta la durata della cronologia globale.
nl.ro.HelpSecurityConfig8:Klik met KIES om de tijdsduur van de browsergeschiedenis per dag te vermeerderen,
en.ro.HelpSecurityConfig10:\Sreset the Security options back to their default values.
de.ro.HelpSecurityConfig10:Stellt die Standardeinstellungen wieder her.
@@ -5684,7 +5652,7 @@ nl.ro.HelpSecurityConfig12:Klik met KIES om de gemaakte wijzigingen te bewaren e
en.ro.HelpThemeConfig:\Ttheme configuration \w
de.ro.HelpThemeConfig:Fenster zur Auswahl des Anzeigethemas
fr.ro.HelpThemeConfig:\Tla fenêtre de configuration de thème
-it.ro.HelpThemeConfig:\Ttheme configuration \w
+it.ro.HelpThemeConfig:\Tconfigurazione del tema \w
nl.ro.HelpThemeConfig:Het thema kan in dit venster gewijzigd worden.
en.ro.HelpThemeConfig2:\Sreset the Theme options back to their default values.
de.ro.HelpThemeConfig2:Stellt die Standardeinstellungen wieder her.
@@ -5732,7 +5700,7 @@ fr.ami.HelpToolbarReload:Reload\nLMB: Reloads the page\nShift+LMB: Reloads the p
it.ami.HelpToolbarReload:Ricarica
nl.ami.HelpToolbarReload:Herlaad\nLMB: Herlaad de pagina\nShift+LMB: Herlaad de pagina inclusief alle objecten
en.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
-de.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
+de.ami.HelpToolbarHome:Home\nLMB: Homepage ansteuern
fr.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
it.ami.HelpToolbarHome:Pagina iniziale
nl.ami.HelpToolbarHome:Startpagina\nLMB: Opent de ingestelde startpagina
@@ -5782,7 +5750,7 @@ nl.all.con_fonts:Lettertypen
en.all.con_home:Home page
de.all.con_home:Homepage
fr.all.con_home:Page d'accueil
-it.all.con_home:Home Page
+it.all.con_home:Pagina iniziale
nl.all.con_home:Startpagina
en.all.con_image:Images
de.all.con_image:Bilder
@@ -5900,7 +5868,7 @@ fr.all.Scripting:Scripts
it.all.Scripting:Scripting
nl.all.Scripting:Scripts
en.all.EnableJS:Enable JavaScript
-de.all.EnableJS:Enable JavaScript
+de.all.EnableJS:JavaScript benutzen
fr.all.EnableJS:Activer le JavaScript
it.all.EnableJS:Attiva JavaScript
nl.all.EnableJS:JavaScript ingeschakeld
@@ -5920,7 +5888,7 @@ fr.all.SendReferer:Permettre l'envoi du referer en entête
it.all.SendReferer:Invia informazioni sul referral del sito
nl.all.SendReferer:Zend websitereferentie
en.ami.DoNotTrack:Send header to tell websites not to track
-de.ami.DoNotTrack:Send header to tell websites not to track
+de.ami.DoNotTrack:Webseiten das Tracking verbieten - Wunsch
fr.ami.DoNotTrack:Activer l'envoi d'une requête "Ne pas suivre à la trace"
it.ami.DoNotTrack:Invia header al sito per la richiesta di non tracciamento
nl.ami.DoNotTrack:Websites laten weten dat gebruiker niet gevolgd wil worden
@@ -6032,7 +6000,7 @@ fr.all.ScaleQuality:Graduation de qualité supérieur
it.all.ScaleQuality:Massima qualità di visualizzazione
nl.all.ScaleQuality:Hogere schaalkwaliteit
en.ami.DitherQuality:Dither quality
-de.ami.DitherQuality:Dither quality
+de.ami.DitherQuality:Dithern
fr.ami.DitherQuality:Qualité de tramage
it.ami.DitherQuality:Qualità dither
nl.ami.DitherQuality:Kwaliteit kleurbenadering
@@ -6138,7 +6106,7 @@ fr.all.FontFantasy:Fantaisie
it.all.FontFantasy:Fantasia
nl.all.FontFantasy:Fantasie
en.ami.FontFallback:Preferred fallback
-de.ami.FontFallback:Preferred fallback
+de.ami.FontFallback:wenns nicht klappt
fr.ami.FontFallback:Police de caractères de secour préférée
it.ami.FontFallback:Fallback preferito
nl.ami.FontFallback:Favoriete reserve lettertype
@@ -6163,24 +6131,24 @@ fr.all.Pt:pt
it.all.Pt:pt
nl.all.Pt:pt
en.ami.FontAntialiasing:Use anti-aliasing (when possible)
-de.ami.FontAntialiasing:Use anti-aliasing (when possible)
+de.ami.FontAntialiasing:Anti-aliasing nutzen (wenn möglich)
fr.ami.FontAntialiasing:Utiliser l'anticrénelage (si possible)
it.ami.FontAntialiasing:Usa anti-aliasing (quando possibile)
nl.ami.FontAntialiasing:Anti-aliasing (indien mogelijk) gebruiken
en.ami.FontBitmap:Allow bitmap fonts
-de.ami.FontBitmap:Allow bitmap fonts
+de.ami.FontBitmap:Bitmap Fonts zulassen
fr.ami.FontBitmap:Allow bitmap fonts
-it.ami.FontBitmap:Allow bitmap fonts
+it.ami.FontBitmap:Permetti font bitmap
nl.ami.FontBitmap:Allow bitmap fonts
# Font scanning
en.ami.FontScanning:Scanning fonts...
-de.ami.FontScanning:Scanning fonts...
+de.ami.FontScanning:Lese Fonts ein...
fr.ami.FontScanning:Balayage de polices de caractères...
it.ami.FontScanning:Scansione dei font in corso...
nl.ami.FontScanning:Scannen lettertypen...
en.ami.FontGlyphs:%ld unique glyphs found
-de.ami.FontGlyphs:%ld unique glyphs found
+de.ami.FontGlyphs:%ld eigenständige Glyphen gefunden
fr.ami.FontGlyphs:%ld glyphe(s) unique(s) trouvé
it.ami.FontGlyphs:%ld glifi unici trovati
nl.ami.FontGlyphs:%ld unieke tekens gevonden
@@ -6234,17 +6202,17 @@ fr.all.TabMiddle:Bouton du milieu de la souris ouvre un onglet
it.all.TabMiddle:Usa tasto centrale del mouse per aprire le schede
nl.all.TabMiddle:Middelste muisknop opent een nieuw tabblad
en.all.TabLast:Open new tabs after all existing tabs
-de.all.TabLast:Open new tabs after all existing tabs
+de.all.TabLast:Neue Tabs hinter letztem öffnen
fr.all.TabLast:Ouvrir de nouveaux onglets après tous les onglets existants
it.all.TabLast:Apri le nuove schede dopo quella corrente
nl.all.TabLast:Open nieuw tabblad na alle bestaande tabbladen
en.ami.TabClose:Warn when closing multiple tabs
-de.ami.TabClose:Warn when closing multiple tabs
+de.ami.TabClose:Warnen beim Schließen vieler Tabs
fr.ami.TabClose:Avertir lors de la fermeture de plusieurs onglets
it.ami.TabClose:Avvisa quando si chiudono più schede
nl.ami.TabClose:Waarschuwen wanneer meerdere tabbladen tegelijkertijd worden gesloten
en.ami.TabAlways:Always show tabs
-de.ami.TabAlways:Always show tabs
+de.ami.TabAlways:Tabs immer zeigen
fr.ami.TabAlways:Toujours afficher les onglets
it.ami.TabAlways:Mostra sempre la barra delle schede
nl.ami.TabAlways:Tabbladen altijd tonen
@@ -6253,6 +6221,7 @@ nl.ami.TabAlways:Tabbladen altijd tonen
#
en.all.Downloads:Downloads
+de.all.Downloads:Downloads
it.all.Downloads:Trasferimenti
nl.all.Downloads:Opgehaalde items
@@ -6335,7 +6304,7 @@ it.all.OptionNoWindow:Non aprire la finestra all'avvio (avvio da AmiDock)
nl.all.OptionNoWindow:Geen venster openen na starten programma
en.all.OptionNoQuit:Do not quit when last window closed
-de.all.OptionNoQuit:Nicht beenden beim Schließen des letzten Fensters
+de.all.OptionNoQuit:Nicht Beenden beim Schließen des letzten Fensters
fr.all.OptionNoQuit:Ne pas quitter lorsque la dernière fenêtre se trouve fermée
it.all.OptionNoQuit:Iconifica su AmiDock alla chiusura di NetSurf
nl.all.OptionNoQuit:Stop programma niet als laatste venster worden gesloten
@@ -6375,6 +6344,7 @@ nl.all.Bottom:Onder
en.all.MM:mm
fr.all.MM:mm
nl.all.MM:mm
+it.all.MM:mm
en.all.Scaling:Scaling
de.all.Scaling:Skalierung
diff --git a/!NetSurf/Resources/AdBlock,f79 b/resources/adblock.css
index eaf1d484e..eaf1d484e 100644
--- a/!NetSurf/Resources/AdBlock,f79
+++ b/resources/adblock.css
diff --git a/!NetSurf/Resources/ca-bundle b/resources/ca-bundle
index 76adf8346..39ba33683 100644
--- a/!NetSurf/Resources/ca-bundle
+++ b/resources/ca-bundle
@@ -1,20 +1,20 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Jan 20 04:12:04 2016
+## Certificate data from Mozilla as of: Wed Sep 20 03:12:05 2017 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
-## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
+## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
-## Conversion done with mk-ca-bundle.pl version 1.25.
-## SHA1: 0ab47e2f41518f8d223eab517cb799e5b071231e
+## Conversion done with mk-ca-bundle.pl version 1.27.
+## SHA256: 2b2dbe5244e0047e088c597998883a913f6c5fffd1cb5c0fe5a368c8466cb2ec
##
@@ -130,30 +130,6 @@ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
-AddTrust Low-Value Services Root
-================================
------BEGIN CERTIFICATE-----
-MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
-cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
-CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
-ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
-AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
-54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
-oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
-Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
-GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
-HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
-AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
-HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
-ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
-iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
-eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
-mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
-ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
------END CERTIFICATE-----
-
AddTrust External Root
======================
-----BEGIN CERTIFICATE-----
@@ -178,54 +154,6 @@ e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----
-AddTrust Public Services Root
-=============================
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
-cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
-BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
-dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
-nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
-d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
-Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
-HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
-A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
-A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
-JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
-+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
-GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
-Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
-EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
------END CERTIFICATE-----
-
-AddTrust Qualified Certificates Root
-====================================
------BEGIN CERTIFICATE-----
-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
-cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
-CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
-IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
-64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
-KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
-L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
-wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
-MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
-BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
-azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
-ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
-GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
-dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
-RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
-iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
------END CERTIFICATE-----
-
Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
@@ -252,27 +180,6 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----
-RSA Security 2048 v3
-====================
------BEGIN CERTIFICATE-----
-MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
-ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
-MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
-BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
-Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
-WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
-KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
-+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
-MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
-FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
-v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
-0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
-VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
-nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
-pKnXwiJPZ9d37CAFYd4=
------END CERTIFICATE-----
-
GeoTrust Global CA
==================
-----BEGIN CERTIFICATE-----
@@ -294,27 +201,6 @@ XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
Mw==
-----END CERTIFICATE-----
-GeoTrust Global CA 2
-====================
------BEGIN CERTIFICATE-----
-MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
-R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
-MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
-LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
-NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
-LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
-Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
-HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
-K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
-srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
-ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
-OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
-x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
-H4z1Ir+rzoPz4iIprn2DQKi6bA==
------END CERTIFICATE-----
-
GeoTrust Universal CA
=====================
-----BEGIN CERTIFICATE-----
@@ -440,56 +326,6 @@ Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
-Comodo Secure Services root
-===========================
------BEGIN CERTIFICATE-----
-MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
-R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
-TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
-MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
-Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
-BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
-9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
-rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
-oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
-p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
-FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
-gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
-YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
-aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
-4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
-Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
-DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
-pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
-RR3B7Hzs/Sk=
------END CERTIFICATE-----
-
-Comodo Trusted Services root
-============================
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
-R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
-TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
-MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
-bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
-IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
-3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
-/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
-juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
-ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
-DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
-ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
-cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
-uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
-pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
-BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
-R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
-9y5Xt5hwXsjEeLBi
------END CERTIFICATE-----
-
QuoVadis Root CA
================
-----BEGIN CERTIFICATE-----
@@ -629,54 +465,6 @@ EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
llpwrN9M
-----END CERTIFICATE-----
-Staat der Nederlanden Root CA
-=============================
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
-ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
-Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
-HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
-bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
-vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
-jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
-C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
-vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
-22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
-HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
-dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
-BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
-EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
-MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
-nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
-iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
------END CERTIFICATE-----
-
-UTN USERFirst Hardware Root CA
-==============================
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
-BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
-IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
-BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
-OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
-eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
-ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
-wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
-tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
-i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
-Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
-gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
-lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
-UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
-BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
-XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
-lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
-iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
-nfhmqA==
------END CERTIFICATE-----
-
Camerfirma Chambers of Commerce Root
====================================
-----BEGIN CERTIFICATE-----
@@ -731,41 +519,6 @@ IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
-----END CERTIFICATE-----
-NetLock Notary (Class A) Root
-=============================
------BEGIN CERTIFICATE-----
-MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
-EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
-dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
-ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
-DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
-EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
-VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
-cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
-D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
-z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
-/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
-tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
-4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
-A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
-Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
-bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
-IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
-LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
-ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
-IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
-IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
-b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
-bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
-Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
-bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
-ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
-ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
-CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
-KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
-8CgHrTwXZoi1/baI
------END CERTIFICATE-----
-
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
@@ -909,38 +662,6 @@ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
-----END CERTIFICATE-----
-Swisscom Root CA 1
-==================
------BEGIN CERTIFICATE-----
-MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG
-EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
-dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4
-MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
-aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC
-IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM
-MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF
-NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe
-AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC
-b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn
-7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN
-cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp
-WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5
-haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY
-MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
-HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
-BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9
-MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn
-jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ
-MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H
-VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl
-vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl
-OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3
-1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq
-nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy
-x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW
-NY6E0F/6MBr1mmz0DlP5OlvRHA==
------END CERTIFICATE-----
-
DigiCert Assured ID Root CA
===========================
-----BEGIN CERTIFICATE-----
@@ -1298,33 +1019,6 @@ wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
-----END CERTIFICATE-----
-WellsSecure Public Root Certificate Authority
-=============================================
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
-F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
-NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
-MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
-bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
-VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
-iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
-i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
-bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
-K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
-AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
-cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
-lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
-i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
-GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
-Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
-K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
-bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
-qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
-E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
-tylv2G0xffX8oRAHh84vWdw+WNs=
------END CERTIFICATE-----
-
COMODO ECC Certification Authority
==================================
-----BEGIN CERTIFICATE-----
@@ -1342,30 +1036,6 @@ FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
-IGC/A
-=====
------BEGIN CERTIFICATE-----
-MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
-VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
-Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
-MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
-EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
-STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
-TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
-So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
-HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
-frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
-tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
-egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
-iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
-q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
-MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
-Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
-lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
-0mBWWg==
------END CERTIFICATE-----
-
Security Communication EV RootCA1
=================================
-----BEGIN CERTIFICATE-----
@@ -1410,46 +1080,6 @@ hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
-----END CERTIFICATE-----
-Microsec e-Szigno Root CA
-=========================
------BEGIN CERTIFICATE-----
-MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
-BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
-EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
-MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
-dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
-GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
-d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
-oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
-QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
-PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
-MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
-IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
-VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
-LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
-dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
-AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
-4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
-AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
-egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
-Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
-PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
-c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
-cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
-IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
-WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
-MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
-MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
-Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
-HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
-nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
-aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
-86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
-yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
-S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
------END CERTIFICATE-----
-
Certigna
========
-----BEGIN CERTIFICATE-----
@@ -1575,58 +1205,6 @@ LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
-----END CERTIFICATE-----
-Buypass Class 2 CA 1
-====================
------BEGIN CERTIFICATE-----
-MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
-QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
-MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
-c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
-cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
-0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
-0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
-uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
-MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
-AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
-1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
-7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
-fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
-wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
------END CERTIFICATE-----
-
-EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
-==========================================================================
------BEGIN CERTIFICATE-----
-MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
-QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
-Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
-ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
-IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
-X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
-gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
-eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
-TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
-Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
-uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
-qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
-ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
-Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
-/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
-Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
-FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
-zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
-XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
-bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
-RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
-1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
-2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
-Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
-AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
------END CERTIFICATE-----
-
certSIGN ROOT CA
================
-----BEGIN CERTIFICATE-----
@@ -1647,49 +1225,6 @@ vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
-----END CERTIFICATE-----
-CNNIC ROOT
-==========
------BEGIN CERTIFICATE-----
-MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
-ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
-OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
-o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
-VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
-VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
-czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
-y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
-wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
-lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
-Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
-O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
-BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
-G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
-mxE=
------END CERTIFICATE-----
-
-ApplicationCA - Japanese Government
-===================================
------BEGIN CERTIFICATE-----
-MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
-SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
-MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
-cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
-fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
-wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
-jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
-nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
-WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
-BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
-vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
-o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
-/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
-io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
-dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
-rosot4LKGAfmt1t06SAZf7IbiVQ=
------END CERTIFICATE-----
-
GeoTrust Primary Certification Authority - G3
=============================================
-----BEGIN CERTIFICATE-----
@@ -1821,7 +1356,7 @@ AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
-----END CERTIFICATE-----
NetLock Arany (Class Gold) Főtanúsítvány
-============================================
+========================================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
@@ -1876,58 +1411,6 @@ IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
66+KAQ==
-----END CERTIFICATE-----
-CA Disig
-========
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
-QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
-MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
-bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
-GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
-Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
-hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
-ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
-gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
-AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
-aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
-ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
-BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
-WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
-mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
-CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
-ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
-4Z7CRneC9VkGjCFMhwnN5ag=
------END CERTIFICATE-----
-
-Juur-SK
-=======
------BEGIN CERTIFICATE-----
-MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
-c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
-DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
-SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
-aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
-TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
-+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
-UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
-Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
-MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
-HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
-AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
-cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
-AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
-cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
-FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
-A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
-ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
-abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
-IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
-Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
-yyqcjg==
------END CERTIFICATE-----
-
Hongkong Post Root CA 1
=======================
-----BEGIN CERTIFICATE-----
@@ -2361,7 +1844,7 @@ Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
-----END CERTIFICATE-----
Certinomis - Autorité Racine
-=============================
+============================
-----BEGIN CERTIFICATE-----
MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
@@ -2391,41 +1874,6 @@ wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
vgt2Fl43N+bYdJeimUV5
-----END CERTIFICATE-----
-Root CA Generalitat Valenciana
-==============================
------BEGIN CERTIFICATE-----
-MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
-ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
-IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
-WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
-CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
-F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
-ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
-D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
-JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
-AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
-dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
-ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
-AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
-YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
-AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
-aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
-AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
-YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
-AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
-OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
-dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
-BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
-A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
-b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
-TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
-Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
-NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
-iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
-+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
------END CERTIFICATE-----
-
TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
@@ -2871,93 +2319,6 @@ poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
-----END CERTIFICATE-----
-China Internet Network Information Center EV Certificates Root
-==============================================================
------BEGIN CERTIFICATE-----
-MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
-BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
-aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
-Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
-A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
-PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
-cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
-jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
-98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
-klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
-KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
-7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
-HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
-glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
-0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
-7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
-ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
-5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
------END CERTIFICATE-----
-
-Swisscom Root CA 2
-==================
------BEGIN CERTIFICATE-----
-MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG
-EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
-dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2
-MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
-aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC
-IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM
-LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo
-ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ
-wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH
-Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a
-SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS
-NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab
-mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY
-Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3
-qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
-HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
-BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu
-MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO
-v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ
-82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz
-o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs
-a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx
-OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW
-mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o
-+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC
-rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX
-5OfNeOI5wSsSnqaeG8XmDtkx2Q==
------END CERTIFICATE-----
-
-Swisscom Root EV CA 2
-=====================
------BEGIN CERTIFICATE-----
-MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE
-BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl
-cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN
-MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
-HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg
-Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz
-o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy
-Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti
-GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li
-qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH
-Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG
-alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa
-m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox
-bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi
-xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/
-BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
-MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB
-bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL
-j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU
-wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7
-XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH
-59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/
-23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq
-J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA
-HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi
-uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW
-l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
------END CERTIFICATE-----
-
CA Disig Root R1
================
-----BEGIN CERTIFICATE-----
@@ -3756,7 +3117,7 @@ ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
-----END CERTIFICATE-----
TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5
-=========================================================
+====================================================
-----BEGIN CERTIFICATE-----
MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN
BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
@@ -3779,30 +3140,6 @@ lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8
B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=
-----END CERTIFICATE-----
-TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6
-=========================================================
------BEGIN CERTIFICATE-----
-MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQGEwJUUjEPMA0G
-A1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
-acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5
-MDQxMFoXDTIzMTIxNjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBL
-BgNVBAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSf
-aSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2VydGlm
-aWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQCdsGjW6L0UlqMACprx9MfMkU1xeHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a
-2uqsxgbPJQ1BgfbBOCK9+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EED
-wnS3/faAz1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0pu5Fb
-HH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6plVxiSvgNZ1GpryHV
-+DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMBAAGjQjBAMB0GA1UdDgQWBBTdVRcT
-9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
-9w0BAQsFAAOCAQEAb1gNl0OqFlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3R
-fdCaqaXKGDsCQC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy
-o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKIDgI6tflEATseW
-hvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm9ocJV612ph1jmv3XZch4gyt1
-O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsGtAuYSyher4hYyw==
------END CERTIFICATE-----
-
Certinomis - Root CA
====================
-----BEGIN CERTIFICATE-----
@@ -3891,3 +3228,419 @@ MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0
Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu
a/GRspBl9JrmkO5K
-----END CERTIFICATE-----
+
+SZAFIR ROOT CA2
+===============
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
+A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
+BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
+BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
+VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
+qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
+DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
+2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
+ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
+ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
+AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
+O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
+oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
+4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA 2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
+BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
+bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
+ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
+TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
+IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
+7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
+CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
+Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
+uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
+GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
+9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
+Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
+hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
+BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
+hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
+Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
+L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
+clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
+pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
+w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
+J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
+ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
+is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
+zAYspsbiDrW5viSP
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2015
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
+BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
+aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
+MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
+QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
+BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
+MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
+bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
+iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
+6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
+FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
+i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
+GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
+fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
+iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
+hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
+D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
+d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
+d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
+82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
+davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
+Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
+J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
+JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
+p/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions ECC RootCA 2015
+===========================================================
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
+aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
+MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
+IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
+VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
+Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
+dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
+Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
+GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
+dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+
+Certplus Root CA G1
+===================
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV
+BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe
+Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD
+ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN
+r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx
+Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj
+BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv
+LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2
+z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc
+4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd
+4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj
+jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+
+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
+A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY
+lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
+66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG
+YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/
+2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F
+6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX
+CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe
+tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC
+VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/
++mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+
+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
+-----END CERTIFICATE-----
+
+Certplus Root CA G2
+===================
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT
+AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x
+NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0
+cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA
+BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN
+Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud
+IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV
+HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl
+vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G1
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx
+MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa
+Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87
+ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO
+YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9
+xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO
+9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq
+3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi
+n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9
+URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr
+TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px
+N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
+PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv
+uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK
+n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh
+X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80
+nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm
+GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/
+bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o
+4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA
+OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G2
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy
+MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+
+Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz
+4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV
+eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt
+UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz
+3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj
+3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz
+9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0
+0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT
+y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59
+M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
+Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI
+mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG
+S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp
+EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ
+6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr
+gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo
+SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0
+YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm
+u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G3
+====================
+-----BEGIN CERTIFICATE-----
+MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X
+DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w
+ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B
+ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB
+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf
+BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM
+BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta
+3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB
+-----END CERTIFICATE-----
+
+ISRG Root X1
+============
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
+BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
+EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
+EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
+DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
+Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
+3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
+b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
+Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
+4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
+1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
+hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
+usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
+OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
+9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
+0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
+hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
+TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
+e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
+JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
+YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
+JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
+m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----
+
+AC RAIZ FNMT-RCM
+================
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
+AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
+MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
+TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
+qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
+btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
+j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
+08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
+WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
+tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
+47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
+ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
+i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
+dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
+D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
+j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
+Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
+Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
+8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
+5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
+rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
+-----END CERTIFICATE-----
+
+Amazon Root CA 1
+================
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
+MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
+FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
+gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
+dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
+VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
+DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
+CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
+8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
+2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
+xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
+-----END CERTIFICATE-----
+
+Amazon Root CA 2
+================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
+MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
+kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
+N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
+AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
+fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
+kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
+btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
+Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
+c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
+DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
+A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
+YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
+xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
+gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
+aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
+Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
+KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
+JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
+-----END CERTIFICATE-----
+
+Amazon Root CA 3
+================
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
+f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
+Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
+rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
+eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
+-----END CERTIFICATE-----
+
+Amazon Root CA 4
+================
+-----BEGIN CERTIFICATE-----
+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
+/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
+83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
+MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
+AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
+-----END CERTIFICATE-----
+
+LuxTrust Global Root 2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG
+A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh
+bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW
+MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC
+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm
+Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2
+xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC
+wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm
+1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm
+FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF
+wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/
+a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U
+ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ
+MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB
+/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5
+Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT
++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ
+FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN
+H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW
+7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu
+ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA
+VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR
+TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt
+/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc
+7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I
+iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
+-----END CERTIFICATE-----
+
+TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
+D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
+IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
+TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
+ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
+VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
+c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
+bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
+IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
+6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
+wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
+3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
+WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
+ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
+lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
+e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
+q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
+-----END CERTIFICATE-----
diff --git a/!NetSurf/Resources/de/welcome.html,faf b/resources/de/welcome.html
index 8cbcbd8c5..1a27a8c8c 100644
--- a/!NetSurf/Resources/de/welcome.html,faf
+++ b/resources/de/welcome.html
@@ -6,13 +6,13 @@
</head>
<body>
-<h1 class="banner"><a href="http://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
+<h1 class="banner"><a href="https://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
<ul class="nslinks">
-<li><a href="http://www.netsurf-browser.org/">NetSurf Website</a></li>
-<li><a href="http://www.netsurf-browser.org/documentation/">Dokumentation</a></li>
-<li><a href="http://www.netsurf-browser.org/downloads/">Download neustes NetSurf</a></li>
-<li><a href="http://www.netsurf-browser.org/contact/">Kontakt zu den Entwicklern</a></li>
+<li><a href="https://www.netsurf-browser.org/">NetSurf Website</a></li>
+<li><a href="https://www.netsurf-browser.org/documentation/">Dokumentation</a></li>
+<li><a href="https://www.netsurf-browser.org/downloads/">Download neustes NetSurf</a></li>
+<li><a href="https://www.netsurf-browser.org/contact/">Kontakt zu den Entwicklern</a></li>
</ul>
<div class="onlycontent">
diff --git a/!NetSurf/Resources/CSS,f79 b/resources/default.css
index 44268d6a7..276bc1554 100644
--- a/!NetSurf/Resources/CSS,f79
+++ b/resources/default.css
@@ -114,13 +114,13 @@ form { display: block; }
input, button { background-color: #fff; color: #000; text-align: left;
font-family: sans-serif; width: auto; height: auto; overflow: hidden;
border: 1px solid #444; padding: 2px 3px; line-height: 1.33;
- margin: 1px; }
-input[readonly] { background-color: #ddd; color: #333; }
+ margin: 1px; box-sizing: border-box; }
+input[disabled] { background-color: #ddd; color: #333; }
input[type=button], input[type=reset], input[type=submit], button {
background-color: #d9d9d9; color: #000; text-align: center;
border: 2px outset #d9d9d9; padding: 1px 0.5em; }
input[type=image] { background-color: transparent; color: #000;
- border: none; padding: 0 2px; }
+ border: none; padding: 0 2px; box-sizing: content-box; }
input[type=checkbox], input[type=radio] { background-color: transparent;
border: none; padding: 0 0.1em; }
input[type=file] { background-color: #d9d9d9; color: #000; font-style: italic;
@@ -137,7 +137,7 @@ select:after { content: "\25bc"; border-left: 2px ridge #d9d9d9; }
textarea { background-color: #fff; color: #000; text-align: left;
font-family: monospace; width: auto; height: auto; overflow: scroll;
margin: 1px; border: 1px solid #333; padding: 1px 3px; }
-textarea[readonly] { background-color: #ddd; color: #333; }
+textarea[disabled] { background-color: #ddd; color: #333; }
fieldset { display: block; border: thin solid #888; margin: 1.12em 0; }
diff --git a/!NetSurf/Resources/en/credits.html,faf b/resources/en/credits.html
index b7098df44..7789bcdea 100644
--- a/!NetSurf/Resources/en/credits.html,faf
+++ b/resources/en/credits.html
@@ -92,7 +92,7 @@ div#DevList ul {
</div>
<div class="footer">
-<p>Copyright 2003&ndash;2016 The NetSurf Developers</p>
+<p>Copyright 2003&ndash;2017 The NetSurf Developers</p>
</div>
</body>
diff --git a/!NetSurf/Resources/en/licence.html,faf b/resources/en/licence.html
index da0df454e..515757cd7 100644
--- a/!NetSurf/Resources/en/licence.html,faf
+++ b/resources/en/licence.html
@@ -60,25 +60,25 @@ version.</p>
<dl class="components">
<dt><a href="http://www.netsurf-browser.org/">NetSurf</a></dt>
<dd>
-<span>&copy; 2002&ndash;2016 The NetSurf Developers</span>
+<span>&copy; 2002&ndash;2017 The NetSurf Developers</span>
<span><a href="#gplv2">GPLv2</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libcss/">LibCSS</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/hubbub/">Hubbub</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libparserutils/">LibParserUtils</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -102,19 +102,19 @@ version.</p>
<dt><a href="http://www.netsurf-browser.org/projects/libsvgtiny">Libsvgtiny</a></dt>
<dd>
-<span>&copy; 2008&ndash;2009 James Bursa<br>&copy; 2016 Michael Drake</span>
+<span>&copy; 2008&ndash;2009 James Bursa<br>&copy; 2017 Michael Drake</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libnsbmp/">Libnsbmp</a></dt>
<dd>
-<span>&copy; 2006 Richard Wilson<br>&copy; 2008 Sean Fox<br>&copy; 2016 Vincent Sanders</span>
+<span>&copy; 2006 Richard Wilson<br>&copy; 2008 Sean Fox<br>&copy; 2017 Vincent Sanders</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libnsfb/">Libnsfb</a></dt>
<dd>
-<span>&copy; 2009&ndash;2016 Vincent Sanders<br>&copy; 2009&ndash;2016 Michael Drake</span>
+<span>&copy; 2009&ndash;2017 Vincent Sanders<br>&copy; 2009&ndash;2017 Michael Drake</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -126,7 +126,7 @@ version.</p>
<dt><a href="http://www.netsurf-browser.org/projects/libwapcaplet">LibWapcaplet</a></dt>
<dd>
-<span>&copy; 2009&ndash;2016 NetSurf Browser Project, Daniel Silverstone</span>
+<span>&copy; 2009&ndash;2017 NetSurf Browser Project, Daniel Silverstone</span>
<span><a href="#mit">MIT</a></span>
</dd>
</dl>
@@ -1865,7 +1865,7 @@ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
</div>
<div class="footer">
-<p>Copyright 2003&ndash;2016 The NetSurf Developers</p>
+<p>Copyright 2003&ndash;2017 The NetSurf Developers</p>
</div>
</body>
diff --git a/!NetSurf/Resources/en/maps.html,faf b/resources/en/maps.html
index 2427d8a9c..2427d8a9c 100644
--- a/!NetSurf/Resources/en/maps.html,faf
+++ b/resources/en/maps.html
diff --git a/!NetSurf/Resources/en/welcome.html,faf b/resources/en/welcome.html
index 14884f074..d10735880 100644
--- a/!NetSurf/Resources/en/welcome.html,faf
+++ b/resources/en/welcome.html
@@ -6,13 +6,13 @@
</head>
<body>
-<h1 class="banner"><a href="http://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
+<h1 class="banner"><a href="https://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
<ul class="nslinks">
-<li><a href="http://www.netsurf-browser.org/">NetSurf web&nbsp;site</a></li>
-<li><a href="http://www.netsurf-browser.org/documentation/">Documentation</a></li>
-<li><a href="http://www.netsurf-browser.org/downloads/">Download latest NetSurf</a></li>
-<li><a href="http://www.netsurf-browser.org/contact/">Contact the developers</a></li>
+<li><a href="https://www.netsurf-browser.org/">NetSurf web&nbsp;site</a></li>
+<li><a href="https://www.netsurf-browser.org/documentation/">Documentation</a></li>
+<li><a href="https://www.netsurf-browser.org/downloads/">Download latest NetSurf</a></li>
+<li><a href="https://www.netsurf-browser.org/contact/">Contact the developers</a></li>
</ul>
<div class="onlycontent">
diff --git a/!NetSurf/Resources/Icons/arrow-l.png b/resources/icons/arrow-l.png
index 139e08ff6..139e08ff6 100644
--- a/!NetSurf/Resources/Icons/arrow-l.png
+++ b/resources/icons/arrow-l.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/content.png b/resources/icons/content.png
index 8b0c297f2..8b0c297f2 100644
--- a/!NetSurf/Resources/Icons/content.png
+++ b/resources/icons/content.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/directory.png b/resources/icons/directory.png
index 9f8e99697..9f8e99697 100644
--- a/!NetSurf/Resources/Icons/directory.png
+++ b/resources/icons/directory.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/directory2.png b/resources/icons/directory2.png
index 521413742..521413742 100644
--- a/!NetSurf/Resources/Icons/directory2.png
+++ b/resources/icons/directory2.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/hotlist-add.png b/resources/icons/hotlist-add.png
index 3d6bab7f4..3d6bab7f4 100644
--- a/!NetSurf/Resources/Icons/hotlist-add.png
+++ b/resources/icons/hotlist-add.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/hotlist-rmv.png b/resources/icons/hotlist-rmv.png
index 872e22ed0..872e22ed0 100644
--- a/!NetSurf/Resources/Icons/hotlist-rmv.png
+++ b/resources/icons/hotlist-rmv.png
Binary files differ
diff --git a/!NetSurf/Resources/Icons/search.png b/resources/icons/search.png
index ee109240a..ee109240a 100644
--- a/!NetSurf/Resources/Icons/search.png
+++ b/resources/icons/search.png
Binary files differ
diff --git a/!NetSurf/Resources/internal.css,f79 b/resources/internal.css
index c72dfac06..c72dfac06 100644
--- a/!NetSurf/Resources/internal.css,f79
+++ b/resources/internal.css
diff --git a/!NetSurf/Resources/it/credits.html,faf b/resources/it/credits.html
index fe654439e..cec1912a6 100644
--- a/!NetSurf/Resources/it/credits.html,faf
+++ b/resources/it/credits.html
@@ -91,7 +91,7 @@ div#DevList ul {
</div>
<div class="footer">
-<p><br>Copyright 2003&ndash;2013 The NetSurf Developers</p>
+<p><br>Copyright 2003&ndash;2017 The NetSurf Developers</p>
</div>
</body>
diff --git a/!NetSurf/Resources/it/licence.html,faf b/resources/it/licence.html
index b0a6c8ae3..8b9c4891f 100644
--- a/!NetSurf/Resources/it/licence.html,faf
+++ b/resources/it/licence.html
@@ -52,25 +52,25 @@ dl.components > dd > span + span {
<dl class="components">
<dt><a href="http://www.netsurf-browser.org/">NetSurf</a></dt>
<dd>
-<span>&copy; 2002&ndash;2013 The NetSurf Developers</span>
+<span>&copy; 2002&ndash;2017 The NetSurf Developers</span>
<span><a href="#gplv2">GPLv2</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libcss/">LibCSS</a></dt>
<dd>
-<span>&copy; 2007&ndash;2013 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/hubbub/">Hubbub</a></dt>
<dd>
-<span>&copy; 2007&ndash;2013 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libparserutils/">LibParserUtils</a></dt>
<dd>
-<span>&copy; 2007&ndash;2013 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -106,7 +106,7 @@ dl.components > dd > span + span {
<dt><a href="http://www.netsurf-browser.org/projects/libnsfb/">Libnsfb</a></dt>
<dd>
-<span>&copy; 2009&ndash;2013 Vincent Sanders<br>&copy; 2009&ndash;2013 Michael Drake</span>
+<span>&copy; 2009&ndash;2017 Vincent Sanders<br>&copy; 2009&ndash;2017 Michael Drake</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -118,7 +118,7 @@ dl.components > dd > span + span {
<dt><a href="http://www.netsurf-browser.org/projects/libwapcaplet">LibWapcaplet</a></dt>
<dd>
-<span>&copy; 2009&ndash;2013 NetSurf Browser Project, Daniel Silverstone</span>
+<span>&copy; 2009&ndash;2017 NetSurf Browser Project, Daniel Silverstone</span>
<span><a href="#mit">MIT</a></span>
</dd>
</dl>
@@ -1853,7 +1853,7 @@ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
</div>
<div class="footer">
-<p>Copyright 2003&ndash;2013 The NetSurf Developers</p>
+<p>Copyright 2003&ndash;2017 The NetSurf Developers</p>
</div>
</body>
diff --git a/!NetSurf/Resources/it/welcome.html,faf b/resources/it/welcome.html
index f936fe3a6..c6b12b11d 100644
--- a/!NetSurf/Resources/it/welcome.html,faf
+++ b/resources/it/welcome.html
@@ -6,13 +6,13 @@
</head>
<body>
-<h1 class="banner"><a href="http://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
+<h1 class="banner"><a href="https://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
<ul class="nslinks">
-<li><a href="http://www.netsurf-browser.org/">Pagina principale</a></li>
-<li><a href="http://www.netsurf-browser.org/documentation/">Documentazione</a></li>
-<li><a href="http://www.netsurf-browser.org/downloads/">Scarica NetSurf</a></li>
-<li><a href="http://www.netsurf-browser.org/contact/">Contatta gli sviluppatori</a></li>
+<li><a href="https://www.netsurf-browser.org/">Pagina principale</a></li>
+<li><a href="https://www.netsurf-browser.org/documentation/">Documentazione</a></li>
+<li><a href="https://www.netsurf-browser.org/downloads/">Scarica NetSurf</a></li>
+<li><a href="https://www.netsurf-browser.org/contact/">Contatta gli sviluppatori</a></li>
</ul>
<div class="onlycontent">
diff --git a/!NetSurf/Resources/ja/welcome.html,faf b/resources/ja/welcome.html
index ce7b36343..5db1b7066 100644
--- a/!NetSurf/Resources/ja/welcome.html,faf
+++ b/resources/ja/welcome.html
@@ -7,13 +7,13 @@
</head>
<body>
-<h1 class="banner"><a href="http://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
+<h1 class="banner"><a href="https://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
<ul class="nslinks">
-<li><a href="http://www.netsurf-browser.org/">NetSurfウェブサイト</a></li>
-<li><a href="http://www.netsurf-browser.org/documentation/">ドキュメンテーション</a></li>
-<li><a href="http://www.netsurf-browser.org/downloads/">最新ã®NetSurfをダウンロード</a></li>
-<li><a href="http://www.netsurf-browser.org/contact/">開発者ã¨ã‚³ãƒ³ã‚¿ã‚¯ãƒˆ</a></li>
+<li><a href="https://www.netsurf-browser.org/">NetSurfウェブサイト</a></li>
+<li><a href="https://www.netsurf-browser.org/documentation/">ドキュメンテーション</a></li>
+<li><a href="https://www.netsurf-browser.org/downloads/">最新ã®NetSurfをダウンロード</a></li>
+<li><a href="https://www.netsurf-browser.org/contact/">開発者ã¨ã‚³ãƒ³ã‚¿ã‚¯ãƒˆ</a></li>
</ul>
<div class="onlycontent">
diff --git a/!NetSurf/Resources/netsurf.png,b60 b/resources/netsurf.png
index 8ba116c24..8ba116c24 100644
--- a/!NetSurf/Resources/netsurf.png,b60
+++ b/resources/netsurf.png
Binary files differ
diff --git a/!NetSurf/Resources/nl/credits.html,faf b/resources/nl/credits.html
index 3cae27a54..f9e0932c5 100644
--- a/!NetSurf/Resources/nl/credits.html,faf
+++ b/resources/nl/credits.html
@@ -96,7 +96,7 @@ div#DevList ul {
</div>
<div class="footer">
-<p>Auteursrecht 2003&ndash;2016 De NetSurf-ontwikkelaars</p>
+<p>Auteursrecht 2003&ndash;2017 De NetSurf-ontwikkelaars</p>
</div>
</body>
diff --git a/!NetSurf/Resources/nl/licence.html,faf b/resources/nl/licence.html
index d3272c75c..89ce8564e 100644
--- a/!NetSurf/Resources/nl/licence.html,faf
+++ b/resources/nl/licence.html
@@ -63,25 +63,25 @@ dan verwijder deze uitzonderingverklaring uit uw eigen versie.</p>
<dl class="components">
<dt><a href="http://www.netsurf-browser.org/">NetSurf</a></dt>
<dd>
-<span>&copy; 2002&ndash;2016 De NetSurf-ontwikkerlaars</span>
+<span>&copy; 2002&ndash;2017 De NetSurf-ontwikkerlaars</span>
<span><a href="#gplv2">GPLv2</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libcss/">LibCSS</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/hubbub/">Hubbub</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell<br>&copy; 2008&ndash;2009 Andrew Sidwell</span>
<span><a href="#mit">MIT</a></span>
</dd>
<dt><a href="http://www.netsurf-browser.org/projects/libparserutils/">LibParserUtils</a></dt>
<dd>
-<span>&copy; 2007&ndash;2016 John-Mark Bell</span>
+<span>&copy; 2007&ndash;2017 John-Mark Bell</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -117,7 +117,7 @@ dan verwijder deze uitzonderingverklaring uit uw eigen versie.</p>
<dt><a href="http://www.netsurf-browser.org/projects/libnsfb/">Libnsfb</a></dt>
<dd>
-<span>&copy; 2009&ndash;2016 Vincent Sanders<br>&copy; 2009&ndash;2016 Michael Drake</span>
+<span>&copy; 2009&ndash;2017 Vincent Sanders<br>&copy; 2009&ndash;2017 Michael Drake</span>
<span><a href="#mit">MIT</a></span>
</dd>
@@ -129,7 +129,7 @@ dan verwijder deze uitzonderingverklaring uit uw eigen versie.</p>
<dt><a href="http://www.netsurf-browser.org/projects/libwapcaplet">LibWapcaplet</a></dt>
<dd>
-<span>&copy; 2009&ndash;2016 NetSurf Browser Project, Daniel Silverstone</span>
+<span>&copy; 2009&ndash;2017 NetSurf Browser Project, Daniel Silverstone</span>
<span><a href="#mit">MIT</a></span>
</dd>
</dl>
@@ -1872,7 +1872,7 @@ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
</div>
<div class="footer">
-<p>Auteursrecht 2003&ndash;2016 De NetSurf-ontwikkelaars</p>
+<p>Auteursrecht 2003&ndash;2017 De NetSurf-ontwikkelaars</p>
</div>
</body>
diff --git a/!NetSurf/Resources/nl/welcome.html,faf b/resources/nl/welcome.html
index aec47e74e..c4678f8ce 100644
--- a/!NetSurf/Resources/nl/welcome.html,faf
+++ b/resources/nl/welcome.html
@@ -6,13 +6,13 @@
</head>
<body>
-<h1 class="banner"><a href="http://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
+<h1 class="banner"><a href="https://www.netsurf-browser.org/"><img src="about:logo" alt="NetSurf"></a></h1>
<ul class="nslinks">
-<li><a href="http://www.netsurf-browser.org/"><strong>NetSurf-website</strong> </a> (Engels)</li>
-<li><a href="http://www.netsurf-browser.org/documentation/">Engelstalige documentatie</a></li>
-<li>Nieuwste <a href="http://www.netsurf-browser.org/downloads/"><strong>NetSurf-versie</strong></a> ophalen</li>
-<li>Schrijf de <a href="http://www.netsurf-browser.org/contact/"><strong>ontwikkelaars</strong> </a> (Engels)</li>
+<li><a href="https://www.netsurf-browser.org/"><strong>NetSurf-website</strong> </a> (Engels)</li>
+<li><a href="https://www.netsurf-browser.org/documentation/">Engelstalige documentatie</a></li>
+<li>Nieuwste <a href="https://www.netsurf-browser.org/downloads/"><strong>NetSurf-versie</strong></a> ophalen</li>
+<li>Schrijf de <a href="https://www.netsurf-browser.org/contact/"><strong>ontwikkelaars</strong> </a> (Engels)</li>
<li>Schrijf de <a href="mailto:g.vankatwijk@freeler.nl">vertalers</a>
</ul>
diff --git a/!NetSurf/Resources/Quirks,f79 b/resources/quirks.css
index 2f0f9f369..2f0f9f369 100644
--- a/!NetSurf/Resources/Quirks,f79
+++ b/resources/quirks.css
diff --git a/test/Makefile b/test/Makefile
index d5e9d0033..4f9dd22c9 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -10,29 +10,35 @@ TESTS := \
urlescape \
utils \
messages \
- time #llcache
+ time \
+ mimesniff \
+ corestrings #llcache
+
+# sources necessary to use nsurl functionality
+NSURL_SOURCES := utils/nsurl/nsurl.c utils/nsurl/parse.c utils/idna.c \
+ utils/punycode.c
# nsurl sources
-nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
- test/log.c test/nsurl.c
+nsurl_SRCS := $(NSURL_SOURCES) utils/corestrings.c test/log.c test/nsurl.c
# url database test sources
-urldbtest_SRCS := content/urldb.c \
- utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
- utils/corestrings.c utils/punycode.c \
- utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
- test/log.c test/urldbtest.c
+urldbtest_SRCS := $(NSURL_SOURCES) \
+ utils/bloom.c utils/nsoption.c utils/corestrings.c utils/time.c \
+ utils/hashtable.c utils/messages.c utils/utils.c \
+ utils/http/primitives.c utils/http/generics.c \
+ utils/http/strict-transport-security.c \
+ content/urldb.c \
+ test/log.c test/urldbtest.c
# low level cache sources
llcache_SRCS := content/fetch.c content/fetchers/curl.c \
- content/fetchers/about.c content/fetchers/data.c \
- content/fetchers/resource.c content/llcache.c \
- content/urldb.c \
- image/image_cache.c \
- utils/base64.c utils/corestrings.c utils/hashtable.c \
- utils/nsurl.c utils/messages.c utils/url.c utils/useragent.c \
- utils/utils.c \
- test/log.c test/llcache.c
+ content/fetchers/about.c content/fetchers/data.c \
+ content/fetchers/resource.c content/llcache.c \
+ content/urldb.c \
+ image/image_cache.c \
+ $(NSURL_SOURCES) utils/base64.c utils/corestrings.c utils/hashtable.c \
+ utils/messages.c utils/url.c utils/useragent.c utils/utils.c \
+ test/log.c test/llcache.c
# messages test sources
messages_SRCS := utils/messages.c utils/hashtable.c test/log.c test/messages.c
@@ -50,13 +56,26 @@ hashtable_SRCS := utils/hashtable.c test/log.c test/hashtable.c
urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
-utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
- test/log.c test/utils.c
+utils_SRCS := $(NSURL_SOURCES) utils/utils.c utils/messages.c \
+ utils/hashtable.c utils/corestrings.c \
+ test/log.c test/utils.c
# time test sources
time_SRCS := utils/time.c test/log.c test/time.c
+# mimesniff test sources
+mimesniff_SRCS := $(NSURL_SOURCES) utils/hashtable.c utils/corestrings.c \
+ utils/http/generics.c utils/http/content-type.c \
+ utils/http/primitives.c utils/messages.c utils/http/parameter.c \
+ content/mimesniff.c \
+ test/log.c test/mimesniff.c
+
+# corestrings test sources
+corestrings_SRCS := $(NSURL_SOURCES) utils/corestrings.c \
+ test/log.c test/corestrings.c
+corestrings_LD := -lmalloc_fig
+
+
# Coverage builds need additional flags
COV_ROOT := build/$(HOST)-coverage
ifeq ($(MAKECMDGOALS),coverage)
@@ -64,10 +83,19 @@ ifeq ($(MAKECMDGOALS),coverage)
COV_CXXFLAGS ?= -fprofile-arcs -ftest-coverage -O0
COV_LDFLAGS ?= -lgcov -fprofile-arcs
TESTROOT := $(COV_ROOT)
+ ifeq ($(NOASSERTCOVERAGE),yes)
+ NOCOV_TESTSOURCES ?=
+ COV_CPPFLAGS ?=
+ else
+ NOCOV_TESTSOURCES ?= test/assert.c
+ COV_CPPFLAGS ?= -D__assert_fail=__ns_assert_fail
+ endif
else
COV_CFLAGS ?= -O0
COV_CXXFLAGS ?= -O0
+ COV_CPPFLAGS ?=
TESTROOT := build/$(HOST)-test
+ NOCOV_TESTSOURCES ?=
endif
@@ -106,21 +134,29 @@ ifneq ($(CC_MAJOR),2)
COMMON_WARNFLAGS += -Wno-unused-parameter
endif
-TESTCFLAGS := -std=c99 -g \
- $(COMMON_WARNFLAGS) \
- -D_BSD_SOURCE \
- -D_POSIX_C_SOURCE=200809L \
- -D_XOPEN_SOURCE=600 \
- -Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
- -Dnsgtk \
- $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
- $(LIB_CFLAGS) \
- $(COV_CFLAGS)
-
-TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) -lz \
- $(LIB_LDFLAGS)\
- $(COV_LDFLAGS)
-
+BASE_TESTCFLAGS := -std=c99 -g \
+ $(COMMON_WARNFLAGS) \
+ -D_DEFAULT_SOURCE \
+ -D_POSIX_C_SOURCE=200809L \
+ -D_XOPEN_SOURCE=600 \
+ -Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
+ -Dnsgtk \
+ $(SAN_FLAGS) \
+ $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
+ $(LIB_CFLAGS)
+TESTCFLAGS := $(BASE_TESTCFLAGS) \
+ $(COV_CFLAGS) \
+ $(COV_CPPFLAGS)
+
+TESTLDFLAGS := -L$(TESTROOT) \
+ $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) -lz \
+ $(SAN_FLAGS) \
+ $(LIB_LDFLAGS)\
+ $(COV_LDFLAGS)
+
+# malloc faliure injection generator
+$(TESTROOT)/libmalloc_fig.so:test/malloc_fig.c
+ $(CC) -shared -fPIC -I. -std=c99 $(COMMON_WARNFLAGS) $^ -o $@
# Source files for all tests being compiled
TESTSOURCES :=
@@ -128,15 +164,15 @@ TESTSOURCES :=
GCOV ?= gcov
define gen_test_target
-$$(TESTROOT)/$(1): $$(sort $$(addprefix $$(TESTROOT)/,$$(subst /,_,$$(patsubst %.c,%.o,$$(patsubst %.cpp,%.o,$$(patsubst %.m,%.o,$$(patsubst %.s,%.o,$$($(1)_SRCS))))))))
+$$(TESTROOT)/$(1): $$(sort $$(addprefix $$(TESTROOT)/,$$(subst /,_,$$(patsubst %.c,%.o,$$(patsubst %.cpp,%.o,$$(patsubst %.m,%.o,$$(patsubst %.s,%.o,$$($(1)_SRCS) $$(NOCOV_TESTSOURCES))))))))
$$(VQ)echo "LINKTEST: $$@"
- $$(Q)$$(CC) $$(TESTCFLAGS) $$^ -o $$@ $$(TESTLDFLAGS)
+ $$(Q)$$(CC) $$(TESTCFLAGS) $$^ -o $$@ $$($(1)_LD) $$(TESTLDFLAGS)
.PHONY:$(1)_test
$(1)_test:$$(TESTROOT)/$(1)
$$(VQ)echo "RUN TEST: $(1)"
- $$(Q)$$(TESTROOT)/$(1)
+ $$(Q)LD_LIBRARY_PATH=$$(TESTROOT)/ $$(TESTROOT)/$(1)
TESTSOURCES += $$($(1)_SRCS)
@@ -150,19 +186,30 @@ $$(TESTROOT)/$(2): $(1) $$(TESTROOT)/created
endef
+define compile_test_nocov_target_c
+$$(TESTROOT)/$(2): $(1) $$(TESTROOT)/created
+ $$(VQ)echo " COMPILE: $(1) (No coverage)"
+ $$(Q)$$(RM) $$(TESTROOT)/$(2)
+ $$(Q)$$(CC) $$(BASE_TESTCFLAGS) -o $$(TESTROOT)/$(2) -c $(1)
+
+endef
+
# Generate target for each test program and the list of objects it needs
$(eval $(foreach TST,$(TESTS), $(call gen_test_target,$(TST))))
# generate target rules for test objects
$(eval $(foreach SOURCE,$(sort $(filter %.c,$(TESTSOURCES))), \
$(call compile_test_target_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.o)),$(subst /,_,$(SOURCE:.c=.d)))))
+$(eval $(foreach SOURCE,$(sort $(filter %.c,$(NOCOV_TESTSOURCES))), \
+ $(call compile_test_nocov_target_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.o)),$(subst /,_,$(SOURCE:.c=.d)))))
-.PHONY:test coverage
+.PHONY:test coverage sanitize
-test: $(TESTROOT)/created $(addsuffix _test,$(TESTS))
+test: $(TESTROOT)/created $(TESTROOT)/libmalloc_fig.so $(addsuffix _test,$(TESTS))
coverage: test
+sanitize: test
$(TESTROOT)/created:
$(VQ)echo " MKDIR: $(TESTROOT)"
diff --git a/test/assert.c b/test/assert.c
new file mode 100644
index 000000000..d21926e5e
--- /dev/null
+++ b/test/assert.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Hack for assertion coverage output
+ */
+
+/* Bring in the real __assert_fail */
+#include <assert.h>
+
+/* This is what everyone else calls */
+extern void
+__ns_assert_fail(const char *__assertion, const char *__file,
+ unsigned int __line, const char *__function)
+ __THROW __attribute__ ((__noreturn__));
+
+/* We use this to flush coverage data */
+extern void __gcov_flush(void);
+
+/* And here's our entry point */
+void
+__ns_assert_fail(const char *__assertion, const char *__file,
+ unsigned int __line, const char *__function)
+{
+ __gcov_flush();
+ __assert_fail(__assertion, __file, __line, __function);
+}
diff --git a/test/corestrings.c b/test/corestrings.c
new file mode 100644
index 000000000..02640c953
--- /dev/null
+++ b/test/corestrings.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Tests for corestrings.
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+#include <limits.h>
+
+#include "utils/corestrings.h"
+
+#include "test/malloc_fig.h"
+
+/**
+ * The number of corestrings.
+ *
+ * This is used to test all the out of memory paths in initialisation.
+ */
+#define CORESTRING_TEST_COUNT 435
+
+START_TEST(corestrings_test)
+{
+ nserror ires;
+ nserror res;
+
+ malloc_limit(_i);
+
+ ires = corestrings_init();
+ res = corestrings_fini();
+
+ malloc_limit(UINT_MAX);
+
+ ck_assert_int_eq(ires, NSERROR_NOMEM);
+ ck_assert_int_eq(res, NSERROR_OK);
+}
+END_TEST
+
+
+static TCase *corestrings_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("corestrings");
+
+ tcase_add_loop_test(tc, corestrings_test, 0, CORESTRING_TEST_COUNT);
+
+ return tc;
+}
+
+
+/*
+ * corestrings test suite creation
+ */
+static Suite *corestrings_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("Corestrings API");
+
+ suite_add_tcase(s, corestrings_case_create());
+
+ return s;
+}
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(corestrings_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/data/Choices-all b/test/data/Choices-all
index b9cab1fb3..9f2e18377 100644
--- a/test/data/Choices-all
+++ b/test/data/Choices-all
@@ -95,6 +95,8 @@ sys_colour_ThreeDShadow:d5d5d5
sys_colour_Window:f1f1f1
sys_colour_WindowFrame:4e4e4e
sys_colour_WindowText:000000
+log_filter:level:WARNING
+verbose_filter:level:VERBOSE
render_resample:1
downloads_clear:0
request_overwrite:1
diff --git a/test/data/cookies b/test/data/cookies
index 739618e4d..585c1e02c 100644
--- a/test/data/cookies
+++ b/test/data/cookies
@@ -1,4 +1,3 @@
-# >/home/vince/.config/netsurf/Cookies
# NetSurf cookies file.
#
# Lines starting with a '#' are comments, blank lines are ignored.
@@ -8,31 +7,31 @@
# Version Domain Domain from Set-Cookie Path Path from Set-Cookie Secure HTTP-Only Expires Last used No destroy Name Value Value was quoted Scheme URL Comment
Version: 102
0 .theguardian.com 1 / 1 0 0 1476054669 1468278669 0 GU_mvt_id 439080 0 unused unused
-0 .reddit.com 1 / 1 0 1 1499814590 1468278656 0 __cfduid d2c9a13e6ed171f4318aabcf558fcc6661468278590 0 unused unused
-0 www.reddit.com 0 / 1 1 0 1531350591 1468278656 0 loid lLGqu0nblR8T852T20 0 https https://www.reddit.com/
-0 www.reddit.com 0 / 1 1 0 1531350591 1468278656 0 loidcreated 2016-07-11T23%3A09%3A50.925Z 0 https https://www.reddit.com/
-0 .giffgaff.com 1 / 1 0 0 1503402870 1440407964 0 visid_incap_456843 MSQtdY7lSvK9UJiZDP3daK0S2lUAAAAAQUIPAAAAAAAudOMnRSt1V9mQN5dPPA+R 0 unused unused
-0 .google.com 1 / 1 0 0 1497632093 1470493285 0 SID DQAAAMoAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pfmO6LX8ezViJMABtqGPoO8Y8r8-eFRzLlsfbhCqM2OHkDRfoofXJCtIvDMi7Xyzoh6D5PsXbrfFZhcLSlfZpBtP 0 unused unused
-0 .google.com 1 / 1 0 1 1497632093 1470493285 0 HSID A1rFmKHX-G1exnHNv 0 unused unused
-0 .google.com 1 / 1 1 1 1497632093 1470493285 0 SSID A4wVZcYgXrCrwWns8 0 unused unused
-0 .google.com 1 / 1 0 0 1497632093 1470493285 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
-0 .google.com 1 / 1 1 0 1497632093 1470493285 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
-0 accounts.google.com 0 / 1 1 1 1497632093 0 0 GAPS 1:-F43DfTc9MQPBnPFtQw7SBXNDYxGRw:-byarQeQN13vrH8I 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
-0 accounts.google.com 0 / 1 1 1 1497632093 0 0 LSID mail|o.mail.google.com|s.GB|ss:DQAAAMwAAADuReoJNLFTfcVkka4Mpznq77VRSAgK_50UNJQeyKZS6zdAktvmMi42CsHIKCA_qkMe373-3PwvTioyn8OGHoKi8a2tas-mS1US4KPOXsp6GrewaR6bwkvkAudNj5H97wu9p9uek5EMljgPSIcFHyTRDwGghHc918-Z5-QVQMYswD9fA8DObnL4iFPrYJyYsz2MJcYKOMTdgBc9cutZ-zgRVJLVV1IJiluuTeQb5pjfpX4ROfo8kf4M_boTxfuwO19fn_zp5jT9qdPr4jDBM9lM 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
-0 accounts.google.com 0 / 1 1 1 1497632093 0 0 ACCOUNT_CHOOSER AFx_qI5IqJoq6XeRvabQu34G7bErRw0LzimzBZXUqP_9H8Zh2kqTpBc-jooLHKNNCggYdxTq_ENRPogKK0V35Ap5s9N-88xwKmZLX7xXnZ25EBl-8FHjjvfMxKIj2-_xnpyKtWa5fWac 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
-0 mail.google.com 0 / 1 1 1 1497632093 1435272960 0 OSID DQAAANsAAABjm3QWm7iyror5Q-r_twvLnU2MeBpDTpzoY-d-4pEomtilsx1VjIp_SphmVJcv084Ilg4o1COlySeuNAVSkeYn6qPyK93aIKN7MOmQxKvYQXIAlPiBAXD7bVX2HoAQpDXKc1BQZUfL2wLIjCwns0NQVGawofTWf8gve_FAwp6hXF9hXHrZRTU9lgt3N0yBpjElda_UiyNkhUIZP27zSS1LpXh7GaYcUgM69IUrczTnfkfIX_XunEaXBT59fmc49pbFEYlMMURG3ydiPjIhGdN9eHO27V9JhxqhuYUryTM8kg 0 https https://mail.google.com/accounts/SetOSID?continue=https%3A%2F%2Faccounts.google.co.uk%2Faccounts%2FSetSID%3Fssdc%3D1%26sidt%3DALWU2ctR9Uxp0qhL0HVYNURm01UOebegtyVV3GH%252BiVgIY9WIfqGs5NmqjVyX2IzkD0jDdGMV%252BgDLYwi9XrR%252FWsOIdwC4OO803V%252FimpsuKeLB7lk3%252FV10vr4C6wTc20A0I3ep6BLOe%252FQZgYJjfrcjzRiV2zT6fOiYXka1QrtyPIugR3R%252FaSWI%252Fau79w9hvBc%252FqqATVRi7F%252FDHv%252Be3cHMLPNOYoKwwUSOA9ORjKsyc5bCpnWM6X%252BrjsfzEEqlV5iui3EPKbBvTvCnfdF7UJjMg4EfWyMhVZaeytZdvGqJ2DfvPNmm2toULDQd4rcAAkfRZJQ95ySI4fq1ifZkfA0dhr7xnBQ0cl3%252BYTdl0yp%252BXjztO8YivQb%252Feip7gihmjfE9yRXoEboirDW8lIscN6cDDsuxzD07npdjHjRUX2wYrG4V3MLI4luHO52mwY%252BHZMN3O681HumCIBYvX%26continue%3Dhttps%253A%252F%252Fmail.google.com%252Fmail%252F%253Fauth%253DDQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk&osidt=ALWU2cvhIheonCPoG5pecDWKf0i1a-AsQKBMvxay9B54taUbBKAxr9vzwWXg2UJDvM3oYcjYFVDxpERiv9sed5ZQXUKh9UPV5epNA25PUuVZwNDOkePm6agrIhUGR9wVz4x7I6-uU0uF4VHDwS1KDpWZvQY6tMw5vti1qF2bVdLMO_UTLcEW9mdV7Oze8OZXWxFsppfVGSxHN8N1rH8xRMCj3A5QjC-OU5h-pS3N4-AI4A5LwrMj_zvtwS0BW5otNhVmt503yBBXKIIkF5i4gGXiQGVVhCFlBeosv7KbWx97PEPTzeqf59R0ZgY9p1cd_jQWi0gYUmTn
-0 mail.google.com 0 /mail 1 1 1 1497632094 1435272960 0 GX DQAAAMoAAADuReoJNLFTfcVkka4MpznqQGgtWpCWbF9qPINtXVzsE62rPcFtkl_t5MhqS9Ab1zrEmWlZefvaR2bknrPqFsBfVZAtMoThXQxvoQQ7K2A1XTWfEeX09w0dJvN0A8SXsjAEebTY93dZkJr5fMomABLkbizqoRqSkv6sh4x7Ysat6VGX6m6eTg81aiCjuBHzLwlAKx63On5joEI1qYhXvKF1JMc3oEzaETTv9mw-vXHt_J-YYlPQi_nG4jQKoDFJ-XCx1fjVVGlqBsPj5Pf1-SGT 0 https https://mail.google.com/mail/?auth=DQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk
-0 www.ccrexplorers.com 0 / 1 0 0 1499619054 1468082755 0 bb_lastvisit 1468083054 0 http http://www.ccrexplorers.com/forumdisplay.php?f=17
+0 .reddit.com 1 / 1 0 1 2147483647 1468278656 0 __cfduid d2c9a13e6ed171f4318aabcf558fcc6661468278590 0 unused unused
+0 www.reddit.com 0 / 1 1 0 2147483647 1468278656 0 loid lLGqu0nblR8T852T20 0 https https://www.reddit.com/
+0 www.reddit.com 0 / 1 1 0 2147483647 1468278656 0 loidcreated 2016-07-11T23%3A09%3A50.925Z 0 https https://www.reddit.com/
+0 .giffgaff.com 1 / 1 0 0 2147483647 1440407964 0 visid_incap_456843 MSQtdY7lSvK9UJiZDP3daK0S2lUAAAAAQUIPAAAAAAAudOMnRSt1V9mQN5dPPA+R 0 unused unused
+0 .google.com 1 / 1 0 0 2147483647 1470493285 0 SID DQAAAMoAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pfmO6LX8ezViJMABtqGPoO8Y8r8-eFRzLlsfbhCqM2OHkDRfoofXJCtIvDMi7Xyzoh6D5PsXbrfFZhcLSlfZpBtP 0 unused unused
+0 .google.com 1 / 1 0 1 2147483647 1470493285 0 HSID A1rFmKHX-G1exnHNv 0 unused unused
+0 .google.com 1 / 1 1 1 2147483647 1470493285 0 SSID A4wVZcYgXrCrwWns8 0 unused unused
+0 .google.com 1 / 1 0 0 2147483647 1470493285 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
+0 .google.com 1 / 1 1 0 2147483647 1470493285 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 GAPS 1:-F43DfTc9MQPBnPFtQw7SBXNDYxGRw:-byarQeQN13vrH8I 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 LSID mail|o.mail.google.com|s.GB|ss:DQAAAMwAAADuReoJNLFTfcVkka4Mpznq77VRSAgK_50UNJQeyKZS6zdAktvmMi42CsHIKCA_qkMe373-3PwvTioyn8OGHoKi8a2tas-mS1US4KPOXsp6GrewaR6bwkvkAudNj5H97wu9p9uek5EMljgPSIcFHyTRDwGghHc918-Z5-QVQMYswD9fA8DObnL4iFPrYJyYsz2MJcYKOMTdgBc9cutZ-zgRVJLVV1IJiluuTeQb5pjfpX4ROfo8kf4M_boTxfuwO19fn_zp5jT9qdPr4jDBM9lM 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 ACCOUNT_CHOOSER AFx_qI5IqJoq6XeRvabQu34G7bErRw0LzimzBZXUqP_9H8Zh2kqTpBc-jooLHKNNCggYdxTq_ENRPogKK0V35Ap5s9N-88xwKmZLX7xXnZ25EBl-8FHjjvfMxKIj2-_xnpyKtWa5fWac 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 mail.google.com 0 / 1 1 1 2147483647 1435272960 0 OSID DQAAANsAAABjm3QWm7iyror5Q-r_twvLnU2MeBpDTpzoY-d-4pEomtilsx1VjIp_SphmVJcv084Ilg4o1COlySeuNAVSkeYn6qPyK93aIKN7MOmQxKvYQXIAlPiBAXD7bVX2HoAQpDXKc1BQZUfL2wLIjCwns0NQVGawofTWf8gve_FAwp6hXF9hXHrZRTU9lgt3N0yBpjElda_UiyNkhUIZP27zSS1LpXh7GaYcUgM69IUrczTnfkfIX_XunEaXBT59fmc49pbFEYlMMURG3ydiPjIhGdN9eHO27V9JhxqhuYUryTM8kg 0 https https://mail.google.com/accounts/SetOSID?continue=https%3A%2F%2Faccounts.google.co.uk%2Faccounts%2FSetSID%3Fssdc%3D1%26sidt%3DALWU2ctR9Uxp0qhL0HVYNURm01UOebegtyVV3GH%252BiVgIY9WIfqGs5NmqjVyX2IzkD0jDdGMV%252BgDLYwi9XrR%252FWsOIdwC4OO803V%252FimpsuKeLB7lk3%252FV10vr4C6wTc20A0I3ep6BLOe%252FQZgYJjfrcjzRiV2zT6fOiYXka1QrtyPIugR3R%252FaSWI%252Fau79w9hvBc%252FqqATVRi7F%252FDHv%252Be3cHMLPNOYoKwwUSOA9ORjKsyc5bCpnWM6X%252BrjsfzEEqlV5iui3EPKbBvTvCnfdF7UJjMg4EfWyMhVZaeytZdvGqJ2DfvPNmm2toULDQd4rcAAkfRZJQ95ySI4fq1ifZkfA0dhr7xnBQ0cl3%252BYTdl0yp%252BXjztO8YivQb%252Feip7gihmjfE9yRXoEboirDW8lIscN6cDDsuxzD07npdjHjRUX2wYrG4V3MLI4luHO52mwY%252BHZMN3O681HumCIBYvX%26continue%3Dhttps%253A%252F%252Fmail.google.com%252Fmail%252F%253Fauth%253DDQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk&osidt=ALWU2cvhIheonCPoG5pecDWKf0i1a-AsQKBMvxay9B54taUbBKAxr9vzwWXg2UJDvM3oYcjYFVDxpERiv9sed5ZQXUKh9UPV5epNA25PUuVZwNDOkePm6agrIhUGR9wVz4x7I6-uU0uF4VHDwS1KDpWZvQY6tMw5vti1qF2bVdLMO_UTLcEW9mdV7Oze8OZXWxFsppfVGSxHN8N1rH8xRMCj3A5QjC-OU5h-pS3N4-AI4A5LwrMj_zvtwS0BW5otNhVmt503yBBXKIIkF5i4gGXiQGVVhCFlBeosv7KbWx97PEPTzeqf59R0ZgY9p1cd_jQWi0gYUmTn
+0 mail.google.com 0 /mail 1 1 1 2147483647 1435272960 0 GX DQAAAMoAAADuReoJNLFTfcVkka4MpznqQGgtWpCWbF9qPINtXVzsE62rPcFtkl_t5MhqS9Ab1zrEmWlZefvaR2bknrPqFsBfVZAtMoThXQxvoQQ7K2A1XTWfEeX09w0dJvN0A8SXsjAEebTY93dZkJr5fMomABLkbizqoRqSkv6sh4x7Ysat6VGX6m6eTg81aiCjuBHzLwlAKx63On5joEI1qYhXvKF1JMc3oEzaETTv9mw-vXHt_J-YYlPQi_nG4jQKoDFJ-XCx1fjVVGlqBsPj5Pf1-SGT 0 https https://mail.google.com/mail/?auth=DQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk
+0 www.ccrexplorers.com 0 / 1 0 0 2147483647 1468082755 0 bb_lastvisit 1468083054 0 http http://www.ccrexplorers.com/forumdisplay.php?f=17
0 .theregister.co.uk 1 / 1 0 1 1471944077 1468278443 0 __cfduid dbda67dd4386142349a936c252ebac7391440408077 0 unused unused
0 nir.theregister.co.uk 0 / 1 0 0 1470697643 0 0 c 1/front.front.578426ab 0 http http://nir.theregister.co.uk/?g=c&g=sa&s=c/front.front
-0 nir.theregister.co.uk 0 / 1 0 0 1499814443 0 0 sa 1 0 http http://nir.theregister.co.uk/?g=c&g=sa&s=c/front.front
+0 nir.theregister.co.uk 0 / 1 0 0 2147483647 0 0 sa 1 0 http http://nir.theregister.co.uk/?g=c&g=sa&s=c/front.front
0 .regmedia.co.uk 1 / 1 0 1 1471944079 1468278443 0 __cfduid d82e13431caf77499b09ccf54c21999941440408079 0 unused unused
-0 .google.co.uk 1 / 1 0 0 1497632093 1468278489 0 SID DQAAAMkAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pflIfSnKeEn0Y2mEVyhc1qUiGcJhVKqIRd6xaGKk7l235kOpqxjGK7I4_jTQaORZbp2-RWozAg7SHESSaOpxQ0ZT 0 unused unused
-0 .google.co.uk 1 / 1 0 1 1497632093 1468278489 0 HSID ANVWylWAbjjzFxKxI 0 unused unused
-0 .google.co.uk 1 / 1 1 1 1497632093 1468278489 0 SSID ANtGv1CSBG3CWbdtr 0 unused unused
-0 .google.co.uk 1 / 1 0 0 1497632093 1468278489 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
-0 .google.co.uk 1 / 1 1 0 1497632093 1468278489 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
+0 .google.co.uk 1 / 1 0 0 2147483647 1468278489 0 SID DQAAAMkAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pflIfSnKeEn0Y2mEVyhc1qUiGcJhVKqIRd6xaGKk7l235kOpqxjGK7I4_jTQaORZbp2-RWozAg7SHESSaOpxQ0ZT 0 unused unused
+0 .google.co.uk 1 / 1 0 1 2147483647 1468278489 0 HSID ANVWylWAbjjzFxKxI 0 unused unused
+0 .google.co.uk 1 / 1 1 1 2147483647 1468278489 0 SSID ANtGv1CSBG3CWbdtr 0 unused unused
+0 .google.co.uk 1 / 1 0 0 2147483647 1468278489 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
+0 .google.co.uk 1 / 1 1 0 2147483647 1468278489 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
0 .google.co.uk 1 / 1 0 1 1484089690 0 0 NID 81=BGSfpwd63LrhVNUii2KYHfuyCUKzQv2Zg2ik1H_byGynWUgd9_q-kY48oCRapIewLtzMNYtf2KzYBk0_5OoAtNrD-0YSqXDzKalLWfQ8Vxwyywy79YDvAaX_3tprJzjp 0 unused unused
-0 .bbc.co.uk 1 / 1 0 0 1595541997 1470493359 0 BBC-UID 35e7d9a5837b2e9d026d30f521339ac6826814226444c1ee4a2134fef248fe180NetSurf/3.6%20(Linux) 0 unused unused
-0 news.bbc.co.uk 0 / 1 0 0 1500933997 1469574171 0 BBC-UID 25a73995333b5e9d8ea88a16a17c7b8beea45e555eb863e913853a4de2dcbdb80NetSurf%2f3%2e6%20%28Linux%29 0 http http://news.bbc.co.uk/
+0 .bbc.co.uk 1 / 1 0 0 2147483647 1470493359 0 BBC-UID 35e7d9a5837b2e9d026d30f521339ac6826814226444c1ee4a2134fef248fe180NetSurf/3.6%20(Linux) 0 unused unused
+0 news.bbc.co.uk 0 / 1 0 0 2147483647 1469574171 0 BBC-UID 25a73995333b5e9d8ea88a16a17c7b8beea45e555eb863e913853a4de2dcbdb80NetSurf%2f3%2e6%20%28Linux%29 0 http http://news.bbc.co.uk/
0 en.wikipedia.org 0 / 1 1 1 1473249600 1470493303 0 WMF-Last-Access 06-Aug-2016 0 http http://en.wikipedia.org/wiki/Main_Page
diff --git a/test/data/cookies-out b/test/data/cookies-out
new file mode 100644
index 000000000..404419eae
--- /dev/null
+++ b/test/data/cookies-out
@@ -0,0 +1,31 @@
+# NetSurf cookies file.
+#
+# Lines starting with a '#' are comments, blank lines are ignored.
+#
+# All lines prior to "Version: 102" are discarded.
+#
+# Version Domain Domain from Set-Cookie Path Path from Set-Cookie Secure HTTP-Only Expires Last used No destroy Name Value Value was quoted Scheme URL Comment
+Version: 102
+0 www.ccrexplorers.com 0 / 1 0 0 2147483647 1468082755 0 bb_lastvisit 1468083054 0 http http://www.ccrexplorers.com/forumdisplay.php?f=17
+0 .google.com 1 / 1 0 0 2147483647 1470493285 0 SID DQAAAMoAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pfmO6LX8ezViJMABtqGPoO8Y8r8-eFRzLlsfbhCqM2OHkDRfoofXJCtIvDMi7Xyzoh6D5PsXbrfFZhcLSlfZpBtP 0 unused unused
+0 .google.com 1 / 1 0 1 2147483647 1470493285 0 HSID A1rFmKHX-G1exnHNv 0 unused unused
+0 .google.com 1 / 1 1 1 2147483647 1470493285 0 SSID A4wVZcYgXrCrwWns8 0 unused unused
+0 .google.com 1 / 1 0 0 2147483647 1470493285 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
+0 .google.com 1 / 1 1 0 2147483647 1470493285 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
+0 mail.google.com 0 / 1 1 1 2147483647 1435272960 0 OSID DQAAANsAAABjm3QWm7iyror5Q-r_twvLnU2MeBpDTpzoY-d-4pEomtilsx1VjIp_SphmVJcv084Ilg4o1COlySeuNAVSkeYn6qPyK93aIKN7MOmQxKvYQXIAlPiBAXD7bVX2HoAQpDXKc1BQZUfL2wLIjCwns0NQVGawofTWf8gve_FAwp6hXF9hXHrZRTU9lgt3N0yBpjElda_UiyNkhUIZP27zSS1LpXh7GaYcUgM69IUrczTnfkfIX_XunEaXBT59fmc49pbFEYlMMURG3ydiPjIhGdN9eHO27V9JhxqhuYUryTM8kg 0 https https://mail.google.com/accounts/SetOSID?continue=https%3A%2F%2Faccounts.google.co.uk%2Faccounts%2FSetSID%3Fssdc%3D1%26sidt%3DALWU2ctR9Uxp0qhL0HVYNURm01UOebegtyVV3GH%252BiVgIY9WIfqGs5NmqjVyX2IzkD0jDdGMV%252BgDLYwi9XrR%252FWsOIdwC4OO803V%252FimpsuKeLB7lk3%252FV10vr4C6wTc20A0I3ep6BLOe%252FQZgYJjfrcjzRiV2zT6fOiYXka1QrtyPIugR3R%252FaSWI%252Fau79w9hvBc%252FqqATVRi7F%252FDHv%252Be3cHMLPNOYoKwwUSOA9ORjKsyc5bCpnWM6X%252BrjsfzEEqlV5iui3EPKbBvTvCnfdF7UJjMg4EfWyMhVZaeytZdvGqJ2DfvPNmm2toULDQd4rcAAkfRZJQ95ySI4fq1ifZkfA0dhr7xnBQ0cl3%252BYTdl0yp%252BXjztO8YivQb%252Feip7gihmjfE9yRXoEboirDW8lIscN6cDDsuxzD07npdjHjRUX2wYrG4V3MLI4luHO52mwY%252BHZMN3O681HumCIBYvX%26continue%3Dhttps%253A%252F%252Fmail.google.com%252Fmail%252F%253Fauth%253DDQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk&osidt=ALWU2cvhIheonCPoG5pecDWKf0i1a-AsQKBMvxay9B54taUbBKAxr9vzwWXg2UJDvM3oYcjYFVDxpERiv9sed5ZQXUKh9UPV5epNA25PUuVZwNDOkePm6agrIhUGR9wVz4x7I6-uU0uF4VHDwS1KDpWZvQY6tMw5vti1qF2bVdLMO_UTLcEW9mdV7Oze8OZXWxFsppfVGSxHN8N1rH8xRMCj3A5QjC-OU5h-pS3N4-AI4A5LwrMj_zvtwS0BW5otNhVmt503yBBXKIIkF5i4gGXiQGVVhCFlBeosv7KbWx97PEPTzeqf59R0ZgY9p1cd_jQWi0gYUmTn
+0 mail.google.com 0 /mail 1 1 1 2147483647 1435272960 0 GX DQAAAMoAAADuReoJNLFTfcVkka4MpznqQGgtWpCWbF9qPINtXVzsE62rPcFtkl_t5MhqS9Ab1zrEmWlZefvaR2bknrPqFsBfVZAtMoThXQxvoQQ7K2A1XTWfEeX09w0dJvN0A8SXsjAEebTY93dZkJr5fMomABLkbizqoRqSkv6sh4x7Ysat6VGX6m6eTg81aiCjuBHzLwlAKx63On5joEI1qYhXvKF1JMc3oEzaETTv9mw-vXHt_J-YYlPQi_nG4jQKoDFJ-XCx1fjVVGlqBsPj5Pf1-SGT 0 https https://mail.google.com/mail/?auth=DQAAAL8AAABzUu3D7vQTObQbtiQU-X_6NnwgrsDnQe_7yXrUrFrniwP5j04Q9jVgc203CAd7rwHnO0tvXTI8MSlRISJz3tGutyOc_uw5khR4FHviJuyTEuxKJZPUmQXnIWxZf_CQoJXGGaxn1kT0scUyrxiBjTfXllUWBVa5iuEzL2lgbAINKmSlLmyg3BaTFb-l0nmDdqGznAJMDgspYtD8iBTcPnOWpGkHXUVtkE0C6KK_3z1eULl0wEne4aU0LNJhlhUa8Xk
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 GAPS 1:-F43DfTc9MQPBnPFtQw7SBXNDYxGRw:-byarQeQN13vrH8I 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 LSID mail|o.mail.google.com|s.GB|ss:DQAAAMwAAADuReoJNLFTfcVkka4Mpznq77VRSAgK_50UNJQeyKZS6zdAktvmMi42CsHIKCA_qkMe373-3PwvTioyn8OGHoKi8a2tas-mS1US4KPOXsp6GrewaR6bwkvkAudNj5H97wu9p9uek5EMljgPSIcFHyTRDwGghHc918-Z5-QVQMYswD9fA8DObnL4iFPrYJyYsz2MJcYKOMTdgBc9cutZ-zgRVJLVV1IJiluuTeQb5pjfpX4ROfo8kf4M_boTxfuwO19fn_zp5jT9qdPr4jDBM9lM 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 accounts.google.com 0 / 1 1 1 2147483647 0 0 ACCOUNT_CHOOSER AFx_qI5IqJoq6XeRvabQu34G7bErRw0LzimzBZXUqP_9H8Zh2kqTpBc-jooLHKNNCggYdxTq_ENRPogKK0V35Ap5s9N-88xwKmZLX7xXnZ25EBl-8FHjjvfMxKIj2-_xnpyKtWa5fWac 0 https https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2&emr=1&osid=1
+0 .giffgaff.com 1 / 1 0 0 2147483647 1440407964 0 visid_incap_456843 MSQtdY7lSvK9UJiZDP3daK0S2lUAAAAAQUIPAAAAAAAudOMnRSt1V9mQN5dPPA+R 0 unused unused
+0 .reddit.com 1 / 1 0 1 2147483647 1468278656 0 __cfduid d2c9a13e6ed171f4318aabcf558fcc6661468278590 0 unused unused
+0 www.reddit.com 0 / 1 1 0 2147483647 1468278656 0 loid lLGqu0nblR8T852T20 0 https https://www.reddit.com/
+0 www.reddit.com 0 / 1 1 0 2147483647 1468278656 0 loidcreated 2016-07-11T23%3A09%3A50.925Z 0 https https://www.reddit.com/
+0 .google.co.uk 1 / 1 0 0 2147483647 1468278489 0 SID DQAAAMkAAACuniK1mc17JMX-o-sfAVqvl0EWP0kiNpQg4lWeslWBnU_km8BK6Eww-1mC6zvnm7Jiv2vft4BOwWiAOmRzN66pbzxGNxKKGzSz2GNdWrcwvuYyQHkevwrtwmKmZGDKsgLljofq6NyNf0AP5xGXfHj18awhbbnymmv5UaDqypGx7FvptGQSMQkj_1hY6NJ5pflIfSnKeEn0Y2mEVyhc1qUiGcJhVKqIRd6xaGKk7l235kOpqxjGK7I4_jTQaORZbp2-RWozAg7SHESSaOpxQ0ZT 0 unused unused
+0 .google.co.uk 1 / 1 0 1 2147483647 1468278489 0 HSID ANVWylWAbjjzFxKxI 0 unused unused
+0 .google.co.uk 1 / 1 1 1 2147483647 1468278489 0 SSID ANtGv1CSBG3CWbdtr 0 unused unused
+0 .google.co.uk 1 / 1 0 0 2147483647 1468278489 0 APISID IeJTJt20VmceF7bS/AACvc5cSFPpX8FJMj 0 unused unused
+0 .google.co.uk 1 / 1 1 0 2147483647 1468278489 0 SAPISID baCIIjpj-o3XQCkH/A-WEZgPvnNnguijDQ 0 unused unused
+0 nir.theregister.co.uk 0 / 1 0 0 2147483647 0 0 sa 1 0 http http://nir.theregister.co.uk/?g=c&g=sa&s=c/front.front
+0 .bbc.co.uk 1 / 1 0 0 2147483647 1470493359 0 BBC-UID 35e7d9a5837b2e9d026d30f521339ac6826814226444c1ee4a2134fef248fe180NetSurf/3.6%20(Linux) 0 unused unused
+0 news.bbc.co.uk 0 / 1 0 0 2147483647 1469574171 0 BBC-UID 25a73995333b5e9d8ea88a16a17c7b8beea45e555eb863e913853a4de2dcbdb80NetSurf%2f3%2e6%20%28Linux%29 0 http http://news.bbc.co.uk/
diff --git a/test/data/urldb b/test/data/urldb
index 62e0da805..41c1a08de 100644
--- a/test/data/urldb
+++ b/test/data/urldb
@@ -5,7 +5,7 @@ http
/wiki/Main_Page
1
-1470493303
+1000000000
0
@@ -13,7 +13,7 @@ https
/wiki/Main_Page
1
-1470493304
+2100000000
1
Wikipedia, the free encyclopedia
@@ -43,7 +43,7 @@ http
/
2
-1469961837
+2100000000
0
@@ -51,7 +51,7 @@ https
/
3
-1470350373
+2100000000
1
Slashdot: News for nerds, stuff that matters
@@ -61,7 +61,7 @@ http
/news/science_and_environment
1
-1470493359
+2100000000
1
Science & Environment - BBC News
diff --git a/test/data/urldb-out b/test/data/urldb-out
new file mode 100644
index 000000000..11f400e02
--- /dev/null
+++ b/test/data/urldb-out
@@ -0,0 +1,39 @@
+107
+en.wikipedia.org 0 0
+1
+https
+
+/wiki/Main_Page
+1
+2100000000
+1
+
+Wikipedia, the free encyclopedia
+slashdot.org 0 0
+2
+http
+
+/
+2
+2100000000
+0
+
+
+https
+
+/
+3
+2100000000
+1
+
+Slashdot: News for nerds, stuff that matters
+www.bbc.co.uk 0 0
+1
+http
+
+/news/science_and_environment
+1
+2100000000
+1
+
+Science & Environment - BBC News
diff --git a/test/hashtable.c b/test/hashtable.c
index 11c58c625..ea74b78b2 100644
--- a/test/hashtable.c
+++ b/test/hashtable.c
@@ -25,11 +25,13 @@
*/
#include <assert.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <check.h>
+#include "utils/errors.h"
#include "utils/hashtable.h"
/* Limit for hash table tests which use /usr/share/dict/words */
diff --git a/test/log.c b/test/log.c
index 90b4379e9..fc6b6285c 100644
--- a/test/log.c
+++ b/test/log.c
@@ -42,13 +42,15 @@ void nslog_log(const char *file, const char *func, int ln, const char *format, .
{
va_list ap;
- fprintf(stderr, "%s:%i %s: ", file, ln, func);
+ if (verbose_log) {
+ fprintf(stderr, "%s:%i %s: ", file, ln, func);
- va_start(ap, format);
+ va_start(ap, format);
- vfprintf(stderr, format, ap);
+ vfprintf(stderr, format, ap);
- va_end(ap);
+ va_end(ap);
- fputc('\n', stderr);
+ fputc('\n', stderr);
+ }
}
diff --git a/test/malloc_fig.c b/test/malloc_fig.c
new file mode 100644
index 000000000..19ff91e76
--- /dev/null
+++ b/test/malloc_fig.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * heap fault injection generation.
+ *
+ * This library inject allocation faults into NetSurf tests
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <dlfcn.h>
+
+#include "test/malloc_fig.h"
+
+static unsigned int count = UINT_MAX;
+
+void malloc_limit(unsigned int newcount)
+{
+ count = newcount;
+ //fprintf(stderr, "malloc_limit %d\n", count);
+}
+
+void* malloc(size_t size)
+{
+ static void* (*real_malloc)(size_t) = NULL;
+ void *p = NULL;
+
+ if (real_malloc == NULL) {
+ real_malloc = dlsym(RTLD_NEXT, "malloc");
+ }
+
+ if (count > 0) {
+ p = real_malloc(size);
+ count--;
+ }
+ //fprintf(stderr, "malloc(%d) = %p remian:%d\n", size, p, count);
+ return p;
+}
diff --git a/frontends/cocoa/bitmap.h b/test/malloc_fig.h
index 1eeed1767..3871f62a8 100644
--- a/frontends/cocoa/bitmap.h
+++ b/test/malloc_fig.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,13 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef COCOA_BITMAP_H
-#define COCOA_BITMAP_H
+/**
+ * \file
+ *
+ * Interface to heap fault injection generation.
+ *
+ * This library is used to inject allocation faults into NetSurf tests
+ */
-CGImageRef cocoa_get_cgimage( void *bitmap );
+#ifndef NETSURF_TEST_MALLOC_FIG_H
+#define NETSURF_TEST_MALLOC_FIG_H
-void cocoa_bitmap_modified(void *bitmap);
+void malloc_limit(unsigned int count);
-struct gui_bitmap_table *cocoa_bitmap_table;
+void* malloc(size_t size);
#endif
diff --git a/test/messages.c b/test/messages.c
index 050b6d4d3..ae82d1ede 100644
--- a/test/messages.c
+++ b/test/messages.c
@@ -52,7 +52,6 @@ struct message_test_vec_s message_errorcode_test_vec[] = {
{ NSERROR_SAVE_FAILED, "SaveFailed" },
{ NSERROR_CLONE_FAILED, "CloneFailed" },
{ NSERROR_INIT_FAILED, "InitFailed" },
- { NSERROR_MNG_ERROR, "Error converting MNG/PNG/JNG: %i" },
{ NSERROR_BAD_ENCODING, "BadEncoding" },
{ NSERROR_NEED_DATA, "NeedData" },
{ NSERROR_ENCODING_CHANGE, "EncodingChanged" },
@@ -81,6 +80,9 @@ START_TEST(messages_errorcode_test)
/* ensure result data is correct */
ck_assert_str_eq(res_str, tst->res);
+
+ /* cleanup */
+ messages_destroy();
}
END_TEST
@@ -90,6 +92,9 @@ START_TEST(message_inline_load_test)
res = messages_add_from_inline(test_data_Messages,
test_data_Messages_len);
ck_assert_int_eq(res, NSERROR_OK);
+
+ /* cleanup */
+ messages_destroy();
}
END_TEST
@@ -98,9 +103,34 @@ START_TEST(message_file_load_test)
nserror res;
res = messages_add_from_file(test_messages_path);
ck_assert_int_eq(res, NSERROR_OK);
+
+ /* cleanup */
+ messages_destroy();
}
END_TEST
+START_TEST(message_get_buff_test)
+{
+ nserror res;
+ char *buf;
+ res = messages_add_from_inline(test_data_Messages,
+ test_data_Messages_len);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ buf = messages_get_buff("DefinitelyNotAKey");
+ ck_assert_str_eq(buf, "DefinitelyNotAKey");
+ free(buf);
+
+ buf = messages_get_buff("NoMemory");
+ ck_assert_str_eq(buf, "NetSurf is running out of memory. Please free some memory and try again.");
+ free(buf);
+
+ /* cleanup */
+ messages_destroy();
+}
+END_TEST
+
+
static TCase *message_session_case_create(void)
{
TCase *tc;
@@ -110,6 +140,7 @@ static TCase *message_session_case_create(void)
tcase_add_test(tc, message_inline_load_test);
tcase_add_loop_test(tc, messages_errorcode_test,
0, NELEMS(message_errorcode_test_vec));
+ tcase_add_test(tc, message_get_buff_test);
return tc;
}
diff --git a/test/mimesniff.c b/test/mimesniff.c
new file mode 100644
index 000000000..eeb52e29e
--- /dev/null
+++ b/test/mimesniff.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Test mime sniffing
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+
+#include "utils/utils.h"
+#include "utils/corestrings.h"
+#include "content/content_factory.h"
+#include "content/mimesniff.h"
+
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
+
+struct test_mimetype {
+ const uint8_t* data;
+ const size_t len;
+ lwc_string **mime_type;
+ bool safe;
+};
+
+/* helpers */
+
+/**
+ * test implentation of mime type to content type conversion
+ *
+ * in the full implementation this converts a mime type to content
+ * type for content types with handler in the browser. This
+ * implementation provides a minimal version to pretends to support a
+ * couple of image types
+ */
+content_type content_factory_type_from_mime_type(lwc_string *mime_type)
+{
+ content_type type = CONTENT_NONE;
+ bool match;
+
+ if (lwc_string_caseless_isequal(mime_type,
+ corestring_lwc_image_gif,
+ &match) == lwc_error_ok && match) {
+ type = CONTENT_IMAGE;
+ }
+ if (lwc_string_caseless_isequal(mime_type,
+ corestring_lwc_image_jpeg,
+ &match) == lwc_error_ok && match) {
+ type = CONTENT_IMAGE;
+ }
+ return type;
+}
+
+/* Fixtures */
+
+static void corestring_create(void)
+{
+ ck_assert(corestrings_init() == NSERROR_OK);
+}
+
+/**
+ * iterator for any remaining strings in teardown fixture
+ */
+static void netsurf_lwc_iterator(lwc_string *str, void *pw)
+{
+ fprintf(stderr,
+ "[%3u] %.*s",
+ str->refcnt,
+ (int)lwc_string_length(str),
+ lwc_string_data(str));
+}
+
+static void corestring_teardown(void)
+{
+ corestrings_fini();
+
+ lwc_iterate_strings(netsurf_lwc_iterator, NULL);
+}
+
+/* tests */
+
+START_TEST(mimesniff_api_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+
+ /* no header type, no data and sniffing not allowed */
+ err = mimesniff_compute_effective_type(NULL,
+ NULL,
+ 0,
+ false,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_NOT_FOUND);
+
+ /* no header type, no data and sniffing allowed */
+ err = mimesniff_compute_effective_type(NULL,
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_NEED_DATA);
+
+}
+END_TEST
+
+
+static TCase *mimesniff_api_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("mimesniff API");
+
+
+ tcase_add_test(tc, mimesniff_api_test);
+
+ return tc;
+}
+
+
+/* unknown header exact binary type checks in safe context */
+#define SIG(s,m,a) { (const uint8_t *)s, SLEN(s), &corestring_lwc_##m, a }
+static struct test_mimetype match_unknown_exact_tests[] = {
+ SIG("GIF87a", image_gif, true),
+ SIG("GIF89a", image_gif, true),
+ SIG("\x89PNG\r\n\x1a\n", image_png, true),
+ SIG("\xff\xd8\xff", image_jpeg, true),
+ SIG("BM", image_bmp, true),
+ SIG("\x00\x00\x01\x00", image_vnd_microsoft_icon, true),
+ SIG("OggS\x00", application_ogg, true),
+ SIG("\x1a\x45\xdf\xa3", video_webm, true),
+ SIG("Rar \x1a\x07\x00", application_x_rar_compressed, true),
+ SIG("PK\x03\x04", application_zip, true),
+ SIG("\x1f\x8b\x08", application_x_gzip, true),
+ SIG("%!PS-Adobe-", application_postscript, true),
+ SIG("%PDF-", application_pdf, false),
+};
+
+static struct test_mimetype match_unknown_riff_tests[] = {
+ SIG("RIFF WEBPVP", image_webp, true),
+ SIG("RIFF WAVE", audio_wave, true),
+};
+
+static struct test_mimetype match_unknown_bom_tests[] = {
+ SIG("\xfe\xff",text_plain, false),
+ SIG("\xff\xfe", text_plain, false),
+ SIG("\xef\xbb\xbf", text_plain, false),
+};
+
+static struct test_mimetype match_unknown_ws_tests[] = {
+ SIG("<?xml", text_xml, false),
+ SIG("<!DOCTYPE HTML>", text_html, false),
+ SIG("<HTML ", text_html, false),
+ SIG("<HEAD ", text_html, false),
+ SIG("<SCRIPT ", text_html, false),
+ SIG("<IFRAME ", text_html, false),
+ SIG("<H1 ", text_html, false),
+ SIG("<DIV ", text_html, false),
+ SIG("<FONT ", text_html, false),
+ SIG("<TABLE ", text_html, false),
+ SIG("<A ", text_html, false),
+ SIG("<STYLE ", text_html, false),
+ SIG("<TITLE ", text_html, false),
+ SIG("<B ", text_html, false),
+ SIG("<BODY ", text_html, false),
+ SIG("<BR ", text_html, false),
+ SIG("<P ", text_html, false),
+ SIG("<!-- ", text_html, false),
+};
+
+static struct test_mimetype match_unknown_mp4_tests[] = {
+ SIG("\x00\x00\x00\040ftypisom\x00\x00\x02\x00isomiso2avc1mp41", video_mp4, true),
+ SIG("\x00\x00\x00\040ftypmp41\x00\x00\x02\x00isomiso2avc1mp41", video_mp4, true),
+};
+
+static struct test_mimetype match_unknown_bad_mp4_tests[] = {
+ SIG("\x00\x00\x00\044ftypisom\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\037ftypmp41\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\040atypmp41\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\040faypmp41\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\040ftapmp41\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\040ftyamp41\x00\x00\x02\x00isomiso2avc1mp41", application_octet_stream, true),
+ SIG("\x00\x00\x00\040ftypmp31\x00\x00\x02\x00isomiso2avc1mp31", application_octet_stream, true),
+ SIG("\x00\x00\x00\040ftypma41\x00\x00\x02\x00isomiso2avc1ma41", application_octet_stream, true),
+};
+
+static struct test_mimetype match_unknown_txtbin_tests[] = {
+ SIG("a\nb\tc ", text_plain, true),
+ SIG("\x1b\r\f ", text_plain, true),
+ SIG("a\nb\tc \x01", application_octet_stream, true),
+};
+
+#undef SIG
+
+/**
+ * exact unknown tests
+ *
+ * allows return of unsafe type matches
+ */
+START_TEST(mimesniff_match_unknown_exact_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_exact_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * riff test
+ */
+START_TEST(mimesniff_match_unknown_riff_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_riff_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * BOM test
+ */
+START_TEST(mimesniff_match_unknown_bom_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_bom_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * ws test
+ */
+START_TEST(mimesniff_match_unknown_ws_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_ws_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * mp4 test
+ */
+START_TEST(mimesniff_match_unknown_mp4_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_mp4_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * mp4 test
+ */
+START_TEST(mimesniff_match_unknown_bad_mp4_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_bad_mp4_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+/**
+ * unknown header text/binary test
+ */
+START_TEST(mimesniff_match_unknown_txtbin_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &match_unknown_txtbin_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type(NULL,
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+
+static TCase *mimesniff_match_unknown_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("mimesniff");
+
+ tcase_add_unchecked_fixture(tc,
+ corestring_create,
+ corestring_teardown);
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_exact_test,
+ 0, NELEMS(match_unknown_exact_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_riff_test,
+ 0, NELEMS(match_unknown_riff_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_bom_test,
+ 0, NELEMS(match_unknown_bom_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_ws_test,
+ 0, NELEMS(match_unknown_ws_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_mp4_test,
+ 0, NELEMS(match_unknown_mp4_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_bad_mp4_test,
+ 0, NELEMS(match_unknown_bad_mp4_tests));
+
+ tcase_add_loop_test(tc,
+ mimesniff_match_unknown_txtbin_test,
+ 0, NELEMS(match_unknown_txtbin_tests));
+
+ return tc;
+}
+
+
+START_TEST(mimesniff_unparsable_header_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+
+ /* unparsable header type, no data and sniffing not allowed */
+ err = mimesniff_compute_effective_type("badheader",
+ NULL,
+ 0,
+ false,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NOT_FOUND);
+
+ /* unparsable header type, no data and sniffing allowed */
+ err = mimesniff_compute_effective_type("badheader",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NEED_DATA);
+
+}
+END_TEST
+
+
+START_TEST(mimesniff_parsable_header_nosniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* unparsable header type, no data and sniffing not allowed */
+ err = mimesniff_compute_effective_type("text/plain",
+ NULL,
+ 0,
+ false,
+ false,
+ &effective_type);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_text_plain,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+START_TEST(mimesniff_svg_header_sniff_imageonly_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* svg header type, no data and sniffing allowed images only*/
+ err = mimesniff_compute_effective_type("image/svg+xml",
+ NULL,
+ 0,
+ true,
+ true,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_image_svg,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+START_TEST(mimesniff_image_header_sniff_imageonly_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* jpeg header type, no data and sniffing allowed images only */
+ err = mimesniff_compute_effective_type("image/jpeg",
+ NULL,
+ 0,
+ true,
+ true,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NEED_DATA);
+
+ /* svg header type, unsniffable data and sniffing allowed images only */
+ err = mimesniff_compute_effective_type("image/jpeg",
+ (const uint8_t*)"notsniffablejpeg",
+ 12,
+ true,
+ true,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_image_jpeg,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+ /* svg header type, gif data and sniffing allowed images only */
+ err = mimesniff_compute_effective_type("image/jpeg",
+ (const uint8_t*)"GIF87a",
+ 6,
+ true,
+ true,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_image_gif,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+
+}
+END_TEST
+
+START_TEST(mimesniff_text_header_nodata_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* text header type, no data and sniffing allowed */
+ err = mimesniff_compute_effective_type("text/plain",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NEED_DATA);
+
+ /* svg header type, unsniffable data and sniffing allowed images only */
+ err = mimesniff_compute_effective_type("text/plain",
+ (const uint8_t*)"a\nb\tc \x01",
+ 7,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_application_octet_stream,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+}
+END_TEST
+
+#define SIG(s,m,a) { (const uint8_t *)s, SLEN(s), &corestring_lwc_##m, a }
+static struct test_mimetype text_header_tests[] = {
+ SIG("text/plain", text_plain, true),
+ SIG("text/plain; charset=ISO-8859-1", text_plain, true),
+ SIG("text/plain; charset=iso-8859-1", text_plain, true),
+ SIG("text/plain; charset=UTF-8", text_plain, true),
+};
+#undef SIG
+
+START_TEST(mimesniff_text_header_sniff_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &text_header_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+
+ err = mimesniff_compute_effective_type((const char*)tst->data,
+ (const uint8_t*)"text",
+ 4,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_text_plain,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+
+START_TEST(mimesniff_unknown_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* unknown header type, sniffable data and sniffing allowed */
+ err = mimesniff_compute_effective_type("unknown/unknown",
+ match_unknown_riff_tests[0].data,
+ match_unknown_riff_tests[0].len,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *match_unknown_riff_tests[0].mime_type,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+ /* unknown header type, sniffable data and sniffing allowed */
+ err = mimesniff_compute_effective_type("application/unknown",
+ match_unknown_riff_tests[1].data,
+ match_unknown_riff_tests[1].len,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *match_unknown_riff_tests[1].mime_type,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+ /* unknown header type, sniffable data and sniffing allowed */
+ err = mimesniff_compute_effective_type("*/*",
+ match_unknown_riff_tests[0].data,
+ match_unknown_riff_tests[0].len,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *match_unknown_riff_tests[0].mime_type,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+}
+END_TEST
+
+
+START_TEST(mimesniff_plusxml_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ /* unknown header type, sniffable data and sniffing allowed */
+ err = mimesniff_compute_effective_type("image/svg+xml",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_image_svg,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+START_TEST(mimesniff_xml_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type("text/xml",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_text_xml,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+ err = mimesniff_compute_effective_type("application/xml",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_application_xml,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+}
+END_TEST
+
+
+START_TEST(mimesniff_supported_image_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type("image/gif",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NEED_DATA);
+
+ err = mimesniff_compute_effective_type("image/gif",
+ match_unknown_exact_tests[0].data,
+ match_unknown_exact_tests[0].len,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ corestring_lwc_image_gif,
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+}
+END_TEST
+
+
+START_TEST(mimesniff_html_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+
+ err = mimesniff_compute_effective_type("text/html",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_NEED_DATA);
+}
+END_TEST
+
+
+#define SIG(s,m,a) { (const uint8_t *)s, SLEN(s), &corestring_lwc_##m, a }
+static struct test_mimetype text_html_header_tests[] = {
+ SIG("text", text_html, true),
+ SIG("\xef\xbb\xbf\t\n\r <!-- a comment --><!DOCTYPE HTML><?pi?><head>", text_html, true),
+ SIG("\xef\xbb\xbf\t\n\r <!DOCTYPE HTML><?pi?><rss version=\"2.0\">", application_rss_xml, true),
+ SIG("\t\n\r <? pi ?><feed>", application_atom_xml, true),
+ SIG("<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns=\"http://purl.org/rss/1.0\">", application_rss_xml, true),
+ SIG("<rdf:RDF xmlns=\"http://purl.org/rss/1.0\">", text_html, true),
+ SIG("<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">", text_html, true),
+};
+#undef SIG
+
+
+START_TEST(mimesniff_text_html_header_sniff_test)
+{
+ nserror err;
+ const struct test_mimetype *tst = &text_html_header_tests[_i];
+ lwc_string *effective_type;
+ bool match;
+
+ err = mimesniff_compute_effective_type("text/html",
+ tst->data,
+ tst->len,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ *(tst->mime_type),
+ &match) == lwc_error_ok && match);
+ lwc_string_unref(effective_type);
+
+}
+END_TEST
+
+
+START_TEST(mimesniff_text_fancy_header_sniff_test)
+{
+ nserror err;
+ lwc_string *effective_type;
+ lwc_string *text_fancy;
+ bool match;
+
+ ck_assert(lwc_intern_string("text/fancy", SLEN("text/fancy"), &text_fancy) == lwc_error_ok);
+
+ err = mimesniff_compute_effective_type("text/fancy",
+ NULL,
+ 0,
+ true,
+ false,
+ &effective_type);
+ ck_assert_int_eq(err, NSERROR_OK);
+
+ ck_assert(lwc_string_caseless_isequal(effective_type,
+ text_fancy,
+ &match) == lwc_error_ok && match);
+
+ lwc_string_unref(effective_type);
+ lwc_string_unref(text_fancy);
+}
+END_TEST
+
+
+/* test cases with header mime type */
+static TCase *mimesniff_header_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("mimesniff header");
+
+ tcase_add_unchecked_fixture(tc,
+ corestring_create,
+ corestring_teardown);
+
+ tcase_add_test(tc, mimesniff_unparsable_header_test);
+ tcase_add_test(tc, mimesniff_parsable_header_nosniff_test);
+ tcase_add_test(tc, mimesniff_svg_header_sniff_imageonly_test);
+ tcase_add_test(tc, mimesniff_image_header_sniff_imageonly_test);
+ tcase_add_test(tc, mimesniff_text_header_nodata_sniff_test);
+ tcase_add_loop_test(tc,
+ mimesniff_text_header_sniff_test,
+ 0, NELEMS(text_header_tests));
+ tcase_add_test(tc, mimesniff_unknown_header_sniff_test);
+ tcase_add_test(tc, mimesniff_plusxml_header_sniff_test);
+ tcase_add_test(tc, mimesniff_xml_header_sniff_test);
+ tcase_add_test(tc, mimesniff_supported_image_header_sniff_test);
+
+ tcase_add_test(tc, mimesniff_html_header_sniff_test);
+ tcase_add_loop_test(tc,
+ mimesniff_text_html_header_sniff_test,
+ 0, NELEMS(text_html_header_tests));
+
+ tcase_add_test(tc, mimesniff_text_fancy_header_sniff_test);
+
+ return tc;
+}
+
+
+static Suite *mimesniff_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("mime sniffing");
+
+ suite_add_tcase(s, mimesniff_api_case_create());
+ suite_add_tcase(s, mimesniff_match_unknown_case_create());
+ suite_add_tcase(s, mimesniff_header_case_create());
+
+ return s;
+}
+
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(mimesniff_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/nsoption.c b/test/nsoption.c
index 3b75ca750..8f2388a5b 100644
--- a/test/nsoption.c
+++ b/test/nsoption.c
@@ -39,6 +39,20 @@ const char *test_choices_all_path = "test/data/Choices-all";
const char *test_choices_full_path = "test/data/Choices-full";
const char *test_choices_missing_path = "test/data/Choices-missing";
+/* Stubs */
+nserror nslog_set_filter_by_options() { return NSERROR_OK; }
+
+/**
+ * generate test output filenames
+ */
+static char *testnam(char *out)
+{
+ static int count = 0;
+ static char name[64];
+ snprintf(name, 64, "/tmp/nsoptiontest%d", count);
+ count++;
+ return name;
+}
static nserror gui_options_init_defaults(struct nsoption_s *defaults)
{
@@ -160,7 +174,7 @@ START_TEST(nsoption_session_test)
nsoption_set_colour(sys_colour_ActiveBorder, 0x00d0000d);
/* write options out */
- outnam = tmpnam(NULL);
+ outnam = testnam(NULL);
res = nsoption_write(outnam, NULL, NULL);
ck_assert_int_eq(res, NSERROR_OK);
@@ -300,7 +314,7 @@ START_TEST(nsoption_dump_test)
res = nsoption_read(test_choices_path, NULL);
ck_assert_int_eq(res, NSERROR_OK);
- outnam = tmpnam(NULL);
+ outnam = testnam(NULL);
fp = fopen(outnam, "w");
res = nsoption_dump(fp, NULL);
@@ -325,7 +339,7 @@ START_TEST(nsoption_write_test)
res = nsoption_read(test_choices_path, NULL);
ck_assert_int_eq(res, NSERROR_OK);
- outnam = tmpnam(NULL);
+ outnam = testnam(NULL);
res = nsoption_write(outnam, NULL, NULL);
ck_assert_int_eq(res, NSERROR_OK);
diff --git a/test/nsurl.c b/test/nsurl.c
index 04c52345f..ba024291b 100644
--- a/test/nsurl.c
+++ b/test/nsurl.c
@@ -53,6 +53,16 @@ struct test_compare {
bool res;
};
+/* Fixtures */
+
+static void corestring_create(void)
+{
+ ck_assert(corestrings_init() == NSERROR_OK);
+}
+
+/**
+ * iterator for any remaining strings in teardown fixture
+ */
static void netsurf_lwc_iterator(lwc_string *str, void *pw)
{
fprintf(stderr,
@@ -62,6 +72,15 @@ static void netsurf_lwc_iterator(lwc_string *str, void *pw)
lwc_string_data(str));
}
+static void corestring_teardown(void)
+{
+ corestrings_fini();
+
+ lwc_iterate_strings(netsurf_lwc_iterator, NULL);
+}
+
+/* tests */
+
static const char *base_str = "http://a/b/c/d;p?q";
static const struct test_pairs create_tests[] = {
@@ -97,6 +116,8 @@ static const struct test_pairs create_tests[] = {
{ "http://www.ns-b.org:/",
"http://www.ns-b.org/" },
+ { "http://///////////www.ns-b.org:/",
+ "http://www.ns-b.org/" },
{ "http://u@www.ns-b.org:/hello",
"http://u@www.ns-b.org/hello" },
{ "http://u:p@www.ns-b.org:/hello",
@@ -110,11 +131,43 @@ static const struct test_pairs create_tests[] = {
{ "mailto:u@a", "mailto:u@a" },
{ "mailto:@a", "mailto:a" },
+ { "file:///", "file:///" },
+ { "file://", "file:///" },
+ { "file:/", "file:///" },
+ { "file:", "file:///" },
+ { "file:////", "file:////" },
+ { "file://///", "file://///" },
+
+ { "file://localhost/", "file:///" },
+ { "file://foobar/", "file:///" },
+ { "file://foobar", "file:///" },
+ { "file:///foobar", "file:///foobar" },
+ { "file://tlsa@foo/", "file:///" },
+
/* test case insensitivity */
{ "HTTP://a/b", "http://a/b" },
+ { "HTTPS://a/b", "https://a/b" },
{ "ftp://a/b", "ftp://a/b" },
{ "FTP://a/b", "ftp://a/b" },
+ { "MAILTO:foo@bar", "mailto:foo@bar" },
+ { "FILE:///", "file:///" },
+ { "http://HOST/", "http://host/" },
+
+ /* punycode */
+ { "http://a.कॉम/a", "http://a.xn--11b4c3d/a" },
+ { "https://smog.大众汽车/test", "https://smog.xn--3oq18vl8pn36a/test"},
+ /* unnecessary escape */
+ { "http://%7a%7A/", "http://zz/" },
+
+ /* bad escape */
+ { "http://%1g%G0/", "http://%1g%g0/" },
+
+ { " http://www.ns-b.org/", "http://www.ns-b.org/" },
+ { "http://www.ns-b.org/ ", "http://www.ns-b.org/" },
+ { "http://www.ns-b.org ", "http://www.ns-b.org/" },
+ { "http://www.ns-b.org/?q ", "http://www.ns-b.org/?q" },
+ { "http://www.ns-b.org/#f ", "http://www.ns-b.org/#f" },
};
/**
@@ -377,6 +430,9 @@ static const struct test_pairs join_tests[] = {
{ " / ", "http://a/" },
{ " ? ", "http://a/b/c/d;p?" },
{ " h ", "http://a/b/c/h" },
+ { "//foo?", "http://foo/?" },
+ { "//foo#bar", "http://foo/#bar" },
+ { "//foo/", "http://foo/" },
{ "http://<!--#echo var=", "http://<!--/#echo%20var="},
/* [1] Extra slash beyond rfc3986 5.4.1 example, since we're
* testing normalisation in addition to joining */
@@ -583,6 +639,8 @@ START_TEST(nsurl_compare_test)
END_TEST
+/* component test case */
+
/**
* url component tests
*
@@ -591,18 +649,27 @@ END_TEST
* result is checked against test1 and res as approprite.
*/
static const struct test_compare component_tests[] = {
- { "http://a/b/c/d;p?q",
- "http",
- NSURL_SCHEME,
- true },
-
- { "file:///",
- NULL,
- NSURL_HOST,
- false },
+ { "http://u:p@a:66/b/c/d;p?q#f", "http", NSURL_SCHEME, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "u", NSURL_USERNAME, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "p", NSURL_PASSWORD, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "a", NSURL_HOST, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "66", NSURL_PORT, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "/b/c/d;p", NSURL_PATH, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "?q", NSURL_QUERY, true },
+ { "http://u:p@a:66/b/c/d;p?q#f", "f", NSURL_FRAGMENT, true },
+
+ { "file:", "file", NSURL_SCHEME, true },
+ { "file:", NULL, NSURL_USERNAME, false },
+ { "file:", NULL, NSURL_PASSWORD, false },
+ { "file:", NULL, NSURL_HOST, false },
+ { "file:", NULL, NSURL_PORT, false },
+ { "file:", "/", NSURL_PATH, true },
+ { "file:", NULL, NSURL_QUERY, false },
+ { "file:", NULL, NSURL_FRAGMENT, false },
};
+
/**
* get component
*/
@@ -629,6 +696,7 @@ START_TEST(nsurl_get_component_test)
}
END_TEST
+
/**
* has component
*/
@@ -650,6 +718,30 @@ START_TEST(nsurl_has_component_test)
}
END_TEST
+
+/**
+ * test case for componnet get and has API
+ */
+static TCase *nsurl_component_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Component");
+
+ tcase_add_unchecked_fixture(tc,
+ corestring_create,
+ corestring_teardown);
+
+ tcase_add_loop_test(tc,
+ nsurl_get_component_test,
+ 0, NELEMS(component_tests));
+ tcase_add_loop_test(tc,
+ nsurl_has_component_test,
+ 0, NELEMS(component_tests));
+
+ return tc;
+}
+
+
static const struct test_pairs fragment_tests[] = {
{ "http://www.f.org/a/b/c#def", "http://www.f.org/a/b/c" },
};
@@ -728,40 +820,6 @@ START_TEST(nsurl_refragment_test)
}
END_TEST
-static const struct test_pairs parent_tests[] = {
- { "http://www.f.org/a/b/c", "http://www.f.org/a/b/" },
-};
-
-/**
- * generate parent url
- */
-START_TEST(nsurl_parent_test)
-{
- nserror err;
- nsurl *url;
- nsurl *res_url;
- const struct test_pairs *tst = &parent_tests[_i];
-
- /* not testing create, this should always succeed */
- err = nsurl_create(tst->test, &url);
- ck_assert(err == NSERROR_OK);
-
- err = nsurl_parent(url, &res_url);
- if (tst->res == NULL) {
- /* result must be invalid (bad input) */
- ck_assert(err != NSERROR_OK);
- } else {
- /* result must be valid */
- ck_assert(err == NSERROR_OK);
-
- ck_assert_str_eq(nsurl_access(res_url), tst->res);
-
- nsurl_unref(res_url);
- }
- nsurl_unref(url);
-
-}
-END_TEST
/**
@@ -1136,6 +1194,7 @@ START_TEST(nsurl_api_assert_nice_test)
}
END_TEST
+
/**
* check parent asserts on NULL parameter
*/
@@ -1150,22 +1209,133 @@ START_TEST(nsurl_api_assert_parent_test)
END_TEST
-/* Fixtures */
-static void corestring_create(void)
+
+/* parent test case */
+
+static const struct test_pairs parent_tests[] = {
+ { "http://www.f.org/a/b/c", "http://www.f.org/a/b/" },
+ { "https://www.moo.org/", "https://www.moo.org/" },
+ { "https://www.moo.org/asinglepathelementthatsquitelong/", "https://www.moo.org/" },
+ { "https://user:pw@www.moo.org/a/b#x?a=b", "https://user:pw@www.moo.org/a/" },
+};
+
+/**
+ * generate parent url
+ */
+START_TEST(nsurl_parent_test)
{
- ck_assert(corestrings_init() == NSERROR_OK);
+ nserror err;
+ nsurl *url;
+ nsurl *res_url;
+ const struct test_pairs *tst = &parent_tests[_i];
+
+ /* not testing create, this should always succeed */
+ err = nsurl_create(tst->test, &url);
+ ck_assert(err == NSERROR_OK);
+
+ err = nsurl_parent(url, &res_url);
+ if (tst->res == NULL) {
+ /* result must be invalid (bad input) */
+ ck_assert(err != NSERROR_OK);
+ } else {
+ /* result must be valid */
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(nsurl_access(res_url), tst->res);
+
+ nsurl_unref(res_url);
+ }
+ nsurl_unref(url);
+
}
+END_TEST
-static void corestring_teardown(void)
+
+/**
+ * test case for parent API
+ */
+static TCase *nsurl_parent_case_create(void)
{
- corestrings_fini();
+ TCase *tc;
+ tc = tcase_create("Parent");
- lwc_iterate_strings(netsurf_lwc_iterator, NULL);
+ tcase_add_unchecked_fixture(tc,
+ corestring_create,
+ corestring_teardown);
+
+ tcase_add_loop_test(tc,
+ nsurl_parent_test,
+ 0, NELEMS(parent_tests));
+
+ return tc;
}
-/* suite generation */
+/* utf8 test case */
+
+/**
+ * utf8 tests
+ */
+static const struct test_pairs utf8_tests[] = {
+ { "http://a.xn--11b4c3d/a", "http://a.कॉम/a" },
+ { "https://smog.xn--3oq18vl8pn36a/test", "https://smog.大众汽车/test"},
+
+};
+
+
+/**
+ * get utf8 test
+ */
+START_TEST(nsurl_get_utf8_test)
+{
+ nserror err;
+ nsurl *url;
+ const struct test_pairs *tst = &utf8_tests[_i];
+ char *utf8out;
+ size_t utf8out_len;
+
+ /* not testing create, this should always succeed */
+ err = nsurl_create(tst->test, &url);
+ ck_assert(err == NSERROR_OK);
+
+ err = nsurl_get_utf8(url, &utf8out, &utf8out_len);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(utf8out, tst->res);
+
+ free(utf8out);
+
+ nsurl_unref(url);
+}
+END_TEST
+
+
+/**
+ * test case for utf8 output
+ */
+static TCase *nsurl_utf8_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("UTF-8 output");
+
+ tcase_add_unchecked_fixture(tc,
+ corestring_create,
+ corestring_teardown);
+
+ tcase_add_loop_test(tc,
+ nsurl_get_utf8_test,
+ 0, NELEMS(utf8_tests));
+
+ return tc;
+}
+
+
+/* test suite */
+
+/**
+ * nsurl suite generation
+ */
static Suite *nsurl_suite(void)
{
Suite *s;
@@ -1178,8 +1348,6 @@ static Suite *nsurl_suite(void)
TCase *tc_join;
TCase *tc_compare;
TCase *tc_fragment;
- TCase *tc_component;
- TCase *tc_parent;
s = suite_create("nsurl");
@@ -1348,47 +1516,29 @@ static Suite *nsurl_suite(void)
tcase_add_loop_test(tc_fragment,
nsurl_defragment_test,
- 0, NELEMS(parent_tests));
+ 0, NELEMS(fragment_tests));
tcase_add_loop_test(tc_fragment,
nsurl_refragment_test,
- 0, NELEMS(parent_tests));
+ 0, NELEMS(fragment_tests));
suite_add_tcase(s, tc_fragment);
/* component */
- tc_component = tcase_create("Component");
-
- tcase_add_unchecked_fixture(tc_component,
- corestring_create,
- corestring_teardown);
-
- tcase_add_loop_test(tc_component,
- nsurl_get_component_test,
- 0, NELEMS(component_tests));
- tcase_add_loop_test(tc_component,
- nsurl_has_component_test,
- 0, NELEMS(component_tests));
-
- suite_add_tcase(s, tc_component);
+ suite_add_tcase(s, nsurl_component_case_create());
/* parent */
- tc_parent = tcase_create("Parent");
+ suite_add_tcase(s, nsurl_parent_case_create());
- tcase_add_unchecked_fixture(tc_parent,
- corestring_create,
- corestring_teardown);
+ /* UTF-8 output */
+ suite_add_tcase(s, nsurl_utf8_case_create());
- tcase_add_loop_test(tc_parent,
- nsurl_parent_test,
- 0, NELEMS(parent_tests));
-
- suite_add_tcase(s, tc_parent);
return s;
}
+
int main(int argc, char **argv)
{
int number_failed;
diff --git a/test/urldbtest.c b/test/urldbtest.c
index bc707edfb..1c76de1ee 100644
--- a/test/urldbtest.c
+++ b/test/urldbtest.c
@@ -43,13 +43,94 @@
#include "desktop/gui_internal.h"
#include "desktop/cookie_manager.h"
+/**
+ * url database used as input to test sets
+ */
const char *test_urldb_path = "test/data/urldb";
+/**
+ * url database used as output reference
+ */
+const char *test_urldb_out_path = "test/data/urldb-out";
+
+/**
+ * cookie database used as input
+ */
const char *test_cookies_path = "test/data/cookies";
+/**
+ * cookie database used as output reference
+ */
+const char *test_cookies_out_path = "test/data/cookies-out";
const char *wikipedia_url = "http://www.wikipedia.org/";
struct netsurf_table *guit = NULL;
+
+struct test_urls {
+ const char* url;
+ const char* title;
+ const content_type type;
+ const bool persistent;
+};
+
+
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
+
+
+/* Stubs */
+nserror nslog_set_filter_by_options() { return NSERROR_OK; }
+
+/**
+ * generate test output filenames
+ */
+static char *testnam(char *out)
+{
+ static int count = 0;
+ static char name[64];
+ snprintf(name, 64, "/tmp/urldbtest%d-%d", getpid(), count);
+ count++;
+ return name;
+}
+
+/**
+ * compare two files contents
+ */
+static int cmp(const char *f1, const char *f2)
+{
+ int res = 0;
+ FILE *fp1;
+ FILE *fp2;
+ int ch1;
+ int ch2;
+
+ fp1 = fopen(f1, "r");
+ if (fp1 == NULL) {
+ return -1;
+ }
+ fp2 = fopen(f2, "r");
+ if (fp2 == NULL) {
+ fclose(fp1);
+ return -1;
+ }
+
+ while (res == 0) {
+ ch1 = fgetc(fp1);
+ ch2 = fgetc(fp2);
+
+ if (ch1 != ch2) {
+ res = 1;
+ }
+
+ if (ch1 == EOF) {
+ break;
+ }
+ }
+
+ fclose(fp1);
+ fclose(fp2);
+ return res;
+}
+
/*************** original test helpers ************/
bool cookie_manager_add(const struct cookie_data *data)
@@ -65,33 +146,12 @@ static nsurl *make_url(const char *url)
{
nsurl *nsurl;
if (nsurl_create(url, &nsurl) != NSERROR_OK) {
- LOG("failed creating nsurl");
+ NSLOG(netsurf, INFO, "failed creating nsurl");
exit(1);
}
return nsurl;
}
-static char *make_path_query(nsurl *url)
-{
- size_t len;
- char *path_query;
- if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &path_query, &len) !=
- NSERROR_OK) {
- LOG("failed creating path_query");
- exit(1);
- }
- return path_query;
-}
-
-static lwc_string *make_lwc(const char *str)
-{
- lwc_string *lwc;
- if (lwc_intern_string(str, strlen(str), &lwc) != lwc_error_ok) {
- LOG("failed creating lwc_string");
- exit(1);
- }
- return lwc;
-}
static bool test_urldb_set_cookie(const char *header, const char *url,
const char *referer)
@@ -172,9 +232,8 @@ static void urldb_lwc_iterator(lwc_string *str, void *pw)
{
int *scount = pw;
- LOG("[%3u] %.*s", str->refcnt,
- (int)lwc_string_length(str),
- lwc_string_data(str));
+ NSLOG(netsurf, INFO, "[%3u] %.*s", str->refcnt,
+ (int)lwc_string_length(str), lwc_string_data(str));
(*scount)++;
}
@@ -188,7 +247,7 @@ static void urldb_teardown(void)
corestrings_fini();
- LOG("Remaining lwc strings:");
+ NSLOG(netsurf, INFO, "Remaining lwc strings:");
lwc_iterate_strings(urldb_lwc_iterator, &scount);
ck_assert_int_eq(scount, 0);
}
@@ -199,67 +258,28 @@ static void urldb_teardown(void)
START_TEST(urldb_original_test)
{
- struct host_part *h;
- struct path_data *p;
- const struct url_data *u;
- lwc_string *scheme;
- lwc_string *fragment;
nsurl *url;
nsurl *urlr;
- char *path_query;
-
- h = urldb_add_host("127.0.0.1");
- ck_assert_msg(h != NULL, "failed adding host");
-
- h = urldb_add_host("intranet");
- ck_assert_msg(h != NULL, "failed adding host");
-
- url = make_url("http://intranet/");
- scheme = nsurl_get_component(url, NSURL_SCHEME);
- p = urldb_add_path(scheme, 0, h, strdup("/"), NULL, url);
- ck_assert_msg(p != NULL, "failed adding path");
- lwc_string_unref(scheme);
-
- urldb_set_url_title(url, "foo");
-
- u = urldb_get_url_data(url);
- assert(u && strcmp(u->title, "foo") == 0);
- nsurl_unref(url);
-
- /* Get host entry */
- h = urldb_add_host("netsurf.strcprstskrzkrk.co.uk");
- ck_assert_msg(h != NULL, "failed adding host");
-
- /* Get path entry */
+ /* fragments */
url = make_url("http://netsurf.strcprstskrzkrk.co.uk/path/to/resource.htm?a=b");
- scheme = nsurl_get_component(url, NSURL_SCHEME);
- path_query = make_path_query(url);
- fragment = make_lwc("zz");
- p = urldb_add_path(scheme, 0, h, strdup(path_query), fragment, url);
- ck_assert_msg(p != NULL, "failed adding path");
-
- lwc_string_unref(fragment);
-
- fragment = make_lwc("aa");
- p = urldb_add_path(scheme, 0, h, strdup(path_query), fragment, url);
- ck_assert_msg(p != NULL, "failed adding path");
-
- lwc_string_unref(fragment);
+ ck_assert(urldb_add_url(url) == true);
+ nsurl_unref(url);
- fragment = make_lwc("yy");
- p = urldb_add_path(scheme, 0, h, strdup(path_query), fragment, url);
- ck_assert_msg(p != NULL, "failed adding path");
+ url = make_url("http://netsurf.strcprstskrzkrk.co.uk/path/to/resource.htm#zz?a=b");
+ ck_assert(urldb_add_url(url) == true);
+ nsurl_unref(url);
- free(path_query);
- lwc_string_unref(fragment);
- lwc_string_unref(scheme);
+ url = make_url("http://netsurf.strcprstskrzkrk.co.uk/path/to/resource.htm#aa?a=b");
+ ck_assert(urldb_add_url(url) == true);
nsurl_unref(url);
- url = make_url("file:///home/");
- urldb_add_url(url);
+ url = make_url("http://netsurf.strcprstskrzkrk.co.uk/path/to/resource.htm#yy?a=b");
+ ck_assert(urldb_add_url(url) == true);
nsurl_unref(url);
+
+ /* set cookies on urls */
url = make_url("http://www.minimarcos.org.uk/cgi-bin/forum/Blah.pl?,v=login,p=2");
urldb_set_cookie("mmblah=foo; path=/; expires=Thur, 31-Dec-2099 00:00:00 GMT\r\n", url, NULL);
nsurl_unref(url);
@@ -292,37 +312,6 @@ START_TEST(urldb_original_test)
urldb_get_cookie(url, true);
nsurl_unref(url);
- /* Mantis bug #993 */
- url = make_url("http:moodle.org");
- ck_assert(urldb_add_url(url) == true);
- ck_assert(urldb_get_url(url) != NULL);
- nsurl_unref(url);
-
- /* Mantis bug #993 */
- url = make_url("http://a_a/");
- ck_assert(urldb_add_url(url));
- ck_assert(urldb_get_url(url));
- nsurl_unref(url);
-
- /* Mantis bug #996 */
- url = make_url("http://foo@moose.com/");
- if (urldb_add_url(url)) {
- LOG("added %s", nsurl_access(url));
- ck_assert(urldb_get_url(url) != NULL);
- }
- nsurl_unref(url);
-
- /* Mantis bug #913 */
- url = make_url("http://www2.2checkout.com/");
- ck_assert(urldb_add_url(url));
- ck_assert(urldb_get_url(url));
- nsurl_unref(url);
-
- /* Numeric subdomains */
- url = make_url("http://2.bp.blogspot.com/_448y6kVhntg/TSekubcLJ7I/AAAAAAAAHJE/yZTsV5xT5t4/s1600/covers.jpg");
- ck_assert(urldb_add_url(url));
- ck_assert(urldb_get_url(url));
- nsurl_unref(url);
/* Valid path */
ck_assert(test_urldb_set_cookie("name=value;Path=/\r\n", "http://www.google.com/", NULL));
@@ -332,16 +321,16 @@ START_TEST(urldb_original_test)
/* Defaulted path */
ck_assert(test_urldb_set_cookie("name=value\r\n", "http://www.example.org/foo/bar/baz/bat.html", NULL));
- ck_assert(test_urldb_get_cookie("http://www.example.org/foo/bar/baz/quux.htm"));
+ ck_assert(test_urldb_get_cookie("http://www.example.org/foo/bar/baz/quux.htm") != NULL);
/* Defaulted path with no non-leaf path segments */
ck_assert(test_urldb_set_cookie("name=value\r\n", "http://no-non-leaf.example.org/index.html", NULL));
- ck_assert(test_urldb_get_cookie("http://no-non-leaf.example.org/page2.html"));
- ck_assert(test_urldb_get_cookie("http://no-non-leaf.example.org/"));
+ ck_assert(test_urldb_get_cookie("http://no-non-leaf.example.org/page2.html") != NULL);
+ ck_assert(test_urldb_get_cookie("http://no-non-leaf.example.org/") != NULL);
/* Valid path (includes leafname) */
ck_assert(test_urldb_set_cookie("name=value;Version=1;Path=/index.cgi\r\n", "http://example.org/index.cgi", NULL));
- ck_assert(test_urldb_get_cookie("http://example.org/index.cgi"));
+ ck_assert(test_urldb_get_cookie("http://example.org/index.cgi") != NULL);
/* Valid path (includes leafname in non-root directory) */
ck_assert(test_urldb_set_cookie("name=value;Path=/foo/index.html\r\n", "http://www.example.org/foo/index.html", NULL));
@@ -401,6 +390,12 @@ START_TEST(urldb_original_test)
}
END_TEST
+/**
+ * test case comprised of tests historicaly found in netsurf
+ *
+ * These tests are carried forward from original open coded tests
+ * found in the url database code.
+ */
static TCase *urldb_original_case_create(void)
{
TCase *tc;
@@ -416,6 +411,172 @@ static TCase *urldb_original_case_create(void)
return tc;
}
+
+/**
+ * add set and get tests
+ */
+static const struct test_urls add_set_get_tests[] = {
+ {
+ "http://intranet/",
+ "foo",
+ CONTENT_HTML,
+ false
+ }, /* from legacy tests */
+ {
+ "http:moodle.org",
+ "buggy",
+ CONTENT_HTML,
+ false
+ }, /* Mantis bug #993 */
+ {
+ "http://a_a/",
+ "buggsy",
+ CONTENT_HTML,
+ false
+ }, /* Mantis bug #993 */
+ {
+ "http://www2.2checkout.com/",
+ "foobar",
+ CONTENT_HTML,
+ false
+ }, /* Mantis bug #913 */
+ {
+ "http://2.bp.blogspot.com/_448y6kVhntg/TSekubcLJ7I/AAAAAAAAHJE/yZTsV5xT5t4/s1600/covers.jpg",
+ "a more complex title",
+ CONTENT_IMAGE,
+ true
+ }, /* Numeric subdomains */
+ {
+ "http://tree.example.com/this_url_has_a_ridiculously_long_path/made_up_from_a_number_of_inoranately_long_elments_some_of_well_over_forty/characters_in_length/the_whole_path_comes_out_well_in_excess_of_two_hundred_characters_in_length/this_is_intended_to_try_and_drive/the_serialisation_code_mad/foo.png",
+ NULL,
+ CONTENT_IMAGE,
+ false
+ },
+ {
+ "https://tree.example.com:8080/example.png",
+ "fishy port ",
+ CONTENT_HTML,
+ false
+ },
+ {
+ "http://tree.example.com/bar.png",
+ "\t ",
+ CONTENT_IMAGE,
+ false
+ }, /* silly title */
+ {
+ "http://[2001:db8:1f70::999:de8:7648:6e8]:100/",
+ "ipv6 with port",
+ CONTENT_TEXTPLAIN,
+ false
+ },
+ {
+ "file:///home/",
+ NULL,
+ CONTENT_HTML,
+ false
+ }, /* no title */
+ {
+ "http://foo@moose.com/",
+ NULL,
+ CONTENT_HTML,
+ false
+ }, /* Mantis bug #996 */
+ {
+ "http://a.xn--11b4c3d/a",
+ "a title",
+ CONTENT_HTML,
+ false
+ },
+ {
+ "https://smog.大众汽车/test",
+ "unicode title 大众汽车",
+ CONTENT_HTML,
+ false
+ },
+};
+
+
+/**
+ * add set and get test
+ */
+START_TEST(urldb_add_set_get_test)
+{
+ nserror err;
+ nsurl *url;
+ nsurl *res_url;
+ const struct url_data *data;
+ const struct test_urls *tst = &add_set_get_tests[_i];
+
+ /* not testing create, this should always succeed */
+ err = nsurl_create(tst->url, &url);
+ ck_assert(err == NSERROR_OK);
+
+ /* add the url to the database */
+ ck_assert(urldb_add_url(url) == true);
+
+ /* set title */
+ err = urldb_set_url_title(url, tst->title);
+ ck_assert(err == NSERROR_OK);
+
+ err = urldb_set_url_content_type(url, tst->type);
+ ck_assert(err == NSERROR_OK);
+
+ /* retrieve the url from the database and check it matches */
+ res_url = urldb_get_url(url);
+ ck_assert(res_url != NULL);
+ ck_assert(nsurl_compare(url, res_url, NSURL_COMPLETE) == true);
+
+ /* retrieve url data and check title matches */
+ data = urldb_get_url_data(url);
+ ck_assert(data != NULL);
+
+ /* ensure title matches */
+ if (tst->title != NULL) {
+ ck_assert_str_eq(data->title, tst->title);
+ } else {
+ ck_assert(data->title == NULL);
+ }
+
+ /* ensure type matches */
+ ck_assert(data->type == tst->type);
+
+ /* release test url */
+ nsurl_unref(url);
+}
+END_TEST
+
+/**
+ * test cases that simply add and then get a url
+ *
+ * these tests exercise the adding and retrival of urls verifying the
+ * data added.
+ */
+static TCase *urldb_add_get_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Add Get tests");
+
+ /* ensure corestrings are initialised and finalised for every test */
+ tcase_add_checked_fixture(tc,
+ urldb_create,
+ urldb_teardown);
+
+ tcase_add_loop_test(tc,
+ urldb_add_set_get_test,
+ 0, NELEMS(add_set_get_tests));
+
+ return tc;
+}
+
+/**
+ * Session basic test case
+ *
+ * The databases are loaded and saved with no manipulation
+ *
+ * \warning This test will fail when 32bit time_t wraps in 2038 as the
+ * cookie database expiry field is limited to that size.
+ */
START_TEST(urldb_session_test)
{
nserror res;
@@ -431,16 +592,26 @@ START_TEST(urldb_session_test)
urldb_load_cookies(test_cookies_path);
/* write database out */
- outnam = tmpnam(NULL);
+ outnam = testnam(NULL);
res = urldb_save(outnam);
ck_assert_int_eq(res, NSERROR_OK);
+ /* check the url database file written and the test file match */
+ ck_assert_int_eq(cmp(outnam, test_urldb_out_path), 0);
+
/* remove test output */
unlink(outnam);
/* write cookies out */
+ outnam = testnam(NULL);
urldb_save_cookies(outnam);
+ /* check the cookies file written and the test file match */
+ ck_assert_int_eq(cmp(outnam, test_cookies_out_path), 0);
+
+ /* remove test output */
+ unlink(outnam);
+
/* finalise options */
res = nsoption_finalise(NULL, NULL);
ck_assert_int_eq(res, NSERROR_OK);
@@ -448,7 +619,81 @@ START_TEST(urldb_session_test)
}
END_TEST
+/**
+ * Session more extensive test case
+ *
+ * The databases are loaded and saved with a host and paths added
+ */
+START_TEST(urldb_session_add_test)
+{
+ nserror res;
+ char *outnam;
+ nsurl *url;
+ unsigned int t;
+
+ /* writing output requires options initialising */
+ res = nsoption_init(NULL, NULL, NULL);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ res = urldb_load(test_urldb_path);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ urldb_load_cookies(test_cookies_path);
+
+ /* add to db */
+ for (t = 0; t < NELEMS(add_set_get_tests); t++) {
+ const struct test_urls *tst = &add_set_get_tests[t];
+ /* not testing url creation, this should always succeed */
+ res = nsurl_create(tst->url, &url);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ /* add the url to the database */
+ ck_assert(urldb_add_url(url) == true);
+
+ /* set title */
+ res = urldb_set_url_title(url, tst->title);
+ ck_assert(res == NSERROR_OK);
+
+ /* update the visit time so it gets serialised */
+ if (tst->persistent) {
+ res = urldb_set_url_persistence(url, true);
+ } else {
+ res = urldb_update_url_visit_data(url);
+ }
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ nsurl_unref(url);
+ }
+
+ /* write database out */
+ outnam = testnam(NULL);
+ res = urldb_save(outnam);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ /* remove urldb test output */
+ unlink(outnam);
+
+ /* write cookies out */
+ outnam = testnam(NULL);
+ urldb_save_cookies(outnam);
+
+ /* remove cookies test output */
+ unlink(outnam);
+
+ /* finalise options */
+ res = nsoption_finalise(NULL, NULL);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+}
+END_TEST
+
+/**
+ * Test case to check entire session
+ *
+ * These tests define a session as loading a url database and cookie
+ * database and then saving them back to disc.
+ */
static TCase *urldb_session_case_create(void)
{
TCase *tc;
@@ -460,6 +705,7 @@ static TCase *urldb_session_case_create(void)
urldb_teardown);
tcase_add_test(tc, urldb_session_test);
+ tcase_add_test(tc, urldb_session_add_test);
return tc;
}
@@ -468,7 +714,7 @@ static int cb_count;
static bool urldb_iterate_entries_cb(nsurl *url, const struct url_data *data)
{
- LOG("url: %s", nsurl_access(url));
+ NSLOG(netsurf, INFO, "url: %s", nsurl_access(url));
/* fprintf(stderr, "url:%s\ntitle:%s\n\n",nsurl_access(url), data->title); */
cb_count++;
return true;
@@ -538,9 +784,9 @@ START_TEST(urldb_iterate_partial_path_test)
END_TEST
/**
- * iterate through partial matches
+ * iterate through partial matches of numeric v4 address
*/
-START_TEST(urldb_iterate_partial_numeric_test)
+START_TEST(urldb_iterate_partial_numeric_v4_test)
{
nsurl *url;
@@ -555,49 +801,74 @@ START_TEST(urldb_iterate_partial_numeric_test)
cb_count = 0;
urldb_iterate_partial("192.168.7.1/", urldb_iterate_entries_cb);
ck_assert_int_eq(cb_count, 1);
-
-
}
END_TEST
-START_TEST(urldb_auth_details_test)
+
+/**
+ * iterate through partial matches of numeric v6 address
+ */
+START_TEST(urldb_iterate_partial_numeric_v6_test)
{
nsurl *url;
- const char *res;
- const char *auth = "mooooo";
- url = make_url(wikipedia_url);
- urldb_set_auth_details(url, "tree", auth);
-
- res = urldb_get_auth_details(url, "tree");
- ck_assert_str_eq(res, auth);
+ cb_count = 0;
+ urldb_iterate_partial("[2001:db8:1f70::999:de8:7648:6e8]",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 0);
+ url = make_url("http://[2001:db8:1f70::999:de8:7648:6e8]/index.html");
+ urldb_add_url(url);
nsurl_unref(url);
+
+ cb_count = 0;
+ urldb_iterate_partial("[2001:db8:1f70::999:de8:7648:6e8]/index.wrong",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 0);
+
+ cb_count = 0;
+ urldb_iterate_partial("[2001:db8:1f70::999:de8:7648:6e8]",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 1);
+
+ cb_count = 0;
+ urldb_iterate_partial("[2001:db8:1f70::999:de8:7648:6e8]/in",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 1);
+
+ /* double path separators are ignored */
+ cb_count = 0;
+ urldb_iterate_partial("[2001:db8:1f70::999:de8:7648:6e8]//index.html",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 1);
+
+ /* bad ipv6 address inet_pton should fail with this */
+ cb_count = 0;
+ urldb_iterate_partial("[2001::1f70::999::7648:8]",
+ urldb_iterate_entries_cb);
+ ck_assert_int_eq(cb_count, 0);
+
}
END_TEST
-START_TEST(urldb_thumbnail_test)
+START_TEST(urldb_auth_details_test)
{
nsurl *url;
- struct bitmap *bmap;
- struct bitmap *res;
- bool set;
+ const char *res;
+ const char *auth = "mooooo";
url = make_url(wikipedia_url);
- bmap = (struct bitmap*)url;
-
- set = urldb_set_thumbnail(url, bmap);
- ck_assert(set == true);
+ urldb_set_auth_details(url, "tree", auth);
- res = urldb_get_thumbnail(url);
- ck_assert(res != NULL);
- ck_assert(res == bmap);
+ res = urldb_get_auth_details(url, "tree");
+ ck_assert_str_eq(res, auth);
nsurl_unref(url);
}
END_TEST
+
START_TEST(urldb_cert_permissions_test)
{
nsurl *url;
@@ -690,9 +961,9 @@ static TCase *urldb_case_create(void)
tcase_add_test(tc, urldb_iterate_partial_nomatch_test);
tcase_add_test(tc, urldb_iterate_partial_add_test);
tcase_add_test(tc, urldb_iterate_partial_path_test);
- tcase_add_test(tc, urldb_iterate_partial_numeric_test);
+ tcase_add_test(tc, urldb_iterate_partial_numeric_v4_test);
+ tcase_add_test(tc, urldb_iterate_partial_numeric_v6_test);
tcase_add_test(tc, urldb_auth_details_test);
- tcase_add_test(tc, urldb_thumbnail_test);
tcase_add_test(tc, urldb_cert_permissions_test);
tcase_add_test(tc, urldb_update_visit_test);
tcase_add_test(tc, urldb_reset_visit_test);
@@ -704,7 +975,7 @@ static TCase *urldb_case_create(void)
static bool urldb_iterate_cookies_cb(const struct cookie_data *data)
{
- LOG("%p", data);
+ NSLOG(netsurf, INFO, "%p", data);
/* fprintf(stderr, "domain:%s\npath:%s\nname:%s\n\n",data->domain, data->path, data->name);*/
return true;
}
@@ -769,16 +1040,56 @@ static TCase *urldb_cookie_case_create(void)
}
+/**
+ * Test urldb_add_url asserting on NULL.
+ */
+START_TEST(urldb_api_add_url_assert_test)
+{
+ bool res;
+ res = urldb_add_url(NULL);
+ ck_assert(res == true);
+}
+END_TEST
/**
- * Test urldb_add_host asserting on NULL.
+ * Test urldb find failing for differing bad url.
*/
-START_TEST(urldb_api_add_host_assert_test)
+START_TEST(urldb_api_url_find_test)
{
- struct host_part *res;
- res = urldb_add_host(NULL);
- ck_assert(res == NULL);
+ nsurl *url;
+ nserror res;
+
+ urldb_create();
+
+ /* search for a url with mailto scheme */
+ res = nsurl_create("mailto:", &url);
+ ck_assert_int_eq(res, NSERROR_OK);
+
+ res = urldb_set_url_persistence(url, true);
+ ck_assert_int_eq(res, NSERROR_NOT_FOUND);
+
+ nsurl_unref(url);
+
+ /* search for a url with odd scheme and no host */
+ res = nsurl_create("fish:///", &url);
+ ck_assert_int_eq(res, NSERROR_OK);
+ ck_assert(nsurl_has_component(url, NSURL_HOST) == false);
+
+ res = urldb_set_url_title(url, NULL);
+ ck_assert_int_eq(res, NSERROR_NOT_FOUND);
+
+ nsurl_unref(url);
+
+ /* search for a url with not found url */
+ res = nsurl_create("http://no.example.com/", &url);
+ ck_assert_int_eq(res, NSERROR_OK);
+ ck_assert(nsurl_has_component(url, NSURL_HOST) == true);
+
+ res = urldb_set_url_persistence(url, true);
+ ck_assert_int_eq(res, NSERROR_NOT_FOUND);
+
+ nsurl_unref(url);
}
END_TEST
@@ -801,22 +1112,27 @@ static TCase *urldb_api_case_create(void)
tc = tcase_create("API_checks");
tcase_add_test_raise_signal(tc,
- urldb_api_add_host_assert_test,
+ urldb_api_add_url_assert_test,
6);
+ tcase_add_test(tc, urldb_api_url_find_test);
+
tcase_add_test(tc, urldb_api_destroy_no_init_test);
return tc;
}
-
+/**
+ * Test suite for url database
+ */
static Suite *urldb_suite_create(void)
{
Suite *s;
s = suite_create("URLDB");
suite_add_tcase(s, urldb_api_case_create());
+ suite_add_tcase(s, urldb_add_get_case_create());
suite_add_tcase(s, urldb_session_case_create());
suite_add_tcase(s, urldb_case_create());
suite_add_tcase(s, urldb_cookie_case_create());
diff --git a/test/utils.c b/test/utils.c
index 62ccf512d..3d5319a28 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -21,6 +21,8 @@
* Tests for utility functions.
*/
+#include "utils/config.h"
+
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
@@ -53,6 +55,9 @@ static const struct test_pairs human_friendly_bytesize_test_vec[] = {
{ 4294967295, "4.00GBytes" },
};
+/**
+ * check each response one at a time
+ */
START_TEST(human_friendly_bytesize_test)
{
char *res_str;
@@ -65,6 +70,26 @@ START_TEST(human_friendly_bytesize_test)
}
END_TEST
+/**
+ * check each response one after another
+ */
+START_TEST(human_friendly_bytesize_all_test)
+{
+ char *res_str;
+ const struct test_pairs *tst;
+ unsigned int idx;
+
+ for (idx = 0; idx < NELEMS(human_friendly_bytesize_test_vec); idx++) {
+ tst = &human_friendly_bytesize_test_vec[idx];
+
+ res_str = human_friendly_bytesize(tst->test);
+
+ /* ensure result data is correct */
+ ck_assert_str_eq(res_str, tst->res);
+ }
+}
+END_TEST
+
static TCase *human_friendly_bytesize_case_create(void)
{
TCase *tc;
@@ -73,6 +98,8 @@ static TCase *human_friendly_bytesize_case_create(void)
tcase_add_loop_test(tc, human_friendly_bytesize_test,
0, NELEMS(human_friendly_bytesize_test_vec));
+ tcase_add_test(tc, human_friendly_bytesize_all_test);
+
return tc;
}
@@ -88,6 +115,10 @@ static const struct test_strings squash_whitespace_test_vec[] = {
{ " \n\r\t ", " " },
{ " a ", " a " },
{ " a b ", " a b " },
+ {
+ " A string with \t \r \n \t lots\tof\nwhitespace\r ",
+ " A string with lots of whitespace "
+ },
};
START_TEST(squash_whitespace_test)
@@ -181,14 +212,191 @@ static TCase *corestrings_case_create(void)
return tc;
}
+
+
+START_TEST(string_utils_cnv_space2nbsp_test)
+{
+ char *res;
+ char comparison[64];
+
+ snprintf(comparison, 64,
+ "%c%cA%c%cstring%c%c%c%cwith%c%c%c%c%c%cwhitespace%c%c",
+ 0xC2, 0xA0, 0xC2, 0xA0, 0xC2, 0xA0, 0xC2, 0xA0,
+ 0xC2, 0xA0, 0xC2, 0xA0, 0xC2, 0xA0, 0xC2, 0xA0);
+
+ res = cnv_space2nbsp(" A string with \t whitespace ");
+ ck_assert(res != NULL);
+ ck_assert_str_eq(res, comparison);
+
+ free(res);
+}
+END_TEST
+
+START_TEST(string_utils_strcasestr_test)
+{
+
+ char *res;
+ const char *haystack = "A big old long haystack string that has a small Needle in the middle of it with a different case";
+
+ res = strcasestr(haystack, "notfound");
+ ck_assert(res == NULL);
+
+ res = strcasestr(haystack, "needle");
+ ck_assert(res != NULL);
+
+ ck_assert_str_eq(res, haystack + 48);
+
+}
+END_TEST
+
+START_TEST(string_utils_strchrnul_test)
+{
+
+ char *res;
+ const char *haystack = "A big old long haystack string that has a small Needle in the middle of it with a different case";
+
+ res = strchrnul(haystack, 'Z');
+ ck_assert(res != NULL);
+ ck_assert(*res == 0);
+
+ res = strchrnul(haystack, 'N');
+ ck_assert(res != NULL);
+
+ ck_assert_str_eq(res, haystack + 48);
+
+}
+END_TEST
+
+
+static TCase *string_utils_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("String utilities");
+
+ tcase_add_test(tc, string_utils_cnv_space2nbsp_test);
+ tcase_add_test(tc, string_utils_strcasestr_test);
+ tcase_add_test(tc, string_utils_strchrnul_test);
+
+ return tc;
+}
+
+
+/**
+ * api tests
+ */
+START_TEST(string_utils_snstrjoin_api_test)
+{
+ nserror res;
+ char outstr[32];
+ char *resstr = &outstr[0];
+ size_t resstrlen = 32;
+
+ /* bad count parameters */
+ res = snstrjoin(&resstr, &resstrlen, ',', 0, "1");
+ ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
+
+ res = snstrjoin(&resstr, &resstrlen, ',', 17, "1");
+ ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
+
+ /* if there is a buffer must set length */
+ res = snstrjoin(&resstr, NULL, ',', 4, "1", "2", "3", "4");
+ ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
+
+ /* null argument value is bad parameter */
+ res = snstrjoin(&resstr, &resstrlen, ',', 4, "1", NULL, "3", "4");
+ ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
+
+ /* attempt to use an undersize buffer */
+ resstrlen = 1;
+ res = snstrjoin(&resstr, &resstrlen, ',', 4, "1", "2", "3", "4");
+ ck_assert_int_eq(res, NSERROR_NOSPACE);
+
+}
+END_TEST
+
+
+/**
+ * good four parameter join
+ */
+START_TEST(string_utils_snstrjoin_four_test)
+{
+ nserror res;
+ char *resstr = NULL;
+ size_t resstrlen;
+
+ res = snstrjoin(&resstr, &resstrlen, ',', 4, "1", "2", "3", "4");
+ ck_assert_int_eq(res, NSERROR_OK);
+ ck_assert(resstr != NULL);
+ ck_assert_int_eq(resstrlen, 8);
+ ck_assert_str_eq(resstr, "1,2,3,4");
+ free(resstr);
+}
+END_TEST
+
+
+/**
+ * good three parameter join with no length
+ */
+START_TEST(string_utils_snstrjoin_three_test)
+{
+ nserror res;
+ char *resstr = NULL;
+
+ res = snstrjoin(&resstr, NULL, ',', 3, "1", "2,", "3");
+ ck_assert_int_eq(res, NSERROR_OK);
+ ck_assert(resstr != NULL);
+ ck_assert_str_eq(resstr, "1,2,3");
+ free(resstr);
+}
+END_TEST
+
+/**
+ * good two parameter join into pre allocated buffer
+ */
+START_TEST(string_utils_snstrjoin_two_test)
+{
+ nserror res;
+ char outstr[32];
+ char *resstr = &outstr[0];
+ size_t resstrlen = 32;
+
+ res = snstrjoin(&resstr, &resstrlen, ',', 2, "1", "2");
+ ck_assert_int_eq(res, NSERROR_OK);
+ ck_assert(resstr != NULL);
+ ck_assert_int_eq(resstrlen, 4);
+ ck_assert_str_eq(resstr, "1,2");
+}
+END_TEST
+
+
+static TCase *snstrjoin_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("snstrjoin utilities");
+
+ tcase_add_test(tc, string_utils_snstrjoin_api_test);
+ tcase_add_test(tc, string_utils_snstrjoin_four_test);
+ tcase_add_test(tc, string_utils_snstrjoin_three_test);
+ tcase_add_test(tc, string_utils_snstrjoin_three_test);
+ tcase_add_test(tc, string_utils_snstrjoin_two_test);
+
+ return tc;
+}
+
+
+/*
+ * Utility test suite creation
+ */
static Suite *utils_suite_create(void)
{
Suite *s;
- s = suite_create("String utils");
+ s = suite_create("Utility API");
suite_add_tcase(s, human_friendly_bytesize_case_create());
suite_add_tcase(s, squash_whitespace_case_create());
suite_add_tcase(s, corestrings_case_create());
+ suite_add_tcase(s, snstrjoin_case_create());
+ suite_add_tcase(s, string_utils_case_create());
return s;
}
diff --git a/utils/Makefile b/utils/Makefile
index 62b7e05e7..2f59501c2 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -12,7 +12,6 @@ S_UTILS := \
log.c \
messages.c \
nsoption.c \
- nsurl.c \
punycode.c \
talloc.c \
time.c \
diff --git a/utils/ascii.h b/utils/ascii.h
index f08e756a0..94d988aed 100644
--- a/utils/ascii.h
+++ b/utils/ascii.h
@@ -111,6 +111,17 @@ static inline bool ascii_is_alphanumerical(char c)
}
/**
+ * Test whether a character is 'a' to 'f' (lowercase).
+ *
+ * \param[in] c Character to test.
+ * \return true iff `c` is 'a' to 'f' (lowercase), else false.
+ */
+static inline bool ascii_is_af_lower(char c)
+{
+ return (c >= 'a' && c <= 'f');
+}
+
+/**
* Test whether a character is hexadecimal (lower case).
*
* \param[in] c Character to test.
@@ -118,8 +129,18 @@ static inline bool ascii_is_alphanumerical(char c)
*/
static inline bool ascii_is_hex_lower(char c)
{
- return (ascii_is_digit(c) ||
- (c >= 'a' && c <= 'f'));
+ return (ascii_is_digit(c) || ascii_is_af_lower(c));
+}
+
+/**
+ * Test whether a character is 'A' to 'F' (uppercase).
+ *
+ * \param[in] c Character to test.
+ * \return true iff `c` is 'A' to 'F' (uppercase), else false.
+ */
+static inline bool ascii_is_af_upper(char c)
+{
+ return (c >= 'A' && c <= 'F');
}
/**
@@ -130,8 +151,7 @@ static inline bool ascii_is_hex_lower(char c)
*/
static inline bool ascii_is_hex_upper(char c)
{
- return (ascii_is_digit(c) ||
- (c >= 'A' && c <= 'F'));
+ return (ascii_is_digit(c) || ascii_is_af_upper(c));
}
/**
@@ -143,8 +163,41 @@ static inline bool ascii_is_hex_upper(char c)
static inline bool ascii_is_hex(char c)
{
return (ascii_is_digit(c) ||
- (c >= 'A' && c <= 'F') ||
- (c >= 'a' && c <= 'f'));
+ ascii_is_af_upper(c) ||
+ ascii_is_af_lower(c));
+}
+
+/**
+ * Convert a hexadecimal character to its value.
+ *
+ * \param[in] c Character to convert.
+ * \return value of character (0-15), or -256 if not a hexadecimal character.
+ */
+static inline int ascii_hex_to_value(char c)
+{
+ if (ascii_is_digit(c)) {
+ return c - '0';
+ } else if (ascii_is_af_lower(c)) {
+ return c - 'a' + 10;
+ } else if (ascii_is_af_upper(c)) {
+ return c - 'A' + 10;
+ }
+
+ /* Invalid hex */
+ return -256;
+}
+
+/**
+ * Converts two hexadecimal characters to a single number
+ *
+ * \param[in] c1 most significant hex digit.
+ * \param[in] c2 least significant hex digit.
+ * \return the total value of the two digit hex number (0-255),
+ * or -ve if input not hex.
+ */
+static inline int ascii_hex_to_value_2_chars(char c1, char c2)
+{
+ return 16 * ascii_hex_to_value(c1) + ascii_hex_to_value(c2);
}
/**
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
new file mode 100644
index 000000000..90dd796a7
--- /dev/null
+++ b/utils/corestringlist.h
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Core string lists
+ *
+ * three macros must be defined to use this header
+ * CORESTRING_LWC_VALUE - wapcaplet strings with a value not derived from name
+ * CORESTRING_DOM_VALUE - dom strings with a value not derived from name
+ * CORESTRING_NSURL - nsurl from given url
+ *
+ * two helper macros are defined that allow simple mapping strings
+ * CORESTRING_LWC_STRING - libwapcaplet strings with a simple name value mapping
+ * CORESTRING_DOM_STRING - dom strings with a simple name value mapping
+ *
+ * \note This header is specificaly intented to be included multiple
+ * times with different macro definitions so there is no guard.
+ */
+
+#if !defined(CORESTRING_LWC_VALUE) | !defined(CORESTRING_DOM_VALUE) | !defined(CORESTRING_NSURL)
+#error "missing macro definition. This header must not be directly included"
+#endif
+
+#undef CORESTRING_LWC_STRING
+#define CORESTRING_LWC_STRING(NAME) CORESTRING_LWC_VALUE(NAME, #NAME)
+
+#undef CORESTRING_DOM_STRING
+#define CORESTRING_DOM_STRING(NAME) CORESTRING_DOM_VALUE(NAME, #NAME);
+
+/* lwc_string strings */
+CORESTRING_LWC_STRING(a);
+CORESTRING_LWC_STRING(about);
+CORESTRING_LWC_STRING(abscenter);
+CORESTRING_LWC_STRING(absmiddle);
+CORESTRING_LWC_STRING(align);
+CORESTRING_LWC_STRING(applet);
+CORESTRING_LWC_STRING(base);
+CORESTRING_LWC_STRING(baseline);
+CORESTRING_LWC_STRING(body);
+CORESTRING_LWC_STRING(bottom);
+CORESTRING_LWC_STRING(button);
+CORESTRING_LWC_STRING(caption);
+CORESTRING_LWC_STRING(charset);
+CORESTRING_LWC_STRING(center);
+CORESTRING_LWC_STRING(checkbox);
+CORESTRING_LWC_STRING(circle);
+CORESTRING_LWC_STRING(col);
+CORESTRING_LWC_STRING(data);
+CORESTRING_LWC_STRING(default);
+CORESTRING_LWC_STRING(div);
+CORESTRING_LWC_STRING(embed);
+CORESTRING_LWC_STRING(file);
+CORESTRING_LWC_STRING(filename);
+CORESTRING_LWC_STRING(font);
+CORESTRING_LWC_STRING(frame);
+CORESTRING_LWC_STRING(frameset);
+CORESTRING_LWC_STRING(ftp);
+CORESTRING_LWC_STRING(h1);
+CORESTRING_LWC_STRING(h2);
+CORESTRING_LWC_STRING(h3);
+CORESTRING_LWC_STRING(h4);
+CORESTRING_LWC_STRING(h5);
+CORESTRING_LWC_STRING(h6);
+CORESTRING_LWC_STRING(head);
+CORESTRING_LWC_STRING(hidden);
+CORESTRING_LWC_STRING(hr);
+CORESTRING_LWC_STRING(html);
+CORESTRING_LWC_STRING(http);
+CORESTRING_LWC_STRING(https);
+CORESTRING_LWC_STRING(icon);
+CORESTRING_LWC_STRING(iframe);
+CORESTRING_LWC_STRING(image);
+CORESTRING_LWC_STRING(img);
+CORESTRING_LWC_STRING(includesubdomains);
+CORESTRING_LWC_STRING(input);
+CORESTRING_LWC_STRING(javascript);
+CORESTRING_LWC_STRING(justify);
+CORESTRING_LWC_STRING(left);
+CORESTRING_LWC_STRING(li);
+CORESTRING_LWC_STRING(link);
+CORESTRING_LWC_STRING(mailto);
+CORESTRING_LWC_STRING(meta);
+CORESTRING_LWC_STRING(middle);
+CORESTRING_LWC_STRING(no);
+CORESTRING_LWC_STRING(noscript);
+CORESTRING_LWC_STRING(object);
+CORESTRING_LWC_STRING(optgroup);
+CORESTRING_LWC_STRING(option);
+CORESTRING_LWC_STRING(p);
+CORESTRING_LWC_STRING(param);
+CORESTRING_LWC_STRING(password);
+CORESTRING_LWC_STRING(poly);
+CORESTRING_LWC_STRING(polygon);
+CORESTRING_LWC_STRING(post);
+CORESTRING_LWC_STRING(radio);
+CORESTRING_LWC_STRING(rect);
+CORESTRING_LWC_STRING(rectangle);
+CORESTRING_LWC_STRING(refresh);
+CORESTRING_LWC_STRING(reset);
+CORESTRING_LWC_STRING(resource);
+CORESTRING_LWC_STRING(right);
+CORESTRING_LWC_STRING(search);
+CORESTRING_LWC_STRING(select);
+CORESTRING_LWC_STRING(src);
+CORESTRING_LWC_STRING(style);
+CORESTRING_LWC_STRING(submit);
+CORESTRING_LWC_STRING(table);
+CORESTRING_LWC_STRING(tbody);
+CORESTRING_LWC_STRING(td);
+CORESTRING_LWC_STRING(text);
+CORESTRING_LWC_STRING(textarea);
+CORESTRING_LWC_STRING(texttop);
+CORESTRING_LWC_STRING(tfoot);
+CORESTRING_LWC_STRING(th);
+CORESTRING_LWC_STRING(thead);
+CORESTRING_LWC_STRING(title);
+CORESTRING_LWC_STRING(top);
+CORESTRING_LWC_STRING(tr);
+CORESTRING_LWC_STRING(ul);
+CORESTRING_LWC_STRING(url);
+CORESTRING_LWC_STRING(yes);
+CORESTRING_LWC_STRING(_blank);
+CORESTRING_LWC_STRING(_parent);
+CORESTRING_LWC_STRING(_self);
+CORESTRING_LWC_STRING(_top);
+
+/* unusual lwc strings */
+CORESTRING_LWC_VALUE(shortcut_icon, "shortcut icon");
+CORESTRING_LWC_VALUE(slash_, "/");
+CORESTRING_LWC_VALUE(max_age, "max-age");
+
+/* mime types */
+CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");
+CORESTRING_LWC_VALUE(text_css, "text/css");
+CORESTRING_LWC_VALUE(unknown_unknown, "unknown/unknown");
+CORESTRING_LWC_VALUE(application_unknown, "application/unknown");
+CORESTRING_LWC_VALUE(any, "*/*");
+CORESTRING_LWC_VALUE(text_xml, "text/xml");
+CORESTRING_LWC_VALUE(application_xml, "application/xml");
+CORESTRING_LWC_VALUE(text_html, "text/html");
+CORESTRING_LWC_VALUE(text_plain, "text/plain");
+CORESTRING_LWC_VALUE(application_octet_stream, "application/octet-stream");
+CORESTRING_LWC_VALUE(image_gif, "image/gif");
+CORESTRING_LWC_VALUE(image_png, "image/png");
+CORESTRING_LWC_VALUE(image_jpeg, "image/jpeg");
+CORESTRING_LWC_VALUE(image_bmp, "image/bmp");
+CORESTRING_LWC_VALUE(image_vnd_microsoft_icon, "image/vnd.microsoft.icon");
+CORESTRING_LWC_VALUE(image_webp, "image/webp");
+CORESTRING_LWC_VALUE(application_rss_xml, "application/rss+xml");
+CORESTRING_LWC_VALUE(application_atom_xml, "application/atom+xml");
+CORESTRING_LWC_VALUE(audio_wave, "audio/wave");
+CORESTRING_LWC_VALUE(application_ogg, "application/ogg");
+CORESTRING_LWC_VALUE(video_webm, "video/webm");
+CORESTRING_LWC_VALUE(application_x_rar_compressed, "application/x-rar-compressed");
+CORESTRING_LWC_VALUE(application_zip, "application/zip");
+CORESTRING_LWC_VALUE(application_x_gzip, "application/x-gzip");
+CORESTRING_LWC_VALUE(application_postscript, "application/postscript");
+CORESTRING_LWC_VALUE(application_pdf, "application/pdf");
+CORESTRING_LWC_VALUE(video_mp4, "video/mp4");
+CORESTRING_LWC_VALUE(image_svg, "image/svg+xml");
+
+
+/* DOM strings */
+CORESTRING_DOM_STRING(a);
+CORESTRING_DOM_STRING(abort);
+CORESTRING_DOM_STRING(afterprint);
+CORESTRING_DOM_STRING(align);
+CORESTRING_DOM_STRING(alt);
+CORESTRING_DOM_STRING(area);
+CORESTRING_DOM_STRING(async);
+CORESTRING_DOM_STRING(background);
+CORESTRING_DOM_STRING(beforeprint);
+CORESTRING_DOM_STRING(beforeunload);
+CORESTRING_DOM_STRING(bgcolor);
+CORESTRING_DOM_STRING(blur);
+CORESTRING_DOM_STRING(border);
+CORESTRING_DOM_STRING(bordercolor);
+CORESTRING_DOM_STRING(cancel);
+CORESTRING_DOM_STRING(canplay);
+CORESTRING_DOM_STRING(canplaythrough);
+CORESTRING_DOM_STRING(cellpadding);
+CORESTRING_DOM_STRING(cellspacing);
+CORESTRING_DOM_STRING(change);
+CORESTRING_DOM_STRING(charset);
+CORESTRING_DOM_STRING(class);
+CORESTRING_DOM_STRING(classid);
+CORESTRING_DOM_STRING(click);
+CORESTRING_DOM_STRING(close);
+CORESTRING_DOM_STRING(codebase);
+CORESTRING_DOM_STRING(color);
+CORESTRING_DOM_STRING(cols);
+CORESTRING_DOM_STRING(colspan);
+CORESTRING_DOM_STRING(content);
+CORESTRING_DOM_STRING(contextmenu);
+CORESTRING_DOM_STRING(coords);
+CORESTRING_DOM_STRING(cuechange);
+CORESTRING_DOM_STRING(data);
+CORESTRING_DOM_STRING(dblclick);
+CORESTRING_DOM_STRING(defer);
+CORESTRING_DOM_STRING(DOMAttrModified);
+CORESTRING_DOM_STRING(DOMNodeInserted);
+CORESTRING_DOM_STRING(DOMNodeInsertedIntoDocument);
+CORESTRING_DOM_STRING(DOMSubtreeModified);
+CORESTRING_DOM_STRING(drag);
+CORESTRING_DOM_STRING(dragend);
+CORESTRING_DOM_STRING(dragenter);
+CORESTRING_DOM_STRING(dragleave);
+CORESTRING_DOM_STRING(dragover);
+CORESTRING_DOM_STRING(dragstart);
+CORESTRING_DOM_STRING(drop);
+CORESTRING_DOM_STRING(durationchange);
+CORESTRING_DOM_STRING(emptied);
+CORESTRING_DOM_STRING(ended);
+CORESTRING_DOM_STRING(error);
+CORESTRING_DOM_STRING(focus);
+CORESTRING_DOM_STRING(frameborder);
+CORESTRING_DOM_STRING(hashchange);
+CORESTRING_DOM_STRING(height);
+CORESTRING_DOM_STRING(href);
+CORESTRING_DOM_STRING(hreflang);
+CORESTRING_DOM_STRING(hspace);
+/* http-equiv: see below */
+CORESTRING_DOM_STRING(id);
+CORESTRING_DOM_STRING(input);
+CORESTRING_DOM_STRING(invalid);
+CORESTRING_DOM_STRING(keydown);
+CORESTRING_DOM_STRING(keypress);
+CORESTRING_DOM_STRING(keyup);
+CORESTRING_DOM_STRING(link);
+CORESTRING_DOM_STRING(load);
+CORESTRING_DOM_STRING(loadeddata);
+CORESTRING_DOM_STRING(loadedmetadata);
+CORESTRING_DOM_STRING(loadstart);
+CORESTRING_DOM_STRING(map);
+CORESTRING_DOM_STRING(marginheight);
+CORESTRING_DOM_STRING(marginwidth);
+CORESTRING_DOM_STRING(media);
+CORESTRING_DOM_STRING(message);
+CORESTRING_DOM_STRING(mousedown);
+CORESTRING_DOM_STRING(mousemove);
+CORESTRING_DOM_STRING(mouseout);
+CORESTRING_DOM_STRING(mouseover);
+CORESTRING_DOM_STRING(mouseup);
+CORESTRING_DOM_STRING(mousewheel);
+CORESTRING_DOM_STRING(name);
+CORESTRING_DOM_STRING(nohref);
+CORESTRING_DOM_STRING(noresize);
+CORESTRING_DOM_STRING(nowrap);
+CORESTRING_DOM_STRING(offline);
+CORESTRING_DOM_STRING(online);
+CORESTRING_DOM_STRING(pagehide);
+CORESTRING_DOM_STRING(pageshow);
+CORESTRING_DOM_STRING(pause);
+CORESTRING_DOM_STRING(play);
+CORESTRING_DOM_STRING(playing);
+CORESTRING_DOM_STRING(popstate);
+CORESTRING_DOM_STRING(progress);
+CORESTRING_DOM_STRING(ratechange);
+CORESTRING_DOM_STRING(readystatechange);
+CORESTRING_DOM_STRING(rect);
+CORESTRING_DOM_STRING(rel);
+CORESTRING_DOM_STRING(reset);
+CORESTRING_DOM_STRING(resize);
+CORESTRING_DOM_STRING(rows);
+CORESTRING_DOM_STRING(rowspan);
+CORESTRING_DOM_STRING(scroll);
+CORESTRING_DOM_STRING(scrolling);
+CORESTRING_DOM_STRING(seeked);
+CORESTRING_DOM_STRING(seeking);
+CORESTRING_DOM_STRING(select);
+CORESTRING_DOM_STRING(selected);
+CORESTRING_DOM_STRING(shape);
+CORESTRING_DOM_STRING(show);
+CORESTRING_DOM_STRING(size);
+CORESTRING_DOM_STRING(sizes);
+CORESTRING_DOM_STRING(src);
+CORESTRING_DOM_STRING(stalled);
+CORESTRING_DOM_STRING(storage);
+CORESTRING_DOM_STRING(style);
+CORESTRING_DOM_STRING(submit);
+CORESTRING_DOM_STRING(suspend);
+CORESTRING_DOM_STRING(target);
+CORESTRING_DOM_STRING(text);
+CORESTRING_DOM_STRING(timeupdate);
+CORESTRING_DOM_STRING(title);
+CORESTRING_DOM_STRING(type);
+CORESTRING_DOM_STRING(unload);
+CORESTRING_DOM_STRING(valign);
+CORESTRING_DOM_STRING(value);
+CORESTRING_DOM_STRING(vlink);
+CORESTRING_DOM_STRING(volumechange);
+CORESTRING_DOM_STRING(vspace);
+CORESTRING_DOM_STRING(waiting);
+CORESTRING_DOM_STRING(width);
+/* DOM node names, not really CSS */
+CORESTRING_DOM_STRING(BUTTON);
+CORESTRING_DOM_STRING(INPUT);
+CORESTRING_DOM_STRING(SELECT);
+CORESTRING_DOM_STRING(TEXTAREA);
+CORESTRING_DOM_STRING(BODY);
+CORESTRING_DOM_STRING(HEAD);
+/* DOM input types, not really CSS */
+CORESTRING_DOM_STRING(button);
+CORESTRING_DOM_STRING(image);
+CORESTRING_DOM_STRING(radio);
+CORESTRING_DOM_STRING(checkbox);
+CORESTRING_DOM_STRING(file);
+/* DOM event prefix */
+CORESTRING_DOM_STRING(on);
+/* DOM events forwarded from body to window */
+CORESTRING_DOM_STRING(onblur);
+CORESTRING_DOM_STRING(onerror);
+CORESTRING_DOM_STRING(onfocus);
+CORESTRING_DOM_STRING(onload);
+CORESTRING_DOM_STRING(onresize);
+CORESTRING_DOM_STRING(onscroll);
+/* Corestrings used by DOM event registration */
+CORESTRING_DOM_STRING(autocomplete);
+CORESTRING_DOM_STRING(autocompleteerror);
+CORESTRING_DOM_STRING(dragexit);
+CORESTRING_DOM_STRING(mouseenter);
+CORESTRING_DOM_STRING(mouseleave);
+CORESTRING_DOM_STRING(wheel);
+CORESTRING_DOM_STRING(sort);
+CORESTRING_DOM_STRING(toggle);
+/* DOM userdata keys, not really CSS */
+CORESTRING_DOM_STRING(__ns_key_box_node_data);
+CORESTRING_DOM_STRING(__ns_key_libcss_node_data);
+CORESTRING_DOM_STRING(__ns_key_file_name_node_data);
+CORESTRING_DOM_STRING(__ns_key_image_coords_node_data);
+CORESTRING_DOM_STRING(__ns_key_html_content_data);
+
+/* unusual DOM strings */
+CORESTRING_DOM_VALUE(text_javascript, "text/javascript");
+CORESTRING_DOM_VALUE(http_equiv, "http-equiv");
+CORESTRING_DOM_VALUE(html_namespace, "http://www.w3.org/1999/xhtml");
+
+CORESTRING_NSURL(about_blank, "about:blank");
+
+#undef CORESTRING_LWC_STRING
+#undef CORESTRING_DOM_STRING
diff --git a/utils/corestrings.c b/utils/corestrings.c
index 87a342313..d8934b739 100644
--- a/utils/corestrings.c
+++ b/utils/corestrings.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Useful interned string pointers (implementation).
+/**
+ * \file
+ * Useful interned string tables implementation.
*/
#include <dom/dom.h>
@@ -26,280 +27,19 @@
#include "utils/nsurl.h"
#include "utils/utils.h"
-/* lwc_string strings */
-lwc_string *corestring_lwc_a;
-lwc_string *corestring_lwc_about;
-lwc_string *corestring_lwc_abscenter;
-lwc_string *corestring_lwc_absmiddle;
-lwc_string *corestring_lwc_align;
-lwc_string *corestring_lwc_applet;
-lwc_string *corestring_lwc_base;
-lwc_string *corestring_lwc_baseline;
-lwc_string *corestring_lwc_body;
-lwc_string *corestring_lwc_bottom;
-lwc_string *corestring_lwc_button;
-lwc_string *corestring_lwc_caption;
-lwc_string *corestring_lwc_center;
-lwc_string *corestring_lwc_charset;
-lwc_string *corestring_lwc_checkbox;
-lwc_string *corestring_lwc_circle;
-lwc_string *corestring_lwc_col;
-lwc_string *corestring_lwc_data;
-lwc_string *corestring_lwc_default;
-lwc_string *corestring_lwc_div;
-lwc_string *corestring_lwc_embed;
-lwc_string *corestring_lwc_file;
-lwc_string *corestring_lwc_filename;
-lwc_string *corestring_lwc_font;
-lwc_string *corestring_lwc_frame;
-lwc_string *corestring_lwc_frameset;
-lwc_string *corestring_lwc_h1;
-lwc_string *corestring_lwc_h2;
-lwc_string *corestring_lwc_h3;
-lwc_string *corestring_lwc_h4;
-lwc_string *corestring_lwc_h5;
-lwc_string *corestring_lwc_h6;
-lwc_string *corestring_lwc_head;
-lwc_string *corestring_lwc_hidden;
-lwc_string *corestring_lwc_hr;
-lwc_string *corestring_lwc_html;
-lwc_string *corestring_lwc_http;
-lwc_string *corestring_lwc_https;
-lwc_string *corestring_lwc_icon;
-lwc_string *corestring_lwc_iframe;
-lwc_string *corestring_lwc_image;
-lwc_string *corestring_lwc_img;
-lwc_string *corestring_lwc_input;
-lwc_string *corestring_lwc_javascript;
-lwc_string *corestring_lwc_justify;
-lwc_string *corestring_lwc_left;
-lwc_string *corestring_lwc_li;
-lwc_string *corestring_lwc_link;
-lwc_string *corestring_lwc_mailto;
-lwc_string *corestring_lwc_meta;
-lwc_string *corestring_lwc_middle;
-lwc_string *corestring_lwc_multipart_form_data;
-lwc_string *corestring_lwc_no;
-lwc_string *corestring_lwc_noscript;
-lwc_string *corestring_lwc_object;
-lwc_string *corestring_lwc_optgroup;
-lwc_string *corestring_lwc_option;
-lwc_string *corestring_lwc_p;
-lwc_string *corestring_lwc_param;
-lwc_string *corestring_lwc_password;
-lwc_string *corestring_lwc_poly;
-lwc_string *corestring_lwc_polygon;
-lwc_string *corestring_lwc_post;
-lwc_string *corestring_lwc_radio;
-lwc_string *corestring_lwc_rect;
-lwc_string *corestring_lwc_rectangle;
-lwc_string *corestring_lwc_refresh;
-lwc_string *corestring_lwc_reset;
-lwc_string *corestring_lwc_resource;
-lwc_string *corestring_lwc_right;
-lwc_string *corestring_lwc_search;
-lwc_string *corestring_lwc_select;
-lwc_string *corestring_lwc_shortcut_icon;
-lwc_string *corestring_lwc_src;
-lwc_string *corestring_lwc_style;
-lwc_string *corestring_lwc_submit;
-lwc_string *corestring_lwc_table;
-lwc_string *corestring_lwc_tbody;
-lwc_string *corestring_lwc_td;
-lwc_string *corestring_lwc_text;
-lwc_string *corestring_lwc_textarea;
-lwc_string *corestring_lwc_texttop;
-lwc_string *corestring_lwc_text_css;
-lwc_string *corestring_lwc_tfoot;
-lwc_string *corestring_lwc_th;
-lwc_string *corestring_lwc_thead;
-lwc_string *corestring_lwc_title;
-lwc_string *corestring_lwc_top;
-lwc_string *corestring_lwc_tr;
-lwc_string *corestring_lwc_ul;
-lwc_string *corestring_lwc_url;
-lwc_string *corestring_lwc_yes;
-lwc_string *corestring_lwc__blank;
-lwc_string *corestring_lwc__parent;
-lwc_string *corestring_lwc__self;
-lwc_string *corestring_lwc__top;
-lwc_string *corestring_lwc_slash_;
-
-/* dom_string strings */
-dom_string *corestring_dom_a;
-dom_string *corestring_dom_alt;
-dom_string *corestring_dom_abort;
-dom_string *corestring_dom_afterprint;
-dom_string *corestring_dom_align;
-dom_string *corestring_dom_area;
-dom_string *corestring_dom_async;
-dom_string *corestring_dom_background;
-dom_string *corestring_dom_beforeprint;
-dom_string *corestring_dom_beforeunload;
-dom_string *corestring_dom_bgcolor;
-dom_string *corestring_dom_blur;
-dom_string *corestring_dom_border;
-dom_string *corestring_dom_bordercolor;
-dom_string *corestring_dom_cancel;
-dom_string *corestring_dom_canplay;
-dom_string *corestring_dom_canplaythrough;
-dom_string *corestring_dom_cellpadding;
-dom_string *corestring_dom_cellspacing;
-dom_string *corestring_dom_change;
-dom_string *corestring_dom_charset;
-dom_string *corestring_dom_class;
-dom_string *corestring_dom_classid;
-dom_string *corestring_dom_click;
-dom_string *corestring_dom_close;
-dom_string *corestring_dom_codebase;
-dom_string *corestring_dom_color;
-dom_string *corestring_dom_cols;
-dom_string *corestring_dom_colspan;
-dom_string *corestring_dom_content;
-dom_string *corestring_dom_contextmenu;
-dom_string *corestring_dom_coords;
-dom_string *corestring_dom_cuechange;
-dom_string *corestring_dom_data;
-dom_string *corestring_dom_dblclick;
-dom_string *corestring_dom_defer;
-dom_string *corestring_dom_DOMAttrModified;
-dom_string *corestring_dom_DOMNodeInserted;
-dom_string *corestring_dom_DOMNodeInsertedIntoDocument;
-dom_string *corestring_dom_DOMSubtreeModified;
-dom_string *corestring_dom_drag;
-dom_string *corestring_dom_dragend;
-dom_string *corestring_dom_dragenter;
-dom_string *corestring_dom_dragleave;
-dom_string *corestring_dom_dragover;
-dom_string *corestring_dom_dragstart;
-dom_string *corestring_dom_drop;
-dom_string *corestring_dom_durationchange;
-dom_string *corestring_dom_emptied;
-dom_string *corestring_dom_ended;
-dom_string *corestring_dom_error;
-dom_string *corestring_dom_focus;
-dom_string *corestring_dom_frameborder;
-dom_string *corestring_dom_hashchange;
-dom_string *corestring_dom_height;
-dom_string *corestring_dom_href;
-dom_string *corestring_dom_hreflang;
-dom_string *corestring_dom_hspace;
-dom_string *corestring_dom_http_equiv;
-dom_string *corestring_dom_id;
-dom_string *corestring_dom_input;
-dom_string *corestring_dom_invalid;
-dom_string *corestring_dom_keydown;
-dom_string *corestring_dom_keypress;
-dom_string *corestring_dom_keyup;
-dom_string *corestring_dom_link;
-dom_string *corestring_dom_load;
-dom_string *corestring_dom_loadeddata;
-dom_string *corestring_dom_loadedmetadata;
-dom_string *corestring_dom_loadstart;
-dom_string *corestring_dom_map;
-dom_string *corestring_dom_marginheight;
-dom_string *corestring_dom_marginwidth;
-dom_string *corestring_dom_media;
-dom_string *corestring_dom_message;
-dom_string *corestring_dom_mousedown;
-dom_string *corestring_dom_mousemove;
-dom_string *corestring_dom_mouseout;
-dom_string *corestring_dom_mouseover;
-dom_string *corestring_dom_mouseup;
-dom_string *corestring_dom_mousewheel;
-dom_string *corestring_dom_name;
-dom_string *corestring_dom_nohref;
-dom_string *corestring_dom_noresize;
-dom_string *corestring_dom_nowrap;
-dom_string *corestring_dom_offline;
-dom_string *corestring_dom_online;
-dom_string *corestring_dom_pagehide;
-dom_string *corestring_dom_pageshow;
-dom_string *corestring_dom_pause;
-dom_string *corestring_dom_play;
-dom_string *corestring_dom_playing;
-dom_string *corestring_dom_popstate;
-dom_string *corestring_dom_progress;
-dom_string *corestring_dom_ratechange;
-dom_string *corestring_dom_readystatechange;
-dom_string *corestring_dom_rect;
-dom_string *corestring_dom_rel;
-dom_string *corestring_dom_reset;
-dom_string *corestring_dom_resize;
-dom_string *corestring_dom_rows;
-dom_string *corestring_dom_rowspan;
-dom_string *corestring_dom_scroll;
-dom_string *corestring_dom_scrolling;
-dom_string *corestring_dom_seeked;
-dom_string *corestring_dom_seeking;
-dom_string *corestring_dom_select;
-dom_string *corestring_dom_selected;
-dom_string *corestring_dom_shape;
-dom_string *corestring_dom_show;
-dom_string *corestring_dom_size;
-dom_string *corestring_dom_sizes;
-dom_string *corestring_dom_src;
-dom_string *corestring_dom_stalled;
-dom_string *corestring_dom_storage;
-dom_string *corestring_dom_style;
-dom_string *corestring_dom_submit;
-dom_string *corestring_dom_suspend;
-dom_string *corestring_dom_target;
-dom_string *corestring_dom_text;
-dom_string *corestring_dom_text_javascript;
-dom_string *corestring_dom_timeupdate;
-dom_string *corestring_dom_title;
-dom_string *corestring_dom_type;
-dom_string *corestring_dom_unload;
-dom_string *corestring_dom_valign;
-dom_string *corestring_dom_value;
-dom_string *corestring_dom_vlink;
-dom_string *corestring_dom_volumechange;
-dom_string *corestring_dom_vspace;
-dom_string *corestring_dom_waiting;
-dom_string *corestring_dom_width;
-dom_string *corestring_dom_BUTTON;
-dom_string *corestring_dom_INPUT;
-dom_string *corestring_dom_SELECT;
-dom_string *corestring_dom_TEXTAREA;
-dom_string *corestring_dom_BODY;
-dom_string *corestring_dom_HEAD;
-dom_string *corestring_dom_html_namespace;
-dom_string *corestring_dom_button;
-dom_string *corestring_dom_image;
-dom_string *corestring_dom_radio;
-dom_string *corestring_dom_checkbox;
-dom_string *corestring_dom_file;
-dom_string *corestring_dom_on;
-dom_string *corestring_dom_onblur;
-dom_string *corestring_dom_onerror;
-dom_string *corestring_dom_onfocus;
-dom_string *corestring_dom_onload;
-dom_string *corestring_dom_onresize;
-dom_string *corestring_dom_onscroll;
-dom_string *corestring_dom_autocomplete;
-dom_string *corestring_dom_autocompleteerror;
-dom_string *corestring_dom_dragexit;
-dom_string *corestring_dom_mouseenter;
-dom_string *corestring_dom_mouseleave;
-dom_string *corestring_dom_wheel;
-dom_string *corestring_dom_sort;
-dom_string *corestring_dom_toggle;
-dom_string *corestring_dom___ns_key_box_node_data;
-dom_string *corestring_dom___ns_key_libcss_node_data;
-dom_string *corestring_dom___ns_key_file_name_node_data;
-dom_string *corestring_dom___ns_key_image_coords_node_data;
-dom_string *corestring_dom___ns_key_html_content_data;
-
-/* nsurl URLs */
-nsurl *corestring_nsurl_about_blank;
-
-/*
- * Free the core strings
- */
-void corestrings_fini(void)
+/* define corestrings */
+#define CORESTRING_LWC_VALUE(NAME,VALUE) lwc_string *corestring_lwc_##NAME
+#define CORESTRING_DOM_VALUE(NAME,VALUE) dom_string *corestring_dom_##NAME
+#define CORESTRING_NSURL(NAME,VALUE) nsurl *corestring_nsurl_##NAME
+#include "utils/corestringlist.h"
+#undef CORESTRING_LWC_VALUE
+#undef CORESTRING_DOM_VALUE
+#undef CORESTRING_NSURL
+
+/* exported interface documented in utils/corestrings.h */
+nserror corestrings_fini(void)
{
-#define CSS_LWC_STRING_UNREF(NAME) \
+#define CORESTRING_LWC_VALUE(NAME,VALUE) \
do { \
if (corestring_lwc_##NAME != NULL) { \
lwc_string_unref(corestring_lwc_##NAME); \
@@ -307,107 +47,7 @@ void corestrings_fini(void)
} \
} while (0)
- CSS_LWC_STRING_UNREF(a);
- CSS_LWC_STRING_UNREF(about);
- CSS_LWC_STRING_UNREF(abscenter);
- CSS_LWC_STRING_UNREF(absmiddle);
- CSS_LWC_STRING_UNREF(align);
- CSS_LWC_STRING_UNREF(applet);
- CSS_LWC_STRING_UNREF(base);
- CSS_LWC_STRING_UNREF(baseline);
- CSS_LWC_STRING_UNREF(body);
- CSS_LWC_STRING_UNREF(bottom);
- CSS_LWC_STRING_UNREF(button);
- CSS_LWC_STRING_UNREF(caption);
- CSS_LWC_STRING_UNREF(charset);
- CSS_LWC_STRING_UNREF(center);
- CSS_LWC_STRING_UNREF(checkbox);
- CSS_LWC_STRING_UNREF(circle);
- CSS_LWC_STRING_UNREF(col);
- CSS_LWC_STRING_UNREF(data);
- CSS_LWC_STRING_UNREF(default);
- CSS_LWC_STRING_UNREF(div);
- CSS_LWC_STRING_UNREF(embed);
- CSS_LWC_STRING_UNREF(file);
- CSS_LWC_STRING_UNREF(filename);
- CSS_LWC_STRING_UNREF(font);
- CSS_LWC_STRING_UNREF(frame);
- CSS_LWC_STRING_UNREF(frameset);
- CSS_LWC_STRING_UNREF(h1);
- CSS_LWC_STRING_UNREF(h2);
- CSS_LWC_STRING_UNREF(h3);
- CSS_LWC_STRING_UNREF(h4);
- CSS_LWC_STRING_UNREF(h5);
- CSS_LWC_STRING_UNREF(h6);
- CSS_LWC_STRING_UNREF(head);
- CSS_LWC_STRING_UNREF(hidden);
- CSS_LWC_STRING_UNREF(hr);
- CSS_LWC_STRING_UNREF(html);
- CSS_LWC_STRING_UNREF(http);
- CSS_LWC_STRING_UNREF(https);
- CSS_LWC_STRING_UNREF(icon);
- CSS_LWC_STRING_UNREF(iframe);
- CSS_LWC_STRING_UNREF(image);
- CSS_LWC_STRING_UNREF(img);
- CSS_LWC_STRING_UNREF(input);
- CSS_LWC_STRING_UNREF(javascript);
- CSS_LWC_STRING_UNREF(justify);
- CSS_LWC_STRING_UNREF(left);
- CSS_LWC_STRING_UNREF(li);
- CSS_LWC_STRING_UNREF(link);
- CSS_LWC_STRING_UNREF(mailto);
- CSS_LWC_STRING_UNREF(meta);
- CSS_LWC_STRING_UNREF(middle);
- CSS_LWC_STRING_UNREF(multipart_form_data);
- CSS_LWC_STRING_UNREF(no);
- CSS_LWC_STRING_UNREF(noscript);
- CSS_LWC_STRING_UNREF(object);
- CSS_LWC_STRING_UNREF(optgroup);
- CSS_LWC_STRING_UNREF(option);
- CSS_LWC_STRING_UNREF(p);
- CSS_LWC_STRING_UNREF(param);
- CSS_LWC_STRING_UNREF(password);
- CSS_LWC_STRING_UNREF(poly);
- CSS_LWC_STRING_UNREF(polygon);
- CSS_LWC_STRING_UNREF(post);
- CSS_LWC_STRING_UNREF(radio);
- CSS_LWC_STRING_UNREF(rect);
- CSS_LWC_STRING_UNREF(rectangle);
- CSS_LWC_STRING_UNREF(refresh);
- CSS_LWC_STRING_UNREF(reset);
- CSS_LWC_STRING_UNREF(resource);
- CSS_LWC_STRING_UNREF(right);
- CSS_LWC_STRING_UNREF(search);
- CSS_LWC_STRING_UNREF(select);
- CSS_LWC_STRING_UNREF(shortcut_icon);
- CSS_LWC_STRING_UNREF(src);
- CSS_LWC_STRING_UNREF(style);
- CSS_LWC_STRING_UNREF(submit);
- CSS_LWC_STRING_UNREF(table);
- CSS_LWC_STRING_UNREF(tbody);
- CSS_LWC_STRING_UNREF(td);
- CSS_LWC_STRING_UNREF(text);
- CSS_LWC_STRING_UNREF(textarea);
- CSS_LWC_STRING_UNREF(texttop);
- CSS_LWC_STRING_UNREF(text_css);
- CSS_LWC_STRING_UNREF(tfoot);
- CSS_LWC_STRING_UNREF(th);
- CSS_LWC_STRING_UNREF(thead);
- CSS_LWC_STRING_UNREF(title);
- CSS_LWC_STRING_UNREF(top);
- CSS_LWC_STRING_UNREF(tr);
- CSS_LWC_STRING_UNREF(ul);
- CSS_LWC_STRING_UNREF(url);
- CSS_LWC_STRING_UNREF(yes);
- CSS_LWC_STRING_UNREF(_blank);
- CSS_LWC_STRING_UNREF(_parent);
- CSS_LWC_STRING_UNREF(_self);
- CSS_LWC_STRING_UNREF(_top);
- CSS_LWC_STRING_UNREF(slash_);
-
-#undef CSS_LWC_STRING_UNREF
-
-#define CSS_DOM_STRING_UNREF(NAME) \
+#define CORESTRING_DOM_VALUE(NAME,VALUE) \
do { \
if (corestring_dom_##NAME != NULL) { \
dom_string_unref(corestring_dom_##NAME); \
@@ -415,547 +55,72 @@ void corestrings_fini(void)
} \
} while (0)
- CSS_DOM_STRING_UNREF(a);
- CSS_DOM_STRING_UNREF(abort);
- CSS_DOM_STRING_UNREF(afterprint);
- CSS_DOM_STRING_UNREF(align);
- CSS_DOM_STRING_UNREF(alt);
- CSS_DOM_STRING_UNREF(area);
- CSS_DOM_STRING_UNREF(async);
- CSS_DOM_STRING_UNREF(background);
- CSS_DOM_STRING_UNREF(beforeprint);
- CSS_DOM_STRING_UNREF(beforeunload);
- CSS_DOM_STRING_UNREF(bgcolor);
- CSS_DOM_STRING_UNREF(blur);
- CSS_DOM_STRING_UNREF(border);
- CSS_DOM_STRING_UNREF(bordercolor);
- CSS_DOM_STRING_UNREF(cancel);
- CSS_DOM_STRING_UNREF(canplay);
- CSS_DOM_STRING_UNREF(canplaythrough);
- CSS_DOM_STRING_UNREF(cellpadding);
- CSS_DOM_STRING_UNREF(cellspacing);
- CSS_DOM_STRING_UNREF(change);
- CSS_DOM_STRING_UNREF(charset);
- CSS_DOM_STRING_UNREF(class);
- CSS_DOM_STRING_UNREF(classid);
- CSS_DOM_STRING_UNREF(click);
- CSS_DOM_STRING_UNREF(close);
- CSS_DOM_STRING_UNREF(codebase);
- CSS_DOM_STRING_UNREF(color);
- CSS_DOM_STRING_UNREF(cols);
- CSS_DOM_STRING_UNREF(colspan);
- CSS_DOM_STRING_UNREF(content);
- CSS_DOM_STRING_UNREF(contextmenu);
- CSS_DOM_STRING_UNREF(coords);
- CSS_DOM_STRING_UNREF(cuechange);
- CSS_DOM_STRING_UNREF(data);
- CSS_DOM_STRING_UNREF(dblclick);
- CSS_DOM_STRING_UNREF(defer);
- CSS_DOM_STRING_UNREF(DOMAttrModified);
- CSS_DOM_STRING_UNREF(DOMNodeInserted);
- CSS_DOM_STRING_UNREF(DOMNodeInsertedIntoDocument);
- CSS_DOM_STRING_UNREF(DOMSubtreeModified);
- CSS_DOM_STRING_UNREF(drag);
- CSS_DOM_STRING_UNREF(dragend);
- CSS_DOM_STRING_UNREF(dragenter);
- CSS_DOM_STRING_UNREF(dragleave);
- CSS_DOM_STRING_UNREF(dragover);
- CSS_DOM_STRING_UNREF(dragstart);
- CSS_DOM_STRING_UNREF(drop);
- CSS_DOM_STRING_UNREF(durationchange);
- CSS_DOM_STRING_UNREF(emptied);
- CSS_DOM_STRING_UNREF(ended);
- CSS_DOM_STRING_UNREF(error);
- CSS_DOM_STRING_UNREF(focus);
- CSS_DOM_STRING_UNREF(frameborder);
- CSS_DOM_STRING_UNREF(hashchange);
- CSS_DOM_STRING_UNREF(height);
- CSS_DOM_STRING_UNREF(href);
- CSS_DOM_STRING_UNREF(hreflang);
- CSS_DOM_STRING_UNREF(hspace);
- CSS_DOM_STRING_UNREF(http_equiv);
- CSS_DOM_STRING_UNREF(id);
- CSS_DOM_STRING_UNREF(input);
- CSS_DOM_STRING_UNREF(invalid);
- CSS_DOM_STRING_UNREF(keydown);
- CSS_DOM_STRING_UNREF(keypress);
- CSS_DOM_STRING_UNREF(keyup);
- CSS_DOM_STRING_UNREF(link);
- CSS_DOM_STRING_UNREF(load);
- CSS_DOM_STRING_UNREF(loadeddata);
- CSS_DOM_STRING_UNREF(loadedmetadata);
- CSS_DOM_STRING_UNREF(loadstart);
- CSS_DOM_STRING_UNREF(map);
- CSS_DOM_STRING_UNREF(marginheight);
- CSS_DOM_STRING_UNREF(marginwidth);
- CSS_DOM_STRING_UNREF(media);
- CSS_DOM_STRING_UNREF(message);
- CSS_DOM_STRING_UNREF(mousedown);
- CSS_DOM_STRING_UNREF(mousemove);
- CSS_DOM_STRING_UNREF(mouseout);
- CSS_DOM_STRING_UNREF(mouseover);
- CSS_DOM_STRING_UNREF(mouseup);
- CSS_DOM_STRING_UNREF(mousewheel);
- CSS_DOM_STRING_UNREF(name);
- CSS_DOM_STRING_UNREF(nohref);
- CSS_DOM_STRING_UNREF(noresize);
- CSS_DOM_STRING_UNREF(nowrap);
- CSS_DOM_STRING_UNREF(offline);
- CSS_DOM_STRING_UNREF(online);
- CSS_DOM_STRING_UNREF(pagehide);
- CSS_DOM_STRING_UNREF(pageshow);
- CSS_DOM_STRING_UNREF(pause);
- CSS_DOM_STRING_UNREF(play);
- CSS_DOM_STRING_UNREF(playing);
- CSS_DOM_STRING_UNREF(popstate);
- CSS_DOM_STRING_UNREF(progress);
- CSS_DOM_STRING_UNREF(ratechange);
- CSS_DOM_STRING_UNREF(readystatechange);
- CSS_DOM_STRING_UNREF(rect);
- CSS_DOM_STRING_UNREF(rel);
- CSS_DOM_STRING_UNREF(reset);
- CSS_DOM_STRING_UNREF(resize);
- CSS_DOM_STRING_UNREF(rows);
- CSS_DOM_STRING_UNREF(rowspan);
- CSS_DOM_STRING_UNREF(scroll);
- CSS_DOM_STRING_UNREF(scrolling);
- CSS_DOM_STRING_UNREF(seeked);
- CSS_DOM_STRING_UNREF(seeking);
- CSS_DOM_STRING_UNREF(select);
- CSS_DOM_STRING_UNREF(selected);
- CSS_DOM_STRING_UNREF(shape);
- CSS_DOM_STRING_UNREF(show);
- CSS_DOM_STRING_UNREF(size);
- CSS_DOM_STRING_UNREF(sizes);
- CSS_DOM_STRING_UNREF(src);
- CSS_DOM_STRING_UNREF(stalled);
- CSS_DOM_STRING_UNREF(storage);
- CSS_DOM_STRING_UNREF(style);
- CSS_DOM_STRING_UNREF(submit);
- CSS_DOM_STRING_UNREF(suspend);
- CSS_DOM_STRING_UNREF(target);
- CSS_DOM_STRING_UNREF(text);
- CSS_DOM_STRING_UNREF(text_javascript);
- CSS_DOM_STRING_UNREF(timeupdate);
- CSS_DOM_STRING_UNREF(title);
- CSS_DOM_STRING_UNREF(type);
- CSS_DOM_STRING_UNREF(unload);
- CSS_DOM_STRING_UNREF(valign);
- CSS_DOM_STRING_UNREF(value);
- CSS_DOM_STRING_UNREF(vlink);
- CSS_DOM_STRING_UNREF(volumechange);
- CSS_DOM_STRING_UNREF(vspace);
- CSS_DOM_STRING_UNREF(waiting);
- CSS_DOM_STRING_UNREF(width);
- /* DOM node names, not really CSS */
- CSS_DOM_STRING_UNREF(BUTTON);
- CSS_DOM_STRING_UNREF(INPUT);
- CSS_DOM_STRING_UNREF(SELECT);
- CSS_DOM_STRING_UNREF(TEXTAREA);
- CSS_DOM_STRING_UNREF(BODY);
- CSS_DOM_STRING_UNREF(HEAD);
- /* DOM namespaces, not really CSS */
- CSS_DOM_STRING_UNREF(html_namespace);
- /* DOM input types, not really CSS */
- CSS_DOM_STRING_UNREF(button);
- CSS_DOM_STRING_UNREF(image);
- CSS_DOM_STRING_UNREF(radio);
- CSS_DOM_STRING_UNREF(checkbox);
- CSS_DOM_STRING_UNREF(file);
- /* DOM event prefix */
- CSS_DOM_STRING_UNREF(on);
- /* DOM events forwarded from body to window */
- CSS_DOM_STRING_UNREF(onblur);
- CSS_DOM_STRING_UNREF(onerror);
- CSS_DOM_STRING_UNREF(onfocus);
- CSS_DOM_STRING_UNREF(onload);
- CSS_DOM_STRING_UNREF(onresize);
- CSS_DOM_STRING_UNREF(onscroll);
- /* Corestrings used by DOM event registration */
- CSS_DOM_STRING_UNREF(autocomplete);
- CSS_DOM_STRING_UNREF(autocompleteerror);
- CSS_DOM_STRING_UNREF(dragexit);
- CSS_DOM_STRING_UNREF(mouseenter);
- CSS_DOM_STRING_UNREF(mouseleave);
- CSS_DOM_STRING_UNREF(wheel);
- CSS_DOM_STRING_UNREF(sort);
- CSS_DOM_STRING_UNREF(toggle);
- /* DOM userdata keys, not really CSS */
- CSS_DOM_STRING_UNREF(__ns_key_box_node_data);
- CSS_DOM_STRING_UNREF(__ns_key_libcss_node_data);
- CSS_DOM_STRING_UNREF(__ns_key_file_name_node_data);
- CSS_DOM_STRING_UNREF(__ns_key_image_coords_node_data);
- CSS_DOM_STRING_UNREF(__ns_key_html_content_data);
-#undef CSS_DOM_STRING_UNREF
+#define CORESTRING_NSURL(NAME,VALUE) \
+ do { \
+ if (corestring_nsurl_##NAME != NULL) { \
+ nsurl_unref(corestring_nsurl_##NAME); \
+ corestring_nsurl_##NAME = NULL; \
+ } \
+ } while (0)
+
+
+#include "utils/corestringlist.h"
- /* nsurl URLs */
- if (corestring_nsurl_about_blank != NULL) {
- nsurl_unref(corestring_nsurl_about_blank);
- corestring_nsurl_about_blank = NULL;
- }
+#undef CORESTRING_LWC_VALUE
+#undef CORESTRING_DOM_VALUE
+#undef CORESTRING_NSURL
+
+ return NSERROR_OK;
}
-/*
- * Create the core strings
- */
+/* exported interface documented in utils/corestrings.h */
nserror corestrings_init(void)
{
lwc_error lerror;
nserror error;
dom_exception exc;
-#define CSS_LWC_STRING_INTERN(NAME) \
+#define CORESTRING_LWC_VALUE(NAME,VALUE) \
do { \
lerror = lwc_intern_string( \
- (const char *)#NAME, \
- sizeof(#NAME) - 1, \
- &corestring_lwc_##NAME ); \
- if ((lerror != lwc_error_ok) || \
- (corestring_lwc_##NAME == NULL)) { \
+ (const char *)VALUE, \
+ sizeof(VALUE) - 1, \
+ &corestring_lwc_##NAME ); \
+ if ((lerror != lwc_error_ok) || \
+ (corestring_lwc_##NAME == NULL)) { \
error = NSERROR_NOMEM; \
goto error; \
} \
} while(0)
- CSS_LWC_STRING_INTERN(a);
- CSS_LWC_STRING_INTERN(about);
- CSS_LWC_STRING_INTERN(abscenter);
- CSS_LWC_STRING_INTERN(absmiddle);
- CSS_LWC_STRING_INTERN(align);
- CSS_LWC_STRING_INTERN(applet);
- CSS_LWC_STRING_INTERN(base);
- CSS_LWC_STRING_INTERN(baseline);
- CSS_LWC_STRING_INTERN(body);
- CSS_LWC_STRING_INTERN(bottom);
- CSS_LWC_STRING_INTERN(button);
- CSS_LWC_STRING_INTERN(caption);
- CSS_LWC_STRING_INTERN(charset);
- CSS_LWC_STRING_INTERN(center);
- CSS_LWC_STRING_INTERN(checkbox);
- CSS_LWC_STRING_INTERN(circle);
- CSS_LWC_STRING_INTERN(col);
- CSS_LWC_STRING_INTERN(data);
- CSS_LWC_STRING_INTERN(default);
- CSS_LWC_STRING_INTERN(div);
- CSS_LWC_STRING_INTERN(embed);
- CSS_LWC_STRING_INTERN(file);
- CSS_LWC_STRING_INTERN(filename);
- CSS_LWC_STRING_INTERN(font);
- CSS_LWC_STRING_INTERN(frame);
- CSS_LWC_STRING_INTERN(frameset);
- CSS_LWC_STRING_INTERN(h1);
- CSS_LWC_STRING_INTERN(h2);
- CSS_LWC_STRING_INTERN(h3);
- CSS_LWC_STRING_INTERN(h4);
- CSS_LWC_STRING_INTERN(h5);
- CSS_LWC_STRING_INTERN(h6);
- CSS_LWC_STRING_INTERN(head);
- CSS_LWC_STRING_INTERN(hidden);
- CSS_LWC_STRING_INTERN(hr);
- CSS_LWC_STRING_INTERN(html);
- CSS_LWC_STRING_INTERN(http);
- CSS_LWC_STRING_INTERN(https);
- CSS_LWC_STRING_INTERN(icon);
- CSS_LWC_STRING_INTERN(iframe);
- CSS_LWC_STRING_INTERN(image);
- CSS_LWC_STRING_INTERN(img);
- CSS_LWC_STRING_INTERN(input);
- CSS_LWC_STRING_INTERN(javascript);
- CSS_LWC_STRING_INTERN(justify);
- CSS_LWC_STRING_INTERN(left);
- CSS_LWC_STRING_INTERN(li);
- CSS_LWC_STRING_INTERN(link);
- CSS_LWC_STRING_INTERN(mailto);
- CSS_LWC_STRING_INTERN(meta);
- CSS_LWC_STRING_INTERN(middle);
- CSS_LWC_STRING_INTERN(no);
- CSS_LWC_STRING_INTERN(noscript);
- CSS_LWC_STRING_INTERN(object);
- CSS_LWC_STRING_INTERN(optgroup);
- CSS_LWC_STRING_INTERN(option);
- CSS_LWC_STRING_INTERN(p);
- CSS_LWC_STRING_INTERN(param);
- CSS_LWC_STRING_INTERN(password);
- CSS_LWC_STRING_INTERN(poly);
- CSS_LWC_STRING_INTERN(polygon);
- CSS_LWC_STRING_INTERN(post);
- CSS_LWC_STRING_INTERN(radio);
- CSS_LWC_STRING_INTERN(rect);
- CSS_LWC_STRING_INTERN(rectangle);
- CSS_LWC_STRING_INTERN(refresh);
- CSS_LWC_STRING_INTERN(reset);
- CSS_LWC_STRING_INTERN(resource);
- CSS_LWC_STRING_INTERN(right);
- CSS_LWC_STRING_INTERN(search);
- CSS_LWC_STRING_INTERN(select);
- CSS_LWC_STRING_INTERN(src);
- CSS_LWC_STRING_INTERN(style);
- CSS_LWC_STRING_INTERN(submit);
- CSS_LWC_STRING_INTERN(table);
- CSS_LWC_STRING_INTERN(tbody);
- CSS_LWC_STRING_INTERN(td);
- CSS_LWC_STRING_INTERN(text);
- CSS_LWC_STRING_INTERN(textarea);
- CSS_LWC_STRING_INTERN(texttop);
- CSS_LWC_STRING_INTERN(tfoot);
- CSS_LWC_STRING_INTERN(th);
- CSS_LWC_STRING_INTERN(thead);
- CSS_LWC_STRING_INTERN(title);
- CSS_LWC_STRING_INTERN(top);
- CSS_LWC_STRING_INTERN(tr);
- CSS_LWC_STRING_INTERN(ul);
- CSS_LWC_STRING_INTERN(url);
- CSS_LWC_STRING_INTERN(yes);
- CSS_LWC_STRING_INTERN(_blank);
- CSS_LWC_STRING_INTERN(_parent);
- CSS_LWC_STRING_INTERN(_self);
- CSS_LWC_STRING_INTERN(_top);
-#undef CSS_LWC_STRING_INTERN
-
-
- lerror = lwc_intern_string("multipart/form-data",
- SLEN("multipart/form-data"),
- &corestring_lwc_multipart_form_data);
- if ((lerror != lwc_error_ok) ||
- (corestring_lwc_multipart_form_data == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
-
- lerror = lwc_intern_string("shortcut icon", SLEN("shortcut icon"),
- &corestring_lwc_shortcut_icon);
- if ((lerror != lwc_error_ok) || (corestring_lwc_shortcut_icon == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
-
- lerror = lwc_intern_string("text/css", SLEN("text/css"),
- &corestring_lwc_text_css);
- if ((lerror != lwc_error_ok) || (corestring_lwc_text_css == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
-
- lerror = lwc_intern_string("/", SLEN("/"),
- &corestring_lwc_slash_);
- if ((lerror != lwc_error_ok) || (corestring_lwc_slash_ == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
-
-
-#define CSS_DOM_STRING_INTERN(NAME) \
+#define CORESTRING_DOM_VALUE(NAME,VALUE) \
do { \
exc = dom_string_create_interned( \
- (const uint8_t *)#NAME, \
- sizeof(#NAME) - 1, \
+ (const uint8_t *)VALUE, \
+ sizeof(VALUE) - 1, \
&corestring_dom_##NAME ); \
- if ((exc != DOM_NO_ERR) || \
+ if ((exc != DOM_NO_ERR) || \
(corestring_dom_##NAME == NULL)) { \
error = NSERROR_NOMEM; \
goto error; \
} \
} while(0)
- CSS_DOM_STRING_INTERN(a);
- CSS_DOM_STRING_INTERN(abort);
- CSS_DOM_STRING_INTERN(afterprint);
- CSS_DOM_STRING_INTERN(align);
- CSS_DOM_STRING_INTERN(alt);
- CSS_DOM_STRING_INTERN(area);
- CSS_DOM_STRING_INTERN(async);
- CSS_DOM_STRING_INTERN(background);
- CSS_DOM_STRING_INTERN(beforeprint);
- CSS_DOM_STRING_INTERN(beforeunload);
- CSS_DOM_STRING_INTERN(bgcolor);
- CSS_DOM_STRING_INTERN(blur);
- CSS_DOM_STRING_INTERN(border);
- CSS_DOM_STRING_INTERN(bordercolor);
- CSS_DOM_STRING_INTERN(cancel);
- CSS_DOM_STRING_INTERN(canplay);
- CSS_DOM_STRING_INTERN(canplaythrough);
- CSS_DOM_STRING_INTERN(cellpadding);
- CSS_DOM_STRING_INTERN(cellspacing);
- CSS_DOM_STRING_INTERN(change);
- CSS_DOM_STRING_INTERN(charset);
- CSS_DOM_STRING_INTERN(class);
- CSS_DOM_STRING_INTERN(classid);
- CSS_DOM_STRING_INTERN(click);
- CSS_DOM_STRING_INTERN(close);
- CSS_DOM_STRING_INTERN(codebase);
- CSS_DOM_STRING_INTERN(color);
- CSS_DOM_STRING_INTERN(cols);
- CSS_DOM_STRING_INTERN(colspan);
- CSS_DOM_STRING_INTERN(content);
- CSS_DOM_STRING_INTERN(contextmenu);
- CSS_DOM_STRING_INTERN(coords);
- CSS_DOM_STRING_INTERN(cuechange);
- CSS_DOM_STRING_INTERN(data);
- CSS_DOM_STRING_INTERN(dblclick);
- CSS_DOM_STRING_INTERN(defer);
- CSS_DOM_STRING_INTERN(DOMAttrModified);
- CSS_DOM_STRING_INTERN(DOMNodeInserted);
- CSS_DOM_STRING_INTERN(DOMNodeInsertedIntoDocument);
- CSS_DOM_STRING_INTERN(DOMSubtreeModified);
- CSS_DOM_STRING_INTERN(drag);
- CSS_DOM_STRING_INTERN(dragend);
- CSS_DOM_STRING_INTERN(dragenter);
- CSS_DOM_STRING_INTERN(dragleave);
- CSS_DOM_STRING_INTERN(dragover);
- CSS_DOM_STRING_INTERN(dragstart);
- CSS_DOM_STRING_INTERN(drop);
- CSS_DOM_STRING_INTERN(durationchange);
- CSS_DOM_STRING_INTERN(emptied);
- CSS_DOM_STRING_INTERN(ended);
- CSS_DOM_STRING_INTERN(error);
- CSS_DOM_STRING_INTERN(focus);
- CSS_DOM_STRING_INTERN(frameborder);
- CSS_DOM_STRING_INTERN(hashchange);
- CSS_DOM_STRING_INTERN(height);
- CSS_DOM_STRING_INTERN(href);
- CSS_DOM_STRING_INTERN(hreflang);
- CSS_DOM_STRING_INTERN(hspace);
- /* http-equiv: see below */
- CSS_DOM_STRING_INTERN(id);
- CSS_DOM_STRING_INTERN(input);
- CSS_DOM_STRING_INTERN(invalid);
- CSS_DOM_STRING_INTERN(keydown);
- CSS_DOM_STRING_INTERN(keypress);
- CSS_DOM_STRING_INTERN(keyup);
- CSS_DOM_STRING_INTERN(link);
- CSS_DOM_STRING_INTERN(load);
- CSS_DOM_STRING_INTERN(loadeddata);
- CSS_DOM_STRING_INTERN(loadedmetadata);
- CSS_DOM_STRING_INTERN(loadstart);
- CSS_DOM_STRING_INTERN(map);
- CSS_DOM_STRING_INTERN(marginheight);
- CSS_DOM_STRING_INTERN(marginwidth);
- CSS_DOM_STRING_INTERN(media);
- CSS_DOM_STRING_INTERN(message);
- CSS_DOM_STRING_INTERN(mousedown);
- CSS_DOM_STRING_INTERN(mousemove);
- CSS_DOM_STRING_INTERN(mouseout);
- CSS_DOM_STRING_INTERN(mouseover);
- CSS_DOM_STRING_INTERN(mouseup);
- CSS_DOM_STRING_INTERN(mousewheel);
- CSS_DOM_STRING_INTERN(name);
- CSS_DOM_STRING_INTERN(nohref);
- CSS_DOM_STRING_INTERN(noresize);
- CSS_DOM_STRING_INTERN(nowrap);
- CSS_DOM_STRING_INTERN(offline);
- CSS_DOM_STRING_INTERN(online);
- CSS_DOM_STRING_INTERN(pagehide);
- CSS_DOM_STRING_INTERN(pageshow);
- CSS_DOM_STRING_INTERN(pause);
- CSS_DOM_STRING_INTERN(play);
- CSS_DOM_STRING_INTERN(playing);
- CSS_DOM_STRING_INTERN(popstate);
- CSS_DOM_STRING_INTERN(progress);
- CSS_DOM_STRING_INTERN(ratechange);
- CSS_DOM_STRING_INTERN(readystatechange);
- CSS_DOM_STRING_INTERN(rect);
- CSS_DOM_STRING_INTERN(rel);
- CSS_DOM_STRING_INTERN(reset);
- CSS_DOM_STRING_INTERN(resize);
- CSS_DOM_STRING_INTERN(rows);
- CSS_DOM_STRING_INTERN(rowspan);
- CSS_DOM_STRING_INTERN(scroll);
- CSS_DOM_STRING_INTERN(scrolling);
- CSS_DOM_STRING_INTERN(seeked);
- CSS_DOM_STRING_INTERN(seeking);
- CSS_DOM_STRING_INTERN(select);
- CSS_DOM_STRING_INTERN(selected);
- CSS_DOM_STRING_INTERN(shape);
- CSS_DOM_STRING_INTERN(show);
- CSS_DOM_STRING_INTERN(size);
- CSS_DOM_STRING_INTERN(sizes);
- CSS_DOM_STRING_INTERN(src);
- CSS_DOM_STRING_INTERN(stalled);
- CSS_DOM_STRING_INTERN(storage);
- CSS_DOM_STRING_INTERN(style);
- CSS_DOM_STRING_INTERN(submit);
- CSS_DOM_STRING_INTERN(suspend);
- CSS_DOM_STRING_INTERN(target);
- CSS_DOM_STRING_INTERN(text);
- CSS_DOM_STRING_INTERN(timeupdate);
- CSS_DOM_STRING_INTERN(title);
- CSS_DOM_STRING_INTERN(type);
- CSS_DOM_STRING_INTERN(unload);
- CSS_DOM_STRING_INTERN(valign);
- CSS_DOM_STRING_INTERN(value);
- CSS_DOM_STRING_INTERN(vlink);
- CSS_DOM_STRING_INTERN(volumechange);
- CSS_DOM_STRING_INTERN(vspace);
- CSS_DOM_STRING_INTERN(waiting);
- CSS_DOM_STRING_INTERN(width);
- /* DOM node names, not really CSS */
- CSS_DOM_STRING_INTERN(BUTTON);
- CSS_DOM_STRING_INTERN(INPUT);
- CSS_DOM_STRING_INTERN(SELECT);
- CSS_DOM_STRING_INTERN(TEXTAREA);
- CSS_DOM_STRING_INTERN(BODY);
- CSS_DOM_STRING_INTERN(HEAD);
- /* DOM input types, not really CSS */
- CSS_DOM_STRING_INTERN(button);
- CSS_DOM_STRING_INTERN(image);
- CSS_DOM_STRING_INTERN(radio);
- CSS_DOM_STRING_INTERN(checkbox);
- CSS_DOM_STRING_INTERN(file);
- /* DOM event prefix */
- CSS_DOM_STRING_INTERN(on);
- /* DOM events forwarded from body to window */
- CSS_DOM_STRING_INTERN(onblur);
- CSS_DOM_STRING_INTERN(onerror);
- CSS_DOM_STRING_INTERN(onfocus);
- CSS_DOM_STRING_INTERN(onload);
- CSS_DOM_STRING_INTERN(onresize);
- CSS_DOM_STRING_INTERN(onscroll);
- /* Corestrings used by DOM event registration */
- CSS_DOM_STRING_INTERN(autocomplete);
- CSS_DOM_STRING_INTERN(autocompleteerror);
- CSS_DOM_STRING_INTERN(dragexit);
- CSS_DOM_STRING_INTERN(mouseenter);
- CSS_DOM_STRING_INTERN(mouseleave);
- CSS_DOM_STRING_INTERN(wheel);
- CSS_DOM_STRING_INTERN(sort);
- CSS_DOM_STRING_INTERN(toggle);
- /* DOM userdata keys, not really CSS */
- CSS_DOM_STRING_INTERN(__ns_key_box_node_data);
- CSS_DOM_STRING_INTERN(__ns_key_libcss_node_data);
- CSS_DOM_STRING_INTERN(__ns_key_file_name_node_data);
- CSS_DOM_STRING_INTERN(__ns_key_image_coords_node_data);
- CSS_DOM_STRING_INTERN(__ns_key_html_content_data);
-#undef CSS_DOM_STRING_INTERN
-
- exc = dom_string_create_interned((const uint8_t *) "text/javascript",
- SLEN("text/javascript"),
- &corestring_dom_text_javascript);
- if ((exc != DOM_NO_ERR) || (corestring_dom_text_javascript == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
-
- exc = dom_string_create_interned((const uint8_t *) "http-equiv",
- SLEN("http-equiv"),
- &corestring_dom_http_equiv);
- if ((exc != DOM_NO_ERR) || (corestring_dom_http_equiv == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
+#define CORESTRING_NSURL(NAME,VALUE) \
+ do { \
+ error = nsurl_create(VALUE, \
+ &corestring_nsurl_##NAME); \
+ if (error != NSERROR_OK) { \
+ goto error; \
+ } \
+ } while(0)
- exc = dom_string_create_interned((const uint8_t *) "http://www.w3.org/1999/xhtml",
- SLEN("http://www.w3.org/1999/xhtml"),
- &corestring_dom_html_namespace);
- if ((exc != DOM_NO_ERR) || (corestring_dom_html_namespace == NULL)) {
- error = NSERROR_NOMEM;
- goto error;
- }
+#include "utils/corestringlist.h"
- error = nsurl_create("about:blank", &corestring_nsurl_about_blank);
- if (error != NSERROR_OK) {
- goto error;
- }
+#undef CORESTRING_LWC_VALUE
+#undef CORESTRING_DOM_VALUE
+#undef CORESTRING_NSURL
return NSERROR_OK;
diff --git a/utils/corestrings.h b/utils/corestrings.h
index 88dc2ce3d..e4bf91e58 100644
--- a/utils/corestrings.h
+++ b/utils/corestrings.h
@@ -32,286 +32,32 @@
/** File url prefix length. */
#define FILE_SCHEME_PREFIX_LEN 8
+/**
+ * Initialise the core string tables
+ *
+ * \return NSERROR_OK on success else appropriate error code
+ */
nserror corestrings_init(void);
-void corestrings_fini(void);
-/* lwc_string strings */
-extern lwc_string *corestring_lwc_a;
-extern lwc_string *corestring_lwc_about;
-extern lwc_string *corestring_lwc_abscenter;
-extern lwc_string *corestring_lwc_absmiddle;
-extern lwc_string *corestring_lwc_align;
-extern lwc_string *corestring_lwc_applet;
-extern lwc_string *corestring_lwc_base;
-extern lwc_string *corestring_lwc_baseline;
-extern lwc_string *corestring_lwc_body;
-extern lwc_string *corestring_lwc_bottom;
-extern lwc_string *corestring_lwc_button;
-extern lwc_string *corestring_lwc_caption;
-extern lwc_string *corestring_lwc_center;
-extern lwc_string *corestring_lwc_charset;
-extern lwc_string *corestring_lwc_checkbox;
-extern lwc_string *corestring_lwc_circle;
-extern lwc_string *corestring_lwc_col;
-extern lwc_string *corestring_lwc_data;
-extern lwc_string *corestring_lwc_default;
-extern lwc_string *corestring_lwc_div;
-extern lwc_string *corestring_lwc_embed;
-extern lwc_string *corestring_lwc_file;
-extern lwc_string *corestring_lwc_filename;
-extern lwc_string *corestring_lwc_font;
-extern lwc_string *corestring_lwc_frame;
-extern lwc_string *corestring_lwc_frameset;
-extern lwc_string *corestring_lwc_h1;
-extern lwc_string *corestring_lwc_h2;
-extern lwc_string *corestring_lwc_h3;
-extern lwc_string *corestring_lwc_h4;
-extern lwc_string *corestring_lwc_h5;
-extern lwc_string *corestring_lwc_h6;
-extern lwc_string *corestring_lwc_head;
-extern lwc_string *corestring_lwc_hidden;
-extern lwc_string *corestring_lwc_hr;
-extern lwc_string *corestring_lwc_html;
-extern lwc_string *corestring_lwc_http;
-extern lwc_string *corestring_lwc_https;
-extern lwc_string *corestring_lwc_icon;
-extern lwc_string *corestring_lwc_iframe;
-extern lwc_string *corestring_lwc_image;
-extern lwc_string *corestring_lwc_img;
-extern lwc_string *corestring_lwc_input;
-extern lwc_string *corestring_lwc_javascript;
-extern lwc_string *corestring_lwc_justify;
-extern lwc_string *corestring_lwc_left;
-extern lwc_string *corestring_lwc_li;
-extern lwc_string *corestring_lwc_link;
-extern lwc_string *corestring_lwc_mailto;
-extern lwc_string *corestring_lwc_meta;
-extern lwc_string *corestring_lwc_middle;
-extern lwc_string *corestring_lwc_multipart_form_data; /* multipart/form-data */
-extern lwc_string *corestring_lwc_no;
-extern lwc_string *corestring_lwc_noscript;
-extern lwc_string *corestring_lwc_object;
-extern lwc_string *corestring_lwc_optgroup;
-extern lwc_string *corestring_lwc_option;
-extern lwc_string *corestring_lwc_p;
-extern lwc_string *corestring_lwc_param;
-extern lwc_string *corestring_lwc_password;
-extern lwc_string *corestring_lwc_poly;
-extern lwc_string *corestring_lwc_polygon;
-extern lwc_string *corestring_lwc_post;
-extern lwc_string *corestring_lwc_radio;
-extern lwc_string *corestring_lwc_rect;
-extern lwc_string *corestring_lwc_rectangle;
-extern lwc_string *corestring_lwc_refresh;
-extern lwc_string *corestring_lwc_reset;
-extern lwc_string *corestring_lwc_resource;
-extern lwc_string *corestring_lwc_right;
-extern lwc_string *corestring_lwc_search;
-extern lwc_string *corestring_lwc_select;
-extern lwc_string *corestring_lwc_shortcut_icon; /* shortcut icon */
-extern lwc_string *corestring_lwc_src;
-extern lwc_string *corestring_lwc_style;
-extern lwc_string *corestring_lwc_submit;
-extern lwc_string *corestring_lwc_table;
-extern lwc_string *corestring_lwc_tbody;
-extern lwc_string *corestring_lwc_td;
-extern lwc_string *corestring_lwc_text;
-extern lwc_string *corestring_lwc_textarea;
-extern lwc_string *corestring_lwc_texttop;
-extern lwc_string *corestring_lwc_text_css; /* text/css */
-extern lwc_string *corestring_lwc_tfoot;
-extern lwc_string *corestring_lwc_th;
-extern lwc_string *corestring_lwc_thead;
-extern lwc_string *corestring_lwc_title;
-extern lwc_string *corestring_lwc_top;
-extern lwc_string *corestring_lwc_tr;
-extern lwc_string *corestring_lwc_ul;
-extern lwc_string *corestring_lwc_url;
-extern lwc_string *corestring_lwc_yes;
-extern lwc_string *corestring_lwc__blank;
-extern lwc_string *corestring_lwc__parent;
-extern lwc_string *corestring_lwc__self;
-extern lwc_string *corestring_lwc__top;
-extern lwc_string *corestring_lwc_slash_; /* / */
+/**
+ * free resources of core string tables.
+ *
+ * \return NSERROR_OK on success else appropriate error code
+ */
+nserror corestrings_fini(void);
struct dom_string;
-/* dom_string strings */
-extern struct dom_string *corestring_dom_a;
-extern struct dom_string *corestring_dom_alt;
-extern struct dom_string *corestring_dom_abort;
-extern struct dom_string *corestring_dom_afterprint;
-extern struct dom_string *corestring_dom_align;
-extern struct dom_string *corestring_dom_area;
-extern struct dom_string *corestring_dom_async;
-extern struct dom_string *corestring_dom_background;
-extern struct dom_string *corestring_dom_beforeprint;
-extern struct dom_string *corestring_dom_beforeunload;
-extern struct dom_string *corestring_dom_bgcolor;
-extern struct dom_string *corestring_dom_blur;
-extern struct dom_string *corestring_dom_border;
-extern struct dom_string *corestring_dom_bordercolor;
-extern struct dom_string *corestring_dom_cancel;
-extern struct dom_string *corestring_dom_canplay;
-extern struct dom_string *corestring_dom_canplaythrough;
-extern struct dom_string *corestring_dom_cellpadding;
-extern struct dom_string *corestring_dom_cellspacing;
-extern struct dom_string *corestring_dom_change;
-extern struct dom_string *corestring_dom_charset;
-extern struct dom_string *corestring_dom_class;
-extern struct dom_string *corestring_dom_classid;
-extern struct dom_string *corestring_dom_click;
-extern struct dom_string *corestring_dom_close;
-extern struct dom_string *corestring_dom_codebase;
-extern struct dom_string *corestring_dom_color;
-extern struct dom_string *corestring_dom_cols;
-extern struct dom_string *corestring_dom_colspan;
-extern struct dom_string *corestring_dom_content;
-extern struct dom_string *corestring_dom_contextmenu;
-extern struct dom_string *corestring_dom_coords;
-extern struct dom_string *corestring_dom_cuechange;
-extern struct dom_string *corestring_dom_data;
-extern struct dom_string *corestring_dom_dblclick;
-extern struct dom_string *corestring_dom_defer;
-extern struct dom_string *corestring_dom_DOMAttrModified;
-extern struct dom_string *corestring_dom_DOMNodeInserted;
-extern struct dom_string *corestring_dom_DOMNodeInsertedIntoDocument;
-extern struct dom_string *corestring_dom_DOMSubtreeModified;
-extern struct dom_string *corestring_dom_drag;
-extern struct dom_string *corestring_dom_dragend;
-extern struct dom_string *corestring_dom_dragenter;
-extern struct dom_string *corestring_dom_dragleave;
-extern struct dom_string *corestring_dom_dragover;
-extern struct dom_string *corestring_dom_dragstart;
-extern struct dom_string *corestring_dom_drop;
-extern struct dom_string *corestring_dom_durationchange;
-extern struct dom_string *corestring_dom_emptied;
-extern struct dom_string *corestring_dom_ended;
-extern struct dom_string *corestring_dom_error;
-extern struct dom_string *corestring_dom_focus;
-extern struct dom_string *corestring_dom_frameborder;
-extern struct dom_string *corestring_dom_hashchange;
-extern struct dom_string *corestring_dom_height;
-extern struct dom_string *corestring_dom_href;
-extern struct dom_string *corestring_dom_hreflang;
-extern struct dom_string *corestring_dom_hspace;
-extern struct dom_string *corestring_dom_http_equiv; /* http-equiv */
-extern struct dom_string *corestring_dom_id;
-extern struct dom_string *corestring_dom_input;
-extern struct dom_string *corestring_dom_invalid;
-extern struct dom_string *corestring_dom_keydown;
-extern struct dom_string *corestring_dom_keypress;
-extern struct dom_string *corestring_dom_keyup;
-extern struct dom_string *corestring_dom_link;
-extern struct dom_string *corestring_dom_load;
-extern struct dom_string *corestring_dom_loadeddata;
-extern struct dom_string *corestring_dom_loadedmetadata;
-extern struct dom_string *corestring_dom_loadstart;
-extern struct dom_string *corestring_dom_map;
-extern struct dom_string *corestring_dom_marginheight;
-extern struct dom_string *corestring_dom_marginwidth;
-extern struct dom_string *corestring_dom_media;
-extern struct dom_string *corestring_dom_message;
-extern struct dom_string *corestring_dom_mousedown;
-extern struct dom_string *corestring_dom_mousemove;
-extern struct dom_string *corestring_dom_mouseout;
-extern struct dom_string *corestring_dom_mouseover;
-extern struct dom_string *corestring_dom_mouseup;
-extern struct dom_string *corestring_dom_mousewheel;
-extern struct dom_string *corestring_dom_name;
-extern struct dom_string *corestring_dom_nohref;
-extern struct dom_string *corestring_dom_noresize;
-extern struct dom_string *corestring_dom_nowrap;
-extern struct dom_string *corestring_dom_offline;
-extern struct dom_string *corestring_dom_online;
-extern struct dom_string *corestring_dom_pagehide;
-extern struct dom_string *corestring_dom_pageshow;
-extern struct dom_string *corestring_dom_pause;
-extern struct dom_string *corestring_dom_play;
-extern struct dom_string *corestring_dom_playing;
-extern struct dom_string *corestring_dom_popstate;
-extern struct dom_string *corestring_dom_progress;
-extern struct dom_string *corestring_dom_ratechange;
-extern struct dom_string *corestring_dom_readystatechange;
-extern struct dom_string *corestring_dom_rect;
-extern struct dom_string *corestring_dom_rel;
-extern struct dom_string *corestring_dom_reset;
-extern struct dom_string *corestring_dom_resize;
-extern struct dom_string *corestring_dom_rows;
-extern struct dom_string *corestring_dom_rowspan;
-extern struct dom_string *corestring_dom_scroll;
-extern struct dom_string *corestring_dom_scrolling;
-extern struct dom_string *corestring_dom_seeked;
-extern struct dom_string *corestring_dom_seeking;
-extern struct dom_string *corestring_dom_select;
-extern struct dom_string *corestring_dom_selected;
-extern struct dom_string *corestring_dom_shape;
-extern struct dom_string *corestring_dom_show;
-extern struct dom_string *corestring_dom_size;
-extern struct dom_string *corestring_dom_sizes;
-extern struct dom_string *corestring_dom_src;
-extern struct dom_string *corestring_dom_stalled;
-extern struct dom_string *corestring_dom_storage;
-extern struct dom_string *corestring_dom_style;
-extern struct dom_string *corestring_dom_submit;
-extern struct dom_string *corestring_dom_suspend;
-extern struct dom_string *corestring_dom_target;
-extern struct dom_string *corestring_dom_text;
-extern struct dom_string *corestring_dom_text_javascript; /* text/javascript */
-extern struct dom_string *corestring_dom_timeupdate;
-extern struct dom_string *corestring_dom_title;
-extern struct dom_string *corestring_dom_type;
-extern struct dom_string *corestring_dom_unload;
-extern struct dom_string *corestring_dom_valign;
-extern struct dom_string *corestring_dom_value;
-extern struct dom_string *corestring_dom_vlink;
-extern struct dom_string *corestring_dom_volumechange;
-extern struct dom_string *corestring_dom_vspace;
-extern struct dom_string *corestring_dom_waiting;
-extern struct dom_string *corestring_dom_width;
-/* DOM node types */
-extern struct dom_string *corestring_dom_BUTTON;
-extern struct dom_string *corestring_dom_INPUT;
-extern struct dom_string *corestring_dom_SELECT;
-extern struct dom_string *corestring_dom_TEXTAREA;
-extern struct dom_string *corestring_dom_BODY;
-extern struct dom_string *corestring_dom_HEAD;
-/* DOM namespaces */
-extern struct dom_string *corestring_dom_html_namespace;
-/* DOM input node types */
-extern struct dom_string *corestring_dom_button;
-/* extern struct dom_string *corestring_dom_submit; */
-/* extern struct dom_string *corestring_dom_reset; */
-extern struct dom_string *corestring_dom_image;
-extern struct dom_string *corestring_dom_radio;
-extern struct dom_string *corestring_dom_checkbox;
-extern struct dom_string *corestring_dom_file;
-/* Event prefix */
-extern struct dom_string *corestring_dom_on;
-/* These are the event attributes which forward from body to window */
-extern struct dom_string *corestring_dom_onblur;
-extern struct dom_string *corestring_dom_onerror;
-extern struct dom_string *corestring_dom_onfocus;
-extern struct dom_string *corestring_dom_onload;
-extern struct dom_string *corestring_dom_onresize;
-extern struct dom_string *corestring_dom_onscroll;
-/* Corestrings used by DOM event registration */
-extern struct dom_string *corestring_dom_autocomplete;
-extern struct dom_string *corestring_dom_autocompleteerror;
-extern struct dom_string *corestring_dom_dragexit;
-extern struct dom_string *corestring_dom_mouseenter;
-extern struct dom_string *corestring_dom_mouseleave;
-extern struct dom_string *corestring_dom_wheel;
-extern struct dom_string *corestring_dom_sort;
-extern struct dom_string *corestring_dom_toggle;
-/* DOM userdata keys */
-extern struct dom_string *corestring_dom___ns_key_box_node_data;
-extern struct dom_string *corestring_dom___ns_key_libcss_node_data;
-extern struct dom_string *corestring_dom___ns_key_file_name_node_data;
-extern struct dom_string *corestring_dom___ns_key_image_coords_node_data;
-extern struct dom_string *corestring_dom___ns_key_html_content_data;
-
-/* URLs */
-extern struct nsurl *corestring_nsurl_about_blank;
+/* declare corestrings */
+#define CORESTRING_LWC_VALUE(NAME,VALUE) \
+ extern lwc_string *corestring_lwc_##NAME
+#define CORESTRING_DOM_VALUE(NAME,VALUE) \
+ extern struct dom_string *corestring_dom_##NAME
+#define CORESTRING_NSURL(NAME,VALUE) \
+ extern struct nsurl *corestring_nsurl_##NAME
+#include "utils/corestringlist.h"
+#undef CORESTRING_LWC_VALUE
+#undef CORESTRING_DOM_VALUE
+#undef CORESTRING_NSURL
#endif
diff --git a/utils/errors.h b/utils/errors.h
index b9e157c66..9a0a9bc04 100644
--- a/utils/errors.h
+++ b/utils/errors.h
@@ -27,58 +27,37 @@
* Enumeration of error codes
*/
typedef enum {
- NSERROR_OK, /**< No error */
-
- NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */
-
- NSERROR_NOMEM, /**< Memory exhaustion */
-
- NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
-
- NSERROR_NOT_FOUND, /**< Requested item not found */
-
- NSERROR_NOT_DIRECTORY, /**< Missing directory */
-
- NSERROR_SAVE_FAILED, /**< Failed to save data */
-
- NSERROR_CLONE_FAILED, /**< Failed to clone handle */
-
- NSERROR_INIT_FAILED, /**< Initialisation failed */
-
- NSERROR_MNG_ERROR, /**< An MNG error occurred */
-
- NSERROR_BAD_ENCODING, /**< The character set is unknown */
-
- NSERROR_NEED_DATA, /**< More data needed */
-
- NSERROR_ENCODING_CHANGE, /**< The character changed */
-
- NSERROR_BAD_PARAMETER, /**< Bad Parameter */
-
- NSERROR_INVALID, /**< Invalid data */
-
- NSERROR_BOX_CONVERT, /**< Box conversion failed */
-
- NSERROR_STOPPED, /**< Content conversion stopped */
-
- NSERROR_DOM, /**< DOM call returned error */
-
- NSERROR_CSS, /**< CSS call returned error */
-
+ NSERROR_OK, /**< No error */
+ NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */
+ NSERROR_NOMEM, /**< Memory exhaustion */
+ NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
+ NSERROR_NOT_FOUND, /**< Requested item not found */
+ NSERROR_NOT_DIRECTORY, /**< Missing directory */
+ NSERROR_SAVE_FAILED, /**< Failed to save data */
+ NSERROR_CLONE_FAILED, /**< Failed to clone handle */
+ NSERROR_INIT_FAILED, /**< Initialisation failed */
+ NSERROR_BMP_ERROR, /**< A BMP error occurred */
+ NSERROR_GIF_ERROR, /**< A GIF error occurred */
+ NSERROR_ICO_ERROR, /**< A ICO error occurred */
+ NSERROR_PNG_ERROR, /**< A PNG error occurred */
+ NSERROR_SPRITE_ERROR, /**< A RISC OS Sprite error occurred */
+ NSERROR_SVG_ERROR, /**< A SVG error occurred */
+ NSERROR_BAD_ENCODING, /**< The character set is unknown */
+ NSERROR_NEED_DATA, /**< More data needed */
+ NSERROR_ENCODING_CHANGE, /**< The character changed */
+ NSERROR_BAD_PARAMETER, /**< Bad Parameter */
+ NSERROR_INVALID, /**< Invalid data */
+ NSERROR_BOX_CONVERT, /**< Box conversion failed */
+ NSERROR_STOPPED, /**< Content conversion stopped */
+ NSERROR_DOM, /**< DOM call returned error */
+ NSERROR_CSS, /**< CSS call returned error */
NSERROR_CSS_BASE, /**< CSS base sheet failed */
-
- NSERROR_BAD_URL, /**< Bad URL */
-
- NSERROR_BAD_CONTENT, /**< Bad Content */
-
+ NSERROR_BAD_URL, /**< Bad URL */
+ NSERROR_BAD_CONTENT, /**< Bad Content */
NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */
-
NSERROR_PERMISSION, /**< Permission error */
-
- NSERROR_NOSPACE, /**< Insufficient space */
-
+ NSERROR_NOSPACE, /**< Insufficient space */
NSERROR_BAD_SIZE, /**< Bad size */
-
NSERROR_NOT_IMPLEMENTED, /**< Functionality is not implemented */
} nserror;
diff --git a/utils/filename.c b/utils/filename.c
index 9c95901a1..f0e1bb0f5 100644
--- a/utils/filename.c
+++ b/utils/filename.c
@@ -84,7 +84,8 @@ const char *filename_request(void)
/* no available slots - create a new directory */
dir = filename_create_directory(NULL);
if (dir == NULL) {
- LOG("Failed to create a new directory.");
+ NSLOG(netsurf, INFO,
+ "Failed to create a new directory.");
return NULL;
}
i = 63;
@@ -182,10 +183,12 @@ bool filename_initialise(void)
for (start = directory; *start != '\0'; start++) {
if (*start == '/') {
*start = '\0';
- LOG("Creating \"%s\"", directory);
+ NSLOG(netsurf, INFO, "Creating \"%s\"", directory);
ret = nsmkdir(directory, S_IRWXU);
if (ret != 0 && errno != EEXIST) {
- LOG("Failed to create directory \"%s\"", directory);
+ NSLOG(netsurf, INFO,
+ "Failed to create directory \"%s\"",
+ directory);
free(directory);
return false;
}
@@ -194,7 +197,7 @@ bool filename_initialise(void)
}
}
- LOG("Temporary directory location: %s", directory);
+ NSLOG(netsurf, INFO, "Temporary directory location: %s", directory);
ret = nsmkdir(directory, S_IRWXU);
free(directory);
@@ -269,18 +272,23 @@ bool filename_flush_directory(const char *folder, int depth)
parent = opendir(folder);
while ((entry = readdir(parent))) {
- struct stat statbuf;
+ int written;
+ struct stat statbuf;
/* Ignore '.' and '..' */
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
- snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name);
- child[sizeof(child) - 1] = '\0';
+ written = snprintf(child, sizeof(child), "%s/%s",
+ folder, entry->d_name);
+ if (written == sizeof(child)) {
+ child[sizeof(child) - 1] = '\0';
+ }
if (stat(child, &statbuf) == -1) {
- LOG("Unable to stat %s: %s", child, strerror(errno));
+ NSLOG(netsurf, INFO, "Unable to stat %s: %s", child,
+ strerror(errno));
continue;
}
@@ -348,7 +356,8 @@ bool filename_flush_directory(const char *folder, int depth)
filename_delete_recursive(child);
if (remove(child))
- LOG("Failed to remove '%s'", child);
+ NSLOG(netsurf, INFO, "Failed to remove '%s'",
+ child);
else
changed = true;
} else {
@@ -378,16 +387,22 @@ bool filename_delete_recursive(char *folder)
parent = opendir(folder);
while ((entry = readdir(parent))) {
+ int written;
+
/* Ignore '.' and '..' */
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
- snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name);
- child[sizeof(child) - 1] = '\0';
+ written = snprintf(child, sizeof(child), "%s/%s",
+ folder, entry->d_name);
+ if (written == sizeof(child)) {
+ child[sizeof(child) - 1] = '\0';
+ }
if (stat(child, &statbuf) == -1) {
- LOG("Unable to stat %s: %s", child, strerror(errno));
+ NSLOG(netsurf, INFO, "Unable to stat %s: %s", child,
+ strerror(errno));
continue;
}
@@ -399,7 +414,7 @@ bool filename_delete_recursive(char *folder)
}
if (remove(child)) {
- LOG("Failed to remove '%s'", child);
+ NSLOG(netsurf, INFO, "Failed to remove '%s'", child);
closedir(parent);
return false;
}
@@ -465,7 +480,7 @@ static struct directory *filename_create_directory(const char *prefix)
/* allocate a new directory */
new_dir = malloc(sizeof(struct directory));
if (new_dir == NULL) {
- LOG("No memory for malloc()");
+ NSLOG(netsurf, INFO, "No memory for malloc()");
return NULL;
}
@@ -499,7 +514,9 @@ static struct directory *filename_create_directory(const char *prefix)
* whilst we are running if there is an error, so we
* don't report this yet and try to create the
* structure normally. */
- LOG("Failed to create optimised structure '%s'", filename_directory);
+ NSLOG(netsurf, INFO,
+ "Failed to create optimised structure '%s'",
+ filename_directory);
}
}
@@ -519,7 +536,9 @@ static struct directory *filename_create_directory(const char *prefix)
if (!is_dir(filename_directory)) {
if (nsmkdir(filename_directory, S_IRWXU)) {
- LOG("Failed to create directory '%s'", filename_directory);
+ NSLOG(netsurf, INFO,
+ "Failed to create directory '%s'",
+ filename_directory);
return NULL;
}
}
diff --git a/utils/hashtable.c b/utils/hashtable.c
index af100dfc9..4935d6b3f 100644
--- a/utils/hashtable.c
+++ b/utils/hashtable.c
@@ -28,11 +28,15 @@
* it that has good coverage along side the other tests.
*/
+#include <stdint.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <stdbool.h>
-#include "utils/hashtable.h"
+#include <zlib.h>
+#include <errno.h>
+
#include "utils/log.h"
+#include "utils/hashtable.h"
struct hash_entry {
@@ -46,6 +50,8 @@ struct hash_table {
struct hash_entry **chain;
};
+/** maximum length of line for file or inline add */
+#define LINE_BUFFER_SIZE 512
/**
* Hash a string, returning a 32bit value. The hash algorithm used is
@@ -75,13 +81,182 @@ static inline unsigned int hash_string_fnv(const char *datum, unsigned int *len)
}
+
+/**
+ * process a line of input.
+ *
+ * \param hash The hash table to add the line to
+ * \param ln The line to process
+ * \param lnlen The length of \ln
+ * \return NSERROR_OK on success else NSERROR_INVALID
+ */
+static nserror
+process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
+{
+ uint8_t *key;
+ uint8_t *value;
+ uint8_t *colon;
+
+ key = ln; /* set key to start of line */
+ value = ln + lnlen; /* set value to end of line */
+
+ /* skip leading whitespace */
+ while ((key < value) &&
+ ((*key == ' ') || (*key == '\t'))) {
+ key++;
+ }
+
+ /* empty or comment lines */
+ if ((*key == 0) || (*key == '#')) {
+ return NSERROR_OK;
+ }
+
+ /* find first colon as key/value separator */
+ for (colon = key; colon < value; colon++) {
+ if (*colon == ':') {
+ break;
+ }
+ }
+ if (colon == value) {
+ /* no colon found */
+ return NSERROR_INVALID;
+ }
+
+ *colon = 0; /* terminate key */
+ value = colon + 1;
+
+ if (hash_add(hash, (char *)key, (char *)value) == false) {
+ NSLOG(netsurf, INFO,
+ "Unable to add %s:%s to hash table", ln, value);
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * adds key/value pairs to a hash from a memory area
+ */
+static nserror
+hash_add_inline_plain(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+ uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+ unsigned int slen = 0;
+ nserror res = NSERROR_OK;
+
+ while (size > 0) {
+ s[slen] = *data;
+
+ if (s[slen] == '\n') {
+ s[slen] = 0; /* replace newline with null termination */
+ res = process_line(ht, s, slen);
+ slen = 0;
+ if (res != NSERROR_OK) {
+ break;
+ }
+ } else {
+ slen++;
+ if (slen > sizeof s) {
+ NSLOG(netsurf, INFO, "Overlength line\n");
+ slen = 0;
+ }
+ }
+
+ size--;
+ data++;
+ }
+ if (slen > 0) {
+ s[slen] = 0;
+ res = process_line(ht, s, slen);
+ }
+
+ return res;
+}
+
+/**
+ * adds key/value pairs to a hash from a compressed memory area
+ */
+static nserror
+hash_add_inline_gzip(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+ nserror res;
+ int ret; /* zlib return value */
+ z_stream strm;
+ uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+ size_t used = 0; /* number of bytes in buffer in use */
+ uint8_t *nl;
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ strm.next_in = (uint8_t *)data;
+ strm.avail_in = size;
+
+ ret = inflateInit2(&strm, 32 + MAX_WBITS);
+ if (ret != Z_OK) {
+ NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
+ return NSERROR_INVALID;
+ }
+
+ do {
+ strm.next_out = s + used;
+ strm.avail_out = sizeof(s) - used;
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
+ break;
+ }
+
+ used = sizeof(s) - strm.avail_out;
+ while (used > 0) {
+ /* find nl */
+ for (nl = &s[0]; nl < &s[used]; nl++) {
+ if (*nl == '\n') {
+ break;
+ }
+ }
+ if (nl == &s[used]) {
+ /* no nl found */
+ break;
+ }
+ /* found newline */
+ *nl = 0; /* null terminate line */
+ res = process_line(ht, &s[0], nl - &s[0]);
+ if (res != NSERROR_OK) {
+ inflateEnd(&strm);
+ return res;
+ }
+
+ /* move data down */
+ memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
+ used -= ((nl +1) - &s[0]);
+ }
+ if (used == sizeof(s)) {
+ /* entire buffer used and no newline */
+ NSLOG(netsurf, INFO, "Overlength line");
+ used = 0;
+ }
+ } while (ret != Z_STREAM_END);
+
+ inflateEnd(&strm);
+
+ if (ret != Z_STREAM_END) {
+ NSLOG(netsurf, INFO, "inflate returned %d", ret);
+ return NSERROR_INVALID;
+ }
+ return NSERROR_OK;
+
+}
+
+
/* exported interface documented in utils/hashtable.h */
struct hash_table *hash_create(unsigned int chains)
{
struct hash_table *r = malloc(sizeof(struct hash_table));
if (r == NULL) {
- LOG("Not enough memory for hash table.");
+ NSLOG(netsurf, INFO, "Not enough memory for hash table.");
return NULL;
}
@@ -89,7 +264,8 @@ struct hash_table *hash_create(unsigned int chains)
r->chain = calloc(chains, sizeof(struct hash_entry *));
if (r->chain == NULL) {
- LOG("Not enough memory for %d hash table chains.", chains);
+ NSLOG(netsurf, INFO,
+ "Not enough memory for %d hash table chains.", chains);
free(r);
return NULL;
}
@@ -134,7 +310,7 @@ bool hash_add(struct hash_table *ht, const char *key, const char *value)
e = malloc(sizeof(struct hash_entry));
if (e == NULL) {
- LOG("Not enough memory for hash entry.");
+ NSLOG(netsurf, INFO, "Not enough memory for hash entry.");
return false;
}
@@ -144,7 +320,8 @@ bool hash_add(struct hash_table *ht, const char *key, const char *value)
v = strlen(value) ;
e->pairing = malloc(v + e->key_length + 2);
if (e->pairing == NULL) {
- LOG("Not enough memory for string duplication.");
+ NSLOG(netsurf, INFO,
+ "Not enough memory for string duplication.");
free(e);
return false;
}
@@ -177,3 +354,51 @@ const char *hash_get(struct hash_table *ht, const char *key)
return NULL;
}
+
+
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_file(struct hash_table *ht, const char *path)
+{
+ nserror res = NSERROR_OK;
+ char s[LINE_BUFFER_SIZE]; /* line buffer */
+ gzFile fp; /* compressed file handle */
+
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ fp = gzopen(path, "r");
+ if (!fp) {
+ NSLOG(netsurf, INFO,
+ "Unable to open file \"%.100s\": %s", path,
+ strerror(errno));
+
+ return NSERROR_NOT_FOUND;
+ }
+
+ while (gzgets(fp, s, sizeof s)) {
+ int slen = strlen(s);
+ s[--slen] = 0; /* remove \n at end */
+
+ res = process_line(ht, (uint8_t *)s, slen);
+ if (res != NSERROR_OK) {
+ break;
+ }
+ }
+
+ gzclose(fp);
+
+ return res;
+}
+
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+ if ((data[0]==0x1f) && (data[1] == 0x8b)) {
+ /* gzip header detected */
+ return hash_add_inline_gzip(ht, data, size);
+ }
+ return hash_add_inline_plain(ht, data, size);
+}
diff --git a/utils/hashtable.h b/utils/hashtable.h
index b0e7392c6..b1c0d5c41 100644
--- a/utils/hashtable.h
+++ b/utils/hashtable.h
@@ -29,8 +29,11 @@
struct hash_table;
/**
- * Create a new hash table, and return a context for it. The memory consumption
- * of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
+ * Create a new hash table
+ *
+ * Allocate a new hash table and return a context for it. The memory
+ * consumption of a hash table is approximately 8 + (nchains * 12)
+ * bytes if it is empty.
*
* \param chains Number of chains/buckets this hash table will have. This
* should be a prime number, and ideally a prime number just
@@ -41,18 +44,22 @@ struct hash_table;
struct hash_table *hash_create(unsigned int chains);
/**
- * Destroys a hash table, freeing all memory associated with it.
+ * Destroys a hash table
+ *
+ * Destroy a hash table freeing all memory associated with it.
*
* \param ht Hash table to destroy. After the function returns, this
- * will nolonger be valid.
+ * will no longer be valid.
*/
void hash_destroy(struct hash_table *ht);
/**
- * Adds a key/value pair to a hash table. If the key you're adding is already
- * in the hash table, it does not replace it, but it does take precedent over
- * it. The old key/value pair will be inaccessable but still in memory until
- * hash_destroy() is called on the hash table.
+ * Adds a key/value pair to a hash table.
+ *
+ * If the key you're adding is already in the hash table, it does not
+ * replace it, but it does take precedent over it. The old key/value
+ * pair will be inaccessable but still in memory until hash_destroy()
+ * is called on the hash table.
*
* \param ht The hash table context to add the key/value pair to.
* \param key The key to associate the value with. A copy is made.
@@ -71,4 +78,34 @@ bool hash_add(struct hash_table *ht, const char *key, const char *value);
*/
const char *hash_get(struct hash_table *ht, const char *key);
+/**
+ * Add key/value pairs to a hash table with data from a file
+ *
+ * The file should be formatted as a series of lines terminated with
+ * newline character. Each line should contain a key/value pair
+ * separated by a colon. If a line is empty or starts with a #
+ * character it will be ignored.
+ *
+ * The file may be optionally gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param path Path to file with key/value pairs in.
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_file(struct hash_table *ht, const char *path);
+
+/**
+ * Add key/value pairs to a hash table with data from a memory buffer
+ *
+ * The data format is the same as in hash_add_file() but held in memory
+ *
+ * The data may optionally be gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param data Source of key/value pairs
+ * \param size length of \a data
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t size);
+
#endif
diff --git a/utils/http.h b/utils/http.h
index 173604fb4..00caf8954 100644
--- a/utils/http.h
+++ b/utils/http.h
@@ -29,6 +29,7 @@
#include "utils/http/content-disposition.h"
#include "utils/http/content-type.h"
+#include "utils/http/strict-transport-security.h"
#include "utils/http/www-authenticate.h"
#endif
diff --git a/utils/http/Makefile b/utils/http/Makefile
index 198588bd4..f3bb765f0 100644
--- a/utils/http/Makefile
+++ b/utils/http/Makefile
@@ -1,6 +1,7 @@
# http utils sources
S_HTTP := challenge.c generics.c primitives.c parameter.c \
- content-disposition.c content-type.c www-authenticate.c
+ content-disposition.c content-type.c \
+ strict-transport-security.c www-authenticate.c
-S_HTTP := $(addprefix utils/http/,$(S_HTTP)) \ No newline at end of file
+S_HTTP := $(addprefix utils/http/,$(S_HTTP))
diff --git a/utils/http/challenge.c b/utils/http/challenge.c
index 578532e97..9b85fccbc 100644
--- a/utils/http/challenge.c
+++ b/utils/http/challenge.c
@@ -92,7 +92,7 @@ nserror http__parse_challenge(const char **input, http_challenge **challenge)
http__skip_LWS(&pos);
if (*pos == ',') {
- error = http__item_list_parse(&pos,
+ error = http__item_list_parse(&pos,
http__parse_parameter, first, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(scheme);
diff --git a/utils/http/content-disposition.c b/utils/http/content-disposition.c
index 5d5e94c26..03bd12bd3 100644
--- a/utils/http/content-disposition.c
+++ b/utils/http/content-disposition.c
@@ -45,7 +45,7 @@ nserror http_parse_content_disposition(const char *header_value,
http__skip_LWS(&pos);
if (*pos == ';') {
- error = http__item_list_parse(&pos,
+ error = http__item_list_parse(&pos,
http__parse_parameter, NULL, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(mtype);
diff --git a/utils/http/content-type.c b/utils/http/content-type.c
index f84da8c8e..d4279f512 100644
--- a/utils/http/content-type.c
+++ b/utils/http/content-type.c
@@ -68,7 +68,7 @@ nserror http_parse_content_type(const char *header_value,
http__skip_LWS(&pos);
if (*pos == ';') {
- error = http__item_list_parse(&pos,
+ error = http__item_list_parse(&pos,
http__parse_parameter, NULL, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(subtype);
diff --git a/utils/http/generics.h b/utils/http/generics.h
index 8c391c4af..a5af73458 100644
--- a/utils/http/generics.h
+++ b/utils/http/generics.h
@@ -19,6 +19,8 @@
#ifndef NETSURF_UTILS_HTTP_GENERICS_H_
#define NETSURF_UTILS_HTTP_GENERICS_H_
+#include <stdbool.h>
+
#include "utils/errors.h"
/**
diff --git a/utils/http/strict-transport-security.c b/utils/http/strict-transport-security.c
new file mode 100644
index 000000000..9de610c73
--- /dev/null
+++ b/utils/http/strict-transport-security.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2018 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include "utils/corestrings.h"
+#include "utils/http.h"
+
+#include "utils/http/generics.h"
+#include "utils/http/primitives.h"
+
+/**
+ * Representation of a Strict-Transport-Security
+ */
+struct http_strict_transport_security {
+ uint32_t max_age; /**< Max age (delta seconds) */
+ bool include_sub_domains; /**< Whether subdomains are included */
+};
+
+/**
+ * Representation of a directive
+ */
+typedef struct http_directive {
+ http__item base;
+
+ lwc_string *name; /**< Parameter name */
+ lwc_string *value; /**< Parameter value (optional) */
+} http_directive;
+
+
+static void http_destroy_directive(http_directive *self)
+{
+ lwc_string_unref(self->name);
+ if (self->value != NULL) {
+ lwc_string_unref(self->value);
+ }
+ free(self);
+}
+
+static nserror http__parse_directive(const char **input,
+ http_directive **result)
+{
+ const char *pos = *input;
+ lwc_string *name;
+ lwc_string *value = NULL;
+ http_directive *directive;
+ nserror error;
+
+ /* token [ "=" ( token | quoted-string ) ] */
+
+ error = http__parse_token(&pos, &name);
+ if (error != NSERROR_OK)
+ return error;
+
+ http__skip_LWS(&pos);
+
+ if (*pos == '=') {
+ pos++;
+
+ http__skip_LWS(&pos);
+
+ if (*pos == '"')
+ error = http__parse_quoted_string(&pos, &value);
+ else
+ error = http__parse_token(&pos, &value);
+
+ if (error != NSERROR_OK) {
+ lwc_string_unref(name);
+ return error;
+ }
+ }
+
+ directive = malloc(sizeof(*directive));
+ if (directive == NULL) {
+ if (value != NULL) {
+ lwc_string_unref(value);
+ }
+ lwc_string_unref(name);
+ return NSERROR_NOMEM;
+ }
+
+ HTTP__ITEM_INIT(directive, NULL, http_destroy_directive);
+ directive->name = name;
+ directive->value = value;
+
+ *result = directive;
+ *input = pos;
+
+ return NSERROR_OK;
+}
+
+static void http_directive_list_destroy(http_directive *list)
+{
+ http__item_list_destroy(list);
+}
+
+static nserror http_directive_list_find_item(const http_directive *list,
+ lwc_string *name, lwc_string **value)
+{
+ bool match;
+
+ while (list != NULL) {
+ if (lwc_string_caseless_isequal(name, list->name,
+ &match) == lwc_error_ok && match)
+ break;
+
+ list = (http_directive *) list->base.next;
+ }
+
+ if (list == NULL)
+ return NSERROR_NOT_FOUND;
+
+ if (list->value != NULL) {
+ *value = lwc_string_ref(list->value);
+ } else {
+ *value = NULL;
+ }
+
+ return NSERROR_OK;
+}
+
+static const http_directive *http_directive_list_iterate(
+ const http_directive *cur,
+ lwc_string **name, lwc_string **value)
+{
+ if (cur == NULL)
+ return NULL;
+
+ *name = lwc_string_ref(cur->name);
+ if (cur->value != NULL) {
+ *value = lwc_string_ref(cur->value);
+ } else {
+ *value = NULL;
+ }
+
+ return (http_directive *) cur->base.next;
+}
+
+static uint32_t count(const http_directive *list, lwc_string *key)
+{
+ uint32_t count = 0;
+ bool match;
+
+ while (list != NULL) {
+ if (lwc_string_caseless_isequal(key, list->name,
+ &match) == lwc_error_ok && match) {
+ count++;
+ }
+
+ list = (http_directive *) list->base.next;
+ }
+
+ return count;
+}
+
+static bool check_duplicates(const http_directive *directives)
+{
+ bool result = true;
+ const http_directive *key = directives;
+
+ if (key == NULL) {
+ /* No directives, so there can't be any duplicates */
+ return true;
+ }
+
+ do {
+ lwc_string *name = NULL, *value = NULL;
+
+ key = http_directive_list_iterate(key, &name, &value);
+
+ result &= (count(directives, name) == 1);
+
+ lwc_string_unref(name);
+ if (value != NULL) {
+ lwc_string_unref(value);
+ }
+ } while (key != NULL);
+
+ return result;
+}
+
+static nserror parse_max_age(lwc_string *value, uint32_t *result)
+{
+ const char *pos = lwc_string_data(value);
+ const char *end = pos + lwc_string_length(value);
+ uint32_t val = 0;
+
+ /* 1*DIGIT */
+
+ if (pos == end) {
+ /* Blank value */
+ return NSERROR_NOT_FOUND;
+ }
+
+ while (pos < end) {
+ if ('0' <= *pos && *pos <= '9') {
+ uint32_t nv = val * 10 + (*pos - '0');
+ if (nv < val) {
+ val = UINT_MAX;
+ } else {
+ val = nv;
+ }
+ } else {
+ /* Non-digit */
+ return NSERROR_NOT_FOUND;
+ }
+
+ pos++;
+ }
+
+ *result = val;
+
+ return NSERROR_OK;
+}
+
+/* See strict-transport-security.h for documentation */
+nserror http_parse_strict_transport_security(const char *header_value,
+ http_strict_transport_security **result)
+{
+ const char *pos = header_value;
+ http_strict_transport_security *sts;
+ http_directive *first = NULL;
+ http_directive *directives = NULL;
+ lwc_string *max_age_str = NULL, *isd_str = NULL;
+ uint32_t max_age;
+ bool include_sub_domains = false;
+ nserror error;
+
+ /* directive *( ";" directive ) */
+
+ http__skip_LWS(&pos);
+
+ error = http__parse_directive(&pos, &first);
+ if (error != NSERROR_OK) {
+ return error;
+ }
+
+ http__skip_LWS(&pos);
+
+ if (*pos == ';') {
+ error = http__item_list_parse(&pos,
+ http__parse_directive, first, &directives);
+ if (error != NSERROR_OK) {
+ if (directives != NULL) {
+ http_directive_list_destroy(directives);
+ }
+ return error;
+ }
+ } else {
+ directives = first;
+ }
+
+ /* Each directive must only appear once */
+ if (check_duplicates(directives) == false) {
+ http_directive_list_destroy(directives);
+ return NSERROR_NOT_FOUND;
+ }
+
+ /* max-age is required */
+ error = http_directive_list_find_item(directives,
+ corestring_lwc_max_age, &max_age_str);
+ if (error != NSERROR_OK || max_age_str == NULL) {
+ http_directive_list_destroy(directives);
+ return NSERROR_NOT_FOUND;
+ }
+
+ error = parse_max_age(max_age_str, &max_age);
+ if (error != NSERROR_OK) {
+ lwc_string_unref(max_age_str);
+ http_directive_list_destroy(directives);
+ return NSERROR_NOT_FOUND;
+ }
+ lwc_string_unref(max_age_str);
+
+ /* includeSubDomains is optional and valueless */
+ error = http_directive_list_find_item(directives,
+ corestring_lwc_includesubdomains, &isd_str);
+ if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
+ http_directive_list_destroy(directives);
+ return NSERROR_NOT_FOUND;
+ } else if (error == NSERROR_OK) {
+ if (isd_str != NULL) {
+ /* Present, but not valueless: invalid */
+ lwc_string_unref(isd_str);
+ http_directive_list_destroy(directives);
+ return NSERROR_NOT_FOUND;
+ }
+ include_sub_domains = true;
+ }
+ http_directive_list_destroy(directives);
+
+ sts = malloc(sizeof(*sts));
+ if (sts == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ sts->max_age = max_age;
+ sts->include_sub_domains = include_sub_domains;
+
+ *result = sts;
+
+ return NSERROR_OK;
+}
+
+/* See strict-transport-security.h for documentation */
+void http_strict_transport_security_destroy(
+ http_strict_transport_security *victim)
+{
+ free(victim);
+}
+
+/* See strict-transport-security.h for documentation */
+uint32_t http_strict_transport_security_max_age(
+ http_strict_transport_security *sts)
+{
+ return sts->max_age;
+}
+
+/* See strict-transport-security.h for documentation */
+bool http_strict_transport_security_include_subdomains(
+ http_strict_transport_security *sts)
+{
+ return sts->include_sub_domains;
+}
+
diff --git a/utils/http/strict-transport-security.h b/utils/http/strict-transport-security.h
new file mode 100644
index 000000000..4e52419fc
--- /dev/null
+++ b/utils/http/strict-transport-security.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_STRICT_TRANSPORT_SECURITY_H_
+#define NETSURF_UTILS_HTTP_STRICT_TRANSPORT_SECURITY_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+typedef struct http_strict_transport_security http_strict_transport_security;
+
+/**
+ * Parse an HTTP Strict-Transport-Security header value
+ *
+ * \param header_value Header value to parse
+ * \param result Pointer to location to receive result
+ * \return NSERROR_OK on success,
+ * NSERROR_NOMEM on memory exhaustion,
+ * appropriate error otherwise
+ */
+nserror http_parse_strict_transport_security(const char *header_value,
+ http_strict_transport_security **result);
+
+/**
+ * Destroy a strict transport security object
+ *
+ * \param victim Object to destroy
+ */
+void http_strict_transport_security_destroy(
+ http_strict_transport_security *victim);
+
+/**
+ * Get the value of a strict transport security's max-age
+ *
+ * \param sts Object to inspect
+ * \return Max age, in delta-seconds
+ */
+uint32_t http_strict_transport_security_max_age(
+ http_strict_transport_security *sts);
+
+/**
+ * Get the value of a strict transport security's includeSubDomains flag
+ *
+ * \param sts Object to inspect
+ * \return Whether subdomains should be included
+ */
+bool http_strict_transport_security_include_subdomains(
+ http_strict_transport_security *sts);
+
+#endif
diff --git a/utils/idna.c b/utils/idna.c
index 34cc40f83..572882ecb 100644
--- a/utils/idna.c
+++ b/utils/idna.c
@@ -63,17 +63,17 @@ static nserror punycode_status_to_nserror(enum punycode_status status)
break;
case punycode_bad_input:
- LOG("Bad input");
+ NSLOG(netsurf, INFO, "Bad input");
ret = NSERROR_BAD_ENCODING;
break;
case punycode_big_output:
- LOG("Output too big");
+ NSLOG(netsurf, INFO, "Output too big");
ret = NSERROR_BAD_SIZE;
break;
case punycode_overflow:
- LOG("Overflow");
+ NSLOG(netsurf, INFO, "Overflow");
ret = NSERROR_NOSPACE;
break;
@@ -437,7 +437,8 @@ static bool idna__is_valid(int32_t *label, size_t len)
/* 2. Check characters 3 and 4 are not '--'. */
if ((label[2] == 0x002d) && (label[3] == 0x002d)) {
- LOG("Check failed: characters 2 and 3 are '--'");
+ NSLOG(netsurf, INFO,
+ "Check failed: characters 2 and 3 are '--'");
return false;
}
@@ -447,7 +448,8 @@ static bool idna__is_valid(int32_t *label, size_t len)
if ((unicode_props->category == UTF8PROC_CATEGORY_MN) ||
(unicode_props->category == UTF8PROC_CATEGORY_MC) ||
(unicode_props->category == UTF8PROC_CATEGORY_ME)) {
- LOG("Check failed: character 0 is a combining mark");
+ NSLOG(netsurf, INFO,
+ "Check failed: character 0 is a combining mark");
return false;
}
@@ -456,14 +458,20 @@ static bool idna__is_valid(int32_t *label, size_t len)
/* 4. Check characters not DISALLOWED by RFC5892 */
if (idna_prop == IDNA_P_DISALLOWED) {
- LOG("Check failed: character %" PRIsizet " (%x) is DISALLOWED", i, label[i]);
+ NSLOG(netsurf, INFO,
+ "Check failed: character %"PRIsizet" (%x) is DISALLOWED",
+ i,
+ label[i]);
return false;
}
/* 5. Check CONTEXTJ characters conform to defined rules */
if (idna_prop == IDNA_P_CONTEXTJ) {
if (idna__contextj_rule(label, i, len) == false) {
- LOG("Check failed: character %" PRIsizet " (%x) does not conform to CONTEXTJ rule", i, label[i]);
+ NSLOG(netsurf, INFO,
+ "Check failed: character %"PRIsizet" (%x) does not conform to CONTEXTJ rule",
+ i,
+ label[i]);
return false;
}
}
@@ -472,14 +480,20 @@ static bool idna__is_valid(int32_t *label, size_t len)
/** \todo optionally we can check conformance to this rule */
if (idna_prop == IDNA_P_CONTEXTO) {
if (idna__contexto_rule(label[i]) == false) {
- LOG("Check failed: character %" PRIsizet " (%x) has no CONTEXTO rule defined", i, label[i]);
+ NSLOG(netsurf, INFO,
+ "Check failed: character %"PRIsizet" (%x) has no CONTEXTO rule defined",
+ i,
+ label[i]);
return false;
}
}
/* 7. Check characters are not UNASSIGNED */
if (idna_prop == IDNA_P_UNASSIGNED) {
- LOG("Check failed: character %" PRIsizet " (%x) is UNASSIGNED", i, label[i]);
+ NSLOG(netsurf, INFO,
+ "Check failed: character %"PRIsizet" (%x) is UNASSIGNED",
+ i,
+ label[i]);
return false;
}
@@ -588,7 +602,8 @@ static bool idna__verify(const char *label, size_t len)
return true;
}
- LOG("Re-encoded ACE label %s does not match input", ace);
+ NSLOG(netsurf, INFO, "Re-encoded ACE label %s does not match input",
+ ace);
free(ace);
return false;
@@ -641,7 +656,8 @@ idna_encode(const char *host, size_t len, char **ace_host, size_t *ace_len)
/* This is already a DNS-valid ASCII string */
if ((idna__is_ace(host, label_len) == true) &&
(idna__verify(host, label_len) == false)) {
- LOG("Cannot verify ACE label %s", host);
+ NSLOG(netsurf, INFO,
+ "Cannot verify ACE label %s", host);
return NSERROR_BAD_URL;
}
strncpy(fqdn_p, host, label_len);
diff --git a/utils/jenkins-build.sh b/utils/jenkins-build.sh
index b6ca21dd7..de6c25944 100755
--- a/utils/jenkins-build.sh
+++ b/utils/jenkins-build.sh
@@ -147,6 +147,23 @@ case ${TARGET} in
;;
+ "amigaos3")
+ case ${HOST} in
+ "m68k-unknown-amigaos")
+ ;;
+
+ *)
+ echo "Target \"${TARGET}\" cannot be built on \"${HOST})\""
+ exit 1
+ ;;
+
+ esac
+
+ PKG_SRC=NetSurf_Amiga/netsurf
+ PKG_SFX=.lha
+ ;;
+
+
"atari")
case ${HOST} in
"m68k-atari-mint")
@@ -291,6 +308,11 @@ case ${TARGET} in
export GCCSDK_INSTALL_CROSSBIN=/opt/netsurf/${HOST}/cross/bin
;;
+ "m68k-unknown-amigaos")
+ export GCCSDK_INSTALL_ENV=/opt/netsurf/${HOST}/env
+ export GCCSDK_INSTALL_CROSSBIN=/opt/netsurf/${HOST}/cross/bin
+ ;;
+
*)
echo "Target \"${TARGET}\" cannot be built on \"${HOST})\""
exit 1
@@ -389,6 +411,12 @@ if [ ${HAVE_DISTCC} = "true" ];then
fi
+########### Prepare a Makefile.config ##################
+
+rm -f Makefile.config
+cat > Makefile.config <<EOF
+override NETSURF_LOG_LEVEL := DEBUG
+EOF
########### Build from source ##################
diff --git a/utils/log.c b/utils/log.c
index 15a7a9e75..e267b3179 100644
--- a/utils/log.c
+++ b/utils/log.c
@@ -1,9 +1,5 @@
/*
- * Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
- * Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2004 John Tytgat <joty@netsurf-browser.org>
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -24,6 +20,7 @@
#include <stdio.h>
#include "utils/config.h"
+#include "utils/nsoption.h"
#include "utils/sys_time.h"
#include "utils/utsname.h"
#include "desktop/version.h"
@@ -36,6 +33,154 @@ bool verbose_log = false;
/** The stream to which logging is sent */
static FILE *logfile;
+/** Subtract the `struct timeval' values X and Y
+ *
+ * \param result The timeval structure to store the result in
+ * \param x The first value
+ * \param y The second value
+ * \return 1 if the difference is negative, otherwise 0.
+ */
+static int
+timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec) {
+ int nsec = (int)(y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if ((int)(x->tv_usec - y->tv_usec) > 1000000) {
+ int nsec = (int)(x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_usec is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+/**
+ * Obtain a formatted string suitable for prepending to a log message
+ *
+ * \return formatted string of the time since first log call
+ */
+static const char *nslog_gettime(void)
+{
+ static struct timeval start_tv;
+ static char buff[32];
+
+ struct timeval tv;
+ struct timeval now_tv;
+
+ if (!timerisset(&start_tv)) {
+ gettimeofday(&start_tv, NULL);
+ }
+ gettimeofday(&now_tv, NULL);
+
+ timeval_subtract(&tv, &now_tv, &start_tv);
+
+ snprintf(buff, sizeof(buff),"(%ld.%06ld)",
+ (long)tv.tv_sec, (long)tv.tv_usec);
+
+ return buff;
+}
+
+#ifdef WITH_NSLOG
+
+NSLOG_DEFINE_CATEGORY(netsurf, "NetSurf default logging");
+NSLOG_DEFINE_CATEGORY(llcache, "Low level cache");
+NSLOG_DEFINE_CATEGORY(fetch, "objet fetching");
+NSLOG_DEFINE_CATEGORY(plot, "rendering system");
+NSLOG_DEFINE_CATEGORY(schedule, "scheduler");
+NSLOG_DEFINE_CATEGORY(fbtk, "Framebuffer toolkit");
+NSLOG_DEFINE_CATEGORY(layout, "Layout");
+
+static void
+netsurf_render_log(void *_ctx,
+ nslog_entry_context_t *ctx,
+ const char *fmt,
+ va_list args)
+{
+ fprintf(logfile,
+ "%s %.*s:%i %.*s: ",
+ nslog_gettime(),
+ ctx->filenamelen,
+ ctx->filename,
+ ctx->lineno,
+ ctx->funcnamelen,
+ ctx->funcname);
+
+ vfprintf(logfile, fmt, args);
+
+ /* Log entries aren't newline terminated add one for clarity */
+ fputc('\n', logfile);
+}
+
+/* exported interface documented in utils/log.h */
+nserror
+nslog_set_filter(const char *filter)
+{
+ nslog_error err;
+ nslog_filter_t *filt = NULL;
+
+ err = nslog_filter_from_text(filter, &filt);
+ if (err != NSLOG_NO_ERROR) {
+ if (err == NSLOG_NO_MEMORY)
+ return NSERROR_NOMEM;
+ else
+ return NSERROR_INVALID;
+ }
+
+ err = nslog_filter_set_active(filt, NULL);
+ filt = nslog_filter_unref(filt);
+ if (err != NSLOG_NO_ERROR) {
+ return NSERROR_NOSPACE;
+ }
+
+ return NSERROR_OK;
+}
+
+#else
+
+void
+nslog_log(const char *file, const char *func, int ln, const char *format, ...)
+{
+ va_list ap;
+
+ if (verbose_log) {
+ fprintf(logfile,
+ "%s %s:%i %s: ",
+ nslog_gettime(),
+ file,
+ ln,
+ func);
+
+ va_start(ap, format);
+
+ vfprintf(logfile, format, ap);
+
+ va_end(ap);
+
+ fputc('\n', logfile);
+ }
+}
+
+/* exported interface documented in utils/log.h */
+nserror
+nslog_set_filter(const char *filter)
+{
+ (void)(filter);
+ return NSERROR_OK;
+}
+
+
+#endif
+
nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
{
struct utsname utsname;
@@ -59,9 +204,9 @@ nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
/* ensure we actually show logging */
verbose_log = true;
} else if (((*pargc) > 2) &&
- (argv[1][0] == '-') &&
- (argv[1][1] == 'V') &&
- (argv[1][2] == 0)) {
+ (argv[1][0] == '-') &&
+ (argv[1][1] == 'V') &&
+ (argv[1][2] == 0)) {
int argcmv;
/* verbose logging to file */
@@ -82,7 +227,7 @@ nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
/* ensure we actually show logging */
verbose_log = true;
}
- } else if (verbose_log == true) {
+ } else {
/* default is logging to stderr */
logfile = stderr;
}
@@ -96,94 +241,65 @@ nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
verbose_log = false;
}
+#ifdef WITH_NSLOG
+
+ if (nslog_set_filter(verbose_log ?
+ NETSURF_BUILTIN_VERBOSE_FILTER :
+ NETSURF_BUILTIN_LOG_FILTER) != NSERROR_OK) {
+ ret = NSERROR_INIT_FAILED;
+ verbose_log = false;
+ } else if (nslog_set_render_callback(netsurf_render_log, NULL) != NSLOG_NO_ERROR) {
+ ret = NSERROR_INIT_FAILED;
+ verbose_log = false;
+ } else if (nslog_uncork() != NSLOG_NO_ERROR) {
+ ret = NSERROR_INIT_FAILED;
+ verbose_log = false;
+ }
+
+#endif
+
/* sucessfull logging initialisation so log system info */
if (ret == NSERROR_OK) {
- LOG("NetSurf version '%s'", netsurf_version);
+ NSLOG(netsurf, INFO, "NetSurf version '%s'", netsurf_version);
if (uname(&utsname) < 0) {
- LOG("Failed to extract machine information");
+ NSLOG(netsurf, INFO,
+ "Failed to extract machine information");
} else {
- LOG("NetSurf on <%s>, node <%s>, release <%s>, version <%s>, machine <%s>",
- utsname.sysname,
- utsname.nodename,
- utsname.release,
- utsname.version,
- utsname.machine);
+ NSLOG(netsurf, INFO,
+ "NetSurf on <%s>, node <%s>, release <%s>, version <%s>, machine <%s>",
+ utsname.sysname,
+ utsname.nodename,
+ utsname.release,
+ utsname.version,
+ utsname.machine);
}
}
return ret;
}
-#ifndef NDEBUG
-
-/* Subtract the `struct timeval' values X and Y,
- storing the result in RESULT.
- Return 1 if the difference is negative, otherwise 0.
-*/
-
-static int
-timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
+/* exported interface documented in utils/log.h */
+nserror
+nslog_set_filter_by_options()
{
- /* Perform the carry for the later subtraction by updating y. */
- if (x->tv_usec < y->tv_usec) {
- int nsec = (int)(y->tv_usec - x->tv_usec) / 1000000 + 1;
- y->tv_usec -= 1000000 * nsec;
- y->tv_sec += nsec;
- }
- if ((int)(x->tv_usec - y->tv_usec) > 1000000) {
- int nsec = (int)(x->tv_usec - y->tv_usec) / 1000000;
- y->tv_usec += 1000000 * nsec;
- y->tv_sec -= nsec;
- }
-
- /* Compute the time remaining to wait.
- tv_usec is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_usec = x->tv_usec - y->tv_usec;
-
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
+ if (verbose_log)
+ return nslog_set_filter(nsoption_charp(verbose_filter));
+ else
+ return nslog_set_filter(nsoption_charp(log_filter));
}
-/**
- * Obtain a formatted string suitable for prepending to a log message
- *
- * \return formatted string of the time since first log call
- */
-static const char *nslog_gettime(void)
+/* exported interface documented in utils/log.h */
+void
+nslog_finalise()
{
- static struct timeval start_tv;
- static char buff[32];
-
- struct timeval tv;
- struct timeval now_tv;
-
- if (!timerisset(&start_tv)) {
- gettimeofday(&start_tv, NULL);
+ NSLOG(netsurf, INFO,
+ "Finalising logging, please report any further messages");
+ verbose_log = true;
+ if (logfile != stderr) {
+ fclose(logfile);
+ logfile = stderr;
}
- gettimeofday(&now_tv, NULL);
-
- timeval_subtract(&tv, &now_tv, &start_tv);
-
- snprintf(buff, sizeof(buff),"(%ld.%06ld)",
- (long)tv.tv_sec, (long)tv.tv_usec);
-
- return buff;
-}
-
-void nslog_log(const char *file, const char *func, int ln, const char *format, ...)
-{
- va_list ap;
-
- fprintf(logfile, "%s %s:%i %s: ", nslog_gettime(), file, ln, func);
-
- va_start(ap, format);
-
- vfprintf(logfile, format, ap);
-
- va_end(ap);
-
- fputc('\n', logfile);
-}
-
+#ifdef WITH_NSLOG
+ nslog_cleanup();
#endif
+}
diff --git a/utils/log.h b/utils/log.h
index 708016b18..b773ec4a2 100644
--- a/utils/log.h
+++ b/utils/log.h
@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _NETSURF_LOG_H_
-#define _NETSURF_LOG_H_
+#ifndef NETSURF_LOG_H
+#define NETSURF_LOG_H
#include <stdio.h>
#include <stdbool.h>
@@ -43,9 +43,59 @@ typedef bool(nslog_ensure_t)(FILE *fptr);
*/
extern nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv);
-#ifdef NDEBUG
-# define LOG(format, ...) ((void) 0)
-#else
+/**
+ * Shut down the logging system.
+ *
+ * Shuts down the logging subsystem, resetting to verbose logging and output
+ * to stderr. Note, if logging is done after calling this, it will be sent
+ * to stderr without filtering.
+ */
+extern void nslog_finalise(void);
+
+/**
+ * Set the logging filter.
+ *
+ * Compiles and enables the given logging filter.
+ */
+extern nserror nslog_set_filter(const char *filter);
+
+/**
+ * Set the logging filter according to the options.
+ */
+extern nserror nslog_set_filter_by_options(void);
+
+/* ensure a logging level is defined */
+#ifndef NETSURF_LOG_LEVEL
+#define NETSURF_LOG_LEVEL INFO
+#endif
+
+#define NSLOG_LVL(level) NSLOG_LEVEL_ ## level
+#define NSLOG_EVL(level) NSLOG_LVL(level)
+#define NSLOG_COMPILED_MIN_LEVEL NSLOG_EVL(NETSURF_LOG_LEVEL)
+
+#ifdef WITH_NSLOG
+
+#include <nslog/nslog.h>
+
+NSLOG_DECLARE_CATEGORY(netsurf);
+NSLOG_DECLARE_CATEGORY(llcache);
+NSLOG_DECLARE_CATEGORY(fetch);
+NSLOG_DECLARE_CATEGORY(plot);
+NSLOG_DECLARE_CATEGORY(schedule);
+NSLOG_DECLARE_CATEGORY(fbtk);
+NSLOG_DECLARE_CATEGORY(layout);
+
+#else /* WITH_NSLOG */
+
+enum nslog_level {
+ NSLOG_LEVEL_DEEPDEBUG = 0,
+ NSLOG_LEVEL_DEBUG = 1,
+ NSLOG_LEVEL_VERBOSE = 2,
+ NSLOG_LEVEL_INFO = 3,
+ NSLOG_LEVEL_WARNING = 4,
+ NSLOG_LEVEL_ERROR = 5,
+ NSLOG_LEVEL_CRITICAL = 6
+};
extern void nslog_log(const char *file, const char *func, int ln, const char *format, ...) __attribute__ ((format (printf, 4, 5)));
@@ -60,13 +110,13 @@ extern void nslog_log(const char *file, const char *func, int ln, const char *fo
# define LOG_LN __LINE__
# endif
-#define LOG(format, args...) \
+#define NSLOG(catname, level, logmsg, args...) \
do { \
- if (verbose_log) { \
- nslog_log(__FILE__, LOG_FN, LOG_LN, format , ##args); \
+ if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \
+ nslog_log(__FILE__, LOG_FN, LOG_LN, logmsg , ##args); \
} \
} while(0)
-#endif
+#endif /* WITH_NSLOG */
#endif
diff --git a/utils/merge-messages.lua b/utils/merge-messages.lua
deleted file mode 100755
index 3aeac697c..000000000
--- a/utils/merge-messages.lua
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env lua5.1
-
-local lfs = require "lfs"
-
-local en_stat = assert(lfs.attributes "!NetSurf/Resources/en/Messages")
-local language = { }
-local sorted = { }
-
-io.stderr:write("loading non-en languages...\n");
-
-for dir in lfs.dir "!NetSurf/Resources" do
- local path = "!NetSurf/Resources/" .. dir
- if dir ~= "en" and lfs.attributes(path .. "/Messages") then
- local f = io.open(path .. "/Messages", "r")
- local c = 0
- io.stderr:write(dir, ":")
- language[dir] = { }
- sorted[#sorted + 1] = dir
- for l in f:lines() do
- if l:sub(1, 1) ~= "#" then
- local tag, msg = l:match "^([^:]*):(.*)$"
- if tag then
- language[dir][tag] = msg
- c = c + 1
- end
- end
- end
- f:close()
- io.stderr:write(tostring(c), " entries.\n")
- end
-end
-
-table.sort(sorted)
-
-io.stderr:write("working through en...\n")
-
-local manipulators = {
- { "^(ami.*)", "ami.%1" },
- { "^(gtk.*)", "gtk.%1" },
- { "^(Help.*)", "ro.%1" },
- { "^(ARexx.*)", "ami.%1" },
-
- { "^(.*)$", "all.%1" } -- must be last
-}
-
-local function manipulate_tag(t)
- for _, m in ipairs(manipulators) do
- local r, s = t:gsub(m[1], m[2])
- if s > 0 then return r end
- end
- return t
-end
-
-local f = io.open("!NetSurf/Resources/en/Messages", "r")
-
-for l in f:lines() do
- if l:sub(1,1) == "#" then
- print(l)
- else
- local tag, msg = l:match "^([^:]*):(.*)$"
- if not tag then
- print(l)
- else
- local mtag = manipulate_tag(tag)
- io.stdout:write("en.", mtag, ":", msg, "\n")
- for _, langname in ipairs(sorted) do
- local trans = language[langname][tag]
- if not trans then
- io.stderr:write("*** language ", langname, " lacks translation for ", mtag, "/", tag, "\n")
- trans = msg
- end
- io.stdout:write(langname, ".", mtag, ":", trans, "\n")
- language[langname][tag] = nil
- end
- end
- end
-end
-
-for _, langname in ipairs(sorted) do
- for tag in pairs(language[langname]) do
- io.stderr:write("*** language ", langname, " contains orphan tag ", tag, "\n")
- end
-end \ No newline at end of file
diff --git a/utils/messages.c b/utils/messages.c
index 0c558cdfc..2e22cc731 100644
--- a/utils/messages.c
+++ b/utils/messages.c
@@ -45,106 +45,43 @@
/** The hash table used to store the standard Messages file for the old API */
static struct hash_table *messages_hash = NULL;
-/**
- * process a line of input.
- */
-static nserror
-message_process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
-{
- uint8_t *value;
- uint8_t *colon;
-
- /* empty or comment lines */
- if (ln[0] == 0 || ln[0] == '#') {
- return NSERROR_OK;
- }
-
- /* find first colon as key/value separator */
- for (colon = ln; colon < (ln + lnlen); colon++) {
- if (*colon == ':') {
- break;
- }
- }
- if (colon == (ln + lnlen)) {
- /* no colon found */
- return NSERROR_INVALID;
- }
-
- *colon = 0; /* terminate key */
- value = colon + 1;
-
- if (hash_add(hash, (char *)ln, (char *)value) == false) {
- LOG("Unable to add %s:%s to hash table", ln, value);
- return NSERROR_INVALID;
- }
- return NSERROR_OK;
-}
/**
* Read keys and values from messages file.
*
* \param path pathname of messages file
- * \param ctx reference of hash table to merge with.
+ * \param ctx reference of hash table to merge with or NULL to create one.
* \return NSERROR_OK on sucess and ctx updated or error code on faliure.
*/
static nserror messages_load_ctx(const char *path, struct hash_table **ctx)
{
- char s[400]; /* line buffer */
- gzFile fp; /* compressed file handle */
struct hash_table *nctx; /* new context */
+ nserror res;
- assert(path != NULL);
-
- fp = gzopen(path, "r");
- if (!fp) {
- LOG("Unable to open messages file \"%.100s\": %s", path, strerror(errno));
-
- return NSERROR_NOT_FOUND;
- }
-
- if (*ctx == NULL) {
- nctx = hash_create(HASH_SIZE);
- } else {
+ if (*ctx != NULL) {
/**
* \note The passed hash is not copied here so this
* updates in place.
*/
- nctx = *ctx;
+ return hash_add_file(*ctx, path);
}
+
+ nctx = hash_create(HASH_SIZE);
if (nctx == NULL) {
- LOG("Unable to create hash table for messages file %s", path);
- gzclose(fp);
+ NSLOG(netsurf, INFO,
+ "Unable to create hash table for messages file %s",
+ path);
return NSERROR_NOMEM;
}
- while (gzgets(fp, s, sizeof s)) {
- char *colon, *value;
-
- if (s[0] == 0 || s[0] == '#')
- continue;
-
- s[strlen(s) - 1] = 0; /* remove \n at end */
- colon = strchr(s, ':');
- if (!colon)
- continue;
- *colon = 0; /* terminate key */
- value = colon + 1;
-
- if (hash_add(nctx, s, value) == false) {
- LOG("Unable to add %s:%s to hash table of %s", s, value, path);
- gzclose(fp);
- if (*ctx == NULL) {
- hash_destroy(nctx);
- }
- return NSERROR_INVALID;
- }
+ res = hash_add_file(nctx, path);
+ if (res == NSERROR_OK) {
+ *ctx = nctx;
+ } else {
+ hash_destroy(nctx);
}
- gzclose(fp);
-
- *ctx = nctx;
-
- return NSERROR_OK;
+ return res;
}
@@ -196,93 +133,28 @@ static void messages_destroy_ctx(struct hash_table *ctx)
/* exported interface documented in messages.h */
nserror messages_add_from_file(const char *path)
{
- nserror err;
-
if (path == NULL) {
return NSERROR_BAD_PARAMETER;
}
- LOG("Loading Messages from '%s'", path);
-
- err = messages_load_ctx(path, &messages_hash);
+ NSLOG(netsurf, INFO, "Loading Messages from '%s'", path);
-
- return err;
+ return messages_load_ctx(path, &messages_hash);
}
/* exported interface documented in messages.h */
-nserror messages_add_from_inline(const uint8_t *data, size_t data_size)
+nserror messages_add_from_inline(const uint8_t *data, size_t size)
{
- z_stream strm;
- int ret;
- uint8_t s[512]; /* line buffer */
- size_t used = 0; /* number of bytes in buffer in use */
- uint8_t *nl;
-
/* ensure the hash table is initialised */
if (messages_hash == NULL) {
messages_hash = hash_create(HASH_SIZE);
}
if (messages_hash == NULL) {
- LOG("Unable to create hash table");
+ NSLOG(netsurf, INFO, "Unable to create hash table");
return NSERROR_NOMEM;
}
-
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
-
- strm.next_in = (uint8_t *)data;
- strm.avail_in = data_size;
-
- ret = inflateInit2(&strm, 32 + MAX_WBITS);
- if (ret != Z_OK) {
- LOG("inflateInit returned %d", ret);
- return NSERROR_INVALID;
- }
-
- do {
- strm.next_out = s + used;
- strm.avail_out = sizeof(s) - used;
-
- ret = inflate(&strm, Z_NO_FLUSH);
- if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
- break;
- }
-
- used = sizeof(s) - strm.avail_out;
- while (used > 0) {
- /* find nl */
- for (nl = &s[0]; nl < &s[used]; nl++) {
- if (*nl == '\n') {
- break;
- }
- }
- if (nl == &s[used]) {
- /* no nl found */
- break;
- }
- /* found newline */
- *nl = 0; /* null terminate line */
- message_process_line(messages_hash, &s[0], nl - &s[0]);
- memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
- used -= ((nl +1) - &s[0]);
- }
- if (used == sizeof(s)) {
- /* entire buffer used and no newline */
- LOG("Overlength line");
- used = 0;
- }
- } while (ret != Z_STREAM_END);
-
- inflateEnd(&strm);
-
- if (ret != Z_STREAM_END) {
- LOG("inflate returned %d", ret);
- return NSERROR_INVALID;
- }
- return NSERROR_OK;
+ return hash_add_inline(messages_hash, data, size);
}
/* exported interface documented in messages.h */
@@ -338,6 +210,10 @@ const char *messages_get_errorcode(nserror code)
/* Requested item not found */
return messages_get_ctx("NotFound", messages_hash);
+ case NSERROR_NOT_DIRECTORY:
+ /* Missing directory */
+ return messages_get_ctx("NotDirectory", messages_hash);
+
case NSERROR_SAVE_FAILED:
/* Failed to save data */
return messages_get_ctx("SaveFailed", messages_hash);
@@ -350,9 +226,29 @@ const char *messages_get_errorcode(nserror code)
/* Initialisation failed */
return messages_get_ctx("InitFailed", messages_hash);
- case NSERROR_MNG_ERROR:
- /* An MNG error occurred */
- return messages_get_ctx("MNGError", messages_hash);
+ case NSERROR_BMP_ERROR:
+ /* A BMP error occurred */
+ return messages_get_ctx("BMPError", messages_hash);
+
+ case NSERROR_GIF_ERROR:
+ /* A GIF error occurred */
+ return messages_get_ctx("GIFError", messages_hash);
+
+ case NSERROR_ICO_ERROR:
+ /* A ICO error occurred */
+ return messages_get_ctx("ICOError", messages_hash);
+
+ case NSERROR_PNG_ERROR:
+ /* A PNG error occurred */
+ return messages_get_ctx("PNGError", messages_hash);
+
+ case NSERROR_SPRITE_ERROR:
+ /* A RISC OS Sprite error occurred */
+ return messages_get_ctx("SpriteError", messages_hash);
+
+ case NSERROR_SVG_ERROR:
+ /* A SVG error occurred */
+ return messages_get_ctx("SVGError", messages_hash);
case NSERROR_BAD_ENCODING:
/* The character set is unknown */
@@ -398,12 +294,40 @@ const char *messages_get_errorcode(nserror code)
/* Bad URL */
return messages_get_ctx("BadURL", messages_hash);
- default:
+ case NSERROR_BAD_CONTENT:
+ /* Bad Content */
+ return messages_get_ctx("BadContent", messages_hash);
+
+ case NSERROR_FRAME_DEPTH:
+ /* Exceeded frame depth */
+ return messages_get_ctx("FrameDepth", messages_hash);
+
+ case NSERROR_PERMISSION:
+ /* Permission error */
+ return messages_get_ctx("PermissionError", messages_hash);
+
+ case NSERROR_BAD_SIZE:
+ /* Bad size */
+ return messages_get_ctx("BadSize", messages_hash);
+
+ case NSERROR_NOSPACE:
+ /* Insufficient space */
+ return messages_get_ctx("NoSpace", messages_hash);
+
+ case NSERROR_NOT_IMPLEMENTED:
+ /* Functionality is not implemented */
+ return messages_get_ctx("NotImplemented", messages_hash);
+
case NSERROR_UNKNOWN:
- break;
+ /* Unknown error */
+ return messages_get_ctx("Unknown", messages_hash);
}
- /* Unknown error */
+ /* The switch has no default, so the compiler should tell us when we
+ * forget to add messages for new error codes. As such, we should
+ * never get here.
+ */
+ assert(0);
return messages_get_ctx("Unknown", messages_hash);
}
@@ -414,4 +338,3 @@ void messages_destroy(void)
messages_destroy_ctx(messages_hash);
messages_hash = NULL;
}
-
diff --git a/utils/nsoption.c b/utils/nsoption.c
index 8f05a911b..09529a0d0 100644
--- a/utils/nsoption.c
+++ b/utils/nsoption.c
@@ -187,7 +187,7 @@ static void nsoption_validate(struct nsoption_s *opts, struct nsoption_s *defs)
break;
}
}
- if (black == true) {
+ if (black == true && defs != NULL) {
for (cloop = NSOPTION_SYS_COLOUR_START;
cloop <= NSOPTION_SYS_COLOUR_END;
cloop++) {
@@ -209,6 +209,9 @@ static void nsoption_validate(struct nsoption_s *opts, struct nsoption_s *defs)
opts[NSOPTION_max_retried_fetches].value.u) > 60) &&
(opts[NSOPTION_max_retried_fetches].value.u > 1))
opts[NSOPTION_max_retried_fetches].value.u--;
+
+ /* We ignore the result because we can't fail to validate. Yay */
+ (void)nslog_set_filter_by_options();
}
/**
@@ -648,11 +651,12 @@ nsoption_read(const char *path, struct nsoption_s *opts)
fp = fopen(path, "r");
if (!fp) {
- LOG("Failed to open file '%s'", path);
+ NSLOG(netsurf, INFO, "Failed to open file '%s'", path);
return NSERROR_NOT_FOUND;
}
- LOG("Successfully opened '%s' for Options file", path);
+ NSLOG(netsurf, INFO, "Successfully opened '%s' for Options file",
+ path);
while (fgets(s, NSOPTION_MAX_LINE_LEN, fp)) {
char *colon, *value;
@@ -718,7 +722,8 @@ nsoption_write(const char *path,
fp = fopen(path, "w");
if (!fp) {
- LOG("failed to open file '%s' for writing", path);
+ NSLOG(netsurf, INFO, "failed to open file '%s' for writing",
+ path);
return NSERROR_NOT_FOUND;
}
@@ -798,7 +803,7 @@ nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
/* arg+arglen is the option to set, val is the value */
- LOG("%.*s = %s", arglen, arg, val);
+ NSLOG(netsurf, INFO, "%.*s = %s", arglen, arg, val);
for (entry_loop = 0;
entry_loop < NSOPTION_LISTEND;
@@ -818,6 +823,8 @@ nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
}
*pargc -= (idx - 1);
+ nsoption_validate(opts, nsoptions_default);
+
return NSERROR_OK;
}
diff --git a/utils/nsoption.h b/utils/nsoption.h
index 62c89c464..e60ebd114 100644
--- a/utils/nsoption.h
+++ b/utils/nsoption.h
@@ -18,10 +18,10 @@
/**
* \file
- * Option reading and saving (interface).
+ * Option reading and saving interface.
*
* Global options are defined in desktop/options.h
- * Distinct target options are defined in <TARGET>/options.h
+ * Distinct target options are defined in ${TARGET}/options.h
*
* The implementation API is slightly compromised because it still has
* "global" tables for both the default and current option tables.
diff --git a/utils/nsurl.h b/utils/nsurl.h
index f97562bf0..054baf26b 100644
--- a/utils/nsurl.h
+++ b/utils/nsurl.h
@@ -301,6 +301,25 @@ nserror nsurl_replace_query(const nsurl *url, const char *query,
/**
+ * Create a NetSurf URL object, with scheme replaced
+ *
+ * \param url NetSurf URL to create new NetSurf URL from
+ * \param scheme Scheme to use
+ * \param new_url Returns new NetSurf URL with scheme provided
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * If return value != NSERROR_OK, nothing will be returned in new_url.
+ *
+ * It is up to the client to call nsurl_unref when they are finished with
+ * the created object.
+ *
+ * Any scheme component in url is replaced with scheme in new_url.
+ */
+nserror nsurl_replace_scheme(const nsurl *url, lwc_string *scheme,
+ nsurl **new_url);
+
+
+/**
* Attempt to find a nice filename for a URL.
*
* \param url A NetSurf URL object to create a filename from
diff --git a/utils/nsurl/Makefile b/utils/nsurl/Makefile
new file mode 100644
index 000000000..71304b292
--- /dev/null
+++ b/utils/nsurl/Makefile
@@ -0,0 +1,7 @@
+# nsurl utils sources
+
+S_NSURL := \
+ nsurl.c \
+ parse.c
+
+S_NSURL := $(addprefix utils/nsurl/,$(S_NSURL)) \ No newline at end of file
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
new file mode 100644
index 000000000..8c769cfff
--- /dev/null
+++ b/utils/nsurl/nsurl.c
@@ -0,0 +1,939 @@
+/*
+ * Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * NetSurf URL handling implementation.
+ *
+ * This is the common implementation of all URL handling within the
+ * browser. This implementation is based upon RFC3986 although this has
+ * been superceeded by https://url.spec.whatwg.org/ which is based on
+ * actual contemporary implementations.
+ *
+ * Care must be taken with character encodings within this module as
+ * the specifications work with specific ascii ranges and must not be
+ * affected by locale. Hence the c library character type functions
+ * are not used.
+ */
+
+#include <assert.h>
+#include <libwapcaplet/libwapcaplet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "utils/ascii.h"
+#include "utils/corestrings.h"
+#include "utils/errors.h"
+#include "utils/idna.h"
+#include "utils/log.h"
+#include "utils/nsurl/private.h"
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+
+
+/**
+ * Compare two component values.
+ *
+ * Sets match to false if the components are not the same.
+ * Does nothing if the components are the same, so ensure match is
+ * preset to true.
+ */
+#define nsurl__component_compare(c1, c2, match) \
+ if (c1 && c2 && lwc_error_ok == \
+ lwc_string_isequal(c1, c2, match)) { \
+ /* do nothing */ \
+ } else if (c1 || c2) { \
+ *match = false; \
+ }
+
+
+
+/******************************************************************************
+ * NetSurf URL Public API *
+ ******************************************************************************/
+
+/* exported interface, documented in nsurl.h */
+nsurl *nsurl_ref(nsurl *url)
+{
+ assert(url != NULL);
+
+ url->count++;
+
+ return url;
+}
+
+
+/* exported interface, documented in nsurl.h */
+void nsurl_unref(nsurl *url)
+{
+ assert(url != NULL);
+ assert(url->count > 0);
+
+ if (--url->count > 0)
+ return;
+
+#ifdef NSURL_DEBUG
+ nsurl__dump(url);
+#endif
+
+ /* Release lwc strings */
+ nsurl__components_destroy(&url->components);
+
+ /* Free the NetSurf URL */
+ free(url);
+}
+
+
+/* exported interface, documented in nsurl.h */
+bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
+{
+ bool match = true;
+
+ assert(url1 != NULL);
+ assert(url2 != NULL);
+
+ /* Compare URL components */
+
+ /* Path, host and query first, since they're most likely to differ */
+
+ if (parts & NSURL_PATH) {
+ nsurl__component_compare(url1->components.path,
+ url2->components.path, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_HOST) {
+ nsurl__component_compare(url1->components.host,
+ url2->components.host, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_QUERY) {
+ nsurl__component_compare(url1->components.query,
+ url2->components.query, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_SCHEME) {
+ nsurl__component_compare(url1->components.scheme,
+ url2->components.scheme, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_USERNAME) {
+ nsurl__component_compare(url1->components.username,
+ url2->components.username, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_PASSWORD) {
+ nsurl__component_compare(url1->components.password,
+ url2->components.password, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_PORT) {
+ nsurl__component_compare(url1->components.port,
+ url2->components.port, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_FRAGMENT) {
+ nsurl__component_compare(url1->components.fragment,
+ url2->components.fragment, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ return true;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_get(const nsurl *url, nsurl_component parts,
+ char **url_s, size_t *url_l)
+{
+ assert(url != NULL);
+
+ return nsurl__components_to_string(&(url->components), parts, 0,
+ url_s, url_l);
+}
+
+
+/* exported interface, documented in nsurl.h */
+lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part)
+{
+ assert(url != NULL);
+
+ switch (part) {
+ case NSURL_SCHEME:
+ return (url->components.scheme != NULL) ?
+ lwc_string_ref(url->components.scheme) : NULL;
+
+ case NSURL_USERNAME:
+ return (url->components.username != NULL) ?
+ lwc_string_ref(url->components.username) : NULL;
+
+ case NSURL_PASSWORD:
+ return (url->components.password != NULL) ?
+ lwc_string_ref(url->components.password) : NULL;
+
+ case NSURL_HOST:
+ return (url->components.host != NULL) ?
+ lwc_string_ref(url->components.host) : NULL;
+
+ case NSURL_PORT:
+ return (url->components.port != NULL) ?
+ lwc_string_ref(url->components.port) : NULL;
+
+ case NSURL_PATH:
+ return (url->components.path != NULL) ?
+ lwc_string_ref(url->components.path) : NULL;
+
+ case NSURL_QUERY:
+ return (url->components.query != NULL) ?
+ lwc_string_ref(url->components.query) : NULL;
+
+ case NSURL_FRAGMENT:
+ return (url->components.fragment != NULL) ?
+ lwc_string_ref(url->components.fragment) : NULL;
+
+ default:
+ NSLOG(netsurf, INFO,
+ "Unsupported value passed to part param.");
+ assert(0);
+ }
+
+ return NULL;
+}
+
+
+/* exported interface, documented in nsurl.h */
+bool nsurl_has_component(const nsurl *url, nsurl_component part)
+{
+ assert(url != NULL);
+
+ switch (part) {
+ case NSURL_SCHEME:
+ if (url->components.scheme != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_CREDENTIALS:
+ /* Only username required for credentials section */
+ /* Fall through */
+ case NSURL_USERNAME:
+ if (url->components.username != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PASSWORD:
+ if (url->components.password != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_HOST:
+ if (url->components.host != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PORT:
+ if (url->components.port != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PATH:
+ if (url->components.path != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_QUERY:
+ if (url->components.query != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_FRAGMENT:
+ if (url->components.fragment != NULL)
+ return true;
+ else
+ return false;
+
+ default:
+ NSLOG(netsurf, INFO,
+ "Unsupported value passed to part param.");
+ assert(0);
+ }
+
+ return false;
+}
+
+
+/* exported interface, documented in nsurl.h */
+const char *nsurl_access(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->string;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l)
+{
+ nserror err;
+ lwc_string *host;
+ char *idna_host = NULL;
+ size_t idna_host_len;
+ char *scheme = NULL;
+ size_t scheme_len;
+ char *path = NULL;
+ size_t path_len;
+
+ assert(url != NULL);
+
+ if (url->components.host == NULL) {
+ return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l);
+ }
+
+ host = url->components.host;
+ err = idna_decode(lwc_string_data(host), lwc_string_length(host),
+ &idna_host, &idna_host_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ err = nsurl_get(url,
+ NSURL_SCHEME | NSURL_CREDENTIALS,
+ &scheme, &scheme_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ err = nsurl_get(url,
+ NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT,
+ &path, &path_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */
+ *url_s = malloc(*url_l);
+
+ if (*url_s == NULL) {
+ err = NSERROR_NOMEM;
+ goto cleanup;
+ }
+
+ snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path);
+
+ err = NSERROR_OK;
+
+cleanup:
+ free(idna_host);
+ free(scheme);
+ free(path);
+
+ return err;
+}
+
+
+/* exported interface, documented in nsurl.h */
+const char *nsurl_access_leaf(const nsurl *url)
+{
+ size_t path_len;
+ const char *path;
+ const char *leaf;
+
+ assert(url != NULL);
+
+ if (url->components.path == NULL)
+ return "";
+
+ path = lwc_string_data(url->components.path);
+ path_len = lwc_string_length(url->components.path);
+
+ if (path_len == 0)
+ return "";
+
+ if (path_len == 1 && *path == '/')
+ return "/";
+
+ leaf = path + path_len;
+
+ do {
+ leaf--;
+ } while ((leaf != path) && (*leaf != '/'));
+
+ if (*leaf == '/')
+ leaf++;
+
+ return leaf;
+}
+
+
+/* exported interface, documented in nsurl.h */
+size_t nsurl_length(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->length;
+}
+
+
+/* exported interface, documented in nsurl.h */
+uint32_t nsurl_hash(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->hash;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
+{
+ size_t length;
+ char *pos;
+
+ assert(url != NULL);
+
+ /* check for source url having no fragment already */
+ if (url->components.fragment == NULL) {
+ *no_frag = (nsurl *)url;
+
+ (*no_frag)->count++;
+
+ return NSERROR_OK;
+ }
+
+ /* Find the change in length from url to new_url */
+ length = url->length;
+ if (url->components.fragment != NULL) {
+ length -= 1 + lwc_string_length(url->components.fragment);
+ }
+
+ /* Create NetSurf URL object */
+ *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*no_frag == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Copy components */
+ (*no_frag)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*no_frag)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*no_frag)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*no_frag)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*no_frag)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*no_frag)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*no_frag)->components.query =
+ nsurl__component_copy(url->components.query);
+ (*no_frag)->components.fragment = NULL;
+
+ (*no_frag)->components.scheme_type = url->components.scheme_type;
+
+ (*no_frag)->length = length;
+
+ /* Fill out the url string */
+ pos = (*no_frag)->string;
+ memcpy(pos, url->string, length);
+ pos += length;
+ *pos = '\0';
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*no_frag);
+
+ /* Give the URL a reference */
+ (*no_frag)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
+{
+ int frag_len;
+ int base_len;
+ char *pos;
+ size_t len;
+
+ assert(url != NULL);
+ assert(frag != NULL);
+
+ /* Find the change in length from url to new_url */
+ base_len = url->length;
+ if (url->components.fragment != NULL) {
+ base_len -= 1 + lwc_string_length(url->components.fragment);
+ }
+ frag_len = lwc_string_length(frag);
+
+ /* Set new_url's length */
+ len = base_len + 1 /* # */ + frag_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, base_len);
+ pos += base_len;
+ *pos = '#';
+ memcpy(++pos, lwc_string_data(frag), frag_len);
+ pos += frag_len;
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*new_url)->components.query =
+ nsurl__component_copy(url->components.query);
+ (*new_url)->components.fragment =
+ lwc_string_ref(frag);
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_replace_query(const nsurl *url, const char *query,
+ nsurl **new_url)
+{
+ int query_len; /* Length of new query string, including '?' */
+ int frag_len = 0; /* Length of fragment, including '#' */
+ int base_len; /* Length of URL up to start of query */
+ char *pos;
+ size_t len;
+ lwc_string *lwc_query;
+
+ assert(url != NULL);
+ assert(query != NULL);
+ assert(query[0] == '?');
+
+ /* Get the length of the new query */
+ query_len = strlen(query);
+
+ /* Find the change in length from url to new_url */
+ base_len = url->length;
+ if (url->components.query != NULL) {
+ base_len -= lwc_string_length(url->components.query);
+ }
+ if (url->components.fragment != NULL) {
+ frag_len = 1 + lwc_string_length(url->components.fragment);
+ base_len -= frag_len;
+ }
+
+ /* Set new_url's length */
+ len = base_len + query_len + frag_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
+ free(*new_url);
+ return NSERROR_NOMEM;
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, base_len);
+ pos += base_len;
+ memcpy(pos, query, query_len);
+ pos += query_len;
+ if (url->components.fragment != NULL) {
+ const char *frag = lwc_string_data(url->components.fragment);
+ *pos = '#';
+ memcpy(++pos, frag, frag_len - 1);
+ pos += frag_len - 1;
+ }
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*new_url)->components.query = lwc_query;
+ (*new_url)->components.fragment =
+ nsurl__component_copy(url->components.fragment);
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_replace_scheme(const nsurl *url, lwc_string *scheme,
+ nsurl **new_url)
+{
+ int scheme_len;
+ int base_len;
+ char *pos;
+ size_t len;
+ bool match;
+
+ assert(url != NULL);
+ assert(scheme != NULL);
+
+ /* Get the length of the new scheme */
+ scheme_len = lwc_string_length(scheme);
+
+ /* Find the change in length from url to new_url */
+ base_len = url->length;
+ if (url->components.scheme != NULL) {
+ base_len -= lwc_string_length(url->components.scheme);
+ }
+
+ /* Set new_url's length */
+ len = base_len + scheme_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, lwc_string_data(scheme), scheme_len);
+ memcpy(pos + scheme_len,
+ url->string + url->length - base_len, base_len);
+ pos[len] = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme = lwc_string_ref(scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*new_url)->components.query =
+ nsurl__component_copy(url->components.query);
+ (*new_url)->components.fragment =
+ nsurl__component_copy(url->components.fragment);
+
+ /* Compute new scheme type */
+ if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
+ &match) == lwc_error_ok && match == true) {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_HTTP;
+ } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
+ &match) == lwc_error_ok && match == true) {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_HTTPS;
+ } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
+ &match) == lwc_error_ok && match == true) {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_FILE;
+ } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_ftp,
+ &match) == lwc_error_ok && match == true) {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_FTP;
+ } else if (lwc_string_caseless_isequal(scheme, corestring_lwc_mailto,
+ &match) == lwc_error_ok && match == true) {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_MAILTO;
+ } else {
+ (*new_url)->components.scheme_type = NSURL_SCHEME_OTHER;
+ }
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in utils/nsurl.h */
+nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
+{
+ const char *data;
+ size_t len;
+ size_t pos;
+ bool match;
+ char *name;
+
+ assert(url != NULL);
+
+ *result = 0;
+
+ /* extract the last component of the path, if possible */
+ if ((url->components.path != NULL) &&
+ (lwc_string_length(url->components.path) != 0) &&
+ (lwc_string_isequal(url->components.path,
+ corestring_lwc_slash_, &match) == lwc_error_ok) &&
+ (match == false)) {
+ bool first = true;
+ bool keep_looking;
+
+ /* Get hold of the string data we're examining */
+ data = lwc_string_data(url->components.path);
+ len = lwc_string_length(url->components.path);
+ pos = len;
+
+ do {
+ keep_looking = false;
+ pos--;
+
+ /* Find last '/' with stuff after it */
+ while (pos != 0) {
+ if (data[pos] == '/' && pos < len - 1) {
+ break;
+ }
+ pos--;
+ }
+
+ if (pos == 0) {
+ break;
+ }
+
+ if (first) {
+ if (strncasecmp("/default.", data + pos,
+ SLEN("/default.")) == 0) {
+ keep_looking = true;
+
+ } else if (strncasecmp("/index.",
+ data + pos,
+ 6) == 0) {
+ keep_looking = true;
+
+ }
+ first = false;
+ }
+
+ } while (keep_looking);
+
+ if (data[pos] == '/')
+ pos++;
+
+ if (strncasecmp("default.", data + pos, 8) != 0 &&
+ strncasecmp("index.", data + pos, 6) != 0) {
+ size_t end = pos;
+ while (data[end] != '\0' && data[end] != '/') {
+ end++;
+ }
+ if (end - pos != 0) {
+ name = malloc(end - pos + 1);
+ if (name == NULL) {
+ return NSERROR_NOMEM;
+ }
+ memcpy(name, data + pos, end - pos);
+ name[end - pos] = '\0';
+ if (remove_extensions) {
+ /* strip any extenstion */
+ char *dot = strchr(name, '.');
+ if (dot && dot != name) {
+ *dot = '\0';
+ }
+ }
+ *result = name;
+ return NSERROR_OK;
+ }
+ }
+ }
+
+ if (url->components.host != NULL) {
+ name = strdup(lwc_string_data(url->components.host));
+
+ for (pos = 0; name[pos] != '\0'; pos++) {
+ if (name[pos] == '.') {
+ name[pos] = '_';
+ }
+ }
+
+ *result = name;
+ return NSERROR_OK;
+ }
+
+ return NSERROR_NOT_FOUND;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_parent(const nsurl *url, nsurl **new_url)
+{
+ lwc_string *lwc_path;
+ size_t old_path_len, new_path_len;
+ size_t len;
+ const char* path = NULL;
+ char *pos;
+
+ assert(url != NULL);
+
+ old_path_len = (url->components.path == NULL) ? 0 :
+ lwc_string_length(url->components.path);
+
+ /* Find new path length */
+ if (old_path_len == 0) {
+ new_path_len = old_path_len;
+ } else {
+ path = lwc_string_data(url->components.path);
+
+ new_path_len = old_path_len;
+ if (old_path_len > 1) {
+ /* Skip over any trailing / */
+ if (path[new_path_len - 1] == '/')
+ new_path_len--;
+
+ /* Work back to next / */
+ while (new_path_len > 0 &&
+ path[new_path_len - 1] != '/')
+ new_path_len--;
+ }
+ }
+
+ /* Find the length of new_url */
+ len = url->length;
+ if (url->components.query != NULL) {
+ len -= lwc_string_length(url->components.query);
+ }
+ if (url->components.fragment != NULL) {
+ len -= 1; /* # */
+ len -= lwc_string_length(url->components.fragment);
+ }
+ len -= old_path_len - new_path_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Make new path */
+ if (old_path_len == 0) {
+ lwc_path = NULL;
+ } else if (old_path_len == new_path_len) {
+ lwc_path = lwc_string_ref(url->components.path);
+ } else {
+ if (lwc_intern_string(path, old_path_len - new_path_len,
+ &lwc_path) != lwc_error_ok) {
+ free(*new_url);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, len);
+ pos += len;
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path = lwc_path;
+ (*new_url)->components.query = NULL;
+ (*new_url)->components.fragment = NULL;
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
diff --git a/utils/nsurl.c b/utils/nsurl/parse.c
index c5c614c55..ce6f4435d 100644
--- a/utils/nsurl.c
+++ b/utils/nsurl/parse.c
@@ -43,61 +43,9 @@
#include "utils/idna.h"
#include "utils/log.h"
#include "utils/nsurl.h"
+#include "utils/nsurl/private.h"
#include "utils/utils.h"
-/* Define to enable NSURL debugging */
-#undef NSURL_DEBUG
-
-/**
- * nsurl scheme type
- */
-enum scheme_type {
- NSURL_SCHEME_OTHER,
- NSURL_SCHEME_HTTP,
- NSURL_SCHEME_HTTPS,
- NSURL_SCHEME_FTP,
- NSURL_SCHEME_MAILTO
-};
-
-/**
- * nsurl components
- *
- * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
- *
- * Note:
- * "path" string includes preceding '/', if needed for the scheme
- * "query" string always includes preceding '?'
- *
- * The other spanned punctuation is to be inserted when building URLs from
- * components.
- */
-struct nsurl_components {
- lwc_string *scheme;
- lwc_string *username;
- lwc_string *password;
- lwc_string *host;
- lwc_string *port;
- lwc_string *path;
- lwc_string *query;
- lwc_string *fragment;
-
- enum scheme_type scheme_type;
-};
-
-
-/**
- * NetSurf URL object
- */
-struct nsurl {
- struct nsurl_components components;
-
- int count; /* Number of references to NetSurf URL object */
- uint32_t hash; /* Hash value for nsurl identification */
-
- size_t length; /* Length of string */
- char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
-};
-
/** Marker set, indicating positions of sections within a URL string */
struct url_markers {
@@ -115,41 +63,7 @@ struct url_markers {
size_t end; /** end of URL */
- enum scheme_type scheme_type;
-};
-
-
-/** Marker set, indicating positions of sections within a URL string */
-struct nsurl_component_lengths {
- size_t scheme;
- size_t username;
- size_t password;
- size_t host;
- size_t port;
- size_t path;
- size_t query;
- size_t fragment;
-};
-
-
-/** Flags indicating which parts of a URL string are required for a nsurl */
-enum nsurl_string_flags {
- NSURL_F_SCHEME = (1 << 0),
- NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
- NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
- NSURL_F_USERNAME = (1 << 3),
- NSURL_F_PASSWORD = (1 << 4),
- NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
- NSURL_F_HOST = (1 << 6),
- NSURL_F_PORT = (1 << 7),
- NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
- NSURL_F_PASSWORD |
- NSURL_F_HOST |
- NSURL_F_PORT),
- NSURL_F_PATH = (1 << 8),
- NSURL_F_QUERY = (1 << 9),
- NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
- NSURL_F_FRAGMENT = (1 << 11)
+ enum nsurl_scheme_type scheme_type;
};
@@ -164,16 +78,6 @@ enum url_sections {
};
-#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
-
-#define nsurl__component_compare(c1, c2, match) \
- if (c1 && c2 && lwc_error_ok == \
- lwc_string_isequal(c1, c2, match)) { \
- /* do nothing */ \
- } else if (c1 || c2) { \
- *match = false; \
- }
-
/**
* Return a hex digit for the given numerical value.
*
@@ -366,6 +270,16 @@ static void nsurl__get_string_markers(const char * const url_s,
(*(pos - off + 4) == 'S')))) {
marker.scheme_type = NSURL_SCHEME_HTTPS;
is_http = true;
+ } else if (off == SLEN("file") &&
+ (((*(pos - off + 0) == 'f') ||
+ (*(pos - off + 0) == 'F')) &&
+ ((*(pos - off + 1) == 'i') ||
+ (*(pos - off + 1) == 'I')) &&
+ ((*(pos - off + 2) == 'l') ||
+ (*(pos - off + 2) == 'L')) &&
+ ((*(pos - off + 3) == 'e') ||
+ (*(pos - off + 3) == 'E')))) {
+ marker.scheme_type = NSURL_SCHEME_FILE;
} else if (off == SLEN("ftp") &&
(((*(pos - off + 0) == 'f') ||
(*(pos - off + 0) == 'F')) &&
@@ -537,19 +451,19 @@ static void nsurl__get_string_markers(const char * const url_s,
}
#ifdef NSURL_DEBUG
- LOG("marker.start: %i", marker.start);
- LOG("marker.scheme_end: %i", marker.scheme_end);
- LOG("marker.authority: %i", marker.authority);
+ NSLOG(netsurf, INFO, "marker.start: %i", marker.start);
+ NSLOG(netsurf, INFO, "marker.scheme_end: %i", marker.scheme_end);
+ NSLOG(netsurf, INFO, "marker.authority: %i", marker.authority);
- LOG("marker.colon_first: %i", marker.colon_first);
- LOG("marker.at: %i", marker.at);
- LOG("marker.colon_last: %i", marker.colon_last);
+ NSLOG(netsurf, INFO, "marker.colon_first: %i", marker.colon_first);
+ NSLOG(netsurf, INFO, "marker.at: %i", marker.at);
+ NSLOG(netsurf, INFO, "marker.colon_last: %i", marker.colon_last);
- LOG("marker.path: %i", marker.path);
- LOG("marker.query: %i", marker.query);
- LOG("marker.fragment: %i", marker.fragment);
+ NSLOG(netsurf, INFO, "marker.path: %i", marker.path);
+ NSLOG(netsurf, INFO, "marker.query: %i", marker.query);
+ NSLOG(netsurf, INFO, "marker.fragment: %i", marker.fragment);
- LOG("marker.end: %i", marker.end);
+ NSLOG(netsurf, INFO, "marker.end: %i", marker.end);
#endif
/* Got all the URL components pegged out now */
@@ -571,8 +485,8 @@ static size_t nsurl__remove_dot_segments(char *path, char *output)
while (*path_pos != '\0') {
#ifdef NSURL_DEBUG
- LOG(" in:%s", path_pos);
- LOG("out:%.*s", output_pos - output, output);
+ NSLOG(netsurf, INFO, " in:%s", path_pos);
+ NSLOG(netsurf, INFO, "out:%.*s", output_pos - output, output);
#endif
if (*path_pos == '.') {
if (*(path_pos + 1) == '.' &&
@@ -680,45 +594,6 @@ static size_t nsurl__get_longest_section(struct url_markers *m)
/**
- * Converts two hexadecimal digits to a single number
- *
- * \param c1 most significant hex digit
- * \param c2 least significant hex digit
- * \return the total value of the two digit hex number, or -ve if input not hex
- *
- * For unescaping url encoded characters.
- */
-static inline int nsurl__get_ascii_offset(char c1, char c2)
-{
- int offset;
-
- /* Use 1st char as most significant hex digit */
- if (ascii_is_digit(c1))
- offset = 16 * (c1 - '0');
- else if (c1 >= 'a' && c1 <= 'f')
- offset = 16 * (c1 - 'a' + 10);
- else if (c1 >= 'A' && c1 <= 'F')
- offset = 16 * (c1 - 'A' + 10);
- else
- /* Not valid hex */
- return -1;
-
- /* Use 2nd char as least significant hex digit and sum */
- if (ascii_is_digit(c2))
- offset += c2 - '0';
- else if (c2 >= 'a' && c2 <= 'f')
- offset += c2 - 'a' + 10;
- else if (c2 >= 'A' && c2 <= 'F')
- offset += c2 - 'A' + 10;
- else
- /* Not valid hex */
- return -1;
-
- return offset;
-}
-
-
-/**
* Create the components of a NetSurf URL object for a section of a URL string
*
* \param url_s URL string
@@ -802,7 +677,7 @@ static nserror nsurl__create_from_section(const char * const url_s,
/* Might be an escaped character needing unescaped */
/* Find which character which was escaped */
- ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
+ ascii_offset = ascii_hex_to_value_2_chars(*(pos + 1),
*(pos + 2));
if (ascii_offset < 0) {
@@ -904,6 +779,11 @@ static nserror nsurl__create_from_section(const char * const url_s,
url->username = NULL;
url->password = NULL;
+ /* file: URLs don't have credentials */
+ if (url->scheme_type == NSURL_SCHEME_FILE) {
+ break;
+ }
+
if (length != 0 && *norm_start != ':') {
char *sec_start = norm_start;
if (pegs->colon_first != pegs->authority &&
@@ -940,6 +820,11 @@ static nserror nsurl__create_from_section(const char * const url_s,
url->host = NULL;
url->port = NULL;
+ /* file: URLs don't have a host */
+ if (url->scheme_type == NSURL_SCHEME_FILE) {
+ break;
+ }
+
if (length != 0) {
size_t colon = 0;
char *sec_start = norm_start;
@@ -1038,9 +923,13 @@ static nserror nsurl__create_from_section(const char * const url_s,
&url->path) != lwc_error_ok) {
return NSERROR_NOMEM;
}
- } else if (url->host != NULL &&
- url->scheme_type != NSURL_SCHEME_MAILTO) {
- /* Set empty path to "/", if there's a host */
+ } else if ((url->host != NULL &&
+ url->scheme_type != NSURL_SCHEME_MAILTO) ||
+ url->scheme_type == NSURL_SCHEME_FILE) {
+ /* Set empty path to "/" if:
+ * - there's a host and its not a mailto: URL
+ * - its a file: URL
+ */
if (lwc_intern_string("/", SLEN("/"),
&url->path) != lwc_error_ok) {
return NSERROR_NOMEM;
@@ -1187,14 +1076,14 @@ static void nsurl__get_string_data(const struct nsurl_components *url,
/**
- * Get nsurl string info; total length, component lengths, & components present
+ * Copy url string into provided buffer
*
* \param url NetSurf URL components
* \param url_s Updated to contain the string
* \param l Individual component lengths
* \param flags String flags
*/
-static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
+static void nsurl__get_string(const struct nsurl_components *url, char *url_s,
struct nsurl_component_lengths *l,
enum nsurl_string_flags flags)
{
@@ -1264,12 +1153,49 @@ static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
}
+/* exported interface, documented in nsurl.h */
+nserror nsurl__components_to_string(
+ const struct nsurl_components *components,
+ nsurl_component parts, size_t pre_padding,
+ char **url_s_out, size_t *url_l_out)
+{
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ size_t url_l;
+ char *url_s;
+
+ assert(components != NULL);
+
+ /* Get the string length and find which parts of url need copied */
+ nsurl__get_string_data(components, parts, &url_l,
+ &str_len, &str_flags);
+
+ if (url_l == 0) {
+ return NSERROR_BAD_URL;
+ }
+
+ /* Allocate memory for url string */
+ url_s = malloc(pre_padding + url_l + 1); /* adding 1 for '\0' */
+ if (url_s == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Copy the required parts into the url string */
+ nsurl__get_string(components, url_s + pre_padding, &str_len, str_flags);
+
+ *url_s_out = url_s;
+ *url_l_out = url_l;
+
+ return NSERROR_OK;
+}
+
+
/**
* Calculate hash value
*
* \param url NetSurf URL object to set hash value for
*/
-static void nsurl_calc_hash(nsurl *url)
+void nsurl__calc_hash(nsurl *url)
{
uint32_t hash = 0;
@@ -1298,73 +1224,6 @@ static void nsurl_calc_hash(nsurl *url)
}
-/**
- * Destroy components
- *
- * \param c url components
- */
-static void nsurl_destroy_components(struct nsurl_components *c)
-{
- if (c->scheme)
- lwc_string_unref(c->scheme);
-
- if (c->username)
- lwc_string_unref(c->username);
-
- if (c->password)
- lwc_string_unref(c->password);
-
- if (c->host)
- lwc_string_unref(c->host);
-
- if (c->port)
- lwc_string_unref(c->port);
-
- if (c->path)
- lwc_string_unref(c->path);
-
- if (c->query)
- lwc_string_unref(c->query);
-
- if (c->fragment)
- lwc_string_unref(c->fragment);
-}
-
-
-#ifdef NSURL_DEBUG
-/**
- * Dump a NetSurf URL's internal components
- *
- * \param url The NetSurf URL to dump components of
- */
-static void nsurl__dump(const nsurl *url)
-{
- if (url->components.scheme)
- LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
-
- if (url->components.username)
- LOG("Username: %s", lwc_string_data(url->components.username));
-
- if (url->components.password)
- LOG("Password: %s", lwc_string_data(url->components.password));
-
- if (url->components.host)
- LOG(" Host: %s", lwc_string_data(url->components.host));
-
- if (url->components.port)
- LOG(" Port: %s", lwc_string_data(url->components.port));
-
- if (url->components.path)
- LOG(" Path: %s", lwc_string_data(url->components.path));
-
- if (url->components.query)
- LOG(" Query: %s", lwc_string_data(url->components.query));
-
- if (url->components.fragment)
- LOG("Fragment: %s", lwc_string_data(url->components.fragment));
-}
-#endif
-
/******************************************************************************
* NetSurf URL Public API *
******************************************************************************/
@@ -1376,8 +1235,6 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
struct nsurl_components c;
size_t length;
char *buff;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
nserror e = NSERROR_OK;
bool match;
@@ -1409,7 +1266,7 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
free(buff);
if (e != NSERROR_OK) {
- nsurl_destroy_components(&c);
+ nsurl__components_destroy(&c);
return NSERROR_NOMEM;
}
@@ -1420,30 +1277,22 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
&match) == lwc_error_ok && match == true)) {
/* http, https must have host */
if (c.host == NULL) {
- nsurl_destroy_components(&c);
+ nsurl__components_destroy(&c);
return NSERROR_BAD_URL;
}
}
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*url == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
+ e = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT,
+ sizeof(nsurl), (char **)url, &length);
+ if (e != NSERROR_OK) {
+ return e;
}
(*url)->components = c;
(*url)->length = length;
- /* Fill out the url string */
- nsurl_get_string(&c, (*url)->string, &str_len, str_flags);
-
/* Get the nsurl's hash */
- nsurl_calc_hash(*url);
+ nsurl__calc_hash(*url);
/* Give the URL a reference */
(*url)->count = 1;
@@ -1453,382 +1302,6 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
/* exported interface, documented in nsurl.h */
-nsurl *nsurl_ref(nsurl *url)
-{
- assert(url != NULL);
-
- url->count++;
-
- return url;
-}
-
-
-/* exported interface, documented in nsurl.h */
-void nsurl_unref(nsurl *url)
-{
- assert(url != NULL);
- assert(url->count > 0);
-
- if (--url->count > 0)
- return;
-
-#ifdef NSURL_DEBUG
- nsurl__dump(url);
-#endif
-
- /* Release lwc strings */
- nsurl_destroy_components(&url->components);
-
- /* Free the NetSurf URL */
- free(url);
-}
-
-
-/* exported interface, documented in nsurl.h */
-bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
-{
- bool match = true;
-
- assert(url1 != NULL);
- assert(url2 != NULL);
-
- /* Compare URL components */
-
- /* Path, host and query first, since they're most likely to differ */
-
- if (parts & NSURL_PATH) {
- nsurl__component_compare(url1->components.path,
- url2->components.path, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_HOST) {
- nsurl__component_compare(url1->components.host,
- url2->components.host, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_QUERY) {
- nsurl__component_compare(url1->components.query,
- url2->components.query, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_SCHEME) {
- nsurl__component_compare(url1->components.scheme,
- url2->components.scheme, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_USERNAME) {
- nsurl__component_compare(url1->components.username,
- url2->components.username, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_PASSWORD) {
- nsurl__component_compare(url1->components.password,
- url2->components.password, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_PORT) {
- nsurl__component_compare(url1->components.port,
- url2->components.port, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_FRAGMENT) {
- nsurl__component_compare(url1->components.fragment,
- url2->components.fragment, &match);
-
- if (match == false)
- return false;
- }
-
- return true;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_get(const nsurl *url, nsurl_component parts,
- char **url_s, size_t *url_l)
-{
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
-
- assert(url != NULL);
-
- /* Get the string length and find which parts of url need copied */
- nsurl__get_string_data(&(url->components), parts, url_l,
- &str_len, &str_flags);
-
- if (*url_l == 0) {
- return NSERROR_BAD_URL;
- }
-
- /* Allocate memory for url string */
- *url_s = malloc(*url_l + 1); /* adding 1 for '\0' */
- if (*url_s == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Copy the required parts into the url string */
- nsurl_get_string(&(url->components), *url_s, &str_len, str_flags);
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part)
-{
- assert(url != NULL);
-
- switch (part) {
- case NSURL_SCHEME:
- return (url->components.scheme != NULL) ?
- lwc_string_ref(url->components.scheme) : NULL;
-
- case NSURL_USERNAME:
- return (url->components.username != NULL) ?
- lwc_string_ref(url->components.username) : NULL;
-
- case NSURL_PASSWORD:
- return (url->components.password != NULL) ?
- lwc_string_ref(url->components.password) : NULL;
-
- case NSURL_HOST:
- return (url->components.host != NULL) ?
- lwc_string_ref(url->components.host) : NULL;
-
- case NSURL_PORT:
- return (url->components.port != NULL) ?
- lwc_string_ref(url->components.port) : NULL;
-
- case NSURL_PATH:
- return (url->components.path != NULL) ?
- lwc_string_ref(url->components.path) : NULL;
-
- case NSURL_QUERY:
- return (url->components.query != NULL) ?
- lwc_string_ref(url->components.query) : NULL;
-
- case NSURL_FRAGMENT:
- return (url->components.fragment != NULL) ?
- lwc_string_ref(url->components.fragment) : NULL;
-
- default:
- LOG("Unsupported value passed to part param.");
- assert(0);
- }
-
- return NULL;
-}
-
-
-/* exported interface, documented in nsurl.h */
-bool nsurl_has_component(const nsurl *url, nsurl_component part)
-{
- assert(url != NULL);
-
- switch (part) {
- case NSURL_SCHEME:
- if (url->components.scheme != NULL)
- return true;
- else
- return false;
-
- case NSURL_CREDENTIALS:
- /* Only username required for credentials section */
- /* Fall through */
- case NSURL_USERNAME:
- if (url->components.username != NULL)
- return true;
- else
- return false;
-
- case NSURL_PASSWORD:
- if (url->components.password != NULL)
- return true;
- else
- return false;
-
- case NSURL_HOST:
- if (url->components.host != NULL)
- return true;
- else
- return false;
-
- case NSURL_PORT:
- if (url->components.port != NULL)
- return true;
- else
- return false;
-
- case NSURL_PATH:
- if (url->components.path != NULL)
- return true;
- else
- return false;
-
- case NSURL_QUERY:
- if (url->components.query != NULL)
- return true;
- else
- return false;
-
- case NSURL_FRAGMENT:
- if (url->components.fragment != NULL)
- return true;
- else
- return false;
-
- default:
- LOG("Unsupported value passed to part param.");
- assert(0);
- }
-
- return false;
-}
-
-
-/* exported interface, documented in nsurl.h */
-const char *nsurl_access(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->string;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l)
-{
- nserror err;
- lwc_string *host;
- char *idna_host = NULL;
- size_t idna_host_len;
- char *scheme = NULL;
- size_t scheme_len;
- char *path = NULL;
- size_t path_len;
-
- assert(url != NULL);
-
- if (url->components.host == NULL) {
- return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l);
- }
-
- host = url->components.host;
- err = idna_decode(lwc_string_data(host), lwc_string_length(host),
- &idna_host, &idna_host_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- err = nsurl_get(url,
- NSURL_SCHEME | NSURL_CREDENTIALS,
- &scheme, &scheme_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- err = nsurl_get(url,
- NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT,
- &path, &path_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */
- *url_s = malloc(*url_l);
-
- if (*url_s == NULL) {
- err = NSERROR_NOMEM;
- goto cleanup;
- }
-
- snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path);
-
- err = NSERROR_OK;
-
-cleanup:
- free(idna_host);
- free(scheme);
- free(path);
-
- return err;
-}
-
-
-/* exported interface, documented in nsurl.h */
-const char *nsurl_access_leaf(const nsurl *url)
-{
- size_t path_len;
- const char *path;
- const char *leaf;
-
- assert(url != NULL);
-
- if (url->components.path == NULL)
- return "";
-
- path = lwc_string_data(url->components.path);
- path_len = lwc_string_length(url->components.path);
-
- if (path_len == 0)
- return "";
-
- if (path_len == 1 && *path == '/')
- return "/";
-
- leaf = path + path_len;
-
- do {
- leaf--;
- } while ((leaf != path) && (*leaf != '/'));
-
- if (*leaf == '/')
- leaf++;
-
- return leaf;
-}
-
-
-/* exported interface, documented in nsurl.h */
-size_t nsurl_length(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->length;
-}
-
-
-/* exported interface, documented in nsurl.h */
-uint32_t nsurl_hash(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->hash;
-}
-
-
-/* exported interface, documented in nsurl.h */
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
{
struct url_markers m;
@@ -1837,8 +1310,6 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
char *buff;
char *buff_pos;
char *buff_start;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
nserror error = 0;
enum {
NSURL_F_REL = 0,
@@ -1853,7 +1324,8 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
assert(rel != NULL);
#ifdef NSURL_DEBUG
- LOG("base: \"%s\", rel: \"%s\"", nsurl_access(base), rel);
+ NSLOG(netsurf, INFO, "base: \"%s\", rel: \"%s\"", nsurl_access(base),
+ rel);
#endif
/* Peg out the URL sections */
@@ -1959,14 +1431,15 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
struct url_markers m_path;
size_t new_length;
- if (base->components.host != NULL &&
- base->components.path == NULL) {
- /* Append relative path to "/". */
- *(buff_pos++) = '/';
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
+ /* RFC3986 said to append relative path to "/" if the
+ * base path had no path and an authority.
+ *
+ * However, that specification is redundant, and base paths
+ * are normalised, so file, http, and https URLs will always
+ * have a non-empty path. (Empty paths become "/".)
+ */
- } else {
+ {
/* Append relative path to all but last segment of
* base path. */
size_t path_end = lwc_string_length(
@@ -2049,24 +1522,17 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
return error;
}
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*joined == NULL) {
- return NSERROR_NOMEM;
+ error = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT,
+ sizeof(nsurl), (char **)joined, &length);
+ if (error != NSERROR_OK) {
+ return error;
}
(*joined)->components = c;
(*joined)->length = length;
- /* Fill out the url string */
- nsurl_get_string(&c, (*joined)->string, &str_len, str_flags);
-
/* Get the nsurl's hash */
- nsurl_calc_hash(*joined);
+ nsurl__calc_hash(*joined);
/* Give the URL a reference */
(*joined)->count = 1;
@@ -2074,427 +1540,3 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
return NSERROR_OK;
}
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
-{
- size_t length;
- char *pos;
-
- assert(url != NULL);
-
- /* check for source url having no fragment already */
- if (url->components.fragment == NULL) {
- *no_frag = (nsurl *)url;
-
- (*no_frag)->count++;
-
- return NSERROR_OK;
- }
-
- /* Find the change in length from url to new_url */
- length = url->length;
- if (url->components.fragment != NULL) {
- length -= 1 + lwc_string_length(url->components.fragment);
- }
-
- /* Create NetSurf URL object */
- *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*no_frag == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Copy components */
- (*no_frag)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*no_frag)->components.username =
- nsurl__component_copy(url->components.username);
- (*no_frag)->components.password =
- nsurl__component_copy(url->components.password);
- (*no_frag)->components.host =
- nsurl__component_copy(url->components.host);
- (*no_frag)->components.port =
- nsurl__component_copy(url->components.port);
- (*no_frag)->components.path =
- nsurl__component_copy(url->components.path);
- (*no_frag)->components.query =
- nsurl__component_copy(url->components.query);
- (*no_frag)->components.fragment = NULL;
-
- (*no_frag)->components.scheme_type = url->components.scheme_type;
-
- (*no_frag)->length = length;
-
- /* Fill out the url string */
- pos = (*no_frag)->string;
- memcpy(pos, url->string, length);
- pos += length;
- *pos = '\0';
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*no_frag);
-
- /* Give the URL a reference */
- (*no_frag)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
-{
- int frag_len;
- int base_len;
- char *pos;
- size_t len;
-
- assert(url != NULL);
- assert(frag != NULL);
-
- /* Find the change in length from url to new_url */
- base_len = url->length;
- if (url->components.fragment != NULL) {
- base_len -= 1 + lwc_string_length(url->components.fragment);
- }
- frag_len = lwc_string_length(frag);
-
- /* Set new_url's length */
- len = base_len + 1 /* # */ + frag_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, base_len);
- pos += base_len;
- *pos = '#';
- memcpy(++pos, lwc_string_data(frag), frag_len);
- pos += frag_len;
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path =
- nsurl__component_copy(url->components.path);
- (*new_url)->components.query =
- nsurl__component_copy(url->components.query);
- (*new_url)->components.fragment =
- lwc_string_ref(frag);
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_replace_query(const nsurl *url, const char *query,
- nsurl **new_url)
-{
- int query_len; /* Length of new query string, including '?' */
- int frag_len = 0; /* Length of fragment, including '#' */
- int base_len; /* Length of URL up to start of query */
- char *pos;
- size_t len;
- lwc_string *lwc_query;
-
- assert(url != NULL);
- assert(query != NULL);
- assert(query[0] == '?');
-
- /* Get the length of the new query */
- query_len = strlen(query);
-
- /* Find the change in length from url to new_url */
- base_len = url->length;
- if (url->components.query != NULL) {
- base_len -= lwc_string_length(url->components.query);
- }
- if (url->components.fragment != NULL) {
- frag_len = 1 + lwc_string_length(url->components.fragment);
- base_len -= frag_len;
- }
-
- /* Set new_url's length */
- len = base_len + query_len + frag_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
- free(*new_url);
- return NSERROR_NOMEM;
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, base_len);
- pos += base_len;
- memcpy(pos, query, query_len);
- pos += query_len;
- if (url->components.fragment != NULL) {
- const char *frag = lwc_string_data(url->components.fragment);
- *pos = '#';
- memcpy(++pos, frag, frag_len - 1);
- pos += frag_len - 1;
- }
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path =
- nsurl__component_copy(url->components.path);
- (*new_url)->components.query = lwc_query;
- (*new_url)->components.fragment =
- nsurl__component_copy(url->components.fragment);
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface documented in utils/nsurl.h */
-nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
-{
- const char *data;
- size_t len;
- size_t pos;
- bool match;
- char *name;
-
- assert(url != NULL);
-
- *result = 0;
-
- /* extract the last component of the path, if possible */
- if ((url->components.path != NULL) &&
- (lwc_string_length(url->components.path) != 0) &&
- (lwc_string_isequal(url->components.path,
- corestring_lwc_slash_, &match) == lwc_error_ok) &&
- (match == false)) {
- bool first = true;
- bool keep_looking;
-
- /* Get hold of the string data we're examining */
- data = lwc_string_data(url->components.path);
- len = lwc_string_length(url->components.path);
- pos = len;
-
- do {
- keep_looking = false;
- pos--;
-
- /* Find last '/' with stuff after it */
- while (pos != 0) {
- if (data[pos] == '/' && pos < len - 1) {
- break;
- }
- pos--;
- }
-
- if (pos == 0) {
- break;
- }
-
- if (first) {
- if (strncasecmp("/default.", data + pos,
- SLEN("/default.")) == 0) {
- keep_looking = true;
-
- } else if (strncasecmp("/index.",
- data + pos,
- 6) == 0) {
- keep_looking = true;
-
- }
- first = false;
- }
-
- } while (keep_looking);
-
- if (data[pos] == '/')
- pos++;
-
- if (strncasecmp("default.", data + pos, 8) != 0 &&
- strncasecmp("index.", data + pos, 6) != 0) {
- size_t end = pos;
- while (data[end] != '\0' && data[end] != '/') {
- end++;
- }
- if (end - pos != 0) {
- name = malloc(end - pos + 1);
- if (name == NULL) {
- return NSERROR_NOMEM;
- }
- memcpy(name, data + pos, end - pos);
- name[end - pos] = '\0';
- if (remove_extensions) {
- /* strip any extenstion */
- char *dot = strchr(name, '.');
- if (dot && dot != name) {
- *dot = '\0';
- }
- }
- *result = name;
- return NSERROR_OK;
- }
- }
- }
-
- if (url->components.host != NULL) {
- name = strdup(lwc_string_data(url->components.host));
-
- for (pos = 0; name[pos] != '\0'; pos++) {
- if (name[pos] == '.') {
- name[pos] = '_';
- }
- }
-
- *result = name;
- return NSERROR_OK;
- }
-
- return NSERROR_NOT_FOUND;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_parent(const nsurl *url, nsurl **new_url)
-{
- lwc_string *lwc_path;
- size_t old_path_len, new_path_len;
- size_t len;
- const char* path = NULL;
- char *pos;
-
- assert(url != NULL);
-
- old_path_len = (url->components.path == NULL) ? 0 :
- lwc_string_length(url->components.path);
-
- /* Find new path length */
- if (old_path_len == 0) {
- new_path_len = old_path_len;
- } else {
- path = lwc_string_data(url->components.path);
-
- new_path_len = old_path_len;
- if (old_path_len > 1) {
- /* Skip over any trailing / */
- if (path[new_path_len - 1] == '/')
- new_path_len--;
-
- /* Work back to next / */
- while (new_path_len > 0 &&
- path[new_path_len - 1] != '/')
- new_path_len--;
- }
- }
-
- /* Find the length of new_url */
- len = url->length;
- if (url->components.query != NULL) {
- len -= lwc_string_length(url->components.query);
- }
- if (url->components.fragment != NULL) {
- len -= 1; /* # */
- len -= lwc_string_length(url->components.fragment);
- }
- len -= old_path_len - new_path_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Make new path */
- if (old_path_len == 0) {
- lwc_path = NULL;
- } else if (old_path_len == new_path_len) {
- lwc_path = lwc_string_ref(url->components.path);
- } else {
- if (lwc_intern_string(path, old_path_len - new_path_len,
- &lwc_path) != lwc_error_ok) {
- free(*new_url);
- return NSERROR_NOMEM;
- }
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, len);
- pos += len;
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path = lwc_path;
- (*new_url)->components.query = NULL;
- (*new_url)->components.fragment = NULL;
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
new file mode 100644
index 000000000..bc6737cd6
--- /dev/null
+++ b/utils/nsurl/private.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2011-2017 Michael Drake <tlsa@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_UTILS_NSURL_PRIVATE_H_
+#define NETSURF_UTILS_NSURL_PRIVATE_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+
+
+/* Define to enable NSURL debugging */
+#undef NSURL_DEBUG
+
+
+/** A type for URL schemes */
+enum nsurl_scheme_type {
+ NSURL_SCHEME_OTHER,
+ NSURL_SCHEME_HTTP,
+ NSURL_SCHEME_HTTPS,
+ NSURL_SCHEME_FILE,
+ NSURL_SCHEME_FTP,
+ NSURL_SCHEME_MAILTO
+};
+
+
+/**
+ * nsurl components
+ *
+ * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
+ *
+ * Note:
+ * "path" string includes preceding '/', if needed for the scheme
+ * "query" string always includes preceding '?'
+ *
+ * The other spanned punctuation is to be inserted when building URLs from
+ * components.
+ */
+struct nsurl_components {
+ lwc_string *scheme;
+ lwc_string *username;
+ lwc_string *password;
+ lwc_string *host;
+ lwc_string *port;
+ lwc_string *path;
+ lwc_string *query;
+ lwc_string *fragment;
+
+ enum nsurl_scheme_type scheme_type;
+};
+
+
+/**
+ * NetSurf URL object
+ */
+struct nsurl {
+ struct nsurl_components components;
+
+ int count; /* Number of references to NetSurf URL object */
+ uint32_t hash; /* Hash value for nsurl identification */
+
+ size_t length; /* Length of string */
+ char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
+};
+
+
+/** Marker set, indicating positions of sections within a URL string */
+struct nsurl_component_lengths {
+ size_t scheme;
+ size_t username;
+ size_t password;
+ size_t host;
+ size_t port;
+ size_t path;
+ size_t query;
+ size_t fragment;
+};
+
+
+/** Flags indicating which parts of a URL string are required for a nsurl */
+enum nsurl_string_flags {
+ NSURL_F_SCHEME = (1 << 0),
+ NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
+ NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
+ NSURL_F_USERNAME = (1 << 3),
+ NSURL_F_PASSWORD = (1 << 4),
+ NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
+ NSURL_F_HOST = (1 << 6),
+ NSURL_F_PORT = (1 << 7),
+ NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
+ NSURL_F_PASSWORD |
+ NSURL_F_HOST |
+ NSURL_F_PORT),
+ NSURL_F_PATH = (1 << 8),
+ NSURL_F_QUERY = (1 << 9),
+ NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
+ NSURL_F_FRAGMENT = (1 << 11)
+};
+
+/**
+ * NULL-safe lwc_string_ref
+ */
+#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
+
+
+/**
+ * Convert a set of nsurl components to a single string
+ *
+ * \param[in] components The URL components to stitch together.
+ * \param[in] parts The set of parts wanted in the string.
+ * \param[in] pre_padding Amount in bytes to pad the start of the string by.
+ * \param[out] url_s_out Returns allocated URL string.
+ * \param[out] url_l_out Returns byte length of string, excluding pre_padding.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+nserror nsurl__components_to_string(
+ const struct nsurl_components *components,
+ nsurl_component parts, size_t pre_padding,
+ char **url_s_out, size_t *url_l_out);
+
+/**
+ * Calculate hash value
+ *
+ * \param url NetSurf URL object to set hash value for
+ */
+void nsurl__calc_hash(nsurl *url);
+
+
+
+
+/**
+ * Destroy components
+ *
+ * \param c url components
+ */
+static inline void nsurl__components_destroy(struct nsurl_components *c)
+{
+ if (c->scheme)
+ lwc_string_unref(c->scheme);
+
+ if (c->username)
+ lwc_string_unref(c->username);
+
+ if (c->password)
+ lwc_string_unref(c->password);
+
+ if (c->host)
+ lwc_string_unref(c->host);
+
+ if (c->port)
+ lwc_string_unref(c->port);
+
+ if (c->path)
+ lwc_string_unref(c->path);
+
+ if (c->query)
+ lwc_string_unref(c->query);
+
+ if (c->fragment)
+ lwc_string_unref(c->fragment);
+}
+
+
+
+#ifdef NSURL_DEBUG
+/**
+ * Dump a NetSurf URL's internal components
+ *
+ * \param url The NetSurf URL to dump components of
+ */
+static inline void nsurl__dump(const nsurl *url)
+{
+ if (url->components.scheme)
+ NSLOG(netsurf, INFO,netsurf, INFO,
+ " Scheme: %s",
+ lwc_string_data(url->components.scheme));
+
+ if (url->components.username)
+ NSLOG(netsurf, INFO,
+ "Username: %s",
+ lwc_string_data(url->components.username));
+
+ if (url->components.password)
+ NSLOG(netsurf, INFO,
+ "Password: %s",
+ lwc_string_data(url->components.password));
+
+ if (url->components.host)
+ NSLOG(netsurf, INFO,
+ " Host: %s",
+ lwc_string_data(url->components.host));
+
+ if (url->components.port)
+ NSLOG(netsurf, INFO,
+ " Port: %s",
+ lwc_string_data(url->components.port));
+
+ if (url->components.path)
+ NSLOG(netsurf, INFO,
+ " Path: %s",
+ lwc_string_data(url->components.path));
+
+ if (url->components.query)
+ NSLOG(netsurf, INFO,
+ " Query: %s",
+ lwc_string_data(url->components.query));
+
+ if (url->components.fragment)
+ NSLOG(netsurf, INFO,
+ "Fragment: %s",
+ lwc_string_data(url->components.fragment));
+}
+#endif
+
+
+#endif
diff --git a/utils/split-messages.pl b/utils/split-messages.pl
index 570ae03ca..4b50dded8 100644
--- a/utils/split-messages.pl
+++ b/utils/split-messages.pl
@@ -34,6 +34,8 @@ use strict;
use Getopt::Long ();
use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_APPEND O_RDONLY O_WRONLY );
+use IO::Compress::Gzip;
+
use constant GETOPT_OPTS => qw( auto_abbrev no_getopt_compat bundling );
use constant GETOPT_SPEC =>
qw( output|o=s
@@ -43,6 +45,7 @@ use constant GETOPT_SPEC =>
plat|platform|p=s
format|fmt|f=s
warning|W=s
+ gzip|z
help|h|? );
# default option values:
@@ -214,7 +217,7 @@ sub input_stream ()
return \*STDIN;
}
-sub output_stream ()
+sub underlying_output_stream ()
{
if( $opt{output} )
{
@@ -229,6 +232,18 @@ sub output_stream ()
return \*STDOUT;
}
+sub output_stream ()
+{
+ my $ofh = underlying_output_stream();
+
+ if( $opt{gzip} )
+ {
+ $ofh = new IO::Compress::Gzip( $ofh, AutoClose => 1, -Level => 9 );
+ }
+
+ return $ofh;
+}
+
sub formatter ()
{
my $name = $opt{format};
diff --git a/utils/useragent.c b/utils/useragent.c
index 72e45aada..b528dce4f 100644
--- a/utils/useragent.c
+++ b/utils/useragent.c
@@ -65,7 +65,8 @@ user_agent_build_string(void)
core_user_agent_string = ua_string;
- LOG("Built user agent \"%s\"", core_user_agent_string);
+ NSLOG(netsurf, INFO, "Built user agent \"%s\"",
+ core_user_agent_string);
}
/* This is a function so that later we can override it trivially */
diff --git a/utils/utf8.c b/utils/utf8.c
index 5c930cd13..f0ac0c9b2 100644
--- a/utils/utf8.c
+++ b/utils/utf8.c
@@ -468,7 +468,8 @@ bool utf8_save_text(const char *utf8_text, const char *path)
ret = guit->utf8->utf8_to_local(utf8_text, strlen(utf8_text), &conv);
if (ret != NSERROR_OK) {
- LOG("failed to convert to local encoding, return %d", ret);
+ NSLOG(netsurf, INFO,
+ "failed to convert to local encoding, return %d", ret);
return false;
}
@@ -476,7 +477,7 @@ bool utf8_save_text(const char *utf8_text, const char *path)
if (out) {
int res = fputs(conv, out);
if (res < 0) {
- LOG("Warning: writing data failed");
+ NSLOG(netsurf, INFO, "Warning: writing data failed");
}
res = fputs("\n", out);